MySQL dizinleri - en iyi uygulamalar nelerdir?


208

Bir süredir MySQL veritabanlarımda dizinler kullanıyorum, ancak bunlar hakkında hiçbir zaman doğru bir şekilde öğrenmedim . Genellikle bir WHEREcümle kullanarak arayacağım veya seçeceğim herhangi bir alana bir dizin koyarım, ancak bazen çok siyah ve beyaz görünmez.

MySQL dizinleri için en iyi uygulamalar nelerdir?

Örnek durumlar / ikilemler:

  • Bir tablonun altı sütunu varsa ve bunların tümü aranabilir durumdaysa, hepsini dizine eklemeli miyim yoksa hiçbirini dizine eklemem gerekir mi?

  • Endekslemenin performans üzerindeki olumsuz etkileri nelerdir?

  • Sitemin bölümlerinden aranabilen bir VARCHAR 2500 sütunum varsa, dizine eklemeliyim?


5
Muhtemelen soruyu yeniden etiketlemelisiniz. Dizin seçimi, herhangi bir veritabanı modelinin optimizasyonu için önemli bir parçadır. Ve benim görüşüme göre php ile ilgisiz.
VGE


Yanıtlar:


242

Dizine ekleme konusunda kesinlikle biraz zaman harcamalısınız, bunun hakkında çok şey yazılmıştır ve neler olduğunu anlamak önemlidir.

Genel olarak, bir dizin bir tablonun satırlarına bir sıralama uygular.

Basitçe söylemek gerekirse, bir tablonun sadece büyük bir CSV dosyası olduğunu hayal edin. Bir satır eklendiğinde, sonuna eklenir . Böylece tablonun "doğal" sırası sadece satırların eklendiği sıradır.

CSV dosyasının çok basit bir e-tablo uygulamasına yüklendiğini düşünün. Bu elektronik tablonun yaptığı tek şey verileri görüntülemek ve satırları sırayla numaralandırmaktır.

Şimdi üçüncü sütunda bir miktar "M" olan tüm satırları bulmanız gerektiğini düşünün. Sahip olduklarınız göz önüne alındığında, sadece bir seçeneğiniz vardır. Her satır için üçüncü sütunun değerini kontrol ederek tabloyu tararsınız. Çok sayıda satırınız varsa, bu yöntem (bir "tablo taraması") uzun sürebilir!

Şimdi bu tabloya ek olarak bir endeksinizin olduğunu hayal edin. Bu belirli dizin, üçüncü sütundaki değerlerin dizinidir. Dizin, üçüncü sütundaki tüm değerleri, bazı anlamlı sırayla (alfabetik olarak) listeler ve her biri için, bu değerin göründüğü satır numaralarının bir listesini sağlar.

Şimdi üçüncü sütunun değerinin "M" olduğu tüm satırları bulmak için iyi bir stratejiniz var. Örneğin, bir ikili arama yapabilirsiniz ! Tablo taraması N satırı (burada N satır sayısıdır) aramanızı gerektirirken, ikili arama yalnızca en kötü durumda log-n dizin girişlerine bakmanızı gerektirir. Vay canına, bu çok daha kolay!

Tabii ki, bu dizine sahipseniz ve tabloya satır ekliyorsanız (sonunda, kavramsal tablonuz bu şekilde çalışır), her seferinde dizini güncellemeniz gerekir. Böylece, yeni satırlar yazarken biraz daha fazla iş yaparsınız, ancak bir şey ararken tonlarca zaman kazanırsınız.

Bu nedenle, genel olarak, dizin oluşturma okuma verimliliği ve yazma verimliliği arasında bir denge yaratır. Hiçbir dizin olmadan, ekler çok hızlı olabilir - veritabanı motoru tabloya sadece bir satır ekler. Dizin ekledikçe, eklemeyi gerçekleştirirken motorun her dizini güncellemesi gerekir.

Öte yandan, okumalar çok daha hızlı hale geliyor.

Umarım bu ilk iki sorunuzu kapsar (diğerlerinin yanıtladığı gibi - doğru dengeyi bulmanız gerekir).

