我无法理解为什么使用派生表的第一个查询比第二个查询要慢。 我的表:
iframe
此表包含4.514.856行
查询速度越快:
CREATE TABLE `test` (
`someid` binary(16) NOT NULL,
`indexedcolumn1` int(11) NOT NULL,
`indexedcolumn2` int(10) unsigned NOT NULL,
`data` int(11) NOT NULL,
KEY `indexedcolumn1` (`indexedcolumn1`),
KEY `indexedcolumn2` (`indexedcolumn2`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
结果:
SELECT SUM(isSame) AS same, SUM(isDifferent) AS diff, SUM(isNotSet) AS notSet, indexedcolumn1 FROM (
SELECT
CASE WHEN t.indexedcolumn1 = t.data
THEN 1
ELSE 0
END AS isSame,
CASE WHEN t.indexedcolumn1 != t.data
THEN 1
ELSE 0
END AS isDifferent,
CASE WHEN t.data = 0
THEN 1
ELSE 0
END AS isNotSet,
indexedcolumn1
FROM
test as t
WHERE
t.indexedcolumn2 >= 10000000
)AS tempTable GROUP BY indexedcolumn1;
查询速度较慢:
72 rows in set (4.70 sec)
结果:
SELECT
SUM(CASE WHEN t.indexedcolumn1 = t.data
THEN 1
ELSE 0
END) AS same,
SUM(CASE WHEN t.indexedcolumn1 != t.data
THEN 1
ELSE 0
END) AS diff,
SUM(CASE WHEN t.data = 0
THEN 1
ELSE 0
END) AS notSet,
indexedcolumn1
FROM
test as t
WHERE
t.indexedcolumn2 >= 10000000
GROUP BY indexedcolumn1;
我认为你应该尽可能避免派生表。即使EXPLAIN也没有给出任何暗示: 对于query1:
72 rows in set (5.90 sec)
查询2的:
+----+-------------+------------+------+----------------+------+---------+------+---------+---------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+------------+------+----------------+------+---------+------+---------+---------------------------------+
| 1 | PRIMARY | <derived2> | ALL | NULL | NULL | NULL | NULL | 2257428 | Using temporary; Using filesort |
| 2 | DERIVED | t | ALL | indexedcolumn2 | NULL | NULL | NULL | 4514856 | Using where |
+----+-------------+------------+------+----------------+------+---------+------+---------+---------------------------------+
我也尝试了几次测试,总是得到相同的结果:第一个查询更快......但为什么呢?结果是一样的。
编辑: 我做了一个额外的测试:我删除了 where 子句。即使这样,第一个查询(EXPLAIN)的结果也会更好:
+----+-------------+-------+-------+---------------------------+------------+---------+------+---------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+-------+---------------------------+------------+---------+------+---------+-------------+
| 1 | SIMPLE | t | index | indexedcolumn1,indexedcolumn2 | indexedcolumn1 | 4 | NULL | 4514856 | Using where |
+----+-------------+-------+-------+---------------------------+------------+---------+------+---------+-------------+
解释查询2:
+----+-------------+------------+------+---------------+------+---------+------+---------+---------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+------------+------+---------------+------+---------+------+---------+---------------------------------+
| 1 | PRIMARY | <derived2> | ALL | NULL | NULL | NULL | NULL | 4514856 | Using temporary; Using filesort |
| 2 | DERIVED | t | ALL | NULL | NULL | NULL | NULL | 4514856 | NULL |
+----+-------------+------------+------+---------------+------+---------+------+---------+---------------------------------+
答案 0 :(得分:0)
我最初对性能的差异感到惊讶。派生表会产生实现的开销。 MySQL可能会将其与排序的第一步(用于GROUP BY
)结合起来,因此它可能与ORDER BY
没有区别。
鉴于你只使用了72行,GROUP BY
的开销似乎很小,所以我希望这两者非常相似。
但关键在于索引用法。第一个版本使用索引来过滤数据 - 基本上查找72行中的每一行 - 然后执行分组。我很惊讶这需要几秒钟。
第二个是使用group by
上的索引。这样可以节省排序,但需要全表扫描。
答案 1 :(得分:0)
我有5条不同程度的评论:
(1)使用&#34;覆盖&#34;索引可能会更快:
INDEX(indexedcolumn2, indexedcolumn1, data)
我希望这会使非子查询方法击败另一方。
(2)对于任何InnoDB表,你真的应该有一个'PRIMARY KEY。
(3)轻微缩短:
CASE WHEN t.indexedcolumn1 = t.data
THEN 1
ELSE 0
END AS isSame,
- &GT;
t.indexedcolumn1 = t.data AS isSame,
和
SUM(CASE WHEN t.indexedcolumn1 = t.data
THEN 1
ELSE 0
END) AS same,
- &GT;
SUM(t.indexedcolumn1 = t.data) AS same,
(4)运行时间时,运行查询两次 - 第一次可能涉及I / O(用于缓存)而不是第二次。
(5)查询位于灰色区域,其中优化程序没有足够的数据分布知识,必须选择执行查询的最佳方法。更快的查询更好地利用索引来帮助进行过滤(WHERE
)而不是较慢的查询,后者依赖于避免排序&#39;处理GROUP BY
。
版本5.7具有不同的成本模型&#34;并且可能已选择了&#39;权利&#39;做法。你在用什么版本。