Bug #67241 Partition pruning not working utf8 / skip-character-set-client-handshake options
Submitted: 15 Oct 2012 20:03 Modified: 17 Oct 2012 13:38
Reporter: Nicolas Brousse Email Updates:
Status: Verified Impact on me:
None 
Category:MySQL Server: Partitions Severity:S3 (Non-critical)
Version:5.5 OS:Linux
Assigned to: CPU Architecture:Any

[15 Oct 2012 20:03] Nicolas Brousse
Description:
Partition pruning doesn't seem to work properly when using RANGE partition and to_days();

With MySQL 5.1:

mysql> explain partitions SELECT sum(s) FROM t WHERE time_id >= '2012-10-09 00:00:00' AND time_id < '2012-10-16 00:00:00' AND cid = 'TpqiCvy6S9af5KbEL5fQ';
+----+-------------+--------------------+-----------------------------+------+---------------+---------+---------+-------+------+-------------+
| id | select_type | table              | partitions                  | type | possible_keys | key     | key_len | ref   | rows | Extra       |
+----+-------------+--------------------+-----------------------------+------+---------------+---------+---------+-------+------+-------------+
|  1 | SIMPLE      | t | PM_2010_01_31,PM_2012_10_31 | ref  | PRIMARY       | PRIMARY | 20      | const |    2 | Using where |
+----+-------------+--------------------+-----------------------------+------+---------------+---------+---------+-------+------+-------------+
1 row in set (0.01 sec)

With MySQL 5.5:

mysql> explain partitions SELECT sum(s) FROM t WHERE time_id >= '2012-10-09 00:00:00' AND time_id < '2012-10-16 00:00:00' AND cid = 'TpqiCvy6S9af5KbEL5fQ';
+----+-------------+--------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+------+---------------+---------+---------+-------+------+-------------+
| id | select_type | table              | partitions                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              | type | possible_keys | key     | key_len | ref   | rows | Extra       |
+----+-------------+--------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+------+---------------+---------+---------+-------+------+-------------+
|  1 | SIMPLE      | t | PM_2010_01_31,PM_2010_02_28,PM_2010_03_31,PM_2010_04_30,PM_2010_05_31,PM_2010_06_30,PM_2010_07_31,PM_2010_08_31,PM_2010_09_30,PM_2010_10_31,PM_2010_11_30,PM_2010_12_31,PM_2011_01_31,PM_2011_02_28,PM_2011_03_31,PM_2011_04_30,PM_2011_05_31,PM_2011_06_30,PM_2011_07_31,PM_2011_08_31,PM_2011_09_30,PM_2011_10_31,PM_2011_11_30,PM_2011_12_31,PM_2012_01_31,PM_2012_02_29,PM_2012_03_31,PM_2012_04_30,PM_2012_05_31,PM_2012_06_30,PM_2012_07_31,PM_2012_08_31,PM_2012_09_30,PM_2012_10_31,PM_2012_11_30,PM_2012_12_31 | ref  | PRIMARY       | PRIMARY | 20      | const |    1 | Using where |
+----+-------------+--------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+------+---------------+---------+---------+-------+------+-------------+
1 row in set (0.00 sec)

How to repeat:
Create a table using PARTITION BY RANGE (to_days(time_id)). Explain partitions on a select using a small range that should it only few of the partitions. All partition will be selected.
[15 Oct 2012 20:32] MySQL Verification Team
Please provide the complete test case (sql script), with real results and expected result. Thanks.
[15 Oct 2012 22:51] Nicolas Brousse
Simply create a table this way:

