Bug #70001 | Partitioned tables do not use ICP - severe performance loss after partitioning | ||
---|---|---|---|
Submitted: | 12 Aug 2013 18:46 | Modified: | 6 Nov 2013 15:18 |
Reporter: | Justin Swanhart | Email Updates: | |
Status: | Closed | Impact on me: | |
Category: | MySQL Server: Partitions | Severity: | S1 (Critical) |
Version: | 5.6.13 | OS: | Any |
Assigned to: | CPU Architecture: | Any |
[12 Aug 2013 18:46]
Justin Swanhart
[12 Aug 2013 18:51]
Justin Swanhart
see support/incoming/70001.sql
[13 Aug 2013 17:28]
MySQL Verification Team
Hello Justin, Thank you for the bug report and the test case. Verified as described. Thanks, Umesh
[6 Nov 2013 15:18]
Jon Stephens
Fixed in 5.7. Documented in the 5.7.3 changelog as follows: Index condition pushdown did not work with partitioned tables. Closed.
[13 Apr 2017 11:11]
Rimantas Ragainis
This issue is till present on 5.7.17 Any estimations on when it will be fixed?
[23 Jun 2017 8:20]
Valeriy Kravchuk
Rimantas, Can you, please, upload a test case that shows the problem with 5.7.17? In my primitive test everything works as expected: mysql> show create table cr\G *************************** 1. row *************************** Table: cr Create Table: CREATE TABLE `cr` ( `id` int(11) NOT NULL, `r1` int(11) DEFAULT NULL, `r2` int(11) DEFAULT NULL, `dt1` datetime DEFAULT NULL, `dt2` datetime DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=latin1 1 row in set (0.00 sec) mysql> show create table cc\G *************************** 1. row *************************** Table: cc Create Table: CREATE TABLE `cc` ( `id` int(11) NOT NULL, `cr_id` int(11) DEFAULT NULL, `rt` datetime DEFAULT NULL, `other` int(11) DEFAULT NULL, PRIMARY KEY (`id`), KEY `k2` (`cr_id`,`rt`) ) ENGINE=InnoDB DEFAULT CHARSET=latin1 1 row in set (0.00 sec) mysql> select count(*) from cc; +----------+ | count(*) | +----------+ | 0 | +----------+ 1 row in set (0.00 sec) mysql> select count(*) from cr; +----------+ | count(*) | +----------+ | 0 | +----------+ 1 row in set (0.00 sec) mysql> explain select cc.*, max(r2 - r1) from cr join cc on (cr.id = cc.cr_id and rt between dt1 and dt2); +----+-------------+-------+------------+------+---------------+------+---------+------------+------+----------+-----------------------+ | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +----+-------------+-------+------------+------+---------------+------+---------+------------+------+----------+-----------------------+ | 1 | SIMPLE | cr | NULL | ALL | PRIMARY | NULL | NULL | NULL | 1 | 100.00 | NULL | | 1 | SIMPLE | cc | NULL | ref | k2 | k2 | 5 | test.cr.id | 1 | 100.00 | Using index condition | +----+-------------+-------+------------+------+---------------+------+---------+------------+------+----------+-----------------------+ 2 rows in set, 1 warning (0.00 sec) So, we have ICP used. Now, let me partition the cc table in a simple way: mysql> alter table cc partition by hash(id) partitions 4; Query OK, 0 rows affected (1.58 sec) Records: 0 Duplicates: 0 Warnings: 0 mysql> explain select cc.*, max(r2 - r1) from cr join cc on (cr.id = cc.cr_id and rt between dt1 and dt2); +----+-------------+-------+-------------+------+---------------+------+---------+------------+------+----------+-----------------------+ | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +----+-------------+-------+-------------+------+---------------+------+---------+------------+------+----------+-----------------------+ | 1 | SIMPLE | cr | NULL | ALL | PRIMARY | NULL | NULL | NULL | 1 | 100.00 | NULL | | 1 | SIMPLE | cc | p0,p1,p2,p3 | ref | k2 | k2 | 5 | test.cr.id | 1 | 100.00 | Using index condition | +----+-------------+-------+-------------+------+---------------+------+---------+------------+------+----------+-----------------------+ 2 rows in set, 1 warning (0.27 sec) mysql> select version(); +-----------+ | version() | +-----------+ | 5.7.17 | +-----------+ 1 row in set (0.00 sec) As you can see, ICP is again used.
[23 Jun 2017 9:11]
Rimantas Ragainis
Sure. I used the same table structure for two tables - one is partitioned by date ("test_partitioned") and the other one isn't ("test_solid"). See SQL queries bellow: CREATE TABLE `test_partitioned` ( `service_id` int(10) unsigned NOT NULL, `uid` varchar(32) NOT NULL DEFAULT '', `date` date NOT NULL DEFAULT '0000-00-00', `created` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, `ord_rev` bigint(20) unsigned NOT NULL, PRIMARY KEY (`service_id`,`uid`,`ord_rev`,`date`) ) ENGINE=InnoDB DEFAULT CHARSET=ascii ROW_FORMAT=COMPRESSED /*!50100 PARTITION BY RANGE (TO_DAYS(`date`)) (PARTITION p20161001 VALUES LESS THAN (736634) ENGINE = InnoDB, PARTITION p20161101 VALUES LESS THAN (736664) ENGINE = InnoDB, PARTITION p20161201 VALUES LESS THAN (736695) ENGINE = InnoDB, PARTITION p20170101 VALUES LESS THAN (736726) ENGINE = InnoDB, PARTITION p20170201 VALUES LESS THAN (736754) ENGINE = InnoDB, PARTITION p20170301 VALUES LESS THAN (736785) ENGINE = InnoDB, PARTITION p20170401 VALUES LESS THAN (736815) ENGINE = InnoDB, PARTITION p20170501 VALUES LESS THAN (736846) ENGINE = InnoDB) */; INSERT INTO `test_partitioned` (`service_id`, `uid`, `date`, `created`, `ord_rev`) VALUES (1,'user123','2016-12-12','2016-12-12 07:38:07',9223223884026074696), (1,'user123','2017-01-04','2017-01-04 13:55:37',9223223683041068956), (1,'user123','2017-02-14','2017-02-14 11:17:38',9223223329748968486); CREATE TABLE `test_solid` ( `service_id` int(10) unsigned NOT NULL, `uid` varchar(32) NOT NULL DEFAULT '', `date` date NOT NULL DEFAULT '0000-00-00', `created` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, `ord_rev` bigint(20) unsigned NOT NULL, PRIMARY KEY (`service_id`,`uid`,`ord_rev`,`date`) ) ENGINE=InnoDB DEFAULT CHARSET=ascii ROW_FORMAT=COMPRESSED; INSERT INTO `test_solid` (`service_id`, `uid`, `date`, `created`, `ord_rev`) VALUES (1,'user123','2017-02-14','2017-02-14 11:17:38',9223223329748968486), (1,'user123','2017-01-04','2017-01-04 13:55:37',9223223683041068956), (1,'user123','2016-12-12','2016-12-12 07:38:07',9223223884026074696); mysql> select * from test_partitioned where service_id=1; +------------+---------+------------+---------------------+---------------------+ | service_id | uid | date | created | ord_rev | +------------+---------+------------+---------------------+---------------------+ | 1 | user123 | 2016-12-12 | 2016-12-12 07:38:07 | 9223223884026074696 | | 1 | user123 | 2017-01-04 | 2017-01-04 13:55:37 | 9223223683041068956 | | 1 | user123 | 2017-02-14 | 2017-02-14 11:17:38 | 9223223329748968486 | +------------+---------+------------+---------------------+---------------------+ 3 rows in set (0.00 sec) mysql> select * from test_solid where service_id=1; +------------+---------+------------+---------------------+---------------------+ | service_id | uid | date | created | ord_rev | +------------+---------+------------+---------------------+---------------------+ | 1 | user123 | 2017-02-14 | 2017-02-14 11:17:38 | 9223223329748968486 | | 1 | user123 | 2017-01-04 | 2017-01-04 13:55:37 | 9223223683041068956 | | 1 | user123 | 2016-12-12 | 2016-12-12 07:38:07 | 9223223884026074696 | +------------+---------+------------+---------------------+---------------------+ 3 rows in set (0.01 sec) As you can see from my example, the data from "test_solid" only is returned ordered ascending by primary key as expected.