Praktik terbaik untuk mengikuti dengan indeks basis data [ditutup]


17

Apa sajakah DO dan DONT untuk meningkatkan kinerja database menggunakan indeks?

DO adalah kasus di mana indeks harus dibuat, atau tip terkait indeks lainnya yang akan meningkatkan kinerja.

DONT akan menjadi kasus ketika indeks tidak boleh dibuat, atau tindakan terkait indeks lain yang dapat merusak kinerja.


3
profil, profil, profil
GrandmasterB

Jawaban:


15

Ini sebagian tergantung pada apa yang akan digunakan oleh database, karena secara umum indeks memperlambat sisipan dan pembaruan serta mempercepat kueri. Di gudang data, umumnya tidak ada pembaruan dan sisipan batch, membuatnya lebih mudah untuk membuat indeks, dan banyak dan banyak pertanyaan, yang dipercepat dengan banyak indeks. Dalam database online untuk penjualan web dan sejenisnya, ada banyak sisipan dan pembaruan, sehingga memiliki lebih dari beberapa indeks yang dipilih dengan hati-hati hanya akan memperlambatnya.

Jika Anda mendapatkan banyak kueri dari satu jenis tertentu, Anda bisa membuat indeks untuk kueri, meskipun itu lebih untuk pemrosesan online daripada gudang data. Jika kolom tertentu muncul banyak dalam kueri, Anda mungkin ingin indeks pada kolom itu, dan ini sangat berguna untuk gudang data, yang mendapatkan pertanyaan dalam banyak cara yang berbeda dan seringkali tidak dapat diprediksi.

Setiap kali Anda menambah atau menghapus indeks, cobalah melakukan tes kinerja untuk melihat apa efeknya. Tanpa itu, Anda menembak buta.

Ada buku tentang pencarian tuning dan basis data, seringkali khusus untuk satu sistem basis data dan menggunakan alat RDBMS itu. Namun, jika Anda perlu mengoptimalkan basis data banyak, Anda menjalankan operasi besar dan mungkin harus menyewa DBA dengan keahlian yang sesuai.


17

Ini sangat tergantung pada bagaimana Anda menggunakan tabel Anda. Tidak ada jawaban tunggal dan sederhana.

Saran terbaik yang bisa saya berikan adalah: gunakan penasihat tuning . Mereka akan menganalisis perintah basis data saat Anda menggunakan aplikasi, kemudian mereka akan melakukan tes beban untuk memberikan Anda saran yang berarti.

Mereka ada untuk SQL Server & Oracle . Saya tidak tahu apakah DBMS lain memilikinya, hanya saja saya ragu mereka tidak menyediakan alat dasar seperti itu.

Beberapa rekomendasi acak:

  • Indeks memberikan keuntungan kinerja tinggi ketika diterapkan pada kolom yang sering dimasukkan dalam klausa WHERE
  • Gunakan indeks Clustered untuk kolom yang paling sering digunakan dalam permintaan Anda.
  • Jangan lupa bahwa Anda dapat membuat beberapa indeks dengan kombinasi kolom (seperti yang digunakan dalam permintaan Anda)
  • Memiliki banyak indeks akan menurunkan kinerja perintah INSERT.

Saran terakhir : jika pertunjukan DB benar-benar penting untuk proyek Anda, pekerjakan spesialis. Itu yang saya lakukan.


2
+1 untuk indeks pada kombinasi kolom. Indeks pada kolom adan badalah tidak sama dengan indeks pada (a, b). Yang terakhir ini hampir sama baiknya dengan indeks aktif auntuk mempercepat kueri dengan kondisi aktif a, jauh lebih baik untuk kueri dengan kondisi adan b, dan tidak berguna untuk kueri bsendirian. (Sebagian besar basis data tidak akan menggunakannya. Oracle akan melakukannya, tetapi tidak mendapatkan jarak tempuh seperti yang seharusnya).
btilly

2
+1, akan menambahkan "belajar membaca rencana kueri sehingga Anda akan tahu apa yang akan diindeks"
Steven A. Lowe

4

@Pierre 303 sudah mengatakannya, tapi aku akan mengatakannya lagi. DO menggunakan indeks pada kombinasi kolom. Indeks gabungan aktif (a, b)hanya sedikit lebih lambat untuk kueri adaripada indeks asendirian, dan secara besar-besaran lebih baik jika kueri Anda menggabungkan kedua kolom. Beberapa database dapat bergabung indeks pada adan bsebelum memukul meja, tapi ini tidak sebagus memiliki indeks gabungan. Saat Anda membuat indeks gabungan, Anda harus meletakkan kolom yang paling mungkin dicari pertama kali dalam indeks gabungan.

Jika database Anda mendukungnya, DO menempatkan indeks pada fungsi yang muncul dalam permintaan daripada kolom. (Jika Anda memanggil fungsi pada kolom, indeks pada kolom itu tidak berguna.)

