我的数据库中有一个字典,其中有超过百万条记录和这个简单的选择
select * from Word where languageId = 'en' order by rand() limit 1
随机选择一个词。
问题是这个请求持续了 3-4 秒,这很长,因为我必须重复多次。
有没有一种方法可以达到同样的目的,但速度要快得多?
编辑 - 表架构
wordId - integer, auto increment
languageId - varchar (FK), values like cs, en, de, ...
word - varchar, word itself
数据结构示例
wordId languageId word
--------------------------
1 cs abatyše
...
100000 cs zip
100001 en aardvark
...
etc
SQL
CREATE TABLE Language (
languageId VARCHAR(20) NOT NULL ,
name VARCHAR(255) NULL ,
PRIMARY KEY(languageId));
CREATE TABLE Word (
wordId INTEGER UNSIGNED NOT NULL AUTO_INCREMENT,
languageId VARCHAR(20) NOT NULL ,
word VARCHAR(255) NULL ,
PRIMARY KEY(wordId) ,
INDEX Word_FK_Language(languageId),
FOREIGN KEY(languageId)
REFERENCES Language(languageId)
ON DELETE NO ACTION
ON UPDATE NO ACTION);
最佳答案
如果你有一个 IDs 列并且元素之间的间隙不是很大(没有删除太多元素,否则一些元素会被更频繁地选择)然后尝试这个查询
SELECT * FROM `table`
WHERE id >=
(SELECT FLOOR( MAX(id) * RAND()) FROM `table` WHERE languageId = 'en' )
AND languageId = 'en'
ORDER BY id LIMIT 1;
并在这里查看不同的示例 http://akinas.com/pages/en/blog/mysql_random_row/
ps:我刚刚意识到它只有在不需要 languageId 的情况下才能正常工作,否则相同 languageId 的 ID 之间的差距可能会很大。
已更新 试试这个,它可能会快几倍。我根据您的查询的执行时间检查了它..快了两倍..
SELECT d.* FROM
(SELECT @rn:=0 ) r,
(SELECT FLOOR(count(*)*RAND()) as rnd FROM `Word` WHERE languageId = 'en') t,
(SELECT @rn:=@rn+1 as rn, `Word`.* FROM `Word` WHERE languageId = 'en' ) d
WHERE d.rn >= t.rnd LIMIT 1
基本上它仍然会创建某种连续的 id,但不会按它们排序。
上次更新 这个可能会更快(取决于生成的随机数)
SELECT d.* FROM
( SELECT @rn:=@rn+1 as rn, w.*, t.rnd rnd FROM
(SELECT @rn:=0 ) r,
(SELECT FLOOR(count(*)*RAND()) rnd FROM `Word` WHERE languageId = 'en') t,
`Word` w
WHERE w.languageId = 'en' AND @rn<t.rnd
) d
WHERE d.rn=d.rnd
关于MySQL查询性能优化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9219060/