如何优化MySQL选择查询?

如何优化MySQL选择查询?,mysql,query-optimization,Mysql,Query Optimization,我有一个包含90000多行的数据库表 每行包含一个形容词、副词、名词或动词的单词(如类型栏所示) 我需要运行一个MySQL查询,返回随机选择的少量名词(例如3-10),其中单词的长度介于两个提供的数字(例如4-8)之间 我尝试过的查询的性能没有那么好 以下是表格结构: CREATE TABLE `words` ( `id` int(11) NOT NULL, `type` char(1) COLLATE utf8_unicode_ci NOT NULL, `word` varchar

我有一个包含90000多行的数据库表

每行包含一个形容词、副词、名词或动词的单词(如类型栏所示)

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

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

以下是表格结构:

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\u writing\u prompt列设置为0或1,1表示它是查询的有效选项,0表示忽略它。目前,所有名词都将此列设置为1,但计划将许多单词更改为0,因为它们不是应该返回的名词

以下是按类型列出的行数:

形容词:21499
副词:4475
名词:58670
动词:8978

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

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;

有人对如何优化此查询以提高运行时间有什么想法吗?

复合索引

    WHERE  type='n'
      AND  free_writing_prompt=1
      AND  word_length>=4
      AND  word_length<=8
INDEX(type, free_writing_prompt,   -- in either order
      word_length,                 -- last (for indexing purposes)
      word)                        -- to make "covering"
更好的办法是将其扩展为一个覆盖指数:

    WHERE  type='n'
      AND  free_writing_prompt=1
      AND  word_length>=4
      AND  word_length<=8
INDEX(type, free_writing_prompt,   -- in either order
      word_length,                 -- last (for indexing purposes)
      word)                        -- to make "covering"

您的第一个
选择
将与此覆盖索引配合使用。遗憾的是,它并不完美,因为它将构建一个数千行的临时表,对其进行排序,然后剥离3行。

有一个覆盖索引可能会有所帮助,例如:
(自由书写提示,键入,单词长度[,单词])
;如果按take-then-join进行排序,则应该能够保持
word
不受影响(即join只需要进行3次探测)-查询计划员说发生了什么?另外,一般来说,我认为“按兰德排序()”有“更有利”的解决方案。请注意,覆盖索引的顺序是特定的:
free\u writing\u prompt
type
是直接相等的,而
word\u length
是一个范围(不管它是如何编写的;应该只使用
和word_length>=4和word_length<8
并删除所有的联合来覆盖该操作;在这里通过多重直接相等来执行SQL NoFavors)谢谢-我以前从未使用过覆盖索引。
INDEX(type, free_writing_prompt,   -- in either order
      word_length,                 -- last (for indexing purposes)
      word)                        -- to make "covering"