Bagaimana cara kerja indeks MySQL?


402

Saya benar-benar tertarik dengan cara kerja indeks MySQL, lebih khusus lagi, bagaimana mereka mengembalikan data yang diminta tanpa memindai seluruh tabel?

Itu di luar topik, saya tahu, tetapi jika ada seseorang yang bisa menjelaskan hal ini kepada saya secara terperinci, saya akan sangat, sangat berterima kasih.



Ini pertanyaan yang sangat luas. Jika Anda memiliki contoh spesifik kueri yang tidak akan menggunakan indeks, dan Anda tidak tahu mengapa, Anda bisa mempostingnya dan orang-orang mungkin membantu.
Hammerite

SELECT * FROM members WHERE id = '1'- jadi mengapa dengan indeks berfungsi lebih cepat? Apa yang dilakukan indeks di sini?
good_evening

2
Itu tampak seperti kueri yang hanya mencari catatan tertentu yang diindeks (mungkin diidentifikasi oleh kunci primer). Indeks membuat ini lebih cepat karena disimpan dalam memori, baris indeks yang sesuai dapat dilihat dan berisi pointer ke tempat data aktual disimpan. Jadi MySQL dapat pergi ke lokasi yang tepat di tabel tanpa harus memindai tabel.
Hammerite

Baik sekali terima kasih!
Lightness Races in Orbit

Jawaban:


513

Pada dasarnya indeks di atas meja berfungsi seperti indeks dalam sebuah buku (dari situlah nama itu berasal):

Katakanlah Anda memiliki buku tentang basis data dan Anda ingin mencari beberapa informasi tentang, katakanlah, penyimpanan. Tanpa indeks (dengan asumsi tidak ada bantuan lain, seperti daftar isi) Anda harus melewati halaman satu per satu, sampai Anda menemukan topik (itu a full table scan). Di sisi lain, indeks memiliki daftar kata kunci, sehingga Anda akan berkonsultasi dengan indeks dan melihat yang storagedisebutkan pada halaman 113-120.231 dan 354. Kemudian Anda dapat membalik ke halaman tersebut secara langsung, tanpa mencari (itu pencarian dengan indeks, agak lebih cepat).

Tentu saja, seberapa berguna indeks itu, tergantung pada banyak hal - beberapa contoh, menggunakan perumpamaan di atas:

  • jika Anda memiliki buku tentang database dan mengindeks kata "database", Anda akan melihat bahwa itu disebutkan di halaman 1-59,61-290, dan 292 hingga 400. Dalam kasus seperti itu, indeksnya tidak banyak membantu dan mungkin lebih cepat untuk menelusuri halaman satu per satu (dalam database, ini adalah "selektivitas yang buruk").
  • Untuk buku 10 halaman, tidak masuk akal untuk membuat indeks, karena Anda mungkin berakhir dengan buku 10 halaman yang diawali oleh indeks 5 halaman, yang konyol - cukup pindai 10 halaman dan lakukan dengan itu .
  • Indeks juga perlu berguna - umumnya tidak ada titik untuk diindeks misalnya frekuensi huruf "L" per halaman.

3
Anda menjelaskan apa itu, bukan bagaimana cara kerjanya secara internal.
Tutu Kumari

@Tutu Kumari: Lihat revisi pertanyaan; silakan juga merevisi jawaban agar sesuai dengan pertanyaan saat ini (perhatikan berbagai mesin dan tipe indeks - lihat misalnya dokumentasi di sini: dev.mysql.com/doc/refman/8.0/id/index-btree-hash.html )
Piskvor meninggalkan gedung

259

Hal pertama yang harus Anda ketahui adalah bahwa indeks adalah cara untuk menghindari pemindaian tabel lengkap untuk mendapatkan hasil yang Anda cari.

Ada berbagai jenis indeks dan mereka diterapkan di lapisan penyimpanan, jadi tidak ada standar di antara mereka dan mereka juga bergantung pada mesin penyimpanan yang Anda gunakan.

InnoDB dan indeks B + Tree

