Index Condition Pushdown (ICP) of MySQL 5.6 New Features

http://www.cnblogs.com/zhoujinyi/archive/2013/04/16/3016223.htmlHow
to understand Index_Condition_Pushdown?

        Index Condition Pushdown (ICP) is an optimization of MySQL using indexes to fetch data from tables. If ICP is disabled, the engine layer will look for data rows in the base table through the index, and then return to the MySQL Server layer, and then filter the WHERE conditions for these data rows. ICP is enabled, if some WHERE conditions can use fields in the index, MySQL Server will push this part down to the engine layer. The storage engine uses the index entry, then pushes the index condition for evaluation, and uses this index to read the satisfying row from the table. ICP can reduce the number of times that the engine layer accesses the base table and the number of times that MySQL Server accesses the storage engine. In short, the optimization of ICP can filter out a large amount of data at the engine layer, which can undoubtedly reduce the number of visits to the base table and mysql server. Regarding which filer is pushed down, you can see the where condition in SQL, extract and apply

       the optimization of ICP in the database for the range, ref, eq_ref, and ref_or_null access methods, when these need to access the rows of the entire table. This strategy can be used for INNODB and MyISAM tables.
See the following example:
Index: idx_zip_com_add (`zipcode`, `company`, `address`(255))
without ICP:

copy code
set @@optimizer_switch = "index_condition_pushdown=off"

[email protected] : test 03:45:19>explain ... where zipcode = 843000 and company like '%医院%' and address like '%新疆%';
+----+-------------+-----------------+------+-----------------+-----------------+---------+-------+--------+-------------+
| id | select_type | table           | type | possible_keys   | key             | key_len | ref   | rows   | Extra       |
+----+-------------+-----------------+------+-----------------+-----------------+---------+-------+--------+-------------+
|  1 | SIMPLE      | uc_user_offline | ref  | idx_zip_com_add | idx_zip_com_add | 4       | const | 905734 | Using where |
+----+-------------+-----------------+------+-----------------+-----------------+---------+-------+--------+-------------+

[email protected] : test 03:40:05>show session status like '%handler%';
+----------------------------+--------+
| Variable_name              | Value  |
+----------------------------+--------+
| Handler_commit             | 1      |
| Handler_delete             | 0      |
| Handler_discover           | 0      |
| Handler_external_lock      | 2      |
| Handler_mrr_init           | 0      |
| Handler_prepare            | 0      |
| Handler_read_first         | 0      |
| Handler_read_key           | 1      |
| Handler_read_last          | 0      |
| Handler_read_next          | 499998 |
| Handler_read_prev          | 0      |
| Handler_read_rnd           | 0      |
| Handler_read_rnd_next      | 0      |
| Handler_rollback           | 0      |
| Handler_savepoint          | 0      |
| Handler_savepoint_rollback | 0      |
| Handler_update             | 0      |
| Handler_write              | 0      |
+----------------------------+--------+

[email protected] : test 03:40:37>show profile cpu,block io for query 4;
+----------------------+----------+----------+------------+--------------+---------------+
| Status               | Duration | CPU_user | CPU_system | Block_ops_in | Block_ops_out |
+----------------------+----------+----------+------------+--------------+---------------+
| starting             | 0.000191 | 0.000000 |   0.000000 |            0 |             0 |
| checking permissions | 0.000022 | 0.000000 |   0.000000 |            0 |             0 |
| Opening tables       | 0.000049 | 0.000000 |   0.000000 |            0 |             0 |
| init                 | 0.000076 | 0.000000 |   0.000000 |            0 |             0 |
| System lock          | 0.000030 | 0.000000 |   0.000000 |            0 |             0 |
| optimizing           | 0.000040 | 0.000000 |   0.000000 |            0 |             0 |
| statistics           | 0.000196 | 0.000000 |   0.000000 |            0 |             0 |
| preparing            | 0.000043 | 0.000000 |   0.000000 |            0 |             0 |
| executing            | 0.000014 | 0.000000 |   0.000000 |            0 |             0 |
| Sending data         | 1.435768 | 1.448091 |   0.000000 |          248 |             0 |
| end                  | 0.000073 | 0.000000 |   0.000000 |            0 |             0 |
| query end            | 0.000022 | 0.000000 |   0.000000 |            0 |             0 |
| closing tables       | 0.000022 | 0.000000 |   0.000000 |            0 |             0 |
| freeing items        | 0.000068 | 0.000000 |   0.000000 |            0 |             0 |
| cleaning up          | 0.000060 | 0.000000 |   0.000000 |            0 |             0 |
+----------------------+----------+----------+------------+--------------+---------------+
复制代码
使用ICP:

