Apakah saya memerlukan indeks terpisah untuk setiap jenis kueri, atau apakah satu indeks multi-kolom akan berfungsi?

22

Saya agak tahu jawaban atas pertanyaan ini, tetapi saya selalu merasa seolah-olah ada lebih banyak yang perlu saya bahas pada topik ini.

Pemahaman dasar saya adalah bahwa secara umum, indeks tunggal yang hanya mencakup semua bidang yang Anda tanyakan / sortir pada waktu tertentu sepertinya tidak akan berguna, namun saya telah melihat hal semacam ini. Seperti dalam, seseorang berpikir, "Yah, jika kita hanya meletakkan semua hal ini dalam indeks, database dapat menggunakannya untuk menemukan apa yang dibutuhkan", tanpa pernah melihat rencana eksekusi untuk beberapa pertanyaan aktual yang sedang dijalankan.

Bayangkan sebuah tabel seperti ini:

id int pk/uid
name varchar(50)
customerId int (foreign key)
dateCreated datetime

Saya mungkin melihat indeks tunggal termasuk name, customerIddan dateCreatedbidang.

Tetapi pemahaman saya adalah bahwa indeks seperti itu tidak akan digunakan dalam permintaan seperti, misalnya:

SELECT [id], [name], [customerId], [dateCreated]
   FROM Representatives WHERE customerId=1 
   ORDER BY dateCreated

Untuk permintaan seperti itu, menurut saya ide yang lebih baik adalah indeks termasuk bidang customerIddan dateCreated, dengan customerIdbidang yang 'pertama'. Ini akan membuat indeks yang akan mengatur data sedemikian rupa sehingga permintaan ini dapat dengan cepat menemukan apa yang dibutuhkan - dalam urutan yang dibutuhkan.

Hal lain yang saya lihat, mungkin sesering yang pertama, adalah indeks individu pada setiap bidang; jadi, masing-masing aktif name, customerIddan dateCreatedbidang.

Berbeda dengan contoh pertama, jenis pengaturan ini bagi saya kadang-kadang setidaknya sebagian bermanfaat; rencana eksekusi kueri dapat menunjukkan bahwa setidaknya menggunakan indeks pada customerIduntuk memilih catatan, tapi itu tidak menggunakan indeks dengan dateCreatedbidang untuk mengurutkannya.


Saya tahu ini adalah pertanyaan luas, karena jawaban spesifik untuk setiap kueri tertentu pada set tabel tertentu biasanya untuk melihat apa yang dikatakan rencana eksekusi akan dilakukan, dan jika tidak mengambil spesifik tabel (s) dan pertanyaan ke rekening. Juga, saya tahu bahwa itu tergantung pada seberapa sering kueri dapat dijalankan sebagai lawan dari overhead mempertahankan indeks tertentu untuk itu.

Tetapi saya kira apa yang saya tanyakan adalah sebagai 'titik awal' umum untuk indeks, apakah gagasan memiliki indeks spesifik untuk kueri khusus yang sering ditarik dan bidang dalam klausa WHERE or ORDER BY masuk akal?

Andrew Barber
sumber

Jawaban:

27

Anda benar karena contoh kueri Anda tidak akan menggunakan indeks itu.

Perencana permintaan akan mempertimbangkan untuk menggunakan indeks jika:

  • semua bidang yang terkandung di dalamnya direferensikan dalam kueri
  • beberapa bidang mulai dari awal direferensikan

Itu tidak akan dapat menggunakan indeks yang dimulai dengan bidang yang tidak digunakan oleh kueri.

Jadi untuk contoh Anda:

SELECT [id], [name], [customerId], [dateCreated]
   FROM Representatives WHERE customerId=1 
   ORDER BY dateCreated

itu akan mempertimbangkan indeks seperti:

[customerId]
[customerId], [dateCreated]
[customerId], [dateCreated], [name]

tapi tidak:

[name], [customerId], [dateCreated]

