SQL Server: Meliputi indeks termasuk semua kolom?


9

Tim kami telah mewarisi aplikasi dan database terkait. Pengembang sebelumnya tampaknya telah memberlakukan aturan di mana setiap indeks, di setiap tabel, memiliki klausa TERMASUK untuk selalu menambahkan setiap kolom yang bukan bagian dari kunci. Tabel ini memiliki rata-rata di mana saja dari dua hingga lima indeks atau batasan unik serta kunci asing.

Maksudnya adalah untuk meningkatkan kinerja SELECT terlepas dari permintaan apa yang dilemparkan ke database, karena akses adalah melalui ORM yang secara default (tetapi tidak selalu) mengambil semua kolom. Kami berharap bahwa efek samping dari ini adalah peningkatan persyaratan penyimpanan (mungkin secara signifikan) dan waktu overhead tambahan untuk INSERT / UPDATE / DELETE.

Pertanyaannya adalah, apakah ini strategi yang masuk akal? Tim kami memiliki sejarah dengan SQL Server tetapi tidak ada anggota yang akan menganggap diri mereka ahli dalam perilaku internalnya (meskipun pertanyaan telah diajukan bahwa jika strategi ini optimal, bukankah itu akan menjadi default sekarang?). Apa efek samping lain (server database CPU / memori / penggunaan TempDB, dll) yang harus kita harapkan, atau apakah beberapa asumsi kita di atas salah?

Selain itu, aplikasi dapat diinstal ke dalam SQL Server on-premise (versi sejak 2012), serta Azure SQL - haruskah kita siap untuk perbedaan antara keduanya, atau efek samping tambahan pada Azure, sebagai akibat dari ini pendekatan?

Jawaban:


8

Saya telah melakukan ini pada indeks tertentu sebelum sekarang, untuk membantu permintaan yang sering kali dijalankan. Secara efektif apa yang telah mereka lakukan adalah membuat beberapa indeks berkerumun: ketika salah satu dari indeks tersebut digunakan untuk menemukan baris, tidak diperlukan pekerjaan tambahan untuk mencari sisa data dalam indeks berkerumun nyata (atau tumpukan jika tidak ada indeks berkerumun nyata) .

apakah ini strategi yang masuk akal?

Untuk beberapa indeks di mana diperlukan untuk mendukung pola permintaan tertentu, tentu saja ya.

Tetapi untuk melakukan ini dengan semua indeks, saya hanya akan mengatakan tidak.

Ini akan membuang-buang ruang untuk melakukan di tempat yang tidak benar-benar dibutuhkan, dan akan memperlambat sisipan / pembaruan secara signifikan. Ini mungkin memperlambat permintaan baca sebanyak yang membantu juga, karena setiap halaman indeks menyimpan lebih sedikit catatan sehingga permintaan apa pun yang perlu merujuk potongan indeks untuk difilter tetapi tidak menggunakan semua kolom lain harus mengakses lebih banyak halaman. Ini akan membuat database Anda lebih haus-memori: halaman-halaman tersebut perlu dimuat ke dalam buffer pool, berpotensi mengeluarkan halaman-halaman lain yang bermanfaat jika memori rendah. Jika kompresi digunakan pada indeks tersebut untuk mencoba mengurangi efek pada persyaratan penyimpanan dan memori, maka itu akan mendorong beban tambahan ke CPU sebagai gantinya.

karena akses adalah melalui ORM yang secara default (tetapi tidak selalu) mengambil semua kolom

Ini adalah pola umum dengan penggunaan ORM yang kurang optimal (atau hanya ORM naif) dan dalam kasus ini saya telah melihat penasihat indeks SQL Server (dan alat pihak ketiga yang serupa) menyarankan indeks dengan banyak INCLUDEkolom d, jadi saya akan setuju dengan Anda saran bahwa inilah mengapa indeks telah dibuat dengan cara ini.

Tapi sementara itu mungkin membuat semua pertanyaan seperti itu sedikit lebih cepat dan beberapa dari mereka secara signifikan lebih cepat, saya menduga bahwa dalam banyak kasus, manfaatnya sangat kecil sehingga tidak sebanding dengan jejak memori tambahan yang dibutuhkan oleh set kerja umum Anda, ruang pada disk, dan IO antara disk dan memori.

Juga ingat bahwa ORM mungkin tidak memilih semua kolom dari semua tabel yang disentuh oleh kueri, sehingga manfaat mungkin hanya berlaku untuk target utama permintaan saat ini, dan indeks yang lebih besar dapat menghukum kueri saat objek lain digunakan untuk memfilter tetapi tidak mengembalikan data ( SELECT * FROM table1 WHERE id IN (SELECT someID FROM table2 WHERE someColumn='DesiredValue')mungkin).

