4

我有 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;

可以在这里找到一个 SQLFiddle...

而且我需要从中获取一个唯一的随机词,因为我在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我需要确保 aword今天没有使用,以便被重用,所以 aword可以有多个条目,只要ts_created不与同一日期冲突,因此我检查:

(b.id IS NULL OR  (b.ts_created = CURDATE()))

然而出来的词有 0 随机化,我怎样才能从列表中得到一个随机词?

我已经看到了一些其他问题,您可以在其中使用最大 id 定义随机条目的单个表来执行此操作,但除了单词本身之外,我没有从definition表引用到表。definition_used

  • 简而言之,我需要能够从可用的未使用词中选择一个随机词,这是我不知道该怎么做的。
4

1 回答 1

0

仍在寻找更好的查询/答案,但是,这就是我得出的结论,但需要大约 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
于 2014-08-10T20:27:27.297 回答