NULL değerine sahip boolean'a karşı sorgu yapılırken beklenmeyen Seq Scan


10

auto_reviewSütun türü nerede denilen bir veritabanı sütunu var boolean. Bu alan için ActiveRecord ORM kullanılarak oluşturulan bir dizin vardır.

CREATE INDEX index_table_on_auto_renew ON table USING btree (auto_renew);

Alanı bir boolean değeri için sorguladığımda, PG dizini beklendiği gibi kullanır.

EXPLAIN for: SELECT "table".* FROM "table"  WHERE "table"."auto_renew" = 'f'
                                          QUERY PLAN
----------------------------------------------------------------------------------------------
 Bitmap Heap Scan on table  (cost=51.65..826.50 rows=28039 width=186)
   Filter: (NOT auto_renew)
   ->  Bitmap Index Scan on index_domains_on_auto_renew  (cost=0.00..44.64 rows=2185 width=0)
         Index Cond: (auto_renew = false)
(4 rows)

Değer olduğunda NULL, sıralı bir tarama kullanılır.

EXPLAIN for: SELECT "table".* FROM "table"  WHERE "table"."auto_renew" IS NULL
                           QUERY PLAN
----------------------------------------------------------------
 Seq Scan on table  (cost=0.00..1094.01 rows=25854 width=186)
   Filter: (auto_renew IS NULL)
(2 rows)

Bu seçimin nedenini bilmek istiyorum.

Yanıtlar:


19

Genellikle, col IS NULL(varsayılan) b-ağacı dizin araması için olası bir adaydır. Kılavuz :

Ayrıca, bir dizin sütunundaki bir IS NULLveya IS NOT NULLkoşulu bir B-ağacı diziniyle kullanılabilir.

Kanıt almak için sıralı taramaları devre dışı bırakın (yalnızca test oturumunda!):

SET enable_seqscan = OFF;

Ben burada kılavuzu alıntı :

enable_seqscan (boolean)

Sorgu planlayıcısının sıralı tarama planı türlerini kullanmasını etkinleştirir veya devre dışı bırakır. Sıralı taramaları tamamen bastırmak imkansızdır, ancak bu değişkeni kapatmak, mevcut başka yöntemler varsa planlayıcının birini kullanmasını engeller. Varsayılan ayar açıktır.

Sonra tekrar deneyin:

EXPLAIN ANALYZE SELECT * FROM tbl WHERE auto_renew IS NULL;

Bu muhtemelen tablodaki sıralı bir taramadan daha yavaş olan bir bitmap dizin taraması ile sonuçlanacaktır .

Oturumu sıfırlayın veya kapatın (ayar oturum yereldir).

RESET enable_seqscan;

booleanSütunlardaki dizinler yalnızca belirli durumlarda yararlıdır. Planlayıcı yalnızca daha hızlı olmasını beklerse bir dizin kullanır. Hesaplamalar maliyet ayarlarınıza ve tarafından toplanan istatistiklere dayanır ANALYZE. Tablonun büyük bir kısmı durumunuza uyuyorsa (yaklaşık% 5 veya daha fazla, buna bağlıdır), bunun yerine tam masa taraması yapmak genellikle daha hızlıdır.

Bu , bir sütundaki nadir değeri booleandüz bir dizin için tek yararlı aday olarak bırakır . Bunun yerine (daha özel) bir kısmi dizin oluşturmak genellikle daha etkilidir - bu, bakımı daha ucuz, daha küçük, daha hızlı ve sorgu koşulu eşleşirse daha kolay kullanılır.

Çok sayıda satır arayan sorgularınız varsa auto_renew IS NULLve NULLdurum çok yaygın değilse (ve / veya belirli bir sıralama düzenine ihtiyacınız varsa), bu dizin bu satırları hızlı bir şekilde bulmaya / sıralamaya yardımcı olur:

CREATE INDEX index_tbl_tbl_id_auto_renew_null ON tbl (tbl_id)
WHERE auto_renew IS NULL;

Kısmi dizinin durumu WHERE, sorgu planlayıcısının dizinin uygulanabilir olduğunu fark etmesini sağlamak için bir sorgunun cümlesinde tam olarak tekrarlanmalıdır .

Dizinlenmiş sütun ( tbl_id) isteğe bağlı bir seçimdir. Önemli olan WHEREmadde. Bu belirli dizin, en çok ORDER BY tbl_idek filtreli veya ekli bir sorgu veya birleşim sorgularında etkili olur tbl_id. Bunu çok sütunlu bir indeks haline getirebilirsiniz . Boole sütunları diğerleriyle birlikte genellikle daha kullanışlıdır.

Bir kenara: ORM'ler, RDBMS'nizden tam potansiyeli tam olarak alamayan koltuk değnekleridir.


Mükemmel cevap, teşekkürler Erwin. Üzgünüm, iki kez oy kullanamam.
Simone Carletti
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.