Untuk InnoDB, tipe indeks yang paling umum adalah indeks berbasis B + Tree, yang menyimpan elemen dalam urutan diurutkan. Selain itu, Anda tidak harus mengakses tabel sebenarnya untuk mendapatkan nilai yang diindeks, yang membuat kueri Anda kembali dengan cara yang lebih cepat.

"Masalah" tentang tipe indeks ini adalah Anda harus meminta nilai paling kiri untuk menggunakan indeks. Jadi, jika indeks Anda memiliki dua kolom, ucapkan last_name dan first_name, urutan yang Anda query bidang ini sangat penting .

Jadi, diberikan tabel berikut:

CREATE TABLE person (
    last_name VARCHAR(50) NOT NULL,
    first_name VARCHAR(50) NOT NULL,
    INDEX (last_name, first_name)
);

Kueri ini akan memanfaatkan indeks:

SELECT last_name, first_name FROM person
WHERE last_name = "John" AND first_name LIKE "J%"

Tapi yang berikut tidak mau

SELECT last_name, first_name FROM person WHERE first_name = "Constantine"

Karena Anda menanyakan first_namekolom terlebih dahulu dan itu bukan kolom paling kiri dalam indeks.

Contoh terakhir ini bahkan lebih buruk:

SELECT last_name, first_name FROM person WHERE first_name LIKE "%Constantine"

Karena sekarang, Anda membandingkan bagian paling kanan dari bidang paling kanan dalam indeks.

Indeks hash

Ini adalah tipe indeks berbeda yang sayangnya, hanya dukungan backend memori. Ini kilat cepat tetapi hanya berguna untuk pencarian penuh, yang berarti Anda tidak dapat menggunakannya untuk operasi seperti >, <atau LIKE.

Karena ini hanya berfungsi untuk backend memori, Anda mungkin tidak akan sering menggunakannya. Kasus utama yang dapat saya pikirkan saat ini adalah yang Anda buat tabel sementara di memori dengan satu set hasil dari pilih lain dan melakukan banyak pilihan lain dalam tabel sementara ini menggunakan indeks hash.

Jika Anda memiliki VARCHARbidang besar , Anda dapat "meniru" penggunaan indeks hash saat menggunakan B-Tree, dengan membuat kolom lain dan menyimpan hash dari nilai besar di atasnya. Katakanlah Anda menyimpan url di bidang dan nilainya cukup besar. Anda juga bisa membuat bidang bilangan bulat yang disebut url_hashdan menggunakan fungsi hash seperti CRC32atau fungsi hash lainnya untuk meng-hash url saat memasukkannya. Dan kemudian, ketika Anda perlu menanyakan nilai ini, Anda bisa melakukan sesuatu seperti ini:

SELECT url FROM url_table WHERE url_hash=CRC32("http://gnu.org");

Masalah dengan contoh di atas adalah bahwa karena CRC32fungsi menghasilkan hash yang cukup kecil, Anda akan berakhir dengan banyak tabrakan dalam nilai hash. Jika Anda membutuhkan nilai yang tepat, Anda dapat memperbaiki masalah ini dengan melakukan hal berikut:

SELECT url FROM url_table 
WHERE url_hash=CRC32("http://gnu.org") AND url="http://gnu.org";

Ini masih layak untuk hash hal bahkan jika angka tumbukan tinggi karena Anda hanya akan melakukan perbandingan kedua (string satu) terhadap hash yang diulang.

Sayangnya, menggunakan teknik ini, Anda masih perlu menekan tabel untuk membandingkan urlbidang.

Bungkus

Beberapa fakta yang dapat Anda pertimbangkan setiap kali Anda ingin berbicara tentang pengoptimalan:

  1. Perbandingan integer jauh lebih cepat daripada perbandingan string. Ini dapat diilustrasikan dengan contoh tentang persaingan indeks hash di InnoDB.

  2. Mungkin, menambahkan langkah-langkah tambahan dalam suatu proses membuatnya lebih cepat, bukan lebih lambat. Itu dapat diilustrasikan oleh fakta bahwa Anda dapat mengoptimalkan a SELECTdengan membaginya menjadi dua langkah, membuat yang pertama menyimpan nilai dalam tabel di-memori yang baru dibuat, dan kemudian menjalankan kueri yang lebih berat di tabel kedua ini.

