MySQL dizinleri nasıl çalışır?


402

MySQL dizinlerinin nasıl çalıştığıyla gerçekten ilgileniyorum, daha spesifik olarak, tüm tabloyu taramadan istenen verileri nasıl geri gönderebilirler?

Konu dışı, biliyorum, ama bunu bana ayrıntılı olarak açıklayabilecek biri varsa, çok, çok minnettar olurum.



Bu çok geniş bir soru. Dizin kullanmayan belirli bir sorgu örneğiniz varsa ve nedenini bilmiyorsanız, gönderebilirsiniz ve insanlar yardımcı olabilir.
Hammerite

SELECT * FROM members WHERE id = '1'- Peki neden endeks ile daha hızlı çalışıyor? Bu indeks burada ne yapıyor?
good_evening

2
Bu, yalnızca belirli, dizine alınmış bir kaydı (belki de birincil anahtarla tanımlanır) arayan bir sorguya benziyor. Dizin, bellekte depolandığından, karşılık gelen dizin satırına bakılabildiğinden ve gerçek verilerin depolandığı bir işaretçi içerdiğinden bunu daha hızlı hale getirir. Böylece MySQL, tabloyu taramak zorunda kalmadan tablodaki tam konuma gidebilir.
Hammerite

Çok iyi teşekkür ederim!
Yörüngedeki Hafiflik Yarışları

Yanıtlar:


513

Temel olarak bir tablodaki dizin, bir kitaptaki dizin gibi çalışır (adın geldiği yer budur):

Diyelim ki veritabanları hakkında bir kitabınız var ve depolama hakkında bazı bilgiler bulmak istiyorsunuz. Bir dizin olmadan (içindekiler tablosu gibi başka bir yardım almazsanız), konuyu bulana kadar sayfaları tek tek incelemeniz gerekir (bu a full table scan). Öte yandan, bir dizinde bir anahtar kelime listesi vardır, bu nedenle dizine bakın ve bunun storage113-120,231 ve 354. Sayfalarda bahsedildiğini görürsünüz. Ardından, arama yapmadan bu sayfalara doğrudan geçebilirsiniz (bu, endeksi, biraz daha hızlı).

Tabii ki, endeksin ne kadar yararlı olacağı, birçok şeye bağlıdır - yukarıdaki simile kullanarak birkaç örnek:

  • veritabanları hakkında bir kitabınız varsa ve "veritabanı" kelimesini dizine eklediyseniz, bu sayfanın 1-59,61-290 ve 292 ila 400 sayfalarında belirtildiğini görürsünüz. Böyle bir durumda, dizin çok yardımcı olmaz ve sayfalarda tek tek gezinmek için daha hızlı olun (bir veritabanında bu "zayıf seçicilik" tir).
  • 10 sayfalık bir kitap için, bir dizin oluşturmak mantıklı değildir, çünkü 5 sayfalık bir dizinin önüne 10 sayfalık bir kitap eklenebilir, bu sadece saçmadır - sadece 10 sayfayı tarayın ve onunla iş yapın .
  • Dizinin de yararlı olması gerekir - genellikle dizin oluşturmanın bir anlamı yoktur, örneğin sayfa başına "L" harfinin sıklığı.

3
Dahili olarak ne kadar teknik olarak çalıştığını değil, ne olduğunu açıklıyorsunuz.
Tutu Kumari

@Tutu Kumari: Sorunun revizyonlarına bakın; cevabı mevcut soruya uyacak şekilde revize etmekten çekinmeyin (çeşitli motorlara ve dizin türlerine dikkat edin - örn. buradaki belgelere bakın: dev.mysql.com/doc/refman/8.0/en/index-btree-hash.html )
Piskvor binadan ayrıldı

259

Bilmeniz gereken ilk şey, indekslerin aradığınız sonucu elde etmek için tam tabloyu taramaktan kaçınmanın bir yolu olduğudur.

