Bir boole alanını indekslemede herhangi bir performans kazancı var mı?


104

Ben de a içeren bir sorgu yazmak üzereyim WHERE isok=1. Adından da anlaşılacağı gibi isok, bir boole alanıdır (aslında TINYINT(1) UNSIGNED, gerektiğinde 0 veya 1'e ayarlanmış bir a ).

Bu alanı indekslemede herhangi bir performans kazancı var mı? Motor (bu durumda InnoDB) dizine bakarken daha iyi mi yoksa daha kötü mü performans gösterir?


Yanıtlar:


82

Pek sayılmaz. Bunu bir kitap gibi düşünmelisin. Bir kitapta yalnızca 3 tür kelime olsaydı ve hepsini dizine eklerseniz, normal sayfalarla aynı sayıda dizin sayfasına sahip olurdunuz.

Bir değerin görece az sayıda kaydı varsa, bir performans kazanımı olacaktır. Örneğin 1000 kaydınız varsa ve bunlardan 10 tanesi DOĞRU ise, ile arama yapmanız yararlı olacaktır.isok = 1

Michael Durrant'ın da belirttiği gibi, yazmayı da yavaşlatıyor.

DÜZENLEME: Olası yineleme: Boole alanlarını endeksleme

Burada, bir dizininiz olsa bile, çok fazla kaydınız varsa, yine de dizini kullanmadığını açıklar. MySQL = 1'i kontrol ederken indeks kullanmıyor, ancak = 0 ile kullanıyor


4
"Evet: 2 - hayır: 1" gibi görünüyor. Burada biri yanılıyor, ama kim?
Niet the Dark Absol

4
Bu tamamen doğru değildir, indeks olmadan mySql'in ilgili satırları bulmak için tüm tabloyu taraması gerekir.
ilanco

4
aksi takdirde tüm dizini tarar. (çoğu durumda bu kadar uzundur)
Michael Koper

1
Bir fark yaratabilir. Sadece bir indeks ekleyerek bir sorgunun yarısında yürütme süresini kısaltın ve yazmalar nadir ve yeterince ucuzdur ki cezayı gerçekten umursamıyoruz. Her şeyde olduğu gibi, varsaymayın, ölçün (ayrıca veritabanları her zaman mantıksal olarak beklediğiniz gibi davranmadığı için)
Eelco 09

6
Bu, DOĞRU ve YANLIŞ arasında eşit dağılım olduğunu varsayar. Aşağıda @oucil tarafından belirtildiği gibi, oldukça nadir bir boole değeri arıyorsanız, yine de biraz zaman alabilir. Her zaman dizine eklemeniz gerektiğini söylemiyorum, ancak verilerinizin doğasını ve sorgularınızın da çoğu veritabanı motorunda önemli olduğunu varsayıyorum.
mahemoff

118

Buradaki diğer birkaç cevaba daha ince bir noktayı koymak gerekirse, benim deneyimlerime göre, buna benzer sorulara bakanlar bizim olduğumuz gemide olduğundan, Boole alanlarını indekslemenin anlamsız olduğunu hepimiz duymuşuzdur, ama yine de ...

Yaklaşık 4 milyon satırlık bir tablomuz var, bir seferde sadece 1000 civarında bir Boolean anahtarı işaretlenmiş olacak ve biz buna karşı arama yapıyoruz. Boole alanımıza bir dizin eklemek, sorguları büyüklük sırasına göre hızlandırdı, yaklaşık 9 saniyeden saniyenin bir kısmına çıktı.


Evet, şeylerin 'nedenini' kesinlikle anlamaya çalışmanız gerekirken, teorinizin db motorunun gerçek davranışıyla eşleşip eşleşmediğini görmek için her zaman birlikte ölçün ve gerçek veri kümenizde farklı şeyler deneyin (şaşırırsınız ... )
Eelco

8
@Eelco Haklısınız, ancak bu durumda sonuç aslında temel teoriyle iyi örtüşüyor. Önemsiz olması gerektiği şeklindeki temel fikir, yalnızca aramanızla eşleşen öğelerle karşılaşma olasılığınızın yaklaşık% 50 olması durumunda anlamlıdır. Ardından, 100 eşleşme bulmak için DB'nin 200 öğeyi yinelemesi gerekir. Ancak öğeler yalnızca% 1 oranında eşleşiyorsa, 10.000 öğeyi yinelemesi gerekir.
mahemoff

7
İnsanların sahada gerçekten bir şeyler denemelerini ve sadece felsefe yapmak yerine performans kazanımı geri bildirimleri vermelerini seviyorum.
Viktor Joras

WHERE my_col > 0 Bunun yerine my_col = 1hıza yardımcı oluyor gibi görünüyor
Aaron

28

Gerçek sorgulara ve dizin / sorgu kombinasyonunun seçiciliğine bağlıdır.

Durum A : durum WHERE isok = 1ve orada başka hiçbir şey yok:

SELECT *
FROM tableX
WHERE isok = 1
  • Dizin yeterince seçici ise (diyelim ki 1M satırınız var ve sadece 1k satırınız var isok = 1), o zaman SQL motoru muhtemelen dizini kullanacak ve onsuz olduğundan daha hızlı olacaktır.

  • Dizin yeterince seçici değilse (örneğin 1M satırınız ve 100.000'den fazla satırınız varsa isok = 1), SQL motoru büyük olasılıkla dizini kullanmayacak ve bir tablo taraması yapacaktır.

Durum B : durum WHERE isok = 1ve daha fazlası:

SELECT *
FROM tableX
WHERE isok = 1
  AND another_column = 17

Daha sonra, sahip olduğunuz diğer dizinlere bağlıdır. Üzerinde bir dizin , yalnızca iki olası değeri olan another_columndizinden muhtemelen daha seçici olacaktır isok. Bir indeks (another_column, isok)veya (isok, another_column)daha iyi olurdu.


Bence bu, en iyiye kıyasla daha doğru cevap. ayrıca verilerin dağıtımı.

11

Verilerin dağılımına bağlıdır.

1000 sayfalık bir kitabım olduğunu ve kitabımdaki tek sözcüklerin defalarca tekrarlanan ve rastgele dağıtılmış "evet" ve "hayır" olduğunu hayal edin. Tüm "evet" örneklerini daire içine almam istenirse, kitabın arkasındaki dizin yardımcı olur mu? Değişir.

Y'ların ve hayırların yarım buçuk rastgele dağılımı olsaydı, dizine bakmak yardımcı olmazdı. Dizin kitabı çok daha büyük hale getirebilirdi ve yine de önden başlamak ve her bir maddeye bakmak yerine tüm 'evet' örneklerini aramak ve bunları daire içine almak yerine her sayfada kendi yolumla ilerlemek daha hızlı olurdum. indeks ve ardından referansın indeks girişinden ilgili sayfaya alınması.

Ancak, diyelim ki, bin sayfalık kitabımda sadece on 'evet' örneği olsaydı ve diğer her şey yalnızca milyonlarca hayır ise, o zaman bir dizin, bu on 'evet' örneğini bulmak ve bunları daire içine almak konusunda bana çok zaman kazandırırdı. .

Veritabanlarında da durum aynı. 50:50 dağıtım ise, o zaman bir dizin yardımcı olmayacaktır - veritabanı motorunun verileri baştan sona taraması daha iyidir (tam tablo taraması) ve dizin, veritabanını yalnızca daha büyük hale getirir ve yazmak ve güncellemek daha yavaş. Ancak, 4000: 1 dağılım gibi bir şeyse (bu konudaki oucil başına ), aradığınız 4000 öğede 1 ise, bir dizin araması onu büyük ölçüde hızlandırabilir.


5

Hayır, genellikle hayır.

Yüksek seçiciliğe / kardinaliteye sahip olduklarında genellikle alanları aramak için dizine eklersiniz. Bir boole alanının kardinalitesi çoğu tabloda çok düşüktür. Ayrıca yazma işlemlerinizi fraksiyonel olarak yavaşlatır.


3

Aslında bu, çalıştırdığınız sorgulara bağlıdır. Ancak, genellikle evet, aynı zamanda başka türden bir alanı indekslemenin yanı sıra.


2

Evet, bir dizin performansı artıracaktır, EXPLAIN çıktılarını indeksli ve indekssiz kontrol edin.

Dokümanlardan:

Dizinler, belirli sütun değerlerine sahip satırları hızlı bir şekilde bulmak için kullanılır. Bir indeks olmadan, MySQL ilk satırla başlamalı ve ardından ilgili satırları bulmak için tüm tabloyu okumalıdır. Masa ne kadar büyükse, maliyeti o kadar artar. Tabloda söz konusu sütunlar için bir dizin varsa, MySQL tüm verilere bakmak zorunda kalmadan veri dosyasının ortasında aranacak konumu hızla belirleyebilir.

Bence bir endeksin bu durumda performansı DÜŞÜRMEYECEĞİNİ söylemek de güvenli , bu yüzden sadece ondan kazanmanız gerekiyor.


2
Bir dizin, sabit diskte çok fazla veri verir ve yazmayı yavaşlatır, böylece yalnızca ondan kazanç sağlamazsınız.
Michael Koper

1
Doğru, ancak bu durumda, bir TINYINT(1) UNSIGNEDsütun, verilerin boyutu küçük olacaktır.
ilanco

Ve eklenen yazma yükü muhtemelen oldukça düşük
Eelco

Dizinin boyutu, yalnızca dizine alınan alanın boyutuyla değil, işaret ettiği satırların sayısıyla artmayacak mı?
poolie
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.