在SQLite中选择随机行

Fah*_*dah 52 sql sqlite

在MySQL中,您可以使用以下语句选择X随机行:

SELECT * FROM table ORDER BY RAND() LIMIT X
Run Code Online (Sandbox Code Playgroud)

但是,这在SQLite中不起作用.有同等的吗?

Ali*_*Ali 68

为了更好的性能使用:

SELECT * FROM table WHERE id IN (SELECT id FROM table ORDER BY RANDOM() LIMIT x)
Run Code Online (Sandbox Code Playgroud)

SQL引擎首先将行的预计字段加载到内存然后对它们进行排序,这里我们只对内存中每行的id字段进行随机排序,因为它已被索引,然后将它们分开,然后使用这些X ID查找整行.

因此,随着表的增长,这会占用更少的RAM和CPU!

  • 对于任何想知道 Alex 的评论指的是什么的人,答案曾经显示 2 种方法,而当前显示的是方法 2。我猜测另一个答案(Donnie 的)曾经是公认的答案。 (6认同)

Don*_*nie 58

SELECT * FROM table ORDER BY RANDOM() LIMIT X

  • 对于记录:这是有效的,但在较大的表上运行缓慢.更快的方法(虽然不完全相同)是:`SELECT*FROM table WHERE random()%k = 0 LIMIT n;`.缺点是具有较低主键的记录被选中的机会较高.[取自此处](http://blog.rodolfocarvalho.net/2012/05/how-to-select-random-rows-from-sqlite.html) (4认同)
  • 是的,它会在大表上变慢,因为它最终强制进行表扫描.想要在SQL中做这样的事情的缺点.最好的方法是在前端选择随机偏移量. (2认同)

bka*_*aid 8

SELECT * FROM table ORDER BY RANDOM() LIMIT 1
Run Code Online (Sandbox Code Playgroud)


Max*_*eld 5

接受的答案有效,但需要每个查询进行全表扫描。随着表变得越来越大,这会变得越来越慢,从而使最终用户触发的查询面临风险。

以下解决方案利用索引在 O(log(N)) 时间内运行。

SELECT * FROM table
WHERE rowid > (
  ABS(RANDOM()) % (SELECT max(rowid) FROM table)
)
LIMIT 1;
Run Code Online (Sandbox Code Playgroud)

把它分解

  • SELECT max(rowid) FROM table- 返回表的最大有效 rowid。SQLite 能够使用索引rowid来有效地运行此操作。
  • ABS(RANDOM()) % ...- 返回 0 到 之间的随机数max(rowid) - 1)SQLite的random函数生成-9223372036854775808和+9223372036854775807之间的数字。确保ABS其为正值,模运算符将其选通在 之间max(rowid) - 1
  • rowid > ...- 不要使用 ,而是在生成的随机数对应于已删除的行的情况下=使用。>使用严格大于可确保我们返回行 id 介于 1(大于 0)和max(rowid)(大于max(rowid) - 1)之间的行。SQLite 也使用主键索引来有效地返回此结果。

这也适用于带有WHERE子句的查询。将WHERE子句应用于输出和SELECT max(rowid)子查询。但是,我不确定在哪些条件下这会有效运行。

注:这是从类似问题的答案得出的。