Bug #80580 | count(*) much slower on 5.7 than 5.6 | ||
---|---|---|---|
Submitted: | 2 Mar 2016 6:43 | Modified: | 16 Feb 2017 18:36 |
Reporter: | Qi Xiaobin | Email Updates: | |
Status: | Closed | Impact on me: | |
Category: | MySQL Server: Optimizer | Severity: | S3 (Non-critical) |
Version: | 5.7.2, 5.7.10, 5.7.11 | OS: | Any (Amazon Linux AMI) |
Assigned to: | CPU Architecture: | Any | |
Tags: | count, query performance, WL#6742 |
[2 Mar 2016 6:43]
Qi Xiaobin
[4 Apr 2016 9:34]
MySQL Verification Team
Hello Xiaobin, Thank you for the report. Thanks, Umesh
[24 Aug 2016 7:13]
Daniƫl van Eeden
Could you add some EXPLAIN FORMAT=JSON output? That gives some more info not available in the traditional output. And if possible the output of "show session status like 'Handler\_%';" from before and after running the query. (you might want to run 'flush status' before doing it)
[4 Sep 2016 9:29]
MySQL Verification Team
Hi Xiaobin, Could you please provide exact CREATE statement of the table poi? Please mark it as private after posting here. Thanks, Umesh
[12 Oct 2016 9:29]
MySQL Verification Team
Bug #76280 marked as duplicate of this
[12 Oct 2016 10:00]
Valeriy Kravchuk
In case anyone misses public test case, here it is: drop table if exists tdummy; create table tdummy(id int auto_increment primary key, c1 int, key(c1)) engine=InnoDB; insert into tdummy(c1) values(1); insert into tdummy(c1) select 2 from tdummy; insert into tdummy(c1) select 2 from tdummy; insert into tdummy(c1) select 2 from tdummy; insert into tdummy(c1) select 2 from tdummy; insert into tdummy(c1) select 2 from tdummy; insert into tdummy(c1) select 2 from tdummy; insert into tdummy(c1) select 2 from tdummy; insert into tdummy(c1) select 2 from tdummy; insert into tdummy(c1) select 2 from tdummy; insert into tdummy(c1) select 2 from tdummy; insert into tdummy(c1) select 2 from tdummy; insert into tdummy(c1) select 2 from tdummy; insert into tdummy(c1) select 2 from tdummy; insert into tdummy(c1) select 2 from tdummy; insert into tdummy(c1) select 2 from tdummy; insert into tdummy(c1) select 2 from tdummy; insert into tdummy(c1) select 2 from tdummy; insert into tdummy(c1) select 2 from tdummy; insert into tdummy(c1) select 2 from tdummy; insert into tdummy(c1) select 2 from tdummy; alter table tdummy add column c2 char(200) default 'a'; select version(); explain select count(*) from tdummy; show status like 'Innodb_buffer_pool_read%'; select count(*) from tdummy; show status like 'Innodb_buffer_pool_read%'; On 5.7.15 (started with --no-defaults) I have: ... mysql> insert into tdummy(c1) select 2 from tdummy; Query OK, 524288 rows affected (9.57 sec) Records: 524288 Duplicates: 0 Warnings: 0 mysql> alter table tdummy add column c2 char(200) default 'a'; Query OK, 0 rows affected (53.67 sec) Records: 0 Duplicates: 0 Warnings: 0 mysql> select version(); +-----------+ | version() | +-----------+ | 5.7.15 | +-----------+ 1 row in set (0.00 sec) mysql> mysql> explain select count(*) from tdummy; +----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+------------------------------+ | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+------------------------------+ | 1 | SIMPLE | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL | Select tables optimized away | +----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+------------------------------+ 1 row in set, 1 warning (0.01 sec) mysql> show status like 'Innodb_buffer_pool_read%'; +---------------------------------------+----------+ | Variable_name | Value | +---------------------------------------+----------+ | Innodb_buffer_pool_read_ahead_rnd | 0 | | Innodb_buffer_pool_read_ahead | 3708 | | Innodb_buffer_pool_read_ahead_evicted | 55 | | Innodb_buffer_pool_read_requests | 14145760 | | Innodb_buffer_pool_reads | 59163 | +---------------------------------------+----------+ 5 rows in set (0.00 sec) mysql> select count(*) from tdummy; +----------+ | count(*) | +----------+ | 1048576 | +----------+ 1 row in set (0.52 sec) mysql> show status like 'Innodb_buffer_pool_read%'; +---------------------------------------+----------+ | Variable_name | Value | +---------------------------------------+----------+ | Innodb_buffer_pool_read_ahead_rnd | 0 | | Innodb_buffer_pool_read_ahead | 3900 | | Innodb_buffer_pool_read_ahead_evicted | 110 | | Innodb_buffer_pool_read_requests | 14290454 | | Innodb_buffer_pool_reads | 71263 | +---------------------------------------+----------+ 5 rows in set (0.00 sec) Note time to execute and the difference in Innodb_buffer_pool_read_requests (144694) and Innodb_buffer_pool_reads. On some 5.6 (started with --no-defaults) I have: ... mysql> insert into tdummy(c1) select 2 from tdummy; Query OK, 524288 rows affected (4.50 sec) Records: 524288 Duplicates: 0 Warnings: 0 mysql> alter table tdummy add column c2 char(200) default 'a'; Query OK, 0 rows affected (39.33 sec) Records: 0 Duplicates: 0 Warnings: 0 mysql> select version(); +-------------+ | version() | +-------------+ | 5.6.28-76.1 | +-------------+ 1 row in set (0.00 sec) mysql> mysql> explain select count(*) from tdummy; +----+-------------+--------+-------+---------------+------+---------+------+---------+-------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+--------+-------+---------------+------+---------+------+---------+-------------+ | 1 | SIMPLE | tdummy | index | NULL | c1 | 5 | NULL | 1032785 | Using index | +----+-------------+--------+-------+---------------+------+---------+------+---------+-------------+ 1 row in set (0.00 sec) mysql> show status like 'Innodb_buffer_pool_read%'; +---------------------------------------+----------+ | Variable_name | Value | +---------------------------------------+----------+ | Innodb_buffer_pool_read_ahead_rnd | 0 | | Innodb_buffer_pool_read_ahead | 0 | | Innodb_buffer_pool_read_ahead_evicted | 0 | | Innodb_buffer_pool_read_requests | 13928250 | | Innodb_buffer_pool_reads | 241 | +---------------------------------------+----------+ 5 rows in set (0.00 sec) mysql> select count(*) from tdummy; +----------+ | count(*) | +----------+ | 1048576 | +----------+ 1 row in set (0.24 sec) mysql> show status like 'Innodb_buffer_pool_read%'; +---------------------------------------+----------+ | Variable_name | Value | +---------------------------------------+----------+ | Innodb_buffer_pool_read_ahead_rnd | 0 | | Innodb_buffer_pool_read_ahead | 0 | | Innodb_buffer_pool_read_ahead_evicted | 0 | | Innodb_buffer_pool_read_requests | 14045702 | | Innodb_buffer_pool_reads | 241 | +---------------------------------------+----------+ 5 rows in set (0.00 sec) Note time to execute and difference in read requests: 117452 That's what we have. To summarize, it seems 5.7's "optimization" really requires full table scan or something of that kind, even if EXPLAIN says "Select tables optimized away".
[27 Jan 2017 22:15]
Debra Bartling
This is also an issue for me on Amazon RDS MySQL 5.7.16 after upgrading from MySQL 5.6: Large table (21 million rows) with 21 indexes. Comparing the same select count(*) query on 5.6 and 5.7 versions of the same database: 5.6.22: It completed in 47.50 seconds on a cold database 5.7.16: Still running 50 minutes later, output from show processlist: Command: Query Time: 3054 State: optimizing Info: select count(*) from ... Alternative approaches to the query also take twice as long, for example: select count(anykey) from ...
[16 Feb 2017 18:36]
Daniel Price
Posted by developer: Fixed as of the upcoming 5.7.18, 8.0.1 release, and here's the changelog entry: SELECT COUNT(*) performance regressed in some cases due to a modification introduced in MySQL 5.7.2 that caused InnoDB to count rows by traversing the clustered index instead of a smaller secondary index. The modification was reverted. Thank you for the bug report.
[23 Feb 2017 17:19]
Daniel Price
Posted by developer: The changelog entry noted above now only appears in the 5.7.18 release notes.
[25 May 2018 6:01]
MySQL Verification Team
Bug #80191 marked as duplicate of this one
[3 Sep 2019 15:58]
Bhushan Mer
Recently we were planning to migrate MySQL 5.7 to 8. During benchmarking, we noticed the same issue on Innodb Version 8.0.17. It's working perfectly for SQL_CALC_FOUND_ROWS & count(distinct pk) but whenever tried to use count(*) or count(0) to get count it's fails to use index & going through whole table scan. Can you please guide whether it's a bug or some misconfiguration.