Üçüncü senaryonuz biraz daha karmaşık. LIKE kullanıyorsanız, dizin oluşturma motorları genellikle ilk "%" değerine kadar okuma hızınıza yardımcı olur. Başka bir deyişle, 'foo% bar%' GİBİ NEREDE sütununu SEÇİYORSANIZ, veritabanı, sütunun "foo" ile başladığı tüm satırları bulmak için dizini kullanır ve ardından alt kümeyi bulmak için bu ara satır kümesini taraması gerekir "bar" içerir. SELECT ... NEREDE '% bar%' sütunu dizini kullanamıyorsa. Umarım nedenini görebilirsin.

Son olarak, birden fazla sütundaki dizinleri düşünmeye başlamanız gerekir. Konsept aynıdır ve LIKE malzemelerine benzer şekilde davranır - esas olarak, (a, b, c) üzerinde bir indeksiniz varsa, motor dizini soldan sağa mümkün olan en iyi şekilde kullanmaya devam eder. Bu nedenle a sütunundaki bir arama, (a, b) 'de olduğu gibi (a, b, c) dizinini kullanabilir. Ancak, NEREDE b = 5 VE c = 1'i ararken motorun tam tablo taraması yapması gerekir)

Umarım bu biraz ışık tutmaya yardımcı olur, ancak bunları derinlemesine açıklayan iyi makaleler için birkaç saat kazarak en iyisi olduğunuzu tekrarlamalıyım. Veritabanı sunucunuzun belgelerini okumak da iyi bir fikirdir. Endekslerin sorgu planlayıcıları tarafından uygulanması ve kullanılma şekli oldukça değişkendir.


10
FULLTEXTEndeksler ne olacak ? Gibi koşullara yardımcı olabilirler LIKE '%bar%'mi?
Septagram

2
@Septagram - "kelime" ise bu sorguya FULLTEXTyardımcı olabilir . kelimeleri (alt dizeleri gibi ) değil, gelişigüzel işler . barFULLTEXTLIKE
Rick James

@timdev ilk soruya hangi bölümde açıkça cevap verildi? Değerli cevabınızın birinci ve ikinci bölümünde ( umarım önce ve sonra ilk iki sorunuzu kapsar ) cevaplanan ikinci ve üçüncü soruları tespit edebilirim
Manuel Jordan

1
@ManuelJordan - İlk soruya basit bir cevap yok. Beklenen (veya daha iyi, gözlemlenen) kullanım bağlamında ödünleşmeleri nasıl dengelemek istediğinize bağlıdır.
timdev

57

Daha fazla İndeksleme Sanatında Ustalaşma gibi sunumlara göz atın .

Güncelleme 12/2012: Yeni bir sunum yayınladım: Dizinler Nasıl Tasarlanır, Gerçekten . Bunu Ekim 2012'de Santa Clara'daki ZendCon'da ve Aralık 2012'de Percona Live London'da sundum.

En iyi dizinleri tasarlamak, uygulamanızda çalıştırdığınız sorgularla eşleşmesi gereken bir işlemdir.

Hangi sütunların dizine eklenmesinin en iyi olacağı veya tüm sütunları dizine eklemeniz gerekip gerekmediği, hangi dizinlerin birden çok sütuna yayılması gerektiği vb. Hakkında genel amaçlı kurallar önermek zordur. Çalıştırmanız gereken sorgulara bağlıdır.

Evet, bazı ek yükler var, bu yüzden gereksiz yere dizin oluşturmamalısınız. Ama gereken hızlı çalıştırmak için gereken sorgulara parası vermek indeksleri oluşturma. Bir endeksin ek yükü genellikle yararından çok daha ağır basar.

VARCHAR (2500) olan bir sütun için, muhtemelen bir FULLTEXT dizini veya bir önek dizini kullanmak istersiniz :

CREATE INDEX i ON SomeTable(longVarchar(100));

Bu uzun varchar'ın ortasında olabilecek kelimeleri arıyorsanız geleneksel bir dizinin yardımcı olamayacağını unutmayın. Bunun için bir tam metin dizini kullanın.