Jika Anda menggunakan database dengan tabel sementara benar yang dapat Anda buat dan hancurkan dengan cepat (mis. PostgreSQL, MySQL, tetapi bukan Oracle), maka LAKUKAN membuat indeks pada tabel sementara.

Jika Anda menggunakan database yang memungkinkannya (misalnya Oracle), DO mengunci rencana kueri yang baik. Pengoptimal permintaan dari waktu ke waktu akan mengubah rencana kueri. Mereka biasanya memperbaiki rencana. Tetapi kadang-kadang mereka membuatnya secara dramatis lebih buruk. Anda biasanya tidak akan benar-benar melihat peningkatan rencana - kueri itu bukan hambatan. Tetapi satu rencana buruk dapat menghapus situs yang sibuk.

JANGAN memiliki indeks pada tabel yang akan Anda lakukan memuat data besar. Jauh lebih cepat untuk menjatuhkan indeks, memuat data, lalu membangun kembali indeks daripada mempertahankannya saat Anda memuat tabel.

JANGAN gunakan indeks pada kueri yang harus mengakses lebih dari sebagian kecil dari tabel besar. (Betapa kecilnya tergantung pada perangkat keras. 5% adalah aturan praktis yang layak.) Misalnya, jika Anda memiliki data dengan nama dan jenis kelamin, nama adalah kandidat yang baik untuk pengindeksan karena nama yang diberikan mewakili sebagian kecil dari total baris. Mengindeks gender tidak akan membantu karena Anda masih harus mengakses 50% dari baris. Anda benar-benar ingin menggunakan pemindaian tabel penuh sebagai gantinya. Alasannya adalah bahwa indeks akhirnya mengakses file besar secara acak, menyebabkan Anda perlu mencari disk. Disk berusaha lambat. Sebagai contoh, saya baru-baru ini berhasil mempercepat permintaan selama satu jam yang terlihat seperti:

SELECT small_table.id, SUM(big_table.some_value)
FROM small_table
  JOIN big_table
    ON big_table.small_table_id = small_table.id
GROUP BY small_table.id

di bawah 3 menit dengan menulis ulang sebagai berikut:

SELECT small_table.id, big_table_summary.summed_value
FROM small_table
  JOIN (
      SELECT small_table_id, SUM(some_value) as summed_value
      FROM big_table
      GROUP BY small_table_id
    ) big_table_summary
    ON big_table_summary.small_table_id =  small_table.id

yang memaksa database untuk memahami bahwa seharusnya tidak mencoba menggunakan indeks menggoda big_table.small_table_id. (Basis data yang bagus, seperti Oracle, harus mencari tahu sendiri. Kueri ini berjalan di MySQL.)

Pembaruan: Berikut adalah penjelasan tentang titik pencarian disk yang saya buat. Indeks memberikan pencarian cepat untuk mengatakan di mana data berada di tabel. Ini biasanya menang karena Anda hanya akan melihat data yang perlu Anda lihat. Tetapi tidak selalu, terutama jika Anda pada akhirnya akan melihat banyak data. Disk mengalirkan data dengan baik, tetapi membuat pencarian menjadi lambat. Pencarian acak ke data pada disk membutuhkan 1/200 detik. Versi lambat dari query akhirnya melakukan sesuatu seperti 600.000 dari mereka dan butuh hampir satu jam. (Itu melakukan lebih banyak pencarian daripada itu, tetapi caching menangkap beberapa di antaranya.) Sebaliknya versi cepat tahu itu harus membaca semuanya dan mengalirkan data sekitar 70 MB / detik. Itu bisa melewati meja 11 GB dalam waktu kurang dari 3 menit.


Hai, saya bingung dengan contoh Anda. Saya akan berpikir bahwa menggunakan indeks akan membuat segalanya lebih cepat, bukankah itu titik indeks? Apakah Anda mengatakan bahwa jika kueri akan mengakses> 5% dari sebuah tabel, maka memiliki indeks pada kolom yang Anda cari akan membuat segalanya lebih lambat?
Klik Upvote

@Klik Upvote: Jika kueri mengakses lebih dari 5% (fraksi persis yang sangat bergantung pada perangkat keras dan data) dari sebuah tabel, lebih cepat tidak menggunakan indeks untuk kueri itu. Memiliki indeks tidak sakit selama Anda tidak menggunakannya. Saya akan memperbarui dengan lebih detail mengapa itu terjadi.
btilly

Informasi berguna. Lebih lanjut tentang ini misalnya mysqlperformanceblog.com/2007/08/28/... Tapi saya bertanya-tanya, apakah 'abaikan kunci' tidak sampai seperti ini sehingga Anda perlu menjadikannya subquery?
Inca

