Description:
When using MERGE VIEW in a query with a subquery, MySQL 5.7 uses full table scan instead of an index.
I have a query that works perfectly on MySQL 5.6, but performs very badly on 5.7 - after an in-place upgrade.
How to repeat:
I have two databases:
1.) "kg" - schema with a real table
2.) "kg_view" - schema with a view of the original table from "kg"
The original table is fast:
mysql> use kg
Database changed
mysql> SET @a = 0;
Query OK, 0 rows affected (0.00 sec)
mysql> SELECT `interval`, cnt, ((@a := (@a + tmp1.`cnt`)) ) AS `sum`
-> FROM (
-> SELECT ptai.`interval`, SUM(ptai.`count`) AS cnt
-> FROM PageTimeAggregateInterval ptai
-> WHERE ptai.`time` BETWEEN DATE_SUB('2016-09-26 15:15:54', INTERVAL 5 MINUTE) AND '2016-09-26 15:15:54'
-> GROUP BY ptai.`interval`
-> ORDER BY ptai.`interval`
-> ) AS tmp1
-> ORDER BY tmp1.`interval` ;
+----------+------+------+
| interval | cnt | sum |
+----------+------+------+
| 10 | 30 | 30 |
| 15 | 216 | 246 |
| 20 | 234 | 480 |
...
| 940 | 1 | 4125 |
| 950 | 2 | 4127 |
| 1100 | 1 | 4128 |
| 1400 | 2 | 4130 |
| 2900 | 1 | 4131 |
+----------+------+------+
85 rows in set (0.02 sec)
But when using the view, the query is incredibly slower:
mysql> use kg_views
Database changed
mysql> SET @a = 0;
Query OK, 0 rows affected (0.00 sec)
mysql> SELECT `interval`, cnt, ((@a := (@a + tmp1.`cnt`)) ) AS `sum`
-> FROM (
-> SELECT ptai.`interval`, SUM(ptai.`count`) AS cnt
-> FROM PageTimeAggregateInterval ptai
-> WHERE ptai.`time` BETWEEN DATE_SUB('2016-09-26 15:15:54', INTERVAL 5 MINUTE) AND '2016-09-26 15:15:54'
-> GROUP BY ptai.`interval`
-> ORDER BY ptai.`interval`
-> ) AS tmp1
-> ORDER BY tmp1.`interval` ;
+----------+------+------+
| interval | cnt | sum |
+----------+------+------+
| 10 | 30 | 30 |
| 15 | 216 | 246 |
| 20 | 234 | 480 |
| 25 | 284 | 764 |
...
| 950 | 2 | 4127 |
| 1100 | 1 | 4128 |
| 1400 | 2 | 4130 |
| 2900 | 1 | 4131 |
+----------+------+------+
85 rows in set (7.61 sec)
mysql> EXPLAIN SELECT `interval`, cnt, ((@a := (@a + tmp1.`cnt`)) ) AS `sum`
-> FROM (
-> SELECT ptai.`interval`, SUM(ptai.`count`) AS cnt
-> FROM PageTimeAggregateInterval ptai
-> WHERE ptai.`time` BETWEEN DATE_SUB('2016-09-26 15:15:54', INTERVAL 5 MINUTE) AND '2016-09-26 15:15:54'
-> GROUP BY ptai.`interval`
-> ORDER BY ptai.`interval`
-> ) AS tmp1
-> ORDER BY tmp1.`interval` ;
+----+-------------+---------------------------+------------+------+---------------+------+---------+------+---------+----------+----------------------------------------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+---------------------------+------------+------+---------------+------+---------+------+---------+----------+----------------------------------------------+
| 1 | PRIMARY | <derived2> | NULL | ALL | NULL | NULL | NULL | NULL | 412949 | 100.00 | Using filesort |
| 2 | DERIVED | <derived3> | NULL | ALL | NULL | NULL | NULL | NULL | 3716916 | 11.11 | Using where; Using temporary; Using filesort |
| 3 | DERIVED | PageTimeAggregateInterval | NULL | ALL | NULL | NULL | NULL | NULL | 3716916 | 100.00 | NULL |
+----+-------------+---------------------------+------------+------+---------------+------+---------+------+---------+----------+----------------------------------------------+
3 rows in set, 1 warning (0.00 sec)
mysql> use kg
Database changed
mysql> EXPLAIN SELECT `interval`, cnt, ((@a := (@a + tmp1.`cnt`)) ) AS `sum`
-> FROM (
-> SELECT ptai.`interval`, SUM(ptai.`count`) AS cnt
-> FROM PageTimeAggregateInterval ptai
-> WHERE ptai.`time` BETWEEN DATE_SUB('2016-09-26 15:15:54', INTERVAL 5 MINUTE) AND '2016-09-26 15:15:54'
-> GROUP BY ptai.`interval`
-> ORDER BY ptai.`interval`
-> ) AS tmp1
-> ORDER BY tmp1.`interval` ;
+----+-------------+------------+------------+-------+---------------+------+---------+------+------+----------+--------------------------------------------------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+------------+------------+-------+---------------+------+---------+------+------+----------+--------------------------------------------------------+
| 1 | PRIMARY | <derived2> | NULL | ALL | NULL | NULL | NULL | NULL | 1981 | 100.00 | Using filesort |
| 2 | DERIVED | ptai | NULL | range | time | time | 4 | NULL | 1981 | 100.00 | Using index condition; Using temporary; Using filesort |
+----+-------------+------------+------------+-------+---------------+------+---------+------+------+----------+--------------------------------------------------------+
2 rows in set, 1 warning (0.00 sec)
View definition:
mysql> show create view kg_views.PageTimeAggregateInterval\G
*************************** 1. row ***************************
View: PageTimeAggregateInterval
Create View: CREATE ALGORITHM=MERGE VIEW `kg_views`.`PageTimeAggregateInterval` AS select `kg`.`PageTimeAggregateInterval`.`time` AS `time`,`kg`.`PageTimeAggregateInterval`.`interval` AS `interval`,`kg`.`PageTimeAggregateInterval`.`count` AS `count`,`kg`.`PageTimeAggregateInterval`.`project` AS `project`,`kg`.`PageTimeAggregateInterval`.`server` AS `server` from `kg`.`PageTimeAggregateInterval`
character_set_client: utf8
collation_connection: utf8_general_ci
1 row in set (0.01 sec)
Here is the EXPLAIN on another DB instance with MySQL 5.6 (same dataset):
mysql> EXPLAIN SELECT `interval`, cnt, ((@a := (@a + tmp1.`cnt`)) ) AS `sum`
-> FROM (
-> SELECT ptai.`interval`, SUM(ptai.`count`) AS cnt
-> FROM PageTimeAggregateInterval ptai
-> WHERE ptai.`time` BETWEEN DATE_SUB('2016-09-26 15:15:54', INTERVAL 5 MINUTE) AND '2016-09-26 15:15:54'
-> GROUP BY ptai.`interval`
-> ORDER BY ptai.`interval`
-> ) AS tmp1
-> ORDER BY tmp1.`interval` ;
+----+-------------+---------------------------+-------+---------------+------+---------+------+------+--------------------------------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+---------------------------+-------+---------------+------+---------+------+------+--------------------------------------------------------+
| 1 | PRIMARY | <derived2> | ALL | NULL | NULL | NULL | NULL | 1980 | Using filesort |
| 2 | DERIVED | PageTimeAggregateInterval | range | time | time | 4 | NULL | 1980 | Using index condition; Using temporary; Using filesort |
+----+-------------+---------------------------+-------+---------------+------+---------+------+------+--------------------------------------------------------+
2 rows in set (0.03 sec)