【发布时间】:2016-01-16 16:10:32
【问题描述】:
有什么经验法则吗?问题是我刚刚提出了这个问题,索引无助于通过其预定义的排序更快地运行查询。我有下表tbl:
| p_id | s_id | w_id | amount | currency_id | date |
|integer | integer | integer | numeric | integer | timestamp without time zone|
该表包含大约500k 行,我需要对其执行以下查询:
SELECT p_id, s_id, w_id, amount, currency_id
FROM (
SELECT p_id, s_id, w_id, amount, currency_id,
ROW_NUMBER() OVER(PARTITION BY p_id, s_id, w_id ORDER BY date DESC NULLS LAST) rn
FROM tbl
) sbt
WHERE sbt.rn = 1
在表上没有任何索引的情况下,规划器选择以下操作:
Subquery Scan on sbt (cost=68369.47..90802.76 rows=2991 width=19) (actual time=616.402..958.030 rows=253657 loops=1)
Filter: (sbt.rn = 1)
Rows Removed by Filter: 344564
-> WindowAgg (cost=68369.47..83324.99 rows=598221 width=27) (actual time=616.397..909.711 rows=598221 loops=1)
-> Sort (cost=68369.47..69865.02 rows=598221 width=27) (actual time=616.384..642.357 rows=598221 loops=1)
Sort Key: tbl.p_id, tbl.s_id, tbl.w_id, tbl.date
Sort Method: quicksort Memory: 71313kB
-> Seq Scan on tbl (cost=0.00..10969.21 rows=598221 width=27) (actual time=0.038..111.827 rows=598221 loops=1)
Total runtime: 967.421 ms
根据我的数据,平均需要 7 秒。我认为,排序是一项非常昂贵的操作,因此使用index scan 而不是seq scan + sort 肯定更好。但是如果我创建一个适当的索引:
CREATE INDEX text_idx
ON tbl
USING btree
(p_id, s_id, w_id, date DESC NULLS LAST, currency_id, amount);
为了做到Index Only Scan,计划如下:
Subquery Scan on sbt (cost=0.00..56853.58 rows=2991 width=19) (actual time=167.895..747.224 rows=253657 loops=1)
Filter: (sbt.rn = 1)
Rows Removed by Filter: 344564
-> WindowAgg (cost=0.00..49375.82 rows=598221 width=27) (actual time=167.889..693.238 rows=598221 loops=1)
-> Index Only Scan using test_idx_to_drop on tbl (cost=0.00..35915.84 rows=598221 width=27) (actual time=167.876..365.174 rows=598221 loops=1)
Heap Fetches: 598221
Total runtime: 752.713 ms
看起来不错,但对提高性能没有太大帮助。查询执行的平均时间现在是 6.8 秒。我开始查看表的 I/O 统计信息(pg_statio_user_tables、pg_stat_user_table),我发现:
对于index scan,这里是统计信息(冷缓存):
idx_scan idx_tup_fetch heap_blks_read idx_blk_read
1 598221 4987 3819
和sort+seq扫描
seq_scan seq_tup_read heap_blks_read
1 598221 4987
问题: 是否有一个或多或少的简短规则,在哪里使用索引进行排序,哪里不好。我的表使用索引真的不适合避免排序吗?
【问题讨论】:
-
您完全扫描超过 500k 行,两次。这需要一些时间。 PS:对应的
EXPLAIN ANALYZE是什么?该指数提高了成本:总体提高了两倍,第一行降至 0。这是一项重大改进。 -
@zerkms 你是什么意思解释分析?我提供了关于查询的更完整的统计信息,而不仅仅是
EXPLAIN (ANALYZE, BUFFERS) -
您的查询消除了排序,分析表明这一点。你的问题到底是什么? “你是什么意思解释分析?” --- 我的意思是字面意思,
EXPLAIN ANALYZE的输出是什么? -
Explain analyze for seq scan 表明它还需要 71MB 来对表执行快速排序。你是这个意思吗?
-
不,我很好奇第一行可用的确切时间。如果是
~0ms与5s,那么后一种解决方案 IS 是一种改进(我更不明白你为什么问第二个问题)
标签: sql postgresql sorting indexing