-- 批量插入 10w 数据 DROPPROCEDURE IF EXISTS batchInsert; DELIMITER $ CREATEPROCEDURE batchInsert() BEGINDECLARE i INTDEFAULT1; START TRANSACTION; WHILE i<=100000 DO INSERTINTO test (a,b) VALUES (i,i); SET i=i+1; END WHILE; COMMIT; END $
CALL batchInsert();
-- 得到100000 selectcount(*) from test;
2.2 没有索引
目前默认只有一个主键索引,我们分析下全表查询:
1
explain select*from test;
id
select_type
table
type
possible_keys
key
key_len
ref
rows
Extra
partitions
filtered
1
SIMPLE
test
ALL
NULL
NULL
NULL
NULL
100098
NULL
NULL
100.00
其中 type 值为 ALL,表示全表扫描了,我们看到 rows 这个字段显示有 100098 条,实际上我们一共才 10w 条数据,说明这个字段只是 mysql 的一个预估,不总是准确的。
2.3 单个字段索引
我们给字段 a 添加普通索引。
1
altertable test add index idx_a(a);
1. where 索引
走 a 索引树, 虽1行也要回表。
1
explain select*from test where a =10000;
id
select_type
table
type
possible_keys
key
key_len
ref
rows
Extra
filtered
1
SIMPLE
test
ref
idx_a
idx_a
4
const
1
NULL
100
不走索引, 因为这条语句会从索引中查出 9w 条数据,全表扫描都才 10w 条数据,所以 mysql 决策是还不如直接全表扫描得了。
1
explain select*from test where a >10000;
id
select_type
table
type
possible_keys
key
key_len
ref
rows
Extra
filtered
1
SIMPLE
test
ALL
idx_a
NULL
NULL
NULL
100098
Using where
50.00
使用了 a 索引树, 因为满足索引只有 10000 条数据,mysql 认为 10000 条数据就算回表也要比全表扫描的代价低,因而决定查索引,但还是需要回表。
1
explain select*from test where a >90000;
id
select_type
table
type
possible_keys
key
key_len
ref
rows
Extra
filtered
1
SIMPLE
test
range
idx_a
idx_a
4
NULL
10000
Using index condition
100.00
只select 索引字段, 注意这次 Extra 的值为 Using where; Using index,表示查询用到了索引,且要查询的字段在索引中就能拿到,所以不需要回表。显然这种效率比上面的要高,这也是日常开发中不建议写 select * 的原因,尽量只查询业务所需的字段。
1
explain select a from test where a >10000;
id
select_type
table
type
possible_keys
key
key_len
ref
rows
Extra
filtered
1
SIMPLE
test
range
idx_a
idx_a
4
NULL
50049
Using where; Using index
100.00
2. order by 索引
走 a 索引树, 不回表
1
explain select a from test where a >90000orderby a;
id
select_type
table
type
possible_keys
key
key_len
ref
rows
Extra
filtered
1
SIMPLE
test
range
idx_a
idx_a
4
NULL
10000
Using where; Using index
100.00
走 a 索引树, 需要回表
1 2
explain select*from test where a >90000orderby a; explain select b from test where a >90000orderby a;
id
select_type
table
type
possible_keys
key
key_len
ref
rows
Extra
filtered
1
SIMPLE
test
range
idx_a
idx_a
4
NULL
10000
Using index condition
100.00
Extra中返回了一个 Using filesort,说明无法利用索引完成排序,需要从内存或磁盘进行排序。就算 b 有索引, 也无法避免, 因为也会走 a 的索引树。
1
explain select a from test where a >90000orderby b;
id
select_type
table
type
possible_keys
key
key_len
ref
rows
Extra
filtered
1
SIMPLE
test
range
idx_a
idx_a
4
NULL
10000
Using index condition; Using filesort
100.00
2.4 多个字段索引
1. 多个字段索引
目前a, b 有自己的单个索引。
1 2 3
altertable test drop index idx_a_b; altertable test add index idx_a(a); altertable test add index idx_b(b);
没走索引,是因为无论如何都需要回表, 如果把10000改成90000, 会变成走索引加回表.
1 2 3
explain select*from test where a >10000; explain select a,b from test where a >10000; explain select b from test where a >10000;
id
select_type
table
type
possible_keys
key
key_len
ref
rows
Extra
filtered
1
SIMPLE
test
ALL
idx_a
NULL
NULL
NULL
100098
Using where
50
直接走a 的索引树, 不回表
1
explain select a from test where a >10000;
id
select_type
table
type
possible_keys
key
key_len
ref
rows
Extra
filtered
1
SIMPLE
test
range
idx_a
idx_a
4
NULL
50049
Using where; Using index
100
走 b 的索引树更好,回表
1
explain select a,b from test where a >90000and b =90000;
id
select_type
table
type
possible_keys
key
key_len
ref
rows
Extra
filtered
1
SIMPLE
test
ref
idx_a,idx_b
idx_b
4
const
1
Using where
9.99
走 a 的索引树更好,回表
1
explain select a,b from test where a =90000and b >90000;
id
select_type
table
type
possible_keys
key
key_len
ref
rows
Extra
filtered
1
SIMPLE
test
ref
idx_a,idx_b
idx_a
4
const
1
Using where
9.99
2.5 复合索引
1. 一个复合索引
1 2 3
altertable test drop index idx_a; altertable test drop index idx_b; altertable test add index idx_a_b(a,b);
目前只有一个(a,b)复合索引
走 (a,b) 的索引树, 不回表
1 2 3 4
explain select*from test where a >10000; explain select a,b from test where a >10000; explain select b from test where a >10000; explain select a from test where a >10000;
id
select_type
table
type
possible_keys
key
key_len
ref
rows
Extra
filtered
1
SIMPLE
test
range
idx_a_b
idx_a_b
4
NULL
50049
Using where; Using index
100
不满足最左匹配原则
1
explain select*from test where b >10000;
id
select_type
table
type
possible_keys
key
key_len
ref
rows
Extra
filtered
1
SIMPLE
test
index
NULL
idx_a_b
8
NULL
100098
Using where; Using index
33.33
走 (a,b) 的索引树, 不回表, key_len=4
1
explain select a,b from test where a >90000and b =90000;
id
select_type
table
type
possible_keys
key
key_len
ref
rows
Extra
filtered
1
SIMPLE
test
range
idx_a_b
idx_a_b
4
NULL
18142
Using where; Using index
10
走 (a,b) 的索引树, 不回表, key_len=8
1
explain select a,b from test where a =90000and b >90000;
id
select_type
table
type
possible_keys
key
key_len
ref
rows
Extra
filtered
1
SIMPLE
test
range
idx_a_b
idx_a_b
8
NULL
1
Using where; Using index
100
2. 普通索引和复合索引同时存在
1 2 3
altertable test add index idx_a(a); altertable test add index idx_b(b); altertable test add index idx_a_b(a,b);
目前有2个普通索引,1个复合索引.
走 (a,b) 的索引树更好, 不回表
1 2 3
explain select*from test where a >10000; explain select a,b from test where a >10000; explain select b from test where a >10000;
id
select_type
table
type
possible_keys
key
key_len
ref
rows
Extra
filtered
1
SIMPLE
test
range
idx_a_b,idx_a
idx_a_b
4
NULL
50049
Using where; Using index
100
走 a 的索引树更好, 不回表
1
explain select a from test where a >10000;
id
select_type
table
type
possible_keys
key
key_len
ref
rows
Extra
filtered
1
SIMPLE
test
range
idx_a_b,idx_a
idx_a
4
NULL
50049
Using where; Using index
100
走 b 的索引树, 需要回表. 其实此时走复合索引更好, 所以不建议复合索引和普通索引一起用
1
explain select a,b from test where a >90000and b =90000;
id
select_type
table
type
possible_keys
key
key_len
ref
rows
Extra
filtered
1
SIMPLE
test
ref
idx_a_b,idx_a,idx_b
idx_b
4
const
1
Using where
18.12
走 (a,b) 的索引树, 不回表
1
explain select a,b from test where a =90000and b >90000;