Pertimbangan lain untuk kelebihan ruang yang digunakan, terutama jika datanya besar, adalah bahwa hal itu akan berdampak pada strategi cadangan Anda: biaya penyimpanan dan transfer untuk cadangan tersebut, waktu pemulihan potensial, dan sebagainya.

haruskah kita bersiap untuk perbedaan antara keduanya [on-prem & AzureSQL]

Secara umum saya pikir pertimbangan di sini akan sama dalam setiap kasus, meskipun setiap kelebihan memori / biaya IO yang dikenakan oleh indeks besar mungkin lebih langsung terlihat di Azure di mana Anda dapat mengubah tingkat layanan dan karenanya biaya infrastruktur lebih mudah daripada memiliki sumber daya perangkat keras yang relatif tetap. Jika menggunakan tingkatan standar / premium alih-alih penetapan harga berbasis vcore maka Anda akan lebih terpengaruh oleh biaya IO dalam standar karena premium mencakup lebih banyak IO per DTU secara signifikan. Jika Anda menggunakan cadangan multi-wilayah atau redundansi atau fitur non-lokal lainnya di Azure daripada mungkin ada biaya bandwidth yang terkait dengan ruang ekstra yang diambil oleh indeks lebar yang tidak sempurna.


Kami melanjutkan dan melakukan penghapusan ini. Efek sampingnya adalah pada tabel tertentu, SELECTtanpa menentukan ORDER BYmulai mengembalikan baris yang sama seperti sebelumnya tetapi dengan urutan sewenang-wenang yang berbeda.
T2PS

Itu tidak terduga. Urutan hasil tanpa 'ORDER BY' menurut definisi tidak terdefinisi dan dapat berubah sewaktu-waktu perencana kueri memutuskan untuk mengambil pendekatan yang berbeda, yang dapat dilakukan sebagai hasil dari perubahan indeks atau perubahan dalam pola data Anda seiring pertumbuhannya. Faktor-faktor lain dapat membuat perubahan pemesanan di kemudian hari walaupun tanpa perubahan ini. Jika Anda mengandalkan pemesanan output pernyataan, bahkan secara dangkal, maka Anda perlu menyertakan 'ORDER BY' untuk menjaminnya.
David Spillett

Oh, tentu saja. Komentar sebelumnya lebih dimaksudkan sebagai catatan pengingat bagi siapa pun yang menemukan jawaban ini nanti.
T2PS

5

Pertanyaannya adalah, apakah ini strategi yang masuk akal? .... (meskipun pertanyaan telah diajukan bahwa jika strategi ini optimal, bukankah itu akan menjadi default sekarang?)

Dalam kebanyakan kasus ini bukan strategi yang masuk akal. Alasannya, bahwa dalam database OLTP umum, baris yang dikembalikan ke pengguna akhir tidak akan banyak. (Generalisasi)

Pertanyaan yang harus Anda tanyakan pada diri sendiri adalah, jika Anda mencari di kolom kunci, berapa banyak baris yang akan dikembalikan oleh operasi pencarian itu? Dan ulangi untuk kueri yang mencari di kolom itu.

Pertimbangkan tabel berikut, kembalikan banyak kolom, where SelectiveIDField= ...

select columnA,columnC, ... columnZ
FROM dbo.BigTable
Where SelectiveIDField= '225122141';

Jika hanya satu baris yang akan dikembalikan oleh pencarian selectiveIDField, apakah pencarian kunci tambahan adalah hal yang buruk? (menduga Anda memiliki indeks berkerumun di sini, jika tidak, cari RID)

Itu hanya akan melakukan satu pencarian kunci tambahan, satu eksekusi tambahan + operator bergabung. Bahkan jika itu 10 atau bahkan 100, apakah dampaknya akan sebesar itu? Ini juga tergantung pada seberapa banyak permintaan Anda dieksekusi dan seberapa penting waktu eksekusi.

Dalam hal itu diabaikan, cukup buat indeks SelectiveIDFielddan sebut sehari, itu tidak sepadan dengan keuntungan baca dibandingkan dengan kerugian menulis.

Jadi singkatnya, membuat indeks pada seluruh tabel seharusnya menurut saya bukan pendekatan default kecuali Anda benar-benar melihat masalah dengan kueri dan dapat memperbaikinya secara drastis dengan menambahkan seluruh indeks penutup.

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.