我有一個約10k行的普通表,它通常按名爲'name'的列進行排序。所以,我在這個專欄上增加了一個索引。現在選擇它的速度快:使用PostgreSQL中的約束對ORDER BY使用的索引進行索引
EXPLAIN ANALYZE SELECT * FROM crm_venue ORDER BY name ASC LIMIT 10;
...query plan...
Limit (cost=0.00..1.22 rows=10 width=154) (actual time=0.029..0.065 rows=10 loops=1)
-> Index Scan using crm_venue_name on crm_venue (cost=0.00..1317.73 rows=10768 width=154) (actual time=0.026..0.050 rows=10 loops=1)
Total runtime: 0.130 ms
如果我增加LIMIT
60(這大概是我在應用程序中使用),總運行時間不太多進一步增加。
因爲我在這張表上使用了「邏輯刪除模式」,所以我只考慮其中的delete_date NULL
。因此,這是一種常見的選擇由我自己:
SELECT * FROM crm_venue WHERE delete_date IS NULL ORDER BY name ASC LIMIT 10;
爲了讓這個查詢瞬間以及我把指數在name
列有這樣的約束:
CREATE INDEX name_delete_date_null ON crm_venue (name) WHERE delete_date IS NULL;
現在是快辦使用邏輯刪除約束進行排序:
EXPLAIN ANALYZE SELECT * FROM crm_venue WHERE delete_date IS NULL ORDER BY name ASC LIMIT 10;
Limit (cost=0.00..84.93 rows=10 width=154) (actual time=0.020..0.039 rows=10 loops=1)
-> Index Scan using name_delete_date_null on crm_venue (cost=0.00..458.62 rows=54 width=154) (actual time=0.018..0.033 rows=10 loops=1)
Total runtime: 0.076 ms
太棒了!但這是我讓自己陷入麻煩。應用程序很少調用前10行。所以,讓我們選擇更多的行:
EXPLAIN ANALYZE SELECT * FROM crm_venue WHERE delete_date IS NULL ORDER BY name ASC LIMIT 20;
Limit (cost=135.81..135.86 rows=20 width=154) (actual time=18.171..18.189 rows=20 loops=1)
-> Sort (cost=135.81..135.94 rows=54 width=154) (actual time=18.168..18.173 rows=20 loops=1)
Sort Key: name
Sort Method: top-N heapsort Memory: 21kB
-> Bitmap Heap Scan on crm_venue (cost=4.67..134.37 rows=54 width=154) (actual time=2.355..8.126 rows=10768 loops=1)
Recheck Cond: (delete_date IS NULL)
-> Bitmap Index Scan on crm_venue_delete_date_null_idx (cost=0.00..4.66 rows=54 width=0) (actual time=2.270..2.270 rows=10768 loops=1)
Index Cond: (delete_date IS NULL)
Total runtime: 18.278 ms
正如你所看到的,它從0.1毫秒到18!
很明顯會發生什麼是有一個點,其中排序不能再使用索引來運行排序。我注意到,當我將LIMIT
數字從20增加到更高的數字時,它總是需要大約20-25毫秒。
我做錯了,還是這是PostgreSQL的限制?爲這種類型的查詢設置索引的最佳方式是什麼?
非常感謝你的答案。不幸的是,使用布爾值而不是日期不是一個選項。將它作爲可空日期是A)比bool更實用,B)現在應用程序承擔這種變化已經太遲了。 – 2010-09-26 17:34:59
我的歉意,我不是故意暗示你需要添加一個布爾值。我很習慣軟刪除「旗幟」的人,我毫不猶豫地寫下了它。我將更新條目以讀取「刪除日期」而不是「delete_flag」,以便更清楚。 – 2010-09-27 14:25:33