MySQL查询不使用最佳索引

时间:2014-05-09 13:16:19

标签: mysql indexing

我有一张表如:

CREATE TABLE `order` (
    `id` bigint(10) unsigned NOT NULL,
    `second_id` bigint(10) unsigned NOT NULL,
    `timestamp` bigint(10) unsigned NOT NULL,
    `country` char(2) DEFAULT NULL,
    `qty1` int(10) unsigned NOT NULL,
    `qty2` int(10) unsigned NOT NULL,
    PRIMARY KEY (`id`),
    KEY `timestamp_second_id_country` (`timestamp`,`second_id`,`country`),
    KEY `timestamp_second_id` (`timestamp`,`second_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

根据second_id,每timestamp行,每country行一行。

我需要一个查询,在特定时间范围内(忽略国家/地区)获取特定qty1的数量qty2second_id,如下所示:

SELECT timestamp, SUM(qty1) AS qty1, SUM(qty2) AS qty2
FROM order 
WHERE second_id = "<ID>" 
AND timestamp >= <min date>
AND timestamp < <max date>
GROUP BY timestamp 
ORDER BY timestamp DESC

由于该表包含大约1,200万行,因此该查询需要很长时间(25秒),所以我添加了timestamp_second_id KEY来修复它,但不幸的是,这似乎没有... ,差不多。

这是此查询的EXPLAIN:

+----+-------------+-------+-------+-------------------------------------------------+---------------------+---------+------+----------+-------------+
| id | select_type | table | type  | possible_keys                                   | key                 | key_len | ref  | rows     | Extra       |
+----+-------------+-------+-------+-------------------------------------------------+---------------------+---------+------+----------+-------------+
|  1 | SIMPLE      | order | index | timestamp_second_id_country,timestamp_second_id | timestamp_second_id | 16      | NULL | 12185418 | Using where |
+----+-------------+-------+-------+-------------------------------------------------+---------------------+---------+------+----------+-------------+

所以它看起来都很好,它找到了2个可能的键,使用了正确的键,但它仍然超级慢......当我使用FORCE INDEX (timestamp_second_id)时出现有趣的部分,然后EXPLAIN变为:

+----+-------------+-------+-------+-------------------------------------------------+---------------------+---------+------+---------+-----------------------+
| id | select_type | table | type  | possible_keys                                   | key                 | key_len | ref  | rows    | Extra                 |
+----+-------------+-------+-------+-------------------------------------------------+---------------------+---------+------+---------+-----------------------+
|  1 | SIMPLE      | order | range | timestamp_second_id_country,timestamp_second_id | timestamp_second_id | 16      | NULL | 3465998 | Using index condition |
+----+-------------+-------+-------+-------------------------------------------------+---------------------+---------+------+---------+-----------------------+

基本上,它使用与之前相同的INDEX,但现在“Extra”使用“索引条件”,查询速度非常快(约1秒)。

所以我的问题......为什么没有FORCE INDEX就像查询一样快,即使查看EXPLAIN正在使用相同的INDEX?有没有办法在不强制INDEX的情况下完成这项工作?

(请注意,我还尝试了另一个查询,比如用于对时间戳进行分组的INNER查询,在另一个通过WHERE选择second_id和timestamp的查询中)。

2 个答案:

答案 0 :(得分:0)

索引只能用于第一个范围内的搜索。

因此,将您的相等列放在第一位,然后是一个范围列。不要在WHERE子句中放置任何未过滤的列(实际上,您可以在过滤器中使用的列之后为覆盖索引添加其他列,但它们不会在搜索中使用)。

所以,鉴于你的SELECT

SELECT timestamp, SUM(qty1) AS qty1, SUM(qty2) AS qty2
FROM order 
WHERE second_id = "<ID>" 
AND timestamp >= <min date>
AND timestamp < <max date>
GROUP BY timestamp 
ORDER BY timestamp DESC

您的索引应按顺序显示在以下列中:

(second_id, timestamp)

由于second_id上的搜索条件为=,因此时间戳为“范围”。

对于覆盖索引,它将是:

(second_id, timestamp, qty1, qty2)

答案 1 :(得分:-1)

SELECT timestamp, SUM(qty1) AS qty1, SUM(qty2) AS qty2
FROM order 
WHERE second_id = "<ID>" 
AND timestamp >= <min date>
AND timestamp < <max date>
GROUP BY timestamp 
ORDER BY timestamp DESC;
  

KEY covering_indexsecond_idtimestampqty1qty2

尝试使用此INDEX组合。这称为覆盖指数。

参见覆盖索引和松散索引扫描以供参考
一般来说,如果我们在查询范围内有覆盖索引的范围很快


http://www.arubin.org/blog/2010/11/18/loose-index-scan-vs-covered-indexes-in-mysql/