@ Inca: Saya tidak mengetahui 'kunci diabaikan'. Saya cukup beralih database sehingga sering ada hal-hal khusus database yang saya tidak sadari. Dari suara itu yang akan bekerja, tetapi secara signifikan kurang efisien daripada solusi akhirnya saya. Perbedaannya adalah bahwa yang akan bergabung, lalu grup, sementara milikku dikelompokkan, kemudian bergabung. Ini menghemat pekerjaan pada gabungan karena lebih sedikit catatan yang perlu digabung.
btilly

"Basis data yang bagus (mis. Oracle, tetapi bukan MySQL)": tolong, hindari hal-hal promosi bodoh seperti itu, terutama ketika Anda mengabaikan fakta bahwa MySQL dapat dengan sempurna menggunakan beberapa indeks pada saat yang sama (catat "INDEX MERGE" dalam paket permintaan) .
Patrick Allaert

2

LAKUKAN: Mengindeks beberapa bidang yang paling Anda akses melalui kueri dan / atau perbandingan.

JANGAN: Buat indeks setiap bidang dalam tabel dengan berpikir itu akan membuatnya lebih cepat.

Saya tidak memiliki statistik apa pun tentangnya, tetapi saya mencoba menyimpan tidak lebih dari 4 bidang yang diindeks dalam sebuah tabel jika saya dapat membantu. Normalisasi database saya biasanya membantu menjaga angka-angka ini karena semuanya menjadi dapat dicari dengan tombol numerik (yang lebih cepat lagi). Saya mencoba untuk menjauh dari bidang teks lengkap untuk pengindeksan. Mereka cukup berat.


2

Pada dasarnya, indeks mempercepat pencarian tetapi memperlambat penulisan, dan mereka mengambil ruang. Itu trade-off yang dibuat.

Setiap bidang yang sering digunakan untuk bergabung, mencari / membandingkan atau memesan oleh adalah kandidat untuk indeks. Untuk mengetahui itu benar-benar buatan, ukurlah. Namun, kunci asing dari tabel yang sangat digabung dengan banyak (> 1000) catatan dan beberapa sisipan akan terbayar.

Untuk bidang teks, Anda bisa mengindeks pada bagian bidang (misalnya, 6 karakter pertama) yang akan mempercepat kueri Anda, tetapi meringankan beban indeks. Pencarian teks lengkap (search on like %substring%) membutuhkan teknik yang berbeda, yang saya tidak kenal, jadi saya tidak bisa memberi Anda saran di sana.

Situasi penting di mana indeks tidak akan membantu: Anda tidak dapat menggunakan indeks bidang tanggal atau datetime lengkap ketika Anda mencari (/ bergabung / memesan) pada bagian dari tanggal. Indeks aktif date_createdtidak akan membantu Anda dengan pertanyaan seperti select * from t where year(date_created) = 2011. Di mysql Anda tidak dapat membuat indeks pada bagian tanggal. (Bila Anda menggunakan ' between' daripada year()dapat menggunakan indeks pada field tanggal.)

Info lebih lanjut tentang MYSQL di manual: http://dev.mysql.com/doc/refman/5.6/en/optimization-indexes.html


1

DO: Cobalah untuk menjaga ukuran total indeks berkerumun ke minimum. Entri indeks berkerumun akan dimasukkan dalam indeks non-berkerumun lainnya dan dari sini muncul potensi untuk membuang ruang disk.


1

Pikirkan tabel sebagai leksikon, di mana artikel diurutkan berdasarkan urutan penampilan (atau tidak ada urutan membantu sama sekali), dan indeks tabel sebagai indeks buku untuk leksikon itu.

Anda menggunakan indeks untuk dengan cepat menemukan sesuatu di buku. Alih-alih memindai seluruh buku, Anda hanya perlu menemukan kunci dalam indeks (indeks biasanya entah bagaimana diurutkan (berdasarkan kategori, berdasarkan bidang ilmiah, oleh zaman sejarah, dll.), Ini juga berarti Anda tidak perlu memindai seluruh indeks) lalu lompat ke halaman kanan.

Tidak seperti buku, meja tidak pernah dicetak dan kemudian diubah. Itu diperbarui setiap saat, dan karena itu setiap indeks harus diperbarui dengan itu. Ini tentu saja datang pada biaya ruang dan waktu, yang hanya dapat dibenarkan oleh kegunaan indeks.

Jadi gunakan indeks untuk kolom, jika kolom itu digunakan sebagai kunci dalam permintaan pencarian yang sering, dan jangan gunakan satu, jika tidak. Kata sering adalah kuantifier sebaik yang didapat, ketika secara umum berbicara. Pada akhirnya Anda harus membuat estimasi yang baik mana yang sering, kemudian hanya melakukan benchmark kinerja dengan atau tanpa indeks jika ada keraguan.

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.