复制代码
set @@optimizer_switch = "index_condition_pushdown=on"

[email protected] : test 03:45:47>explain ... where zipcode = 843000 and company like '%医院%' and address like '%新疆%';
+----+-------------+-----------------+------+-----------------+-----------------+---------+-------+--------+------------------------------------+
| id | select_type | table           | type | possible_keys   | key             | key_len | ref   | rows   | Extra                              |
+----+-------------+-----------------+------+-----------------+-----------------+---------+-------+--------+------------------------------------+
|  1 | SIMPLE      | uc_user_offline | ref  | idx_zip_com_add | idx_zip_com_add | 4       | const | 905734 | Using index condition; Using where |
+----+-------------+-----------------+------+-----------------+-----------------+---------+-------+--------+------------------------------------+

[email protected] : test 03:46:35>show session status like '%handler%';
+----------------------------+-------+
| Variable_name              | Value |
+----------------------------+-------+
| Handler_commit             | 1     |
| Handler_delete             | 0     |
| Handler_discover           | 0     |
| Handler_external_lock      | 2     |
| Handler_mrr_init           | 0     |
| Handler_prepare            | 0     |
| Handler_read_first         | 0     |
| Handler_read_key           | 1     |
| Handler_read_last          | 0     |
| Handler_read_next          | 31619 |
| Handler_read_prev          | 0     |
| Handler_read_rnd           | 0     |
| Handler_read_rnd_next      | 0     |
| Handler_rollback           | 0     |
| Handler_savepoint          | 0     |
| Handler_savepoint_rollback | 0     |
| Handler_update             | 0     |
| Handler_write              | 0     |
+----------------------------+-------+

[email protected] : test 03:47:21>show profile cpu,block io for query 21;
+----------------------+----------+----------+------------+--------------+---------------+
| Status               | Duration | CPU_user | CPU_system | Block_ops_in | Block_ops_out |
+----------------------+----------+----------+------------+--------------+---------------+
| starting             | 0.000107 | 0.000000 |   0.000000 |            0 |             0 |
| checking permissions | 0.000022 | 0.000000 |   0.000000 |            0 |             0 |
| Opening tables       | 0.000105 | 0.000000 |   0.000000 |            0 |             0 |
| init                 | 0.000032 | 0.000000 |   0.000000 |            0 |             0 |
| System lock          | 0.000025 | 0.000000 |   0.000000 |            0 |             0 |
| optimizing           | 0.000019 | 0.000000 |   0.000000 |            0 |             0 |
| statistics           | 0.000038 | 0.000000 |   0.000000 |            0 |             0 |
| preparing            | 0.000031 | 0.000000 |   0.000000 |            0 |             0 |
| executing            | 0.000676 | 0.000000 |   0.000000 |            0 |             0 |
| Sending data         | 0.000074 | 0.000000 |   0.000000 |            0 |             0 |
| end                  | 0.000021 | 0.000000 |   0.000000 |            0 |             0 |
| query end            | 0.000016 | 0.000000 |   0.000000 |            0 |             0 |
| closing tables       | 0.000015 | 0.000000 |   0.000000 |            0 |             0 |
| Removing tmp table | 0.000044 | 0.000000 | 0.000000 | 0 | 0 |
| closing tables | 0.000018 | 0.000000 | 0 | 0 |
| freeing items | 0.000064
| | 0.000000 | 0 | 0 |
+----------------------+----------+-------- --+------------+--------------+---------------+
Copy Code
Analysis :
From the above example, it can be seen that using ICP is much better than disabling ICP.
Here's how it works before ICP:
1. Take the next zipcode= record from the index, and use the primary key field to read the entire row.
2. Then use the remaining conditions to judge this complete row to see if it meets the conditions, and filter and process it at the Server layer.

