首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何优化MySQL选择查询?

如何优化MySQL选择查询?
EN

Stack Overflow用户
提问于 2019-08-17 01:01:55
回答 1查看 74关注 0票数 2

我有一个包含90,000多行的数据库表。

每一行都包含一个形容词、副词、名词或动词的单词(如Type列所示)。

我需要运行一个MySQL查询,返回一个随机选择的名词的小数字(例如3-10),其中单词的长度介于两个提供的数字之间(例如4-8)。

我尝试过的查询的性能没有那么好。

以下是表的结构:

代码语言:javascript
复制
CREATE TABLE `words` (
  `id` int(11) NOT NULL,
  `type` char(1) COLLATE utf8_unicode_ci NOT NULL,
  `word` varchar(50) COLLATE utf8_unicode_ci NOT NULL,
  `variations` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
  `free_writing_prompt` smallint(1) NOT NULL DEFAULT '0',
  `word_length` smallint(5) NOT NULL DEFAULT '0'
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

ALTER TABLE `words`
  ADD PRIMARY KEY (`id`),
  ADD UNIQUE KEY `word_type` (`type`,`word`),
  ADD KEY `type` (`type`),
  ADD KEY `Word Length` (`word_length`);

ALTER TABLE `words`
  MODIFY `id` int(11) NOT NULL AUTO_INCREMENT;

free_writing_prompt列被设置为0或1,这意味着它是查询的有效选项,而0表示忽略它。目前,所有名词都将该列设置为1,但计划将许多单词更改为0,因为它们不是应该返回的名词。

以下是按类型分列的行计数:

形容词: 21,499

副词: 4,475

名词: 58,670

动词:8 978

这是我尝试的第一个查询:

代码语言:javascript
复制
SELECT  word
    FROM  words
    WHERE  type='n'
      AND  free_writing_prompt=1
      AND  CHAR_LENGTH(word)>=4
      AND  CHAR_LENGTH(word)<=8
    ORDER BY  RAND()
    LIMIT  3;

在此之后,我决定添加word_length列,它最初不是表定义的一部分,因为当我可以预先计算和存储该值时,对所有这些行使用CHAR_LENGTH函数似乎效率很低。

我还认为在word_length列上构建一个关键索引是值得的,但我不相信它真的有帮助。

然后,我尝试了以下三个查询,但它们仍然需要大约16秒才能运行:

代码语言:javascript
复制
SELECT  word
    FROM  words
    WHERE  type='n'
      AND  free_writing_prompt=1
      AND  word_length>=4
      AND  word_length<=8
    ORDER BY  RAND()
    LIMIT  3;
SELECT  word
    FROM  words
    WHERE  type='n'
      AND  free_writing_prompt=1
      AND  word_length IN (
        SELECT  word_length
            FROM  words
            WHERE  word_length>=4
              AND  word_length<=8
                          )
    ORDER BY  RAND()
    LIMIT  3;
SELECT  word
    FROM  words
    WHERE  word_length IN (
        SELECT  word_length
            FROM  words
            WHERE  type='n'
              AND  free_writing_prompt=1
              AND  word_length>=4
              AND  word_length<=8
                          )
    ORDER BY  RAND()
    LIMIT  3;

然后,我尝试了这个Union查询,它稍微快了一点(但可能还不足以在统计上具有重要意义):

代码语言:javascript
复制
SELECT * FROM (
    SELECT word FROM words WHERE type='n' AND free_writing_prompt=1 AND word_length=4
    UNION
    SELECT word FROM words WHERE type='n' AND free_writing_prompt=1 AND word_length=5
    UNION
    SELECT word FROM words WHERE type='n' AND free_writing_prompt=1 AND word_length=6
    UNION
    SELECT word FROM words WHERE type='n' AND free_writing_prompt=1 AND word_length=7
    UNION
    SELECT word FROM words WHERE type='n' AND free_writing_prompt=1 AND word_length=8
) a
ORDER BY RAND() LIMIT 3;

有人对如何优化这个查询以提高运行时间有任何想法吗?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2019-08-17 01:16:35

综合指数

代码语言:javascript
复制
    WHERE  type='n'
      AND  free_writing_prompt=1
      AND  word_length>=4
      AND  word_length<=8

乞求

代码语言:javascript
复制
INDEX(type, free_writing_prompt,   -- in either order
      word_length)                 -- last

更好的方法是将其扩展到覆盖索引中。

代码语言:javascript
复制
INDEX(type, free_writing_prompt,   -- in either order
      word_length,                 -- last (for indexing purposes)
      word)                        -- to make "covering"

您的第一个SELECT将与此覆盖指数很好地工作。可惜,它并不完美,因为它将构建一个几千个临时表,对其进行排序,然后剥离3行。

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/57532553

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档