我有一个约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