查找此MySQL查询的最佳索引
在MySQL慢速查询日志中,我有以下查询:查找此MySQL查询的最佳索引,mysql,sql,optimization,query-optimization,Mysql,Sql,Optimization,Query Optimization,在MySQL慢速查询日志中,我有以下查询: SELECT * FROM `news_items` WHERE `ctime` > 1465013901 AND `feed_id` IN (1, 2, 9) AND `moderated` = '1' AND `visibility` = '1' ORDER BY `views` DESC LIMIT 5; 以下是解释的结果: +----+-------------+------------+-------+----------------
SELECT * FROM `news_items`
WHERE `ctime` > 1465013901 AND `feed_id` IN (1, 2, 9) AND
`moderated` = '1' AND `visibility` = '1'
ORDER BY `views` DESC
LIMIT 5;
以下是解释的结果:
+----+-------------+------------+-------+---------------------------------------------------------------------------------------+-------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+------------+-------+---------------------------------------------------------------------------------------+-------+---------+------+------+-------------+
| 1 | SIMPLE | news_items | index | feed_id,ctime,ctime_2,feed_id_2,moderated,visibility,feed_id_3,cday_complex,feed_id_4 | views | 4 | NULL | 5 | Using where |
+----+-------------+------------+-------+---------------------------------------------------------------------------------------+-------+---------+------+------+-------------+
1 row in set (0.00 sec)
当我手动运行这个查询时,大约需要0.00秒,但由于某些原因,它出现在MySQL的慢速日志中,有时需要1-5秒。我相信当服务器处于高负载下时会发生这种情况
以下是表格结构:
CREATE TABLE IF NOT EXISTS `news_items` (
`item_id` int(10) NOT NULL,
`category_id` int(10) NOT NULL,
`source_id` int(10) NOT NULL,
`feed_id` int(10) NOT NULL,
`title` varchar(255) CHARACTER SET utf8 NOT NULL,
`announce` varchar(255) CHARACTER SET utf8 NOT NULL,
`content` text CHARACTER SET utf8 NOT NULL,
`hyperlink` varchar(255) CHARACTER SET utf8 NOT NULL,
`ctime` varchar(11) CHARACTER SET utf8 NOT NULL,
`cday` tinyint(2) NOT NULL,
`img` varchar(100) CHARACTER SET utf8 NOT NULL,
`video` text CHARACTER SET utf8 NOT NULL,
`gallery` text CHARACTER SET utf8 NOT NULL,
`comments` int(11) NOT NULL DEFAULT '0',
`views` int(11) NOT NULL DEFAULT '0',
`visibility` enum('1','0') CHARACTER SET utf8 NOT NULL DEFAULT '0',
`pin` tinyint(1) NOT NULL,
`pin_dttm` varchar(10) CHARACTER SET utf8 NOT NULL,
`moderated` tinyint(1) NOT NULL
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
名为“视图”的索引仅包含1个字段-视图。
我还有许多其他索引,例如:
feed_id + views + visibility + moderated
moderated + visibility + feed_id + ctime
moderated + visibility + feed_id + views + ctime
我按照前面提到的顺序使用字段,因为这是MySQL开始使用它们的唯一原因。然而,我从未使用过where;在解释中使用索引
关于如何解释如何使用索引给我看,你有什么想法吗?回答你的问题:使用索引意味着MySQL将只使用索引来满足你的查询。为此,我们需要创建一个覆盖索引,该索引覆盖query=索引,该索引同时覆盖where和order by/group by以及select中的所有字段。但是,您正在执行select*操作,因此这是不实际的 MySQL在视图上选择索引,因为您在查询中有限制5。它做到了这一点,因为1索引很小,所以在这种情况下可以避免文件排序 我相信问题不在于索引,而在于engine=MyISAM。MyISAM使用表级锁,因此如果更改新闻项,它将被锁定。我建议将表转换为InnoDB 另一种可能是,如果表很大,视图索引可能不是最佳选择
如果使用Percona Server,则可以启用慢速日志详细性选项,并查看此处所述的慢速查询的查询计划:如果已将存储引擎更改为InnoDB并创建正确的复合索引,则可以尝试此操作。第一个查询仅获取前5行的项_id。完成完整选择后,将完成限制。因此,最好在没有任何大数据的情况下完成这项工作,然后仅从5个灾难中获得洞行
SELECT idata.* FROM (
SELECT item_id FROM `news_items`
WHERE `ctime` > 1465013901 AND `feed_id` IN (1, 2, 9) AND
`moderated` = '1' AND `visibility` = '1'
ORDER BY `views` DESC
LIMIT 5 ) as i_ids
LEFT JOIN news_items AS idata ON idata.item_id = i_ids.item_id
ORDER BY `views` DESC;
如果您的表也有许多其他索引,为什么它们不显示在showcreate表中 这有两种方式
WHERE `ctime` > 1465013901
AND `feed_id` IN (1, 2, 9)
AND `moderated` = '1'
AND `visibility` = '1'
ORDER BY `views` DESC
可以使用索引:
INDEXviews并希望所需的5行see LIMIT尽早显示。
索引模型、可见性、提要id、ctime
最后一个“复合”索引从两列开始,两列的顺序都是比较=常量,然后转到in,最后是范围ctime>常量。较旧的版本在未来不会过时;较新版本将跳过IN值,并利用ctime上的范围
在复合索引中,在所有WHERE列之前包含ORDER BY列是无用的。但是,在您的案例中包含视图是没有用的,因为ctime上的范围很小
伯纳德建议的“惰性评估”技巧也会有所帮助
我同意InnoDB可能会更好 基本经验法则:在决策上下文中使用的任何字段,例如用于where、join、order by等。。。应该编制索引。你的索引似乎是多余的。如果一个字段显示在多个索引中,那么最好是作为它自己的单独索引。e、 g.如果修改了温和派,你会强制修改三个独立的索引,而不是一个。当我找到最好的索引时,我会删除其中的大部分索引。这只是我如何找到一个好的索引的一个例子。无论如何,谢谢你的评论,我会记住的。嗨,亚历山大!谢谢你的回答。那么您认为views是这个MyISAM表的最佳索引ATM吗?它有3万行,80兆字节。我将尝试在InnoDB上进行一些测试。顺便说一句,我使用Sphinx对这个表进行全文搜索,所以我认为迁移不会是一个大问题。Greg,从MySQL 5.6开始,您可以使用InnoDB和全文索引。使用斯芬克斯也是一个很好的方法。对于80Mb的表,我想说视图索引可能是这里最简单、最好的。我还建议清理其他索引,因为其中一些看起来是重复的。在MySQL 5.6+中,您还可以使用性能模式查找所有未使用的索引。