Farklı türde dizinler vardır ve bunlar depolama katmanında uygulanır, bu nedenle aralarında standart yoktur ve kullandığınız depolama motoruna da bağlıdır.

InnoDB ve B + Tree dizini

InnoDB için, en yaygın dizin türü, öğeleri sıralı bir sırada depolayan B + Ağaç tabanlı dizindir. Ayrıca, dizine alınan değerleri almak için gerçek tabloya erişmeniz gerekmez, bu da sorgunuzun daha hızlı dönmesini sağlar.

Bu dizin türüyle ilgili "sorun", dizini kullanmak için en soldaki değeri sorgulamanız gerektiğidir. Dolayısıyla, dizininizde last_name ve first_name olmak üzere iki sütun varsa, bu alanları sorgulama sırası çok önemlidir .

Yani, aşağıdaki tablo verildiğinde:

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

Bu sorgu dizinden yararlanır:

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

Ama bir sonraki

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

Çünkü önce first_namesütunu sorguluyorsunuz ve bu dizinde en soldaki sütun değil.

Bu son örnek daha da kötü:

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

Çünkü şimdi, dizindeki en sağdaki alanın en sağ kısmını karşılaştırıyorsunuz.

Karma dizini

Bu, maalesef, yalnızca bellek arka ucunun desteklediği farklı bir dizin türüdür. Şimşek hızındadır, ancak yalnızca tam aramalar için kullanışlıdır, yani >, <veya gibi işlemler için kullanamazsınız LIKE.

Yalnızca bellek arka ucu için çalıştığından, muhtemelen çok sık kullanmazsınız. Şu anda düşünebildiğim ana durum, başka bir seçimden bir dizi sonuç ile bellekte geçici bir tablo oluşturduğunuz ve karma dizinleri kullanarak bu geçici tabloda çok sayıda başka seçim gerçekleştirdiğiniz durumdur.

Büyük bir VARCHARalanınız varsa, B-Ağacı kullanırken, başka bir sütun oluşturarak ve büyük değerin bir karmasını üzerine kaydederek bir karma dizininin kullanımını "taklit edebilirsiniz". Diyelim ki bir URL'yi bir alanda saklıyorsunuz ve değerler oldukça büyük. Ayrıca, adlı bir tamsayı alanı oluşturabilir ve URL'yi eklerken hash yapmak için url_hashbenzeri bir hash işlevi CRC32veya başka bir hash işlevi kullanabilirsiniz. Ve sonra, bu değeri sorgulamanız gerektiğinde, böyle bir şey yapabilirsiniz:

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

Yukarıdaki örnekle ilgili sorun, CRC32işlev oldukça küçük bir karma oluşturduğundan, karma değerlerinde çok sayıda çarpışma ile sonuçlanmanızdır. Kesin değerlere ihtiyacınız varsa, aşağıdakileri yaparak bu sorunu çözebilirsiniz:

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

Çarpışma sayısı yüksek olsa bile hala hash yapmaya değer, çünkü tekrarlanan karmalarla sadece ikinci karşılaştırmayı (dize) gerçekleştireceksiniz.

Ne yazık ki, bu tekniği kullanarak, urlalanı karşılaştırmak için yine de masaya vurmanız gerekir .

Sarmak

Optimizasyon hakkında her konuşmak istediğinizde dikkate alabileceğiniz bazı gerçekler:

  1. Tamsayı karşılaştırma, dize karşılaştırmasından çok daha hızlıdır. İçindeki karma indeksinin emülasyonu ile ilgili örnek ile açıklanabilir InnoDB.

  2. Belki de bir sürece ek adımlar eklemek işlemi daha hızlı değil, daha hızlı hale getirir. Bu, SELECTa'yı iki adıma bölerek, ilk olarak yeni oluşturulan bir bellek içi tabloda değerler depolayarak ve daha sonra bu ikinci tabloda daha ağır sorguları yürüterek optimize edebileceğiniz gerçeğiyle açıklanabilir.

