[英]Selecting random words from table
说我有以下基本MySQL数据:
CREATE TABLE my_words (my_word VARCHAR(255));
INSERT INTO my_words VALUES ('dog');
INSERT INTO my_words VALUES ('cat');
INSERT INTO my_words VALUES ('tree');
INSERT INTO my_words VALUES ('ball');
INSERT INTO my_words VALUES ('life');
INSERT INTO my_words VALUES ('complex');
INSERT INTO my_words VALUES ('digeridoo');
INSERT INTO my_words VALUES ('hamster');
INSERT INTO my_words VALUES ('it');
INSERT INTO my_words VALUES ('house');
INSERT INTO my_words VALUES ('love');
INSERT INTO my_words VALUES ('zealous');
INSERT INTO my_words VALUES ('nevis');
INSERT INTO my_words VALUES ('mountain');
INSERT INTO my_words VALUES ('call');
INSERT INTO my_words VALUES ('nail');
INSERT INTO my_words VALUES ('rat');
INSERT INTO my_words VALUES ('hat');
SELECT CONCAT(w1.my_word, w2.my_word) joined
FROM my_words w1, my_words w2
WHERE LENGTH(CONCAT(w1.my_word, w2.my_word)) = 8
ORDER BY RAND() LIMIT 5;
我可以在末尾编写SQL语句,以生成5个由2个单词组成的随机串联字符串的列表,其中字符串的总长度为8个字符。
对于样本中的简单数据表,这很好用。
但是,我正在使用的“实际”表包含大约6,200行。
如果我尝试相同类型的语句,则需要10秒才能生成5个字符串。
我猜SQL效率很低,因为它每次都在表中搜索两次,并且这些表没有以任何方式连接。
我想知道是否有一种更简单的方法来从表中提取由2个单词组成的单词字符串,其中连接字符串的长度为8个字符长(尽管可以更改-我仅以8个为例)。
谢谢
更新1
说明计划:
EXPLAIN
SELECT CONCAT(w1.fld_un, w2.fld_un) joined
FROM j_un w1
JOIN j_un w2 ON w1.fld_len = 8 - w2.fld_len
WHERE w2.fld_len < 8
ORDER BY RAND()
LIMIT 5;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE w2 range un_len un_len 5 \N 2694 Using where; Using temporary; Using filesort
1 SIMPLE w1 ref un_len un_len 5 func 527 Using where
更新2
我不确定是否相关,但是“ fld_un”表大约有6,200行。
“单词”保存在“ fld_un”列中。
该表的结构为:
Field Type Null Key Default Extra
fld_id int(11) NO PRI NULL auto_increment
fld_un varchar(255) YES NULL
fld_cat_id int(11) YES MUL NULL
fld_len int(2) NO MUL NULL
这些索引存在于表中:
Keyname Type Cardinality Field
PRIMARY PRIMARY 6318 fld_id
cat INDEX 15 fld_cat_id
bob INDEX 11 fld_len
表格上已经有主索引有关系吗? 从技术上讲,我不需要。
声明:
SELECT CONCAT(word1, word2) joined
FROM (
SELECT w1.fld_un word1, w2.fld_un word2
FROM j_un2 w1
JOIN j_un2 w2 ON w1.fld_len = 8 - w2.fld_len
WHERE w2.fld_len < 8
ORDER BY RAND()
LIMIT 5) x;
查询花费了23.6805秒
说明计划:
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY <derived2> ALL NULL NULL NULL NULL 5
2 DERIVED w2 range bob bob 4 NULL 4627 Using where; Using temporary; Using filesort
2 DERIVED w1 ref bob bob 4 func 527 Using where
当我按照Thorsten Kettner的建议修改“ bob”索引以包括2列时:
Keyname Type Cardinality Field
bob INDEX 11 fld_len, fld_un
并重新测试:
SELECT CONCAT(word1, word2) joined
FROM (
SELECT w1.fld_un word1, w2.fld_un word2
FROM j_un2 w1
JOIN j_un2 w2 ON w1.fld_len = 8 - w2.fld_len
WHERE w2.fld_len < 8
ORDER BY RAND()
LIMIT 5) x;
该查询花费30.3394秒返回5行。
说明计划:
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY <derived2> ALL NULL NULL NULL NULL 5
2 DERIVED w2 range bob bob 4 NULL 4211 Using where; Using temporary; Using filesort
2 DERIVED w1 ref bob bob 4 func 527 Using where
更新3
在没有“由rand()排序”的情况下运行,它在0.0011秒内运行!
您可以添加一列,例如包含单词长度的word_length
,并在word_length
列上添加索引。 通常,包含可以从另一列派生的数据的设计会很糟糕,但是在这种情况下,为了性能起见,您需要破坏纯度。 然后,您的查询可以在此列中使用JOIN
条件:
SELECT CONCAT(w1.my_word, w2.my_word) joined
FROM my_words w1
JOIN my_words w2 ON w1.word_length = 8 - w2.word_length
WHERE w2.word_length < 8
ORDER BY RAND()
LIMIT 5
您可以使用INSERT
和UPDATE
触发器自动填充word_length
列。
在筛选出5行之后进行连接可能也会有所帮助:
SELECT CONCAT(word1, word2) joined
FROM (
SELECT w1.my_word word1, w2.my_word word2
FROM my_words w1
JOIN my_words w2 ON w1.word_length = 8 - w2.word_length
WHERE w2.word_length < 8
ORDER BY RAND()
LIMIT 5) x
如果可以添加另一列和索引来索引单词的长度,则可以使用第二个单词的长度=所需的长度-第一个单词的长度来执行join ON子句。
我认为这里最慢的部分是rand()。 如果不对笛卡尔乘积进行操作,而对每个表单独进行操作,则可能会得到更好的结果。 尽管这样做的结果有所不同...
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.