指数
x.id
在和上创建索引y.id
- 如果它们是您的主键,您可能已经拥有这些索引。
多列索引也可能有所帮助,尤其是在 pg 9.2+ 中仅扫描索引时:
CREATE INDEX y_mult_idx ON y (id DESC, val)
但是,在我的测试中,最初并没有使用这个索引。必须添加(否则毫无意义)val
以ORDER BY
使查询计划者相信排序顺序匹配。见查询3。
该指数在这种合成设置中几乎没有什么区别。但是对于具有更多列的表,从表中检索val
变得越来越昂贵,使得“覆盖”索引更具吸引力。
查询
1) 简单
SELECT DISTINCT ON (x.id)
x.id, y.val
FROM x
JOIN y ON y.id <= x.id
ORDER BY x.id, y.id DESC;
SQL小提琴。
DISTINCT
在这个相关答案中对该技术的更多解释:
我进行了一些测试,因为我怀疑第一个查询不能很好地扩展。小桌子很快,但大桌子不好。Postgres 没有优化计划,而是从(有限的)交叉连接开始,成本为O(N²)
.
2) 快速
这个查询仍然相当简单并且可以很好地扩展:
SELECT x.id, y.val
FROM x
JOIN (SELECT *, lead(id, 1, 2147483647) OVER (ORDER BY id) AS next_id FROM y) y
ON x.id >= y.id
AND x.id < y.next_id
ORDER BY 1;
窗口函数lead()
是有帮助的。我使用该选项提供一个默认值来覆盖最后一行的极端情况:2147483647
是最大可能的整数。适应您的数据类型。
3)非常简单,几乎一样快
SELECT x.id
,(SELECT val FROM y WHERE id <= x.id ORDER BY id DESC, val LIMIT 1) AS val
FROM x;
通常,相关子查询往往很慢。但是这个可以只从(覆盖)索引中选择一个值,否则它是如此简单以至于它可以竞争。
附加ORDER BY
项目val
(粗体强调)似乎毫无意义。但是添加它可以让查询规划器相信可以使用y_mult_idx
上面的多列索引,因为排序顺序匹配。注意
仅索引扫描使用 y_mult_idx ..
在EXPLAIN
输出中。
测试用例
经过热烈的辩论和多次更新,我收集了迄今为止发布的所有查询,并制作了一个测试用例以进行快速概述。我只使用 1000 行,因此 SQLfiddle 不会因较慢的查询而超时。但是前 4 名(Erwin 2、Clodoaldo、a_horse、Erwin 3)在我所有的本地测试中都是线性扩展的。再次更新以包括我的最新添加,现在按性能改进格式和排序:
Big SQL Fiddle比较性能。