Bug #37329 range scan on partitioned table shows higher Handler_read_next
Submitted: 11 Jun 2008 5:35 Modified: 16 Jun 2008 10:29
Reporter: Sean Pringle Email Updates:
Status: Duplicate Impact on me:
None 
Category:MySQL Server: Partitions Severity:S2 (Serious)
Version:5.1.25-rc OS:Any
Assigned to: Assigned Account CPU Architecture:Any

[11 Jun 2008 5:35] Sean Pringle
Description:
In 5.1.25-rc, a range scan on a partitioned table appears to result in all index entries from the start of the range through to the end of the partition, being accessed.  This is visible as high Handler_read_next activity.

This does not appear to be internal conversion from range to full index scan, as leading index entries are still skipped.

While the result set is correct, presumably this behavior could result in a lot of unneeded index-scan-like load for short ranges near the start of a large partition.

Found this at the same time as bug #37327, but the duplicate rows there do not affect this test case.

How to repeat:
Execute this in 5.1.25-rc:

select version();

DROP TABLE IF EXISTS `t1`;
CREATE TABLE `t1` (
  `c1` int(11) DEFAULT NULL,
  KEY `c1` (`c1`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1;

DROP TABLE IF EXISTS `t2`;
CREATE TABLE `t2` (
  `c1` int(11) DEFAULT NULL,
  KEY `c1` (`c1`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 /*!50100 PARTITION BY RANGE (c1) (PARTITION a VALUES LESS THAN (100) ENGINE = MyISAM, PARTITION b VALUES LESS THAN MAXVALUE ENGINE = MyISAM) */;

INSERT INTO `t1` VALUES (1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(11),(12),(13),(14),(15),(16),(17),(18),(19),(20);
INSERT INTO `t2` VALUES (1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(11),(12),(13),(14),(15),(16),(17),(18),(19),(20);

explain partitions select c1 from t1 where (c1 > 2 and c1 < 5);

flush status;
select c1 from t1 where (c1 > 2 and c1 < 5);
show status like 'Handler_read_%';

explain partitions select c1 from t2 where (c1 > 2 and c1 < 5);

flush status;
select c1 from t2 where (c1 > 2 and c1 < 5);
show status like 'Handler_read_%';

explain partitions select c1 from t1 where (c1 > 12 and c1 < 15);

flush status;
select c1 from t1 where (c1 > 12 and c1 < 15);
show status like 'Handler_read_%';

explain partitions select c1 from t2 where (c1 > 12 and c1 < 15);

flush status;
select c1 from t2 where (c1 > 12 and c1 < 15);
show status like 'Handler_read_%';

Returns:

+-----------+
| version() |
+-----------+
| 5.1.25-rc | 
+-----------+
1 row in set (0.00 sec)

Query OK, 0 rows affected (0.00 sec)

Query OK, 0 rows affected (0.02 sec)

Query OK, 0 rows affected (0.00 sec)

Query OK, 0 rows affected (0.01 sec)

Query OK, 20 rows affected (0.00 sec)
Records: 20  Duplicates: 0  Warnings: 0

Query OK, 20 rows affected (0.00 sec)
Records: 20  Duplicates: 0  Warnings: 0

+----+-------------+-------+------------+-------+---------------+------+---------+------+------+--------------------------+
| id | select_type | table | partitions | type  | possible_keys | key  | key_len | ref  | rows | Extra                    |
+----+-------------+-------+------------+-------+---------------+------+---------+------+------+--------------------------+
|  1 | SIMPLE      | t1    | NULL       | range | c1            | c1   | 5       | NULL |    2 | Using where; Using index | 
+----+-------------+-------+------------+-------+---------------+------+---------+------+------+--------------------------+
1 row in set (0.00 sec)

Query OK, 0 rows affected (0.00 sec)

+------+
| c1   |
+------+
|    3 | 
|    4 | 
+------+
2 rows in set (0.00 sec)

+-----------------------+-------+
| Variable_name         | Value |
+-----------------------+-------+
| Handler_read_first    | 0     | 
| Handler_read_key      | 1     | 
| Handler_read_next     | 2     | 
| Handler_read_prev     | 0     | 
| Handler_read_rnd      | 0     | 
| Handler_read_rnd_next | 0     | 
+-----------------------+-------+
6 rows in set (0.00 sec)

+----+-------------+-------+------------+-------+---------------+------+---------+------+------+--------------------------+
| id | select_type | table | partitions | type  | possible_keys | key  | key_len | ref  | rows | Extra                    |
+----+-------------+-------+------------+-------+---------------+------+---------+------+------+--------------------------+
|  1 | SIMPLE      | t2    | a          | range | c1            | c1   | 5       | NULL |    2 | Using where; Using index | 
+----+-------------+-------+------------+-------+---------------+------+---------+------+------+--------------------------+
1 row in set (0.00 sec)

Query OK, 0 rows affected (0.00 sec)

+------+
| c1   |
+------+
|    3 | 
|    4 | 
+------+
2 rows in set (0.00 sec)

+-----------------------+-------+
| Variable_name         | Value |
+-----------------------+-------+
| Handler_read_first    | 0     | 
| Handler_read_key      | 1     | 
| Handler_read_next     | 18    | 
| Handler_read_prev     | 0     | 
| Handler_read_rnd      | 0     | 
| Handler_read_rnd_next | 0     | 
+-----------------------+-------+
6 rows in set (0.00 sec)

+----+-------------+-------+------------+-------+---------------+------+---------+------+------+--------------------------+
| id | select_type | table | partitions | type  | possible_keys | key  | key_len | ref  | rows | Extra                    |
+----+-------------+-------+------------+-------+---------------+------+---------+------+------+--------------------------+
|  1 | SIMPLE      | t1    | NULL       | range | c1            | c1   | 5       | NULL |    2 | Using where; Using index | 
+----+-------------+-------+------------+-------+---------------+------+---------+------+------+--------------------------+
1 row in set (0.00 sec)

Query OK, 0 rows affected (0.00 sec)

+------+
| c1   |
+------+
|   13 | 
|   14 | 
+------+
2 rows in set (0.00 sec)

+-----------------------+-------+
| Variable_name         | Value |
+-----------------------+-------+
| Handler_read_first    | 0     | 
| Handler_read_key      | 1     | 
| Handler_read_next     | 2     | 
| Handler_read_prev     | 0     | 
| Handler_read_rnd      | 0     | 
| Handler_read_rnd_next | 0     | 
+-----------------------+-------+
6 rows in set (0.00 sec)

+----+-------------+-------+------------+-------+---------------+------+---------+------+------+--------------------------+
| id | select_type | table | partitions | type  | possible_keys | key  | key_len | ref  | rows | Extra                    |
+----+-------------+-------+------------+-------+---------------+------+---------+------+------+--------------------------+
|  1 | SIMPLE      | t2    | a          | range | c1            | c1   | 5       | NULL |    2 | Using where; Using index | 
+----+-------------+-------+------------+-------+---------------+------+---------+------+------+--------------------------+
1 row in set (0.00 sec)

Query OK, 0 rows affected (0.00 sec)

+------+
| c1   |
+------+
|   13 | 
|   14 | 
+------+
2 rows in set (0.00 sec)

+-----------------------+-------+
| Variable_name         | Value |
+-----------------------+-------+
| Handler_read_first    | 0     | 
| Handler_read_key      | 1     | 
| Handler_read_next     | 8     | 
| Handler_read_prev     | 0     | 
| Handler_read_rnd      | 0     | 
| Handler_read_rnd_next | 0     | 
+-----------------------+-------+
6 rows in set (0.00 sec)

Note how Handler_read_next is always 2 for the normal MyISAM table, while it increases inversely proportional to the start of the range for the partitioned table.

Suggested fix:
Might be a 'feature' or range scan limitation for partitioning.  Requires documentation at least.
[16 Jun 2008 10:29] Mattias Jonsson
This is a duplicate of Bug#35931.

After applying the patch for Bug#35931, the Handler_read_next is constant (2 instead of 18 and 8).