如何优化MySQL选择查询?
我有一个包含90000多行的数据库表 每行包含一个形容词、副词、名词或动词的单词(如类型栏所示) 我需要运行一个MySQL查询,返回随机选择的少量名词(例如3-10),其中单词的长度介于两个提供的数字(例如4-8)之间 我尝试过的查询的性能没有那么好 以下是表格结构:如何优化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
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"