对于派生表的mysql总和比没有它的总结更快

时间:2018-02-02 17:12:41

标签: mysql sql performance derived-table

我无法理解为什么使用派生表的第一个查询比第二个查询要慢。   我的表:

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                            |
+----+-------------+------------+------+---------------+------+---------+------+---------+---------------------------------+

2 个答案:

答案 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;做法。你在用什么版本。