在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;
以下是EXPLAIN的结果:
+----+-------------+------------+-------+---------------------------------------------------------------------------------------+-------+---------+------+------+-------------+
| 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;
名为“views”的索引仅包含1个字段 - 视图。 我还有许多其他索引由(例如):
组成feed_id + views + visibility + moderated
moderated + visibility + feed_id + ctime
moderated + visibility + feed_id + views + ctime
我使用了上述顺序的字段,因为这是MySQL开始使用它们的唯一原因。但是,我从来没有在EXPLAIN中使用“在哪里使用索引”。
有关如何让EXPLAIN向我显示“使用索引”的任何想法?
答案 0 :(得分:0)
如果您已将存储引擎更改为InnoDB并创建正确的复合索引,则可以尝试此操作。第一个查询只获取前5行的item_id。完成SELECT后完成限制。因此,没有任何大数据就可以做到这一点,然后只从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;
答案 1 :(得分:0)
如果你的表"还有许多其他索引",为什么它们不会显示在SHOW CREATE TABLE
?
有两种方式
WHERE `ctime` > 1465013901
AND `feed_id` IN (1, 2, 9)
AND `moderated` = '1'
AND `visibility` = '1'
ORDER BY `views` DESC
可以使用索引:
INDEX(views)
并希望提前显示所需的5行(请参阅LIMIT
)。INDEX(moderated, visibility, feed_id, ctime)
这最后一个复合材料' index以比较= constant
的两列(按任意顺序)开始,然后转到IN
,最后转到"范围" (ctime > const
)。旧版本不会超过IN
;较新版本将跳过IN
值并使用ctime
上的范围。 More discussion
在ORDER BY
列的所有之前,将WHERE
列包含在复合索引中是没用的。但是,在您的案例中包含views
是没有用的,因为"范围"在ctime
。
关于懒惰评估的提示' Bernd建议也会有所帮助。
我同意InnoDB可能会更好。 Conversion tips
答案 2 :(得分:-1)
回答你的问题:"使用索引"意味着MySQL将使用 only 索引来满足您的查询。要做到这一点,我们需要创建一个"覆盖" index(索引"涵盖"查询)=索引,涵盖"其中"和"按顺序排列"来自"选择"的所有字段但是,你正在做"选择*"所以这是不切实际的。
MySQL在视图中选择索引,因为查询中有限制5。这样做是因为1)索引很小2)在这种情况下它可以避免使用filesort。
我认为问题不在于索引,而在于引擎= MyISAM。 MyISAM使用表级锁定,因此如果更改news_items,它将被锁定。我建议将表转换为InnoDB。
另一种可能性是,如果表很大,索引(视图)可能不是最佳选择。
如果您使用Percona Server,则可以启用慢速日志详细程度选项,并查看慢速查询的查询计划,如下所述:https://www.percona.com/doc/percona-server/5.5/diagnostics/slow_extended_55.html