查找此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; 以下是解释的结果: +----+-------------+------------+-------+----------------

在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;
以下是解释的结果:

+----+-------------+------------+-------+---------------------------------------------------------------------------------------+-------+---------+------+------+-------------+
| 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+中,您还可以使用性能模式查找所有未使用的索引。