MySQL'in başka dizinleri de var, ama b + ağacı bir şimdiye kadar en çok kullanılan ve karma bir bilmek iyi bir şey olduğunu düşünüyorum, ancak MySQL belgelerinde diğerlerini bulabilirsiniz .

"Yüksek Performanslı MySQL" kitabını okumanızı tavsiye ederim, yukarıdaki cevap kesinlikle indekslerle ilgili bölümüne dayanıyordu.


2
Aşağıdaki durumlarda aşağıdaki sorguların avantajı olur mu? 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
İlk querry olacak, ikinci sorgu olmayacak. EXPLAIN kullanın: dev.mysql.com/doc/refman/5.5/en/explain.html MySQL ile ikinci sorguyu endekslemek için FULLTEXT INDEX kullanmanız gerekir: dev.mysql.com/doc/refman/5.5/en/fulltext- search.html
Emilio Nicolás

5
127 yaşındaydınız ve 1. cevap 256'da olduğunuz için sizi onayladım. Her şeyi güzel ve temiz, ikili olarak yapmaktan kaçınamadım.
Pbarney

Bu benim için yeni bilgilerdi "bu alanları sorgulaman çok önemli." Teşekkürler.
Khatri

1
@pbarney üç yıl sonra sırasıyla 256 ve 512'ye yakınlar, buna ikili-ikili artış diyorum!
nanocv

43

Temel olarak bir dizin, tüm anahtarlarınızın sırayla sıralanmış bir haritasıdır. Sırayla bir liste ile, her anahtarı kontrol etmek yerine, böyle bir şey yapabilir:

1: Listenin ortasına git - aradığımdan daha yüksek veya daha düşük mü?

2: Daha yüksekse, orta ve alt arasında, daha düşük, orta ve üst arasında yarım noktaya gidin

3: Daha yüksek veya daha düşük mü? Tekrar orta noktaya atlayın vb.

Bu mantığı kullanarak, sıralanmış bir listedeki bir öğeyi her öğeyi kontrol etmek yerine yaklaşık 7 adımda bulabilirsiniz.

Açıkçası karmaşıklıklar var, ama bu size temel fikri veriyor.


29
Buna ikili arama denir.
ddlshack

Teşekkürler, nihayet db dizinleri ile nasıl çalıştığını değil, neden daha hızlı olduğunu açıklayan bir cevap.
Gershon Herczeg

Gerçek adım sayısı, verilere bağlıdır - aralığınızdaki benzersiz değer ve dağılım sayısı. 7, 100 değer için teorik maks. Buradaki adım sayısının nasıl hesaplanacağıyla ilgili tam tartışma stackoverflow.com/questions/10571170/…
Joshua

En yaygın MySQL endeksi, ikili aramaya benzer şekilde çalışan ancak tam olarak aynı olmayan bir B + Ağacı'dır. Algoritmik karmaşıklık aynıdır, ancak arama şekli aynı değildir. Bkz. En.wikipedia.org/wiki/B-tree
Matt

4

Bu bağlantıya bir göz atın: http://dev.mysql.com/doc/refman/5.0/en/mysql-indexes.html

Nasıl çalıştıkları bir konunun bir SO yazısında ele alınamayacak kadar geniştir.

İşte gördüğüm dizinlerin en iyi açıklamalarından biri. Ne yazık ki MySQL için değil, SQL Server içindir. İkisinin ne kadar benzer olduğundan emin değilim ...


2
Güzel makale. SQL Server'ı bilmiyorum, ancak temel çalışmalar çok benzer görünüyor. (metanot: 2. bağlantılı makalede CSS stillerini devre dışı bırakmak içeriği
gizler

3

En atın bu Dizini Oluşturma hakkında daha fazla ayrıntı için videolar

