我有一张表如:
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
的数量qty2
和second_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的查询中)。
答案 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_index
(second_id
,timestamp
,qty1
,qty2
)
尝试使用此INDEX组合。这称为覆盖指数。
参见覆盖索引和松散索引扫描以供参考
一般来说,如果我们在查询范围内有覆盖索引的范围很快
http://www.arubin.org/blog/2010/11/18/loose-index-scan-vs-covered-indexes-in-mysql/