当前位置:  开发笔记 > 前端 > 正文

从sqlite表中选择随机行

如何解决《从sqlite表中选择随机行》经验,为你挑选了6个好方法。

我有一个sqlite包含以下架构的表:

CREATE TABLE foo (bar VARCHAR)

我正在使用此表作为字符串列表的存储.

如何从此表中选择随机行?



1> Adriaan Stan..:

看一下从SQLite表中选择一个随机行

SELECT * FROM table ORDER BY RANDOM() LIMIT 1;



2> Suzanne Dupé..:

以下解决方案比anktastic快得多(计数(*)成本很高,但如果你可以缓存它,那么差异不应该那么大),它本身比"random by random()"要快得多.当你有大量的行时,虽然它们有一些不便之处.

如果您的rowid相当紧凑(即少数删除),那么您可以执行以下操作(使用(select max(rowid) from foo)+1而不是max(rowid)+1提供更好的性能,如注释中所述):

select * from foo where rowid = (abs(random()) % (select (select max(rowid) from foo)+1));

如果你有洞,你有时会尝试选择一个不存在的rowid,而select将返回一个空的结果集.如果这是不可接受的,您可以提供如下默认值:

select * from foo where rowid = (abs(random()) % (select (select max(rowid) from foo)+1)) or rowid = (select max(rowid) from node) order by rowid limit 1;

第二种解决方案并不完美:最后一行(具有最高rowid的那一行)的概率分布较高,但如果你经常向表中添加东西,它将成为一个移动目标,概率的分布应该是好多了.

还有另一种解决方案,如果您经常从具有大量空洞的表中选择随机内容,那么您可能希望创建一个包含按随机顺序排序的原始表行的表:

create table random_foo(foo_id);

然后,在periodicalliy中,重新填充表random_foo

delete from random_foo;
insert into random_foo select id from foo;

要选择一个随机行,您可以使用我的第一个方法(这里没有漏洞).当然,最后一种方法存在一些并发性问题,但是重新构建random_foo是一种不太经常发生的维护操作.

然而,我最近在邮件列表中找到的另一种方法是在删除时设置触发器,将具有最大rowid的行移动到当前删除的行中,这样就不会留下任何漏洞.

最后,请注意rowid和整数主键自动增量的行为不相同(使用rowid,当插入新行时,选择max(rowid)+1,其中它是高亮值,有史以来+ 1为一个主键),所以最后的解决方案不适用于random_foo中的自动增量,但其他方法将.


这是一个很好的答案。但是它有一个问题。SELECT max(rowid)+ 1将是一个缓慢的查询-它需要全表扫描。sqlite仅优化查询“ SELECT max(rowid)”。因此,可以通过以下方法来改善此答案:`从foo中选择*,其中rowid =(abs(random())%(从(从foo中选择max(rowid))+ 1)));`参见更多信息:http: //sqlite.1065341.n5.nabble.com/performance-question-SELECT-max-rowid-1-td24311.html

3> Andres Kievs..:

关于什么:

SELECT COUNT(*) AS n FROM foo;

然后在[0,n)中选择一个随机数m

SELECT * FROM foo LIMIT 1 OFFSET m;

您甚至可以在某处保存第一个数字(n),并仅在数据库计数更改时更新它.这样你就不必每次都做SELECT COUNT.



4> Roberto Góes..:

您需要在查询中输入"按RANDOM()排序".

例:

select * from quest order by RANDOM();

让我们看一个完整的例子

    创建一个表:

CREATE TABLE  quest  (
    id  INTEGER PRIMARY KEY AUTOINCREMENT,
    quest TEXT NOT NULL,
    resp_id INTEGER NOT NULL
);

插入一些值:

insert into quest(quest, resp_id) values ('1024/4',6), ('256/2',12), ('128/1',24);

默认选择:

select * from quest;

| id |   quest  | resp_id |
   1     1024/4       6
   2     256/2       12
   3     128/1       24
--

选择随机:

select * from quest order by RANDOM();
| id |   quest  | resp_id |
   3     128/1       24
   1     1024/4       6
   2     256/2       12
--
*每次选择时,订单都会有所不同.

如果您只想返回一行

select * from quest order by RANDOM() LIMIT 1;
| id |   quest  | resp_id |
   2     256/2       12
--
*每次选择时,退货都会有所不同.


我更喜欢这种解决方案,因为它可以搜索n行。就我而言,我需要从数据库中随机抽取100个样本-ORDER BY RANDOM()与LIMIT 100相结合就可以做到这一点。

5> Svetlozar An..:
SELECT   bar
FROM     foo
ORDER BY Random()
LIMIT    1


由于它将首先选择整个表格内容,对于大型表格来说这不是非常耗时吗?

6> vokilam..:

这是@ank解决方案的修改:

SELECT * 
FROM table
LIMIT 1 
OFFSET ABS(RANDOM()) % MAX((SELECT COUNT(*) FROM table), 1)

该解决方案也适用于带有间隙的索引,因为我们将偏移量随机化在[0,count)范围内。MAX用于处理空表的情况。

以下是对具有16k行的表的简单测试结果:

sqlite> .timer on
sqlite> select count(*) from payment;
16049
Run Time: real 0.000 user 0.000140 sys 0.000117

sqlite> select payment_id from payment limit 1 offset abs(random()) % (select count(*) from payment);
14746
Run Time: real 0.002 user 0.000899 sys 0.000132
sqlite> select payment_id from payment limit 1 offset abs(random()) % (select count(*) from payment);
12486
Run Time: real 0.001 user 0.000952 sys 0.000103

sqlite> select payment_id from payment order by random() limit 1;
3134
Run Time: real 0.015 user 0.014022 sys 0.000309
sqlite> select payment_id from payment order by random() limit 1;
9407
Run Time: real 0.018 user 0.013757 sys 0.000208

推荐阅读
手机用户2502851955
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有