在使用PostgreSQL 9.3中的窗口函数进行一些实验时,我遇到了一个相当有趣的案例。与OFFSET vs. ROW_NUMBER()上的答案直接矛盾,我发现窗口函数实际上比OFFSET 更快。
使用偏移,需要~2500ms:
select part_no, description
from inventory
order by part_no
limit 1000 offset 400000
使用row_number()需要~450ms:
select *
from (select part_no, description, row_number() OVER ()
from inventory
order by part_no) AS ss
where row_number >= 400001
limit 1000
这个(新分析的)表有大约450,000行,part_no被索引。 EXPLAIN表示正在row_number()情况下执行索引扫描,并在OFFSET情况下执行顺序扫描。
我尝试过不同的OFFSET,row_number()和不同的偏移量大小以及索引与未索引的排序顺序的组合。所有时间都是几次运行的近似平均值(查询时间通常非常一致。)
-------indexed------- ------unindexed------
offset by OFFSET row_number() OFFSET row_number()
==========================================================
400000 2500ms 450ms 500ms 650ms
40000 80ms 60ms 850ms 650ms
4000 30ms 30ms 390ms 650ms
我想这里真正的问题是;什么是查询规划器在这两种情况下做的不同,我怎样才能让它做出更好的选择(特别是在大偏移+索引列的情况下)?
答案 0 :(得分:3)
您的比较不完全有效。你需要使用:
row_number() OVER (ORDER BY part_no)
获得相同的结果。并且ORDER BY
需要移动到外部查询。所以:
SELECT part_no, description
FROM (
SELECT part_no, description, row_number() OVER (ORDER BY part_no) AS rn
FROM inventory) AS ss
WHERE rn > 400000
ORDER BY rn
LIMIT 1000;
或者:
SELECT part_no, description
FROM (
SELECT part_no, description, row_number() OVER (ORDER BY part_no) AS rn
FROM inventory) AS ss
WHERE rn BETWEEN 400000 AND 401000
ORDER BY rn;
此外,您所指的比较是4年,并且尚未声明Postgres的版本。我假设您正在测试最新的9.3?过去几年有很多改进......