3
Çok teşekkür ederim. slideshare.net/matsunobu/… gerçekten çok yardımcı oldu.
Bishal Paudel



1
İnanılmaz sunum (2012'den bir), gerçekten indekslerin tüm noktasını anladı.
DarkteK

46

Diğer cevaplardaki bazı iyi tavsiyeleri tekrarlamayacağım, ancak ekleyeceğim:

Bileşik Endeksler

Birden çok sütun içeren bir dizin olan bileşik dizinler oluşturabilirsiniz. MySQL bu kullanabilirsiniz sol için doğru . Eğer varsa:

Table A
Id
Name
Category
Age
Description

bu sırayla Ad / Kategori / Yaş içeren bir bileşik dizininiz varsa, bu WHERE deyimleri dizini kullanır:

WHERE Name='Eric' and Category='A'

WHERE Name='Eric' and Category='A' and Age > 18

fakat

WHERE Category='A' and Age > 18

herşeyi soldan sağa doğru kullanmak zorunda olduğu için bu dizini kullanmaz.

Açıklamak

MySQL için hangi indekslerin mevcut olduğunu ve hangisini seçtiğini anlamak için Explain / Explain Extended kullanın. MySQL sadece kullanacağı TEK sorgu başına anahtarı .

EXPLAIN EXTENDED SELECT * from Table WHERE Something='ABC'

Yavaş Sorgu Günlüğü

Hangi sorguların yavaş çalıştığını görmek için yavaş sorgu günlüğünü açın .

Geniş Sütunlar

İlk birkaç karakterde ayrımın EN ÇOK gerçekleştiği geniş bir sütun varsa, dizininizde yalnızca ilk N karakteri kullanabilirsiniz. Örnek: Varchar (255) olarak tanımlanan bir ReferenceNumber sütunumuz var, ancak vakaların% 97'si, referans numarası 10 karakter veya daha az. Dizini yalnızca ilk 10 karaktere bakacak şekilde değiştirdim ve performansı biraz geliştirdim.


Son bölüm hakkında bir sorum var. Bir yerde VARCHAR ile bir sütun oluşturursanız, her zaman 255 olarak ayarlamanız gerektiğini okudum. Şimdi, bu tür bir sütuna ayarlanmış bir dizinin yalnızca ilk 10 karaktere bakmak için sınırlı olabileceğini söylediniz. Bunu tam olarak nasıl yapabilirsin?
AlexioVay

20

Bir tablonun altı sütunu varsa ve hepsi aranabilirse, hepsini dizine eklemeli miyim yoksa hiçbirini

Bir alanda alan bazında mı arama yapıyorsunuz veya bazı alanlar birden çok alan mı kullanıyor? En çok hangi alanlarda arama yapılıyor? Alan türleri nelerdir? (Dizin, INT'lerde örneğin VARCHAR'lardan daha iyi çalışır) Çalıştırılan sorgularda EXPLAIN kullanmayı denediniz mi?

Endekslemenin olumsuz performans etkileri nelerdir?

GÜNCELLEMELER ve EKLER daha yavaş olacaktır. Ekstra depolama alanı gereksinimleri de var, ancak bu bugünlerde her zaman önemsiz.

Sitemin bölümlerinden aranabilen bir VARCHAR 2500 sütunum varsa, dizine eklemeliyim

UNIQUE (zaten dizine eklenmiş olduğu anlamına gelmez ) veya yalnızca bu alanda tam eşleşmeleri (LIKE veya mySQL'in tam metin aramasını kullanmazsanız) sürece hayır .

Genellikle bir WHERE deyimi kullanarak arayacağım veya seçeceğim herhangi bir alana bir dizin koydum

Normalde en çok sorgulanan alanları dizine eklerdim, sonra da INTs / BOOLEANs / ENUMs yerine VARCHARS olan alanları. Unutmayın, genellikle tek bir alanda bir dizin yerine birleşik alanlarda bir dizin oluşturmanız gerekir. EXPLAIN kullanın ve yavaş günlüğü kontrol edin.


11

Verileri Verimli Bir Şekilde Yükleyin Şekilde : Endeksler alımları hızlandırır, ancak endeksli sütunlardaki değerlerin güncellenmesinin yanı sıra ekleme ve silme işlemlerini yavaşlatır. Yani, dizinler yazma içeren çoğu işlemi yavaşlatır. Bunun nedeni, bir satırın yazılması yalnızca veri satırının yazılmasını gerektirmediği için, herhangi bir dizinde de değişiklik yapılması gerektiğidir. Bir tablonun sayısı ne kadar fazlaysa, o kadar fazla değişiklik yapılması gerekir ve ortalama performans düşüşü artar. Çoğu tablo çok sayıda okuma ve az sayıda yazma alır, ancak yazma yüzdesi yüksek olan bir tablo için dizin güncelleme maliyeti önemli olabilir.

Endekslerden Kaçının : Sorguların daha iyi performans göstermesine yardımcı olmak için belirli bir dizine ihtiyacınız yoksa oluşturmayın.

Disk alanı : Bir dizin disk alanını kaplar ve birden çok dizin buna bağlı olarak daha fazla yer kaplar. Bu, tablo boyutu sınırına, dizin yoksa daha hızlı ulaşmanıza neden olabilir. Mümkün olan yerlerde dizinlerden kaçının.

Paket servisi olan restoran: Dizini geçme


5

Genel olarak, dizinler ekstra disk alanı kullanmanın ve yavaşlama INSERT/ UPDATE/ DELETEsorgularının dezavantajına sahip olarak veritabanı aramasının hızlandırılmasına yardımcı olur . EXPLAINMySQL'in endekslerinizi ne zaman kullandığını öğrenmek için sonuçları kullanın ve okuyun.

Bir tablonun altı sütunu varsa ve hepsi aranabilirse, hepsini dizine eklemeli miyim yoksa hiçbirini dizine eklemem mi gerekir?

Altı sütunun tümünü dizine eklemek her zaman en iyi uygulama değildir.

(a) Belirli bilgileri ararken bu sütunlardan herhangi birini kullanacak mısınız?

(b) Bu sütunların seçiciliği nedir (tablodaki toplam kayıt sayısına kıyasla kaç ayrı değer depolanır)?

MySQL, bir sorgu gerçekleştirirken "en ucuz" yolu bulmaya çalışan, maliyete dayalı bir optimize edici kullanır. Düşük seçiciliğe sahip alanlar iyi aday değildir.

Endekslemenin olumsuz performans etkileri nelerdir?

Zaten cevaplandı: ekstra disk alanı, insert - update - delete sırasında daha düşük performans.

Sitemin bölümlerinden aranabilen bir VARCHAR 2500 sütunum varsa, dizine eklemeliyim?

FULLTEXT Dizinini deneyin .


4

1/2) Dizinler belirli seçme işlemlerini hızlandırır, ancak ekleme, güncelleme ve silme gibi diğer işlemleri yavaşlatır. İyi bir denge olabilir.

3) Tam metin dizini veya belki de sfenks kullanın


Bunu önlemek slow down other operations like insert, update and deletesiçin kullanabilirsiniz START TRANSACTION; YOUR CODE HERE; COMMIT Hangi slowing downdiğer işlemlerden kaçınmanıza yardımcı olabilir , çünkü sadece bir kez kısıtlamaları kontrol edecektir. CAVEAT: Eğer kullanırsanız REPLACE INTOve SQL_MODE<> STRICT_ALL_TABLESVEYA TRADITIONALThe Bulk Load, değiştirmeyi yok sayar ve kopyaları ekler.
JayRizzo

İşlemler tüm MySQL motorlarında desteklenmez. AFAIK, işlemler yalnızca örtülü kullanılsa bile DB işlemlerini yavaşlatır. Gerçek performansa dayalı olarak tasarlamamız gereken şey, dizinler ve işlemler de dahil olmak üzere çeşitli optimizasyon seçeneklerinin profilini (performansı ölçmek) yarı otomatik bir yöntemdir.
David Spector
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.