溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

Mysql優(yōu)化器對in list的處理

發(fā)布時(shí)間:2020-08-16 18:39:14 來源:ITPUB博客 閱讀:280 作者:Steven1981 欄目:MySQL數(shù)據(jù)庫

select * from table where id in (....)
這樣的查詢,是走范圍索引還是走等值索引?
select * from table where key_part1 in (....) and key_part2='XX';
這樣的查詢,第二部分還走不走索引?

測試目的,想知道,MYSQL對IN LIST是如何選擇執(zhí)行計(jì)劃的;在單字段索引和復(fù)合索引中;

[@more@]


mysql 5.1.40
os:rhel 5.4
engine=innodb
innodb_file_per_table


# 先來創(chuàng)建測試環(huán)境:
create table index_test ( id int auto_increment , col1 int ,col2 varchar(200) ,content varchar(500),primary key (id) ,key col1 (col1) ) engine=innodb default charset=latin1;
# repeat insert operation 12 times

insert into index_test (col1,col2) select @rownum:=@rownum+1,column_name from information_schema.COLUMNS c , (select @rownum:=0 ) id limit 500 ;


# 測試1:先測對主鍵的IN操作;

# 測試用例:
reset query cache; --清空QUERY_CAHCE
show status like 'Innodb_buffer_pool_read_requests' ; --用來查詢邏輯讀
select * from index_test where id in (2,10,1000,2000,9000);
show status like 'Innodb_buffer_pool_read_requests' ; --與前面的結(jié)果相減,就得到SQL執(zhí)行所帶來的邏輯讀 ;
為了邏輯讀的準(zhǔn)確性, 對同一個(gè)SQL你應(yīng)該多跑幾次,以去掉物理讀 ;


root@127.0.0.1 : test 16:02:16> explain select * from index_test where id in (2,10,1000,2000);
+----+-------------+------------+-------+---------------+---------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+------------+-------+---------------+---------+---------+------+------+-------------+
| 1 | SIMPLE | index_test | range | PRIMARY | PRIMARY | 4 | NULL | 4 | Using where |
+----+-------------+------------+-------+---------------+---------+---------+------+------+-------------+
1 row in set (0.00 sec)

# 從執(zhí)行計(jì)劃看,走的是范圍條件;但我們看看實(shí)際情況 :
# 注意,為了減少篇幅,我把各個(gè)查詢的結(jié)果給刪減了。


select * from index_test where id in (2,10);
RESULTs: 2 rows
LIO ?。?4

select * from index_test where id in (2,1000);
RESULTs: 2 rows
LIO ?。?4

select * from index_test where id in (2,10,100);
RESULTs: 3 rows
LIO  : 6

select * from index_test where id in (2,10,1000,2000);
RESULTs: 4 rows
LIO ?。?8

select * from index_test where id in (2,10,1000,2000,9000);
RESULTs: 5 rows
LIO  : 10

### 在這里看到,邏輯讀根據(jù)IN LIST里KEY的數(shù)量成線性增加,而沒有根據(jù)KEY值的大小變化,所以我們判斷,對主鍵的IN操作,其實(shí)都轉(zhuǎn)成了OR操作。


# 測試2:對非主鍵的IN操作;
# 測試用例:
reset query cache;
show status like 'Innodb_buffer_pool_read_requests' ;
select * from index_test where col1 in (100,500,300,400);
show status like 'Innodb_buffer_pool_read_requests' ;


root@127.0.0.1 : test 16:06:33> explain select * from index_test where col1 in (100,200);
+----+-------------+------------+-------+---------------+------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+------------+-------+---------------+------+---------+------+------+-------------+
| 1 | SIMPLE | index_test | range | col1 | col1 | 5 | NULL | 24 | Using where |
+----+-------------+------------+-------+---------------+------+---------+------+------+-------------+
1 row in set (0.00 sec)

select * from index_test where col1 in (100,101);
RESULTs: 24 rows
LIO : 86

select * from index_test where col1 in (100,500);
RESULTs: 24 rows
LIO : 86

select * from index_test where col1 in (100,500,300);
RESULTs: 36 rows
LIO : 139

select * from index_test where col1 in (100,500,300,400);
RESULTs: 48 rows
LIO : 172

分析: 這個(gè)結(jié)果與測試1的結(jié)果是一樣的;


# 測試3:對復(fù)合索引的前列IN操作;
alter table index_test drop index col1 ,add index col1col2(col1,col2) ;
update index_test set content=concat(col2,col3,col1) ;

主要是測一下,索引的第一個(gè)字段用IN后,優(yōu)化器還會不會使用第二個(gè)字段來進(jìn)行索引搜索;

root@127.0.0.1 : test 18:41:38> explain select content from index_test where col1 in (100,500,300,400) and col2='aaaa';
+----+-------------+------------+-------+---------------+----------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+------------+-------+---------------+----------+---------+------+------+-------------+
| 1 | SIMPLE | index_test | range | col1col2 | col1col2 | 208 | NULL | 4 | Using where |
+----+-------------+------------+-------+---------------+----------+---------+------+------+-------------+
1 row in set (0.00 sec)



select count(*) from index_test where col1 in (100,500,300,400) and col2='aaaa';
RESULTs: 0 rows
LIO : 24

select content from index_test where col1 in (100,500,300,400) and col2='aaaa';
RESULTs: 0 rows
LIO : 24

分析:
#我們發(fā)現(xiàn),兩個(gè)查詢的邏輯讀是一樣,其實(shí)這已經(jīng)表明優(yōu)化器用上了索引的第二個(gè)字段,在索引搜索部分就完成了對COL2的過濾;

總結(jié):MYSQL優(yōu)化器對in list是轉(zhuǎn)成“or” 的“多個(gè)等值”查詢來處理的;并沒有轉(zhuǎn)成范圍查詢 ;

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI