PostgreSQL indekslerinde null değerlerini kullanabilir mi?


10

Bu kitabı okudum ki

Veritabanı, Indexed_Col IS NOT NULL değerinin yararlı olmak için çok büyük bir aralığı kapsadığını varsayar, bu nedenle veritabanı bu koşuldan bir dizine gitmez.

Kitabın 10 yaşından büyük olduğunu biliyorum, ancak zaten oldukça yararlı olduğunu kanıtladı - Sayfalarından toplanan talimatları kullanarak, on kat artarak bir sorgu hızlandırdım.

Ayrıca, EXPLAIN ANALYZEbir SELECTsorgu üzerinde çalışırken, tüm hakları tarafından bile olsa, dizinlerimin hiçbiri kullanılmadığını buldum.

Benim sorum şu:

Sütunu olan, "NOT NULL" içeren bir sütunu olan ve bu sütunu kapsayan bir dizin bulunduğunu varsayarsak, bu dizin, sütunların sorgunun parçası olduğu tablonun sorgusunda kullanılır mı?

Sevmek:

CREATE TABLE my_table(
a varchar NOT NULL
);

CREATE INDEX ix_my_table ON my_table(a);

SELECT a from my_table;

Yanıtlar:


9

PostgreSQL kesinlikle olabilir için bir dizin kullanmak IS NOT NULL. Ben de bu koşul hakkında herhangi bir sorgu planlayıcısı varsayımlar görmüyorum.

Sütun ( pg_statistic.stanullfrac) için null kesri , dizinin sorgu için yararlı olduğunu önerecek kadar düşükse, PostgreSQL bir dizin kullanır.

Ne demeye çalıştığınızı anlayamıyorum:

Bu doğruysa, "NOT NULL" olarak tanımlanan bir sütundaki bir dizinin, bu sütunu kullanan bir sorguda kullanılmadığına dair anlayışım var mı?

Kesinlikle bir dizin IS NOT NULLbir NOT NULLsütundaki bir koşul için kullanılmaz . Her zaman satırların% 100'üyle eşleşir, bu nedenle bir seqscan neredeyse her zaman çok daha hızlı olacaktır.

Endgre, bir sorgu için çok sayıda satıra filtre uygulamazsa dizin kullanmaz. Tek olası istisna, tek bir dizin tarafından kapsanan bir dizi sütun için dizininkiyle eşleşen bir sırada sormanızdır. PostgreSQL daha sonra sadece indeks taraması yapabilir. Örneğin, üzerinde bir dizin varsa t(a, b, c)ve siz:

select a, b FROM t ORDER BY a, b, c;

Hiçbir satır filtrelenmemiş olsa bile PostgreSQL dizininizi kullanabilir, çünkü yalnızca dizini okumak zorundadır ve yığını okumayı atlayabilir, bir sıralama yapmaktan kaçınabilir, vb.


Bu PG itibariyle doğrudur hepsi 9.0
eradman

1
Ve nullable sütununda bile, koşulu olan bir sorgu WHERE column IS NOT NULLdizini kullanamayabilir, çünkü kitabın dediği gibi: "yararlı olmak için çok büyük bir aralığı kapsar". Değerlerin% 90'ı null değilse, bir seqscan da muhtemelen daha hızlı olacaktır.
ypercubeᵀᴹ

Kesinlikle. Ancak, ancak tablonun büyük bir kısmı boşsa olabilir. Genellikle bu durumda kısmi bir dizin zaten daha iyi bir seçimdir.
Craig Ringer

Evet. Ben (anladığım kadarıyla) bölüm "çok büyük bir aralığı kapsar" demeye ama genel olarak endeksi değil, belirli bir koşulu ile ilgili olduğunu söylemeye çalışıyordu .
ypercubeᵀᴹ

2
@FuriousFolder Heh, burada çok fazla olumsuzluk var. PostgreSQL, bu dizin yan tümcenin diğer bölümleri için de yararlı değilse , birleştirme filtreleri vb . İçin de yararlı değilse veya sıralı bir dizin taraması için kullanılamazsa, sorgu NOT NULLiçin sütun üzerinde bir dizin kullanmaz . Başka bir deyişle, tamamen gereksiz görmezden edeceğiz üzerine diğer ayrıntılar göre sütun ve makyaj endeksi kullanım seçenekleri. (Bkz. Yalnızca dizinleri taramayı düzenleme, düzenleme). IS NOT NULLWHEREIS NOT NULLNOT NULL
Craig Ringer

2

Craig'in kapsamlı cevabına ek olarak, referans verdiğiniz kitabın kapağının şunları söylediğini eklemek istedim:

Oracle, DB2 ve SQL Server'ı kapsar

Bu yüzden özellikle PostgreSQL konusunda harika bir tavsiye kaynağı olduğuna inanmam. Her RDBMS şaşırtıcı derecede farklı olabilir!

Orijinal sorunuzla ilgili biraz kafam karıştı, ancak kitabın bölümünün% 100 doğru olmadığını gösteren bir örnek. Daha fazla karışıklığı önlemek için, ilgili paragrafın tamamı, Google Kitap Arama'da görebilirsiniz .

Veritabanı, Indexed_Col IS NOT NULL değerinin yararlı olmak için çok büyük bir aralığı kapsadığını varsayar, bu nedenle veritabanı bu koşuldan bir dizine gitmez. Nadir durumlarda, null olmayan herhangi bir değere sahip olmak o kadar nadirdir ki, olası tüm null olmayan değerler üzerinde bir indeks aralığı taraması yararlıdır. Bu gibi durumlarda, olası tüm değerlerin aralığı için güvenli bir alt veya üst sınır belirleyebiliyorsanız, Positive_ID_Column> -1 veya Date_Column> TO_DATE ('0001/01/01' gibi bir koşulu olan bir aralık taramasını etkinleştirebilirsiniz. , 'YYYY / AA / GG').

Postgres aslında (aşağıda belirtilen durumda) IS NOT NULLönerilen aralık aralığı taramalarını eklemeden sorguları tatmin etmek için bir indeks kullanabilir Positive_ID_Column > -1. Craig'in Postgres'in bu özel durumda neden bu dizini seçtiğine ilişkin sorularına ve kısmi dizin kullanma hakkındaki notlara bakın.

CREATE TABLE bar (a int);
INSERT INTO bar (a) SELECT NULL FROM generate_series(1,1000000);
INSERT INTO bar (a) VALUES (1);
CREATE INDEX bar_idx ON bar (a);

EXPLAIN ANALYZE SELECT * FROM bar WHERE a IS NOT NULL;
                                                QUERY PLAN                                                    
------------------------------------------------------------------------------------------------------------------
 Index Only Scan using bar_idx on bar  (cost=0.42..8.44 rows=1 width=4) (actual time=0.094..0.095 rows=1 loops=1)
   Index Cond: (a IS NOT NULL)
   Heap Fetches: 1
 Total runtime: 0.126 ms
(4 rows)

Bu arada Postgres 9.3, ancak sonuçların 9.1'de kabaca benzer olacağına inanıyorum, ancak "Sadece Dizin Taraması" kullanmasa da.

Düzenleme: Orijinal sorunuzu netleştirdiğinizi görüyorum ve görünüşe göre Postgres'in neden basit bir örnekte bir dizin kullanmadığını merak ediyorsunuz:

CREATE TABLE my_table(
a varchar NOT NULL
);

CREATE INDEX ix_my_table ON my_table(a);

SELECT a from my_table;

Muhtemelen tabloda hiç satırınız olmadığı için. Bu yüzden bazı test verileri ve ekleyin ANALYZE my_table;.


Söz konusu kitabın açıklamasında (vurgu mayını): "Yazar Dan Tow, kullanılan SQL veya karmaşık veritabanı platformunun karmaşıklığına bakılmaksızın , optimum yürütme planını hızlı ve sistematik olarak bulmak için geliştirdiği zaman kazandıran bir yöntemi özetliyor " Ayrıca, belki de sütun olduğunu, yani sorusuna içinde 1 gözardı tanımlandığı şekilde NOT NULL, değil sorgu kullandığı IS NOT NULLonun indeks koşulu olarak. Bu, referans verdiğiniz yorumlarda, ancak soruyu eklemek için güncelleyeceğim.
FuriousFolder

Ayrıca, kitabın kendisi dil agnostiktir: DMBS'ye özgü tek parçalar, Postgres'i oldukça basitleştiren sorgu planlarını göstermekle ilgilidir :)
FuriousFolder

1
@FuriousFolder sütunu NOT NULL olarak tanımlanır ancak bu kısım (sorunuzda, kitaptan): "Indexed_Col IS NOT NULL kapsamıyor ..." sütun tanımına değil, nerede koşuluna atıfta bulunuyor. Emin olmak zor olsa da, bağlam dışında. Belki de kitabın tamamını (önceki) eklemelisiniz.
ypercubeᵀᴹ

-1

Sorgunuzu veya örnek verilerinizi göndermediniz. Ancak endekslerin kullanılmamasının en yaygın nedeni hacim ile ilgilidir.

Dizinler, bir sütunu satır konumuna çeviren bir telefon defteri gibidir. Yalnızca birkaç satır arıyorsanız, telefon defterindeki her satırı aramak ve ardından ana tablodaki satırı aramak mantıklıdır.

Ancak birkaç satırdan daha fazlası için, telefon rehberini atlamak ve ana tablodaki tüm satırları yinelemek daha ucuzdur. Deneyimlerime göre, devrilme noktası yaklaşık 100 satırdır.


"Dizinler, bir sütunu satır konumuna çeviren bir telefon defteri gibidir. Yalnızca birkaç satır arıyorsanız, telefon defterindeki her bir satırı aramak ve ardından ana tablodaki satırı aramak mantıklıdır." Aslında, endeksler indeksledikleri telefon defteri her gün güncellenen daha küçük telefon rehberleri gibidir. Daha küçük bir telefon defteri açtığınızda, dizin oluşturma koşulunun açıkladığı tüm bilgileri bulacağınızı biliyorsunuz. Örneğin bütün insanlar bir endeks masaya 'frank' adlı: CREATE INDEX ix_frank ON people(name) WHERE name ='frank'.
FuriousFolder

Bu, yalnızca küçük telefon rehberini belleğe okuyabileceğiniz için, yalnızca dizin içeren bir taramanın çok daha hızlı olmasını sağlar;
FuriousFolder

@FuriousFolder: Yalnızca dizin içeren bir tarama açıklıyorsunuz. Ancak OP, endekslerinin kullanılmadığını, sadece bir indeks taraması sorguyu tatmin ederse gerçekleşmeyeceğini söylüyor.
Andomar

Andomar ... Ben değilim haha, OP. Amacım tam olarak bu; Bu sorguyu yalnızca dizin içeren bir tarama kullanmak üzere almak için O zamandan beri Craig postgres açıkladı beri, bunu elde ettik olduğu sütunun tanımı içeren bir sütun üzerinde dizin kullanabilmek için NOT NULL
FuriousFolder
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.