Before ICP, Mysql was in the compound index, the first column was a range query, and the second column was usually not able to use the index. It is recommended that the first column be =, <=>, is null. After the ICP came out, there was no such restriction.

With ICP, it is executed like this:
1. Take out the next record of zipcode= from the index, and then use other field conditions of this index to judge, if the condition is true, go to step 2. Filtering and processing is done at the engine layer.
2. Only those qualified in the previous step will use the primary key index to find the complete row and return.

      From the execution plan of the above SQL, it can be seen that the indexes they use are the same, and they all use their first column (key_len=4), so ICP does not affect which index the optimizer chooses, but how to use it. this index. In the above two execution plans, it can be seen that whether or not ICP is a zipcode column indexed by idx_zip_com_add, the indexes used by the two are exactly the same, but the processing methods are different.
      Before there is no ICP, since the optimizer can only use the prefix index to filter the queries that meet the conditions, mysql can only use the first field of the index zipcode to scan the records in the XX table that meet the zipcode = 843000 condition, and the following Because company and address use fuzzy query, they cannot continue to filter records that meet the conditions in the index, which leads to a lot more scans of XX table by the server layer;
      with ICP, mysql continues to check before reading XX table For records that satisfy the company and address conditions, this behavior is done at the engine layer. Directly returning the filtered ones to the Server layer reduces the operations of the Server layer. In short, push down the server layer to the engine layer for processing.

      It can be seen from the above test that the system variable Handler% has been improved a lot, and other variables have also been improved (innodb_buffer_pool_read%, innodb_data_read%d, etc.), which greatly improves the performance of Mysql: on the one hand, it improves The query performance greatly improves the range query speed of the joint index, and on the other hand saves the memory space of BP.



Summary: The optimization of ICP can filter out a large amount of data at the engine layer, which can undoubtedly reduce the number of visits to the base table and mysql server and improve performance.

The query that needs the index condition pushdown is usually a range query when the indexed fields appear in the where clause. For example:
select * from tb where tb.key_part1 < x and tb.key_part2 = y      
select * from tb where tb.key_part1 = x andtb.key_part2 like '%yyyy%'
select * from tb where tb.key_part1 > x and tb. key_part1 < y and tb.key_part1 > xx and tb.key_part2 < yy
But it should be noted that:
1. If the query of the first field of the index is without boundary, such as key_part1 like '%xxx%', then don't say ICP, Even the index will be useless.
2. If all select fields are in the index, then it is a direct index scan, and there is no need for ICP.





Limitations on the use of ICP



1 When SQL requires full table access, the optimization strategy of ICP can be used for data access methods of the range, ref, eq_ref, and ref_or_null types.
2 Supports InnoDB and MyISAM tables.
3 ICP can only be used for secondary indexes, not for primary indexes.
4 Not all where conditions can be screened by ICP.
   If the field of the where condition is not in the index column, it is still necessary to read the records of the entire table to the server side for where filtering.
5 The acceleration effect of ICP depends on the proportion of data filtered out by ICP in the storage engine.
6 The 5.6 version does not support the ICP function of sub-tables, and the 5.7 version starts to support it.
7 The ICP optimization method is not supported when sql uses a covering index.

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=326106877&siteId=291194637