MySQL memiliki indeks lain juga, tapi saya pikir B + Tree adalah yang paling banyak digunakan dan hash adalah hal yang baik untuk diketahui, tetapi Anda dapat menemukan yang lain di dokumentasi MySQL .

Saya sangat menyarankan Anda untuk membaca buku "MySQL Kinerja Tinggi", jawaban di atas pasti didasarkan pada bab tentang indeks.


2
Akankah pertanyaan berikut memiliki kelebihan dalam kasus di atas? 1. SELECT last_name, first_name FROM person WHERE last_name= "Constantine" 2.SELECT last_name, first_name FROM person WHERE last_name LIKE "%Constantine"
Akshay Taru

1
Querry pertama akan, permintaan kedua tidak akan. Gunakan EXPLAIN: dev.mysql.com/doc/refman/5.5/en/explain.html Untuk mengindeks kueri kedua dengan MySQL, Anda harus menggunakan INDEX FULLTEXT: dev.mysql.com/doc/refman/5.5/en/fulltext- search.html
Emilio Nicolás

5
Saya menaikkan peringkat Anda karena Anda berada di 127 dan jawaban # 1 adalah 256. Saya tidak bisa menghindari membuat semuanya bagus dan bersih, dari segi biner.
pbarney

Ini adalah informasi baru bagi saya "agar Anda banyak menanyakan bidang ini." Terima kasih.
Khatri

1
@barney setelah tiga tahun mereka masing-masing hampir 256 dan 512, itulah yang saya sebut peningkatan biner-bijaksana!
nanocv

43

Pada dasarnya indeks adalah peta dari semua kunci Anda yang diurutkan secara berurutan. Dengan daftar secara berurutan, maka alih-alih memeriksa setiap kunci, ia dapat melakukan sesuatu seperti ini:

1: Masuk ke tengah daftar - lebih tinggi atau lebih rendah dari yang saya cari?

2: Jika lebih tinggi, pergi ke titik setengah antara tengah dan bawah, jika lebih rendah, tengah dan atas

3: Apakah lebih tinggi atau lebih rendah? Lompat ke titik tengah lagi, dll.

Dengan menggunakan logika itu, Anda dapat menemukan elemen dalam daftar yang diurutkan dalam sekitar 7 langkah, alih-alih memeriksa setiap item.

Jelas ada kompleksitas, tetapi itu memberi Anda ide dasar.


29
Ini disebut pencarian biner.
ddlshack

Terima kasih, akhirnya jawaban yang menjelaskan mengapa lebih cepat dan bukan hanya bagaimana db berfungsi dengan indeks.
Gershon Herczeg

Jumlah langkah aktual sangat tergantung pada data - jumlah nilai unik dan distribusi di seluruh rentang Anda. 7 adalah maksimum teoritis untuk 100 nilai. Diskusi lengkap tentang cara menghitung jumlah langkah di sini stackoverflow.com/questions/10571170/...
Joshua

Indeks MySQL yang paling umum adalah B + Tree yang bekerja mirip dengan pencarian biner tetapi tidak persis sama. Kompleksitas algoritmiknya sama tetapi cara pencariannya tidak. Lihat en.wikipedia.org/wiki/B-tree
Matt

4

Lihatlah tautan ini: http://dev.mysql.com/doc/refman/5.0/id/mysql-indexes.html

Cara kerjanya terlalu luas untuk dibahas dalam satu pos SO.

Berikut adalah salah satu penjelasan terbaik dari indeks yang saya lihat. Sayangnya itu untuk SQL Server dan bukan MySQL. Saya tidak yakin seberapa mirip keduanya ...


2
Artikel yang bagus. Saya tidak tahu SQL Server, tetapi cara kerjanya terlihat sangat mirip. (metanote: menonaktifkan gaya CSS di artikel yang ditautkan ke-2 menyembunyikan konten)
Piskvor meninggalkan gedung

3

