我跑
SELECT *
FROM
(SELECT
*,
ROW_NUMBER() OVER () AS n
FROM
{table_name}) t
WHERE
n < 10000
Run Code Online (Sandbox Code Playgroud)
在 Postgres 中。我注意到每次运行的结果都不同。
为了测试除了顺序之外内容是否不同,我对列进行了平均。结果很有趣:有主键的表的返回值是一致的,而另一个没有主键的表在每次运行中都不同。
具有PK的表的执行计划:
"Aggregate (cost=139391585.22..139391585.23 rows=1 width=32)"
" -> WindowAgg (cost=0.58..99288350.02 rows=3208258816 width=9090)"
" Run Condition: (row_number() OVER (?) < 10000)"
" -> Index Only Scan using mea_vit_pi_4221ef4deeadcabf_ix on {table_name} (cost=0.58..59185114.82 rows=3208258816 width=8)"
Run Code Online (Sandbox Code Playgroud)
没有pk的表的执行计划:
"Aggregate (cost=83580303.64..83580303.65 rows=1 width=32)"
" -> WindowAgg (cost=0.00..61837074.84 rows=1739458304 width=650)"
" Run Condition: (row_number() OVER (?) < 10000)"
" -> Seq Scan on {table_2} (cost=0.00..40093846.04 rows=1739458304 width=8)"
Run Code Online (Sandbox Code Playgroud)
为什么不一样?如果可以的话,我应该怎样做才能得到稳定的结果?
ROW_NUMBER() OVER ()(不带)以任意排序顺序ORDER BY返回连续的数字,无论 Postgres 碰巧以什么顺序返回行。在您的情况下,不仅同一行可以获得不同的数字,而且每次都可以选择不同的行。
对于小表,顺序通常按照物理排序顺序进行排序,但这是不可靠的!对于更大的表或更复杂的查询,会出现许多扭曲。并行性、缓存效果……
在您的特定测试中,Index Only Scan(大概是在您的 PK 指数上) vs.Seq Scan会产生差异。仅索引扫描返回排序的行。顺序扫描可以自由地以任意顺序获取最便宜的行。
添加确定性ORDER BY子句以获得确定性数字。这意味着,所有ORDER BY表达式一起必须形成每个选定行的唯一值。
在此过程中,WHERE用更便宜的条款替换该条款LIMIT:
SELECT *, row_number() OVER () AS n
FROM tbl
ORDER BY -- your deterministic sort order here!
LIMIT 9999;
Run Code Online (Sandbox Code Playgroud)
row_number()ORDER BY遵循相同的中设置的顺序SELECT。但要绝对明确的是:
SELECT *, row_number() OVER (ORDER BY ... ) AS n -- your deterministic sort order here!
FROM tbl
ORDER BY ... -- same here!
LIMIT 9999;
Run Code Online (Sandbox Code Playgroud)
两个查询都会产生相同的查询计划 - 正如当前实施的那样。只有第二个是有保证的。