我有一个表(“j_un2”),其中有6,318个随机单词,总计数永远不会改变。表中的ID是无间隙的。
我需要生成一个由2个单词组成的5个随机连接字符串的列表,其中字符串的总长度为8个字符。
几天前我已经通过以下方式获得了一些非常有用的帮助: Selecting random words from table
我的基本方法是从表中选择两次,并连接随机选择的单词。
我有一个“fld_len”列,它是单词的长度。
表格结构:
CREATE TABLE `j_un2` (
`fld_id` int(11) NOT NULL AUTO_INCREMENT,
`fld_un` varchar(255) DEFAULT NULL,
`fld_cat_id` int(11) DEFAULT NULL,
`fld_len` int(2) NOT NULL,
PRIMARY KEY (`fld_id`),
KEY `cat` (`fld_cat_id`),
KEY `bob` (`fld_len`,`fld_un`)
);
该表包含以下索引:
Keyname Type Field
PRIMARY PRIMARY fld_id
bob INDEX fld_len, fld_un
如果我做了ORDER BY RAND(),我发现了主要的性能问题。阅读StackOverflow并在此处:http://www.warpconduit.net/2011/03/23/selecting-a-random-record-using-mysql-benchmark-results/
我的查询时间大约为3.7秒:
SELECT CONCAT(w1.fld_un, w2.fld_un) bbb
, FLOOR(1 + RAND() * 6318) 'rand_ind'
FROM j_un2 w1
, j_un2 w2
WHERE w1.fld_len = 8 - w2.fld_len
AND w2.fld_len < 8
AND RAND()<(((1/6318)*10))
ORDER BY rand_ind
LIMIT 20;
这是查询的解释计划:
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE w2 range bob bob 4 NULL 5886 Using where; Using index; Using temporary; Using filesort
1 SIMPLE w1 ref bob bob 4 func 63 Using where; Using index
我想要使用此查询的页面每月获得大约500k页面查看量,所以非常繁忙(无论如何对我来说),如果用户每次刷新页面需要等待大约4秒钟,他们可能会对它感到恼火。
我在选择单词后也尝试做了CONCAT,但这需要10秒才能运行:
SELECT CONCAT(word1, word2) joined
FROM
(SELECT w1.fld_un word1, w2.fld_un word2
, FLOOR(1 + RAND() * 6318) 'rand_ind'
FROM j_un2 w1
, j_un2 w2
WHERE w1.fld_len = 10 - w2.fld_len
AND w2.fld_len < 10
AND RAND()<(((1/6318)*10))
ORDER BY rand_ind
LIMIT 20) bob;
鉴于我正在尝试通过一个相当简单的连接方法连接两个表,我想知道这个查询是否以前所未有的速度运行,或者是否有任何可以加速的范围?
更新1
实际上,我认为性能影响力取决于表连接机制,因为:
SELECT CONCAT(w1.fld_un, w2.fld_un) bbb
FROM j_un2 w1
, j_un2 w2
WHERE w1.fld_len = 8 - w2.fld_len
AND w2.fld_len < 8
AND RAND()<(((1/6318)*10))
ORDER BY rand()
LIMIT 20;
同时运行 - 例如对rand()
的订单没有任何影响答案 0 :(得分:0)
您在什么情况下执行该查询?如果在sql之外生成随机值,效率会更高。
如果是在PHP中:
function get_word() {
$found = false;
while(!$found) {
$rand1 = rand(1, 6138);
$rand2 = rand(1, 6138);
$query = " SELECT CONCAT(w1.fld_un, w2.fld_un) word FROM j_un2 w1 , j_un2 w2 WHERE w1.fld_id = '$rand1' AND w2.fld_id = '$rand2';
... Execute query and save result in $word
if(strlen($word) == 8) $found = true;
}
return $word;
}
这会产生几个但非常有效的查询。
另一种方法:
第二种方式的缺点:
答案 1 :(得分:0)
此处可找到仅限SQL的解决方案:http://mysql.rjweb.org/doc.php/random#case_consecutive_auto_increment。总之,假设id中没有间隙,它基于随机取一行。做两次以获得两行。不需要表扫描。如果需要避免两次使用相同的单词,仍然需要再次尝试代码。
如何使两行的总长度等于8个字符?这是一个有趣的转折。对于第二个查询:添加INDEX(len, id)
,然后在剩余长度内使用MIN和MAX id。然后调整下一个案例&#39;在那个博客(带间隙的AUTO_INCREMENT)中找到第二行。 (好吧,这会变得混乱,但希望我已经给你一些事情要考虑。)
该链接有8&#39;效率&#39; ORDER BY RAND() LIMIT n
的替代品。 (没有&#39;完美&#39;。)