create table test_nico ( cid  char(20) CHARACTER SET latin1 COLLATE latin1_bin NOT NULL, `time_id` datetime NOT NULL, PRIMARY KEY (`cid`, `time_id`), KEY `time_id` (`time_id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci /*!50100 PARTITION BY RANGE (to_days(time_id)) (PARTITION PM_2010_01_31 VALUES LESS THAN (734169) ENGINE = InnoDB,  PARTITION PM_2010_02_28 VALUES LESS THAN (734197) ENGINE = InnoDB,  PARTITION PM_2010_03_31 VALUES LESS THAN (734228) ENGINE = InnoDB,  PARTITION PM_2010_04_30 VALUES LESS THAN (734258) ENGINE = InnoDB,  PARTITION PM_2010_05_31 VALUES LESS THAN (734289) ENGINE = InnoDB,  PARTITION PM_2010_06_30 VALUES LESS THAN (734319) ENGINE = InnoDB,  PARTITION PM_2010_07_31 VALUES LESS THAN (734350) ENGINE = InnoDB,  PARTITION PM_2010_08_31 VALUES LESS THAN (734381) ENGINE = InnoDB,  PARTITION PM_2010_09_30 VALUES LESS THAN (734411) ENGINE = InnoDB,  PARTITION PM_2010_10_31 VALUES LESS THAN (734442) ENGINE = InnoDB,  PARTITION PM_2010_11_30 VALUES LESS THAN (734472) ENGINE = InnoDB,  PARTITION PM_2010_12_31 VALUES LESS THAN (734503) ENGINE = InnoDB,  PARTITION PM_2011_01_31 VALUES LESS THAN (734534) ENGINE = InnoDB,  PARTITION PM_2011_02_28 VALUES LESS THAN (734562) ENGINE = InnoDB,  PARTITION PM_2011_03_31 VALUES LESS THAN (734593) ENGINE = InnoDB,  PARTITION PM_2011_04_30 VALUES LESS THAN (734623) ENGINE = InnoDB,  PARTITION PM_2011_05_31 VALUES LESS THAN (734654) ENGINE = InnoDB,  PARTITION PM_2011_06_30 VALUES LESS THAN (734684) ENGINE = InnoDB,  PARTITION PM_2011_07_31 VALUES LESS THAN (734715) ENGINE = InnoDB,  PARTITION PM_2011_08_31 VALUES LESS THAN (734746) ENGINE = InnoDB,  PARTITION PM_2011_09_30 VALUES LESS THAN (734776) ENGINE = InnoDB,  PARTITION PM_2011_10_31 VALUES LESS THAN (734807) ENGINE = InnoDB,  PARTITION PM_2011_11_30 VALUES LESS THAN (734837) ENGINE = InnoDB,  PARTITION PM_2011_12_31 VALUES LESS THAN (734868) ENGINE = InnoDB,  PARTITION PM_2012_01_31 VALUES LESS THAN (734899) ENGINE = InnoDB,  PARTITION PM_2012_02_29 VALUES LESS THAN (734928) ENGINE = InnoDB,  PARTITION PM_2012_03_31 VALUES LESS THAN (734959) ENGINE = InnoDB,  PARTITION PM_2012_04_30 VALUES LESS THAN (734989) ENGINE = InnoDB,  PARTITION PM_2012_05_31 VALUES LESS THAN (735020) ENGINE = InnoDB,  PARTITION PM_2012_06_30 VALUES LESS THAN (735050) ENGINE = InnoDB,  PARTITION PM_2012_07_31 VALUES LESS THAN (735081) ENGINE = InnoDB,  PARTITION PM_2012_08_31 VALUES LESS THAN (735112) ENGINE = InnoDB,  PARTITION PM_2012_09_30 VALUES LESS THAN (735142) ENGINE = InnoDB,  PARTITION PM_2012_10_31 VALUES LESS THAN (735173) ENGINE = InnoDB,  PARTITION PM_2012_11_30 VALUES LESS THAN (735203) ENGINE = InnoDB,  PARTITION PM_2012_12_31 VALUES LESS THAN (735234) ENGINE = InnoDB) */;

Then, no need of data, run the query on MySQL 5.1:

mysql> explain partitions SELECT * FROM test_nico WHERE time_id >= '2012-10-09 00:00:00' AND time_id < '2012-10-16 00:00:00' AND cid = 'TpqiCvy6S9af5KbEL5fQ';
+----+-------------+-----------+-----------------------------+------+-----------------+---------+---------+-------+------+--------------------------+
| id | select_type | table     | partitions                  | type | possible_keys   | key     | key_len | ref   | rows | Extra                    |
+----+-------------+-----------+-----------------------------+------+-----------------+---------+---------+-------+------+--------------------------+
|  1 | SIMPLE      | test_nico | PM_2010_01_31,PM_2012_10_31 | ref  | PRIMARY,time_id | PRIMARY | 20      | const |   20 | Using where; Using index |
+----+-------------+-----------+-----------------------------+------+-----------------+---------+---------+-------+------+--------------------------+
1 row in set (0.00 sec)

Then on MySQL 5.5:

mysql>  explain partitions SELECT * FROM test_nico WHERE time_id >= '2012-10-09 00:00:00' AND time_id < '2012-10-16 00:00:00' AND cid = 'TpqiCvy6S9af5KbEL5fQ';+----+-------------+-----------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+------+---------------+---------+---------+-------+------+--------------------------+| id | select_type | table     | partitions                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              | type | possible_keys | key     | key_len | ref   | rows | Extra                    |+----+-------------+-----------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+------+---------------+---------+---------+-------+------+--------------------------+|  1 | SIMPLE      | test_nico | PM_2010_01_31,PM_2010_02_28,PM_2010_03_31,PM_2010_04_30,PM_2010_05_31,PM_2010_06_30,PM_2010_07_31,PM_2010_08_31,PM_2010_09_30,PM_2010_10_31,PM_2010_11_30,PM_2010_12_31,PM_2011_01_31,PM_2011_02_28,PM_2011_03_31,PM_2011_04_30,PM_2011_05_31,PM_2011_06_30,PM_2011_07_31,PM_2011_08_31,PM_2011_09_30,PM_2011_10_31,PM_2011_11_30,PM_2011_12_31,PM_2012_01_31,PM_2012_02_29,PM_2012_03_31,PM_2012_04_30,PM_2012_05_31,PM_2012_06_30,PM_2012_07_31,PM_2012_08_31,PM_2012_09_30,PM_2012_10_31,PM_2012_11_30,PM_2012_12_31 | ref  | PRIMARY       | PRIMARY | 20      | const |   36 | Using where; Using index |
+----+-------------+-----------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+------+---------------+---------+---------+-------+------+--------------------------+
1 row in set (0.00 sec)

MySQL 5.5 doesn't do proper pruning and use all partitions instead of the two concerned. It should only use PM_2010_01_31,PM_2012_10_31. Behavior changed between 5.1 and 5.5
[16 Oct 2012 14:32] MySQL Verification Team
Thank you for the feedback. Which 5.5.XX server are you using on my side with most recent source I can't repeat on Windows:

d:\dbs>d:\dbs\5.5\bin\mysql -uroot --port=3541 --prompt="mysql 5.5 >"
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 3
Server version: 5.5.29 Source distribution

Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql 5.5 >use test
Database changed

mysql 5.5 >explain partitions SELECT * FROM test_nico WHERE time_id >= '2012-10-09 00:00:00' AND time_id < '2012-10-16 00:00:00' AND cid = 'TpqiCvy6S9af5Kb
EL5fQ'
    -> ;
+----+-------------+-----------+-----------------------------+------+-----------------+---------+---------+-------+------+--------------------------+
| id | select_type | table     | partitions                  | type | possible_keys   | key     | key_len | ref   | rows | Extra                    |
+----+-------------+-----------+-----------------------------+------+-----------------+---------+---------+-------+------+--------------------------+
|  1 | SIMPLE      | test_nico | PM_2010_01_31,PM_2012_10_31 | ref  | PRIMARY,time_id | PRIMARY | 20      | const |    2 | Using where; Using index |
+----+-------------+-----------+-----------------------------+------+-----------------+---------+---------+-------+------+--------------------------+
1 row in set (0.01 sec)

mysql 5.5 >exit
Bye

d:\dbs>51c

d:\dbs>d:\dbs\5.1\bin\mysql -uroot --port=3510 --prompt="mysql 5.1 >"
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 1
Server version: 5.1.67-Win X64-log Source distribution

Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql 5.1 >use test
Database changed

mysql 5.1 >explain partitions SELECT * FROM test_nico WHERE time_id >= '2012-10-09 00:00:00' AND time_id < '2012-10-16 00:00:00' AND cid = 'TpqiCvy6S9af5Kb
EL5fQ';
+----+-------------+-----------+-----------------------------+------+-----------------+---------+---------+-------+------+--------------------------+
| id | select_type | table     | partitions                  | type | possible_keys   | key     | key_len | ref   | rows | Extra                    |
+----+-------------+-----------+-----------------------------+------+-----------------+---------+---------+-------+------+--------------------------+
|  1 | SIMPLE      | test_nico | PM_2010_01_31,PM_2012_10_31 | ref  | PRIMARY,time_id | PRIMARY | 20      | const |   20 | Using where; Using index |
+----+-------------+-----------+-----------------------------+------+-----------------+---------+---------+-------+------+--------------------------+
1 row in set (0.00 sec)

mysql 5.1 >
[16 Oct 2012 17:17] Nicolas Brousse
Investigating, it seems due to one of my innodb config option. Still digging.

innodb_flush_log_at_trx_commit=0
innodb_buffer_pool_size=4G
innodb_log_file_size=256M
innodb_additional_mem_pool_size = 16M
innodb_data_file_path = ibdata1:10M:autoextend
innodb_log_buffer_size = 8M
innodb_lock_wait_timeout = 300
innodb_log_files_in_group = 2

#innodb_log_group_home_dir=/mysql/logs
innodb_max_purge_lag = 5000000
innodb_max_dirty_pages_pct = 80
[16 Oct 2012 17:23] Nicolas Brousse
So, it's failing due to our utf8 options:

collation_server=utf8_unicode_ci
character_set_server=utf8
skip-character-set-client-handshake

removing those, fix the problem.
[16 Oct 2012 17:28] Nicolas Brousse
That's the one breaking our partition pruning: skip-character-set-client-handshake
[16 Oct 2012 17:33] Nicolas Brousse
Removing the skip-character-set-client-handshake fix our issue. Tho, still seems like a bug since it used to work in 5.1 and stopped working in 5.5.

mysql> explain partitions SELECT sum(streams_viewed) FROM rollup_adlist_camp WHERE time_id between '2012-10-09 00:00:00' AND  '2012-10-16 00:00:00';
+----+-------------+--------------------+-----------------------------+-------+---------------+---------+---------+------+------+-------------+
| id | select_type | table              | partitions                  | type  | possible_keys | key     | key_len | ref  | rows | Extra       |
+----+-------------+--------------------+-----------------------------+-------+---------------+---------+---------+------+------+-------------+
|  1 | SIMPLE      | rollup_adlist_camp | PM_2010_01_31,PM_2012_10_31 | range | time_id       | time_id | 8       | NULL |    2 | Using where |
+----+-------------+--------------------+-----------------------------+-------+---------------+---------+---------+------+------+-------------+
1 row in set (0.00 sec)
[17 Oct 2012 13:38] MySQL Verification Team
Thank you for the feedback. Indeed with the utf8 and skip-character-set-client-handshake options the issue is repeatable then removing skip-character-set-client-handshake the issue not happens anymore.

d:\dbs>d:\dbs\5.5\bin\mysql -uroot --port=3541 --prompt="mysql 5.5 >"
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 2
Server version: 5.5.29 Source distribution

Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql 5.5 >create database gh;
Query OK, 1 row affected (0.00 sec)

mysql 5.5 >use gh
Database changed
mysql 5.5 >create table test_nico 

<cut>

mysql 5.5 >explain partitions SELECT * FROM test_nico WHERE time_id >= '2012-10-09 00:00:00' AND time_id < '2012-10-16 00:00:00' AND cid = 'TpqiCvy6S9
EL5fQ'\G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: test_nico
   partitions: PM_2010_01_31,PM_2010_02_28,PM_2010_03_31,PM_2010_04_30,PM_2010_05_31,PM_2010_06_30,PM_2010_07_31,PM_2010_08_31,PM_2010_09_30,PM_2010_1
PM_2010_11_30,PM_2010_12_31,PM_2011_01_31,PM_2011_02_28,PM_2011_03_31,PM_2011_04_30,PM_2011_05_31,PM_2011_06_30,PM_2011_07_31,PM_2011_08_31,PM_2011_09
M_2011_10_31,PM_2011_11_30,PM_2011_12_31,PM_2012_01_31,PM_2012_02_29,PM_2012_03_31,PM_2012_04_30,PM_2012_05_31,PM_2012_06_30,PM_2012_07_31,PM_2012_08_
_2012_09_30,PM_2012_10_31,PM_2012_11_30,PM_2012_12_31
         type: ref
possible_keys: PRIMARY
          key: PRIMARY
      key_len: 20
          ref: const
         rows: 36
        Extra: Using where; Using index
1 row in set (0.00 sec)

d:\dbs>d:\dbs\5.1\bin\mysql -uroot --port=3510 --prompt="mysql 5.1 >"
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 1
Server version: 5.1.67-Win X64-log Source distribution

Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql 5.1 >create database th;
Query OK, 1 row affected (0.00 sec)

mysql 5.1 >use th
Database changed
mysql 5.1 >create table test_nico ( cid  char(20)

<cut>

mysql 5.1 >explain partitions SELECT * FROM test_nico WHERE time_id >= '2012-10-09 00:00:00' AND time_id < '2012-10-16 00:00:00' AND cid = 'TpqiCvy6S9
EL5fQ'\G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: test_nico
   partitions: PM_2010_01_31,PM_2012_10_31
         type: ref
possible_keys: PRIMARY,time_id
          key: PRIMARY
      key_len: 20
          ref: const
         rows: 20
        Extra: Using where; Using index
1 row in set (0.00 sec)

mysql 5.1 >