Basit Dizin Oluşturma Bir tabloda benzersiz bir dizin oluşturabilirsiniz. Benzersiz bir dizin, iki satırın aynı dizin değerine sahip olamayacağı anlamına gelir. İşte bir tablo üzerinde bir Dizin oluşturmak için sözdizimi

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

Dizin oluşturmak için bir veya daha fazla sütun kullanabilirsiniz. Örneğin, tutorials_tbltutorial_author kullanarak bir dizin oluşturabiliriz .

CREATE UNIQUE INDEX AUTHOR_INDEX
ON tutorials_tbl (tutorial_author)

Bir tabloda basit bir dizin oluşturabilirsiniz. Basit dizin oluşturmak için sorgudan UNIQUE anahtar kelimesini çıkarmanız yeterlidir. Basit dizin, tablodaki yinelenen değerlere izin verir.

Bir sütundaki değerleri azalan sırada dizine eklemek istiyorsanız, ayrılmış DESC sözcüğünü sütun adından sonra ekleyebilirsiniz.

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

1
Stack Overflow'a hoş geldiniz! Tüm yanıtlarınızın kendi videolarınıza bağlandığını belirttim. Açık bir şekilde kendi kendini tanıtmaya izin verilmediğini lütfen unutmayın .
SL Barth - Monica'yı

Videolarını tanıtmak istiyor. LOL
Ilyas karim

1

2 sent eklemek istiyorum. Ben bir veritabanı uzmanı olmaktan uzak, ama son zamanlarda bu konuda biraz okudum; ELI5'i denemem için yeterli. Yani, burada layman'ın açıklaması olabilir.


Bir dizin bir tablonun bir mini ayna gibi, benzer bir dizi gibi anlıyorum. Eğer eşleşen bir anahtarla beslerseniz, o zaman bir "komut" ile o satıra atlayabilirsiniz.

Ancak bu dizine / diziye sahip değilseniz, sorgu yorumlayıcısı tüm satırları gözden geçirmek ve eşleşme (tam tablo taraması) için bir for-loop kullanmalıdır.

Bir dizine sahip olmak, içeriğin daha hızlı aranmasının "üst tarafı" karşılığında, ek depolama alanının (o mini ayna için) "dezavantajına" sahiptir.

Birincil, yabancı veya benzersiz anahtarlar oluşturmanın (db motorunuza bağlı olarak) otomatik olarak ilgili bir dizini oluşturduğunu unutmayın. Aynı prensip temelde bu anahtarların neden ve nasıl çalıştığıdır.


1

Cevap listesine görsel sunum ekleme. resim açıklamasını buraya girin

MySQL fazladan bir dolaylama katmanı kullanır: ikincil dizin kayıtları birincil dizin kayıtlarını gösterir ve birincil dizinin kendisi diskteki satır konumlarını tutar. Bir satır ofseti değişirse, yalnızca birincil dizinin güncellenmesi gerekir.

Uyarı: Disk veri yapısı şemada düz görünüyor ancak aslında bir B + ağacı.

Kaynak: bağlantı


1

MySQL InnoDB'de iki tür dizin vardır.

  1. Kümelenmiş dizin adı verilen birincil anahtar. Dizin anahtar sözcükleri B + Ağaç yaprağı düğümünde gerçek kayıt verileriyle saklanır.

  2. Kümelenmemiş dizin olan ikincil anahtar. Bu dizin, birincil anahtarın anahtar kelimelerini B + Ağaç yaprak düğümünde kendi dizin anahtar sözcükleriyle birlikte depolar. Bu nedenle, ikincil dizinden arama yaparken, önce birincil anahtar dizini anahtar sözcüklerini bulur ve gerçek veri kayıtlarını bulmak için birincil anahtar B + Ağacı'nı tarar. Bu, ikincil dizini birincil dizin aramasına kıyasla daha yavaş hale getirir. Ancak, selectsütunların tümü ikincil dizinde ise, birincil dizin B + Ağacı'nı tekrar aramaya gerek yoktur. Buna örtme indeksi denir.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.