分析慢SQL-Q16
ICP(Index Condition Pushdown) - 索引条件下推
什么是
ICP?不如换个问法,
ICP索引条件下推的作用是什么? 一句话总结:索引条件下推ICP就是尽可量利用二级索引筛除不符合where条件的记录,如此一来减少需要回表继续判断的次数With ICP enabled, and if parts of the WHERE condition can be evaluated by using only columns from the index, the MySQL server pushes this part of the WHERE condition down to the storage engine.The storage engine then evaluates the pushed index condition by using the index entry and only if this is satisfied is the row read from the table. ICP can reduce the number of times the storage engine must access the base table and the number of times the MySQL server must access the storage engine.
MySQL官方示例 - 初次体验ICP
示例如下,这个例子来自
MySQL官方文档:Suppose:假设这个表有联合索引INDEX(zipcode, lastname, firstname)
SELECT * FROM people WHERE zipcode='95054' AND lastname LIKE '%etrunia%' AND address LIKE '%Main Street%';
- 不用
ICP,只使用最左匹配原则。那么只能使用联合索引的zipcode,回表记录不能有效去除。- 使用
ICP,除了匹配zipcode的条件之外,额外匹配联合索引的lastname,看其是否符合where条件中的'%etrunia%',然后进行回表。如此一来,使用联合索引就可以尽可量排除不符合where条件的记录。这就是ICP优化的真谛。 With Index Condition Pushdown, MySQL checks the lastname LIKE '%etrunia%' part before reading the full table row. This avoids reading full rows corresponding to index tuples that match the zipcode condition but not the lastname condition.
为什么应该使用索引下推?
首先联合索引idx_query(user_id, event_id, follower_id),其次搜索条件为user_id in (...) and follower_id = 26407612。完全可以在联合索引idx_query上使用ICP,通过匹配user_id和follower_id两者进行回表,符合条件的记录数相比只使用user_id进行过滤然后回表的记录数一定会少很多。但是根据
explain的结果,Extra只有Using Where && key_len = 4(说明联合索引三个字段只用到了第一个user_id)该语句只是根据user_id进行回表,因为每个用户user_id有非常多的follower_id,回表的记录会非常多,并且这么多记录可能分布在聚促索引的多个页面,这就是随机I/O啊。一下子就将该查询语句变成慢查询。为什么没有使用?
按照对ICP的理解,它就是尽量利用二级索引减少回表的记录数。在这个语句中,明明可以使用ICP,为什么没有使用呢?讲道理,它就应该使用ICP
- select
- p_brand,
- p_type,
- p_size,
- count(distinct ps_suppkey) as supplier_cnt
- from
- partsupp,
- part
- where
- p_partkey = ps_partkey
- and p_brand <> 'Brand#45'
- and p_type not like 'MEDIUM POLISHED%'
- and p_size in (49,
- 14,
- 23,
- 45,
- 19,
- 3,
- 36,
- 9)
- and ps_suppkey not in (
- select
- s_suppkey
- from
- supplier
- where
- s_comment like '%Customer%Complaints%' )
- group by
- p_brand,
- p_type,
- p_size
- order by
- supplier_cnt desc,
- p_brand,
- p_type,
- p_size;
- mysql> desc partsupp;
- +---------------+---------------+------+-----+---------+-------+
- | Field | Type | Null | Key | Default | Extra |
- +---------------+---------------+------+-----+---------+-------+
- | ps_partkey | int(11) | NO | PRI | NULL | |
- | ps_suppkey | int(11) | NO | PRI | NULL | |
- | ps_availqty | int(11) | NO | | NULL | |
- | ps_supplycost | decimal(15,2) | NO | | NULL | |
- | ps_comment | varchar(199) | NO | | NULL | |
- +---------------+---------------+------+-----+---------+-------+
- 5 rows in set (0.01 sec)
- mysql> desc part;
- +---------------+---------------+------+-----+---------+-------+
- | Field | Type | Null | Key | Default | Extra |
- +---------------+---------------+------+-----+---------+-------+
- | p_partkey | int(11) | NO | PRI | NULL | |
- | p_name | varchar(55) | NO | | NULL | |
- | p_mfgr | char(25) | NO | | NULL | |
- | p_brand | char(10) | NO | | NULL | |
- | p_type | varchar(25) | NO | | NULL | |
- | p_size | int(11) | NO | | NULL | |
- | p_container | char(10) | NO | | NULL | |
- | p_retailprice | decimal(15,2) | NO | | NULL | |
- | p_comment | varchar(23) | NO | | NULL | |
- +---------------+---------------+------+-----+---------+-------+
- 9 rows in set (0.00 sec)
- mysql> desc supplier;
- +-------------+---------------+------+-----+---------+-------+
- | Field | Type | Null | Key | Default | Extra |
- +-------------+---------------+------+-----+---------+-------+
- | s_suppkey | int(11) | NO | PRI | NULL | |
- | s_name | char(25) | NO | | NULL | |
- | s_address | varchar(40) | NO | | NULL | |
- | s_nationkey | int(11) | NO | | NULL | |
- | s_phone | char(15) | NO | | NULL | |
- | s_acctbal | decimal(15,2) | NO | | NULL | |
- | s_comment | varchar(101) | NO | | NULL | |
- +-------------+---------------+------+-----+---------+-------+
- 7 rows in set (0.00 sec)
- mysql> explain select
- -> p_brand,
- -> p_type,
- -> p_size,
- -> count(distinct ps_suppkey) as supplier_cnt
- -> from
- -> partsupp,
- -> part
- -> where
- -> p_partkey = ps_partkey
- -> and p_brand <> 'Brand#45'
- -> and p_type not like 'MEDIUM POLISHED%'
- -> and p_size in (49,
- -> 14,
- -> 23,
- -> 45,
- -> 19,
- -> 3,
- -> 36,
- -> 9)
- -> and ps_suppkey not in (
- -> select
- -> s_suppkey
- -> from
- -> supplier
- -> where
- -> s_comment like '%Customer%Complaints%' )
- -> group by
- -> p_brand,
- -> p_type,
- -> p_size
- -> order by
- -> supplier_cnt desc,
- -> p_brand,
- -> p_type,
- -> p_size\G
- ERROR 2006 (HY000): MySQL server has gone away
- No connection. Trying to reconnect...
- Connection id: 20
- Current database: tpch
-
- *************************** 1. row ***************************
- id: 1
- select_type: PRIMARY
- table: partsupp
- partitions: NULL
- type: ALL
- possible_keys: PRIMARY
- key: NULL
- key_len: NULL
- ref: NULL
- rows: 8000000
- filtered: 100.00
- Extra: Using where with pushed condition (not(<in_optimizer>(`tpch`.`partsupp`.`ps_suppkey`,`tpch`.`partsupp`.`ps_suppkey` in ( <materialize> (/* select#2 */ select `tpch`.`supplier`.`s_suppkey` from `tpch`.`supplier` where (`tpch`.`supplier`.`s_comment` like '%Customer%Complaints%') ), <primary_index_lookup>(`tpch`.`partsupp`.`ps_suppkey` in <temporary table> on <auto_key> where ((`tpch`.`partsupp`.`ps_suppkey` = `materialized-subquery`.`s_suppkey`)))))))(t0) Pckrows: 2, susp. 2 (0 empty 0 full). Conditions: 1; Using temporary; Using filesort
- *************************** 2. row ***************************
- id: 1
- select_type: PRIMARY
- table: part
- partitions: NULL
- type: eq_ref
- possible_keys: PRIMARY
- key: PRIMARY
- key_len: 4
- ref: tpch.partsupp.ps_partkey
- rows: 1
- filtered: 40.00
- Extra: Using where with pushed condition ((`tpch`.`part`.`p_brand` <> 'Brand#45') and (not((`tpch`.`part`.`p_type` like 'MEDIUM POLISHED%'))) and (`tpch`.`part`.`p_size` in (49,14,23,45,19,3,36,9)))(t0) Pckrows: 31, susp. 31 (0 empty 0 full). Conditions: 3
- *************************** 3. row ***************************
- id: 2
- select_type: SUBQUERY
- table: supplier
- partitions: NULL
- type: ALL
- possible_keys: PRIMARY
- key: NULL
- key_len: NULL
- ref: NULL
- rows: 100000
- filtered: 11.11
- Extra: Using where with pushed condition (`tpch`.`supplier`.`s_comment` like '%Customer%Complaints%')(t0) Pckrows: 2, susp. 2 (0 empty 0 full). Conditions: 1
- 3 rows in set, 1 warning (0.02 sec)
-
- Using
- where
- with pushed condition (not(<in_optimizer>(`tpch`.`partsupp`.`ps_suppkey`,
- `tpch`.`partsupp`.`ps_suppkey` in ( <materialize> (/* select#2 */
- select
- `tpch`.`supplier`.`s_suppkey`
- from
- `tpch`.`supplier`
- where
- (`tpch`.`supplier`.`s_comment` like '%Customer%Complaints%') ),
- <primary_index_lookup>(`tpch`.`partsupp`.`ps_suppkey` in <temporary
- table
- > on
- <auto_key>
- where
- ((`tpch`.`partsupp`.`ps_suppkey` = `materialized-subquery`.`s_suppkey`)))))))(t0) Pckrows: 2,
- susp. 2 (0 empty 0 full). Conditions: 1;
- Using temporary;
- Using filesort
- (gdb) bt
- #0 my_strnxfrm_unicode (cs=0x487dc20
, dst=0x7f4f8166be20 "", dstlen=16, nweights=16, - src=0x7f50256c3000 "Brand#13Brand#13Brand#42Brand#34Brand#32Brand#24Brand#11Brand#44Brand#43Brand#54Brand#25Brand#33Brand#55Brand#13Brand#15Brand#32Brand#43Brand#11Brand#23Brand#12Brand#33Brand#43Brand#35Brand#52Brand#55"..., srclen=8, flags=64) at /home/jenkins/workspace/stonedb5.7-zsl-centos7.9-30-119-20220805/strings/ctype-utf8.c:5146
- #1 0x00000000030035e9 in Tianmu::common::strnxfrm (collation=..., src=0x7f4f8166be20 "", src_len=16,
- dest=0x7f50256c3000 "Brand#13Brand#13Brand#42Brand#34Brand#32Brand#24Brand#11Brand#44Brand#43Brand#54Brand#25Brand#33Brand#55Brand#13Brand#15Brand#32Brand#43Brand#11Brand#23Brand#12Brand#33Brand#43Brand#35Brand#52Brand#55"..., dest_len=8) at /home/jenkins/workspace/stonedb5.7-zsl-centos7.9-30-119-20220805/storage/tianmu/common/mysql_gate.cpp:45
- #2 0x00000000030273cd in Tianmu::core::ColumnBinEncoder::EncoderText_UTF::Encode (this=0x7f4f816c57f0, buf=0x7f4f8166be20 "", buf_sec=0x7f4f8166be6b "", vc=0x7f4f80a5a580, mit=...,
- update_stats=false) at /home/jenkins/workspace/stonedb5.7-zsl-centos7.9-30-119-20220805/storage/tianmu/core/column_bin_encoder.cpp:941
- #3 0x0000000003023785 in Tianmu::core::ColumnBinEncoder::Encode (this=0x7f4f814e4930, buf=0x7f4f8166be20 "", mit=..., alternative_vc=0x0, update_stats=false)
- at /home/jenkins/workspace/stonedb5.7-zsl-centos7.9-30-119-20220805/storage/tianmu/core/column_bin_encoder.cpp:169
- #4 0x000000000300a2bb in Tianmu::core::GroupTable::PutGroupingValue (this=0x7f72adf6e2e8, col=0, mit=...)
- at /home/jenkins/workspace/stonedb5.7-zsl-centos7.9-30-119-20220805/storage/tianmu/core/group_table.h:85
- #5 0x000000000300a629 in Tianmu::core::GroupByWrapper::PutGroupingValue (this=0x7f72adf6e220, gr_a=0, mit=...)
- at /home/jenkins/workspace/stonedb5.7-zsl-centos7.9-30-119-20220805/storage/tianmu/core/groupby_wrapper.h:82
- #6 0x0000000003007254 in Tianmu::core::AggregationAlgorithm::AggregatePackrow (this=0x7f72adf6e580, gbw=..., mit=0x7f72adf6dee0, cur_tuple=0)
- at /home/jenkins/workspace/stonedb5.7-zsl-centos7.9-30-119-20220805/storage/tianmu/core/aggregation_algorithm.cpp:547
- #7 0x0000000003005b74 in Tianmu::core::AggregationAlgorithm::MultiDimensionalGroupByScan (this=0x7f72adf6e580, gbw=..., limit=@0x7f72adf6e208: 7422784, offset=@0x7f72adf6e608: 0, sender=0x0,
- limit_less_than_no_groups=false) at /home/jenkins/workspace/stonedb5.7-zsl-centos7.9-30-119-20220805/storage/tianmu/core/aggregation_algorithm.cpp:280
- #8 0x00000000030053ca in Tianmu::core::AggregationAlgorithm::Aggregate (this=0x7f72adf6e580, just_distinct=false, limit=@0x7f72adf6e600: -1, offset=@0x7f72adf6e608: 0, sender=0x0)
- at /home/jenkins/workspace/stonedb5.7-zsl-centos7.9-30-119-20220805/storage/tianmu/core/aggregation_algorithm.cpp:196
- #9 0x0000000002df1e3e in Tianmu::core::TempTable::Materialize (this=0x7f4f8165fd80, in_subq=false, sender=0x7f4f816b1cc0, lazy=false)
- at /home/jenkins/workspace/stonedb5.7-zsl-centos7.9-30-119-20220805/storage/tianmu/core/temp_table.cpp:1972
- #10 0x0000000002d3a414 in Tianmu::core::Engine::Execute (this=0x6de5390, thd=0x7f4f800125f0, lex=0x7f4f80014918, result_output=0x7f4f80a3f3c0, unit_for_union=0x0)
- at /home/jenkins/workspace/stonedb5.7-zsl-centos7.9-30-119-20220805/storage/tianmu/core/engine_execute.cpp:426
- #11 0x0000000002d395b6 in Tianmu::core::Engine::HandleSelect (this=0x6de5390, thd=0x7f4f800125f0, lex=0x7f4f80014918, result=@0x7f72adf6ed18: 0x7f4f80a3f3c0, setup_tables_done_option=0,
- res=@0x7f72adf6ed14: 0, optimize_after_tianmu=@0x7f72adf6ed0c: 1, tianmu_free_join=@0x7f72adf6ed10: 1, with_insert=0)
- at /home/jenkins/workspace/stonedb5.7-zsl-centos7.9-30-119-20220805/storage/tianmu/core/engine_execute.cpp:232
- #12 0x0000000002e21e47 in Tianmu::dbhandler::TIANMU_HandleSelect (thd=0x7f4f800125f0, lex=0x7f4f80014918, result=@0x7f72adf6ed18: 0x7f4f80a3f3c0, setup_tables_done_option=0, res=@0x7f72adf6ed14: 0,
- optimize_after_tianmu=@0x7f72adf6ed0c: 1, tianmu_free_join=@0x7f72adf6ed10: 1, with_insert=0)
- at /home/jenkins/workspace/stonedb5.7-zsl-centos7.9-30-119-20220805/storage/tianmu/handler/ha_rcengine.cpp:82
- #13 0x0000000002462f6a in execute_sqlcom_select (thd=0x7f4f800125f0, all_tables=0x7f4f8000f548) at /home/jenkins/workspace/stonedb5.7-zsl-centos7.9-30-119-20220805/sql/sql_parse.cc:5182
- #14 0x000000000245c2ee in mysql_execute_command (thd=0x7f4f800125f0, first_level=true) at /home/jenkins/workspace/stonedb5.7-zsl-centos7.9-30-119-20220805/sql/sql_parse.cc:2831
- #15 0x0000000002463f33 in mysql_parse (thd=0x7f4f800125f0, parser_state=0x7f72adf6feb0) at /home/jenkins/workspace/stonedb5.7-zsl-centos7.9-30-119-20220805/sql/sql_parse.cc:5621
- #16 0x00000000024591cb in dispatch_command (thd=0x7f4f800125f0, com_data=0x7f72adf70650, command=COM_QUERY) at /home/jenkins/workspace/stonedb5.7-zsl-centos7.9-30-119-20220805/sql/sql_parse.cc:1495
- #17 0x00000000024580f7 in do_command (thd=0x7f4f800125f0) at /home/jenkins/workspace/stonedb5.7-zsl-centos7.9-30-119-20220805/sql/sql_parse.cc:1034
- #18 0x000000000258accd in handle_connection (arg=0xcc94f80) at /home/jenkins/workspace/stonedb5.7-zsl-centos7.9-30-119-20220805/sql/conn_handler/connection_handler_per_thread.cc:313
- #19 0x0000000002c71102 in pfs_spawn_thread (arg=0x7334f20) at /home/jenkins/workspace/stonedb5.7-zsl-centos7.9-30-119-20220805/storage/perfschema/pfs.cc:2197
- #20 0x00007f72fcf95ea5 in start_thread () from /lib64/libpthread.so.0
- #21 0x00007f72fb1cab0d in clone () from /lib64/libc.so.6