Jika ditemukan keduanya [customerId]dan [customerId], [dateCreated], [name]keputusannya untuk memilih satu di atas yang lain akan tergantung pada statistik indeks yang bergantung pada perkiraan keseimbangan data di bidang. Jika [customerId], [dateCreated]didefinisikan itu harus lebih disukai daripada dua lainnya kecuali Anda memberikan petunjuk indeks spesifik untuk sebaliknya.

Tidak jarang melihat satu indeks didefinisikan untuk setiap bidang dalam pengalaman saya juga, meskipun ini jarang optimal karena manajemen tambahan yang diperlukan untuk memperbarui indeks pada saat memasukkan / memperbarui, dan ruang ekstra yang dibutuhkan untuk menyimpannya, terbuang ketika setengah dari mereka mungkin tidak pernah digunakan - tetapi kecuali jika DB Anda melihat banyak beban, kinerjanya tidak akan buruk bahkan dengan kelebihan indeks.

Indeks khusus untuk kueri yang sering muncul yang seharusnya lambat karena pemindaian tabel atau indeks umumnya merupakan ide yang baik, meskipun jangan berlebihan karena Anda dapat bertukar satu masalah kinerja dengan yang lain. Jika Anda mendefinisikan [customerId], [dateCreated]sebagai indeks, misalnya, ingatlah bahwa perencana kueri akan dapat menggunakannya untuk permintaan yang akan menggunakan indeks hanya [customerId]jika ada. Meskipun menggunakan hanya [customerId]akan sedikit lebih efisien daripada menggunakan indeks gabungan, ini dapat dikurangi dengan akhirnya memiliki dua indeks yang bersaing untuk mendapatkan ruang dalam RAM alih-alih satu (meskipun jika seluruh rangkaian kerja normal Anda dengan mudah masuk ke dalam RAM, kompetisi memori tambahan ini mungkin tidak sebuah isu).

David Spillett
sumber
+1; info hebat, terutama pengingat (yang saya cenderung lupa!) bahwa perencana dapat menggunakan indeks majemuk pada saat itu hanya membutuhkan bidang pertama (s) dari itu untuk permintaan.
Andrew Barber
6

Untuk menjawab pertanyaan awal Anda, ya, indeks harus dirancang di sekitar kueri , bukan hanya tabel . Urutan bidang dalam indeks sangat penting. Mendesain indeks tunggal agar optimal untuk beberapa kueri lebih sulit, dan Anda harus melakukan trade-off.

Mengenai poin kedua Anda, ya, banyak indeks pada satu bidang tunggal adalah hal yang sangat umum. Saya melihatnya sepanjang waktu di lingkungan saya, dan biasanya merupakan tanda merah bagi saya bahwa tim pengembangan tidak bekerja dengan DBA untuk merancang indeks yang tepat.

Strategi saya untuk merancang indeks, adalah untuk mengindeks:

  • Fields digunakan di WHERE (dalam urutan selektivitas)
  • Bidang yang digunakan dalam ORDER OLEH
  • Sertakan bidang lain (jika perlu) untuk membuat indeks penutup

Jadi untuk contoh Anda:

SELECT [id], [name], [customerId], [dateCreated]
   FROM Representatives WHERE customerId=1 
   ORDER BY dateCreated

Saya mungkin akan merancang indeks pada (ID Pelanggan, dateCreated) TERMASUK (id, nama). Indeks penutup ini berarti permintaan tidak perlu mengenai tabel asli, sangat meningkatkan kinerja.

Contoh ini hampir terlalu sederhana. Indeks naif pada just (CustomerID) akan melakukan hampir juga (dengan asumsi bahwa setiap pelanggan hanya memiliki satu rep, sehingga hanya pencarian bookmark tunggal ke tabel akan diperlukan). Bahkan mungkin bermanfaat untuk benar-benar melakukan pengelompokan indeks pada (ID Pelanggan, ID), tergantung pada pertanyaan apa yang dijalankan terhadap tabel.

BradC
sumber
+1 untuk "indeks harus dirancang di sekitar kueri, bukan hanya tabel", dan seluruh jawabannya, seperti mencatat bahwa contohnya sangat sederhana.
Andrew Barber