1. 程式人生 > >MySQL的聯合索引和覆蓋索引

MySQL的聯合索引和覆蓋索引

關於MySQL的聯合索引,覆蓋索引一直濛濛噠,所以寫點東西來熟悉一下
首先建立一個表orders,結構如下:

create table orders(
order_id int unsigned auto_increment,
order_status int not null,
total_price int unsigned,
settle_type int,
store_id int,
buyer_id int,
goods varchar(20),
create_time datetime default current_timestamp,
primary key(order_id)
);

然後我們建立一個儲存過程,向這個表中插入一些資料:

drop procedure if exists load_orders;
delimiter //
create procedure load_orders(count int unsigned)
begin
declare status int default 0;
declare type int default 0;
declare store int default 133;
declare price int default 85;
declare buyer int default 1001;
declare goods varchar(20
) ; declare i int unsigned default 0; SET goods= 'al'; while i<count DO SET status=mod (status,77); SET type=mod(type,29); IF buyer>2000 THEN SET buyer=1001; end IF; IF price>1000 THEN SET price=200; end IF; IF length(goods)>18 THEN SET goods= 'al'; end IF; insert into orders(order_status,total_price,settle_type,store_id,goods,buyer_id) values (status, price, type
, store, goods, buyer); SET count=count+1; SET status=status+1; SET type=type+1; SET store=store+1; SET price=price+43; SET buyer=buyer+1; SET goods=concat(goods, char(round(rand()*25)+97)); SET i=i+1; end while; end // delimiter ; call load_orders(99999);#呼叫儲存過程

然後我們有表有資料啦,做一些查詢操作:

select count(store_id) as cnt from orders WHERE settle_type = 1   and order_status = 2  and buyer_id=1990;
select count(order_id) as cnt from orders WHERE settle_type = 1   and order_status = 2  and buyer_id=1990;
select count(*) as cnt from orders WHERE settle_type = 1   and order_status = 2  and buyer_id=1990;

結果如圖所示:
這裡寫圖片描述
我們發現,此時count(普通列),count(主鍵索引列),count(*)耗時都是差不多的,需要7秒多,當然還是count(*)最快。
無聯合索引的查詢計劃
從查詢計劃中我們可以看到是全表掃描的,Using where。
我們改變表的結構,給where後的三列新增一個聯合索引:

alter table orders add key union_key(settle_type,order_status,buyer_id);

然後我們再做一下上面的那三個查詢:
插入索引後
我們發現,此時count(普通列)需要用時最久,
count(主鍵索引列),count(*)耗時都是很短。

desc select count(store_id) as cnt from orders WHERE settle_type = 1   and order_status = 2  and buyer_id=1990;
desc select count(order_id) as cnt from orders WHERE settle_type = 1   and order_status = 2  and buyer_id=1990;
desc select count(*) as cnt from orders WHERE settle_type = 1   and order_status = 2  and buyer_id=1990;

新增索引後的查詢計劃

select *  from orders WHERE settle_type = 1   and order_status = 2  and buyer_id=1990;
#4 rows in set (0.00 sec)
select *  from orders WHERE settle_type = 1   and buyer_id=1990;
#243 rows in set (0.53 sec)
select *  from orders WHERE order_status = 2  and buyer_id=1990;
#91 rows in set (10.44 sec)
desc select *  from orders WHERE settle_type = 1   and order_status = 2  and buyer_id=1990;
desc select *  from orders WHERE settle_type = 1   and buyer_id=1990;
desc select *  from orders WHERE order_status = 2  and buyer_id=1990;

這裡寫圖片描述
由上圖我們看到當使用索引的第二列和第三列時根本就用不到索引。
聯合索引中是放著主鍵索引的值的。
上面的Using index condition就是使用到了ICP喲,where會在儲存引擎中過濾後再傳遞給server層。

desc select settle_type  from orders WHERE settle_type = 1   and order_status = 2  and buyer_id=1990;
desc select settle_type  from orders WHERE settle_type = 1   and buyer_id=1990;
desc select settle_type  from orders WHERE order_status = 2  and buyer_id=1990;
desc select buyer_id from orders WHERE settle_type = 1   and order_status = 2  and buyer_id=1990;
desc select buyer_id from orders WHERE settle_type = 1   and buyer_id=1990;
desc select buyer_id from orders WHERE order_status = 2  and buyer_id=1990;