ely*_*ely 6 sql postgresql recursive-query common-table-expression sql-limit
SELECT TOP ...在Postgres 中描述查询的大多数资源都说你应该使用LIMIT,ORDER BY如果需要通过某种顺序选择顶部元素,可能使用子句.
你会怎么做,如果你需要选择一个递归查询,那里是没有排序的前N个元素和有可能的查询可以在不递归返回N多行少(这样TOP的部分是必要的,以确保结果set 至少是 N行,而LIMIT可以允许更少的行)?
我的具体用例是动态SQL模式的修改,用于选择表的随机子样本.
这是我修改的sql源的链接.最简单的方法是查看那里定义的最终函数_random_select.它紧跟上述链接,但在输入表和输出结果集中已经被修改为多态,并且正确地说明了只返回输入表中已经存在的列的需要(还有另一个动态SQL)黑客row_number从最终结果集中排除中期结果).
这是一个眼睛,但它是我最接近可重复的例子.如果您使用_random_select并尝试从大于4500行的表中获取大约4500行的内容,则会开始以较高的概率看到较小的结果集,并且只会随着您增加所需样本的大小而变得更糟(因为重复的出现随着你想要的样本变大,情况会变得更糟)
请注意,在我的修改中,我没有使用_gaps此链接中的技巧,如果某个索引列中存在间隙,则意味着过度采样以抵消采样效率低下.那部分与这个问题无关,在我的情况下,我row_number用来确保有一个整数列,没有可能的间隙.
CTE的是递归的,以确保如果CTE的第一,非递归部分不给你足够的行(因为被去除重复的UNION),那么它会回去经过一轮又一轮的CTE的递归调用,并继续坚持更多的结果,直到你有足够的.
在链接的示例中,LIMIT使用,但我发现这不起作用.该方法返回的结果较少,因为最多LIMIT只能保证N行.
你如何获得至少 N行保证?选择TOPN行似乎是执行此操作的自然方式(因此递归CTE必须保持一直持续直到它获得足够的行来满足TOP条件),但这在Postgres中不可用.
你的评价很中肯。我引用的答案中的递归查询仅比原始的简单查询更灵活。它仍然需要 ID 空间中相对较少的间隙以及远小于表大小的样本大小才能可靠。
虽然我们在简单查询中需要一个舒适的盈余(“限制+缓冲区”)来覆盖丢失和重复的最坏情况,但我们可以使用通常足够的较小盈余 - 因为我们有递归查询的安全网如果我们在第一遍中未达到限制,则会填写。
无论哪种方式,该技术的目的都是快速从大表中随机选择一小部分。
对于间隙太多或(您关注的)样本大小太接近总表大小的情况,该技术毫无意义- 因此递归项可能会在达到限制之前耗尽。对于这种情况,一个简单的旧方法:
SELECT * -- or DISTINCT * to fold duplicates like UNION does
FROM TABLE
ORDER BY random()
LIMIT n;
Run Code Online (Sandbox Code Playgroud)
.. 更高效:无论如何您都会阅读表格的大部分内容。