最佳方式来选择随机行PostgreSQL
我想在PostgreSQL中随机选择行,我试过这样:
select * from table where random() < 0.01; 但一些其他推荐这: select * from table order by random() limit 1000; 我有一个非常大的表有500万行,我想要快。 哪种方法更好?有什么区别?什么是选择随机行的最佳方法?
根据您的规格(加上评论中的其他信息),
>您有一个数字ID列(整数),只有很少(或适度少)的间隙。 下面的查询不需要大表的顺序扫描,只需要索引扫描。 首先,获取主查询的估计值: SELECT count(*) AS ct -- optional,min(id) AS min_id,max(id) AS max_id,max(id) - min(id) AS id_span FROM big; 唯一可能昂贵的部分是count(*)(对于巨大的表)。给定上面的规格,你不需要它。估计会做得很好,几乎没有成本(detailed explanation here): SELECT reltuples AS ct FROM pg_class WHERE oid = 'schema_name.big'::regclass; 只要ct不小于id_span,查询将优于其他方法。 WITH params AS ( SELECT 1 AS min_id -- minimum id <= current min id,5100000 AS id_span -- rounded up. (max_id - min_id + buffer) ) SELECT * FROM ( SELECT p.min_id + trunc(random() * p.id_span)::integer AS id FROM params p,generate_series(1,1100) g -- 1000 + buffer GROUP BY 1 -- trim duplicates ) r JOIN big USING (id) LIMIT 1000; -- trim surplus >在id空间中生成随机数。您有“少许差距”,因此要添加10%(足以容易地覆盖空白)到要检索的行数。 短版本 您可以简化此查询。上述查询中的CTE仅用于教育目的: SELECT * FROM ( SELECT DISTINCT 1 + trunc(random() * 5100000)::integer AS id FROM generate_series(1,1100) g ) r JOIN big USING (id) LIMIT 1000; 用rCTE精简 特别是如果你不太确定差距和估计。 WITH RECURSIVE random_pick AS ( SELECT * FROM ( SELECT 1 + trunc(random() * 5100000)::int AS id FROM generate_series(1,1030) -- 1000 + few percent - adapt to your needs LIMIT 1030 -- hint for query planner ) r JOIN big b USING (id) -- eliminate miss UNION -- eliminate dupe SELECT b.* FROM ( SELECT 1 + trunc(random() * 5100000)::int AS id FROM random_pick r -- plus 3 percent - adapt to your needs LIMIT 999 -- less than 1000,hint for query planner ) r JOIN big b USING (id) -- eliminate miss ) SELECT * FROM random_pick LIMIT 1000; -- actual limit 我们可以在基本查询中使用更小的剩余。如果有太多的间隙,所以我们在第一次迭代中找不到足够的行,rCTE继续使用递归项迭代。我们在ID空间中仍然需要相对较少的间隙,或者递归在达到限制之前可能会运行干涸 – 或者我们必须从足够大的缓冲区开始,这样就不能优化性能。 重复项由rCTE中的UNION消除。 外部LIMIT使得CTE在我们有足够的行时立即停止。 仔细草拟此查询以使用可用索引,实际生成随机行,并且不停止,直到我们达到限制(除非递归运行干)。这里有一些陷阱,如果你要重写它。 换行函数 重复使用不同参数: CREATE OR REPLACE FUNCTION f_random_sample(_limit int = 1000,_gaps real = 1.03) RETURNS SETOF big AS $func$ DECLARE _surplus int := _limit * _gaps; _estimate int := ( -- get current estimate from system SELECT c.reltuples * _gaps FROM pg_class c WHERE c.oid = 'big'::regclass); BEGIN RETURN QUERY WITH RECURSIVE random_pick AS ( SELECT * FROM ( SELECT 1 + trunc(random() * _estimate)::int FROM generate_series(1,_surplus) g LIMIT _surplus -- hint for query planner ) r (id) JOIN big USING (id) -- eliminate misses UNION -- eliminate dupes SELECT * FROM ( SELECT 1 + trunc(random() * _estimate)::int FROM random_pick -- just to make it recursive LIMIT _limit -- hint for query planner ) r (id) JOIN big USING (id) -- eliminate misses ) SELECT * FROM random_pick LIMIT _limit; END $func$ LANGUAGE plpgsql VOLATILE ROWS 1000; 呼叫: SELECT * FROM f_random_sample(); SELECT * FROM f_random_sample(500,1.05); 你甚至可以使这个泛型工作于任何表:取PK列和表的名称作为多态类型,并使用EXECUTE …但这超出了这个问题的范围。看到: > Refactor a PL/pgSQL function to return the output of various SELECT queries 可能的选择 如果你的要求允许相同的集合为重复的电话(我们正在谈论重复的电话)我会考虑一个物化视图。执行上面的查询一次,并将结果写入表。用户以减轻速度得到准随机选择。每隔一段时间或事件刷新您的随机选择。 Postgres 9.5引入了 它很快,但结果不是完全随机的。 The manual:
返回的行数可能会大不相同。对于我们的示例,要获得大约1000行,请尝试: SELECT * FROM big TABLESAMPLE SYSTEM ((1000 * 100) / 5100000.0); 其中n是百分比。手册:
大胆强调我。 有关: > Fast way to discover the row count of a table in PostgreSQL 或者安装附加模块tsm_system_rows以获得所请求的行数(如果有足够的话),并允许更方便的语法: SELECT * FROM big TABLESAMPLE SYSTEM_ROWS(1000); 详情请参见Evan’s answer。 但这还不是完全随机的。 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |
- ruby-on-rails – 在哪里可以找到Rails错误消息密钥列表?
- vue2 前后端分离项目ajax跨域session问题解决方法
- c中函数的导数
- C#连接Oracle数据库使用Oracle.ManagedDataAccess.dll
- cocos2d-x linux环境搭建-基于eclispse cdt
- .net – Moq.Mock >>() – 如何使用Moq将表达式设置为Mock
- ruby – 使用默认值初始化哈希并递增1
- oracle获取上一旬的开始时间和结束时间的实现函数
- jlink烧写Nor Flash时出错正确解决方法汇总:PC of target
- Oracle:ORA-01810:格式代码出现两次 日期格式、时间格式、t