Lihat video ini untuk detail lebih lanjut tentang Pengindeksan

Pengindeksan Sederhana Anda dapat membuat indeks unik di atas meja. Indeks unik berarti bahwa dua baris tidak dapat memiliki nilai indeks yang sama. Berikut adalah sintaks untuk membuat Indeks di atas meja

CREATE UNIQUE INDEX index_name
ON table_name ( column1, column2,...);

Anda dapat menggunakan satu atau beberapa kolom untuk membuat indeks. Misalnya, kita dapat membuat indekstutorials_tbl menggunakan tutorial_author.

CREATE UNIQUE INDEX AUTHOR_INDEX
ON tutorials_tbl (tutorial_author)

Anda dapat membuat indeks sederhana di atas sebuah tabel. Hapus saja kata kunci UNIK dari kueri untuk membuat indeks sederhana. Indeks sederhana memungkinkan nilai duplikat dalam sebuah tabel.

Jika Anda ingin mengindeks nilai dalam kolom dalam urutan menurun, Anda bisa menambahkan kata DESC yang dicadangkan setelah nama kolom.

mysql> CREATE UNIQUE INDEX AUTHOR_INDEX
ON tutorials_tbl (tutorial_author DESC)

1
Selamat Datang di Stack Overflow! Saya mencatat bahwa semua jawaban Anda terhubung ke video Anda sendiri. Harap dicatat bahwa promosi diri terbuka tidak diperbolehkan .
SL Barth - Reinstate Monica

Dia ingin mempromosikan videonya. LOL
Ilyas karim

1

Saya ingin menambahkan 2 sen saya. Saya jauh dari menjadi ahli basis data, tetapi saya baru saja membaca sedikit tentang topik ini; cukup bagi saya untuk mencoba dan memberikan ELI5. Jadi, inilah penjelasan awam.


Saya memahaminya sehingga indeks seperti cermin mini dari meja Anda, seperti array asosiatif. Jika Anda memberi makan dengan kunci yang cocok maka Anda bisa langsung melompat ke baris itu dalam satu "perintah".

Tetapi jika Anda tidak memiliki indeks / array itu, penerjemah kueri harus menggunakan for-loop untuk melewati semua baris dan memeriksa kecocokan (pemindaian tabel penuh).

Memiliki indeks memiliki "sisi buruk" penyimpanan tambahan (untuk mini-mirror itu), dengan imbalan "sisi positif" dari mencari konten lebih cepat.

Perhatikan bahwa (bergantung pada mesin db Anda) membuat kunci primer, asing atau unik secara otomatis mengatur indeks masing-masing. Prinsip yang sama itu pada dasarnya adalah mengapa dan bagaimana kunci-kunci itu bekerja.


1

Menambahkan beberapa representasi visual ke daftar jawaban. masukkan deskripsi gambar di sini

MySQL menggunakan lapisan tipuan tambahan: catatan indeks sekunder menunjuk ke catatan indeks primer, dan indeks primer itu sendiri menyimpan lokasi baris pada disk. Jika baris mengimbangi perubahan, hanya indeks utama yang perlu diperbarui.

Peringatan: Struktur data disk terlihat datar dalam diagram tetapi sebenarnya adalah pohon B +.

Sumber: tautan


1

Di MySQL InnoDB, ada dua jenis indeks.

  1. Kunci utama yang disebut indeks berkerumun. Kata kunci indeks disimpan dengan data rekam nyata dalam simpul daun Pohon B +.

  2. Kunci sekunder yang merupakan indeks non clustered. Indeks ini hanya menyimpan kata-kata kunci kunci utama bersama dengan kata-kata kunci indeks mereka sendiri dalam B + Tree leaf node. Jadi ketika mencari dari indeks sekunder, pertama-tama akan menemukan kata kunci indeks kunci utama dan memindai kunci utama B + Tree untuk menemukan catatan data nyata. Ini akan membuat indeks sekunder lebih lambat dibandingkan dengan pencarian indeks primer. Namun, jika semua selectkolom dalam indeks sekunder, maka tidak perlu mencari indeks primer B + Tree lagi. Ini disebut 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.