我有 2 个表如下(这是一个 phpMyAdmin 转储,这就是为什么它有 ALTER TABLE):
CREATE TABLE IF NOT EXISTS `definition` (
`id` int(10) unsigned NOT NULL,
`page_id` int(10) unsigned NOT NULL,
`title` varchar(255) COLLATE utf8_bin NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin AUTO_INCREMENT=2621401 ;
CREATE TABLE IF NOT EXISTS `definition_used` (
`id` int(10) unsigned NOT NULL,
`word` varchar(255) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL,
`ts_created` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=65 ;
ALTER TABLE `definition`
ADD PRIMARY KEY (`id`), ADD UNIQUE KEY `page_id` (`page_id`), ADD KEY `title` (`title`);
ALTER TABLE `definition_used`
ADD PRIMARY KEY (`id`), ADD KEY `word` (`word`,`ts_created`);
ALTER TABLE `definition`
MODIFY `id` int(10) unsigned NOT NULL AUTO_INCREMENT,AUTO_INCREMENT=2621401;
ALTER TABLE `definition_used`
MODIFY `id` int(10) unsigned NOT NULL AUTO_INCREMENT,AUTO_INCREMENT=65;
A SQLFiddle can be found here...
我需要从中获取一个唯一的随机单词,因为我在
definition
上有数百万条记录。表,使用
RAND
直接,不是一个选项。
我确实有一个查询会得到一个随机词,就是这个:
SELECT r1.title
FROM definition AS r1
JOIN (SELECT (RAND() * (SELECT MAX(id)
FROM definition
)
) AS id
) AS r2
WHERE r1.id >= r2.id
ORDER BY r1.id ASC
LIMIT 1
但是,这将根据 id 选择单词,而无需进行任何我需要的检查。现在假设它随机选择了一个
id
200 万,没有可用的词超过它给定
r1.id >= r2.id
所以我没有得到任何结果,但如果它更少,它可能会有很多结果。
现在我已经归结为:
SELECT a.title
FROM definition a
LEFT JOIN definition_used b
ON a.title = b.word
WHERE (b.id IS NULL OR (b.ts_created = CURDATE())) AND
LOWER(a.title) LIKE @message
LIMIT 1
从表
definition_used
我需要确定一个
word
今天没用,为了复用,所以一个
word
只要
ts_created
就可以有多个条目不会与同一日期发生冲突,因此我检查:
(b.id IS NULL OR (b.ts_created = CURDATE()))
但是,出现的单词随机化为 0,如何从列表中随机获取一个单词?
我已经看到了一些其他问题,您可以使用最大 id 来定义随机条目,但我没有从
definition
中引用单个表。表到
definition_used
词本身以外的表格。
请您参考如下方法:
仍在寻找更好的查询/答案但是,这就是我归结为有效的方法,但是需要大约 2 秒钟才能得到一个我认为可以进一步优化的单词,因此如果有人想试一试并优化或发布对此更好的查询,我很乐意接受它作为正确答案。
SELECT r1.title
FROM definition AS r1
JOIN (SELECT (RAND() * (SELECT MAX(a.id)
FROM definition a
LEFT JOIN definition_used b
ON a.title = b.word
WHERE (b.id IS NULL OR
(b.ts_created = CURDATE())
) AND
LOWER(a.title) LIKE @word
)
) AS id
) AS r2
WHERE r1.id >= r2.id
ORDER BY r1.id ASC
LIMIT 1
这是
EXPLAIN
以防万一有人想看:
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY <derived2> system NULL NULL NULL NULL 1
1 PRIMARY r1 range PRIMARY PRIMARY 4 NULL 1293640 Using where
2 DERIVED NULL NULL NULL NULL NULL NULL NULL No tables used
3 SUBQUERY a index NULL title 767 NULL 2587281 Using where; Using index
3 SUBQUERY b ref word word 767 sebot.a.title 1 Using where; Using index