一、常见mysql索引类型
1.B-Tree索引
大的方面看,都用的是平衡树,但集体的实现上,各引擎稍有不同点,比如:严格的说,NDB引擎使用的是T-tree,但是在myisam,innodb中,默认的使用的是B-tree索引
B-tree索引可以理解称为‘排好序的快速查找结构’
2.hash索引
在memory中,默认的是hash索引,hash的理论查询时间复杂度为O(1)
那为啥hash的查找如此的高效,为什么都不用hash索引?
1.hash函数计算后的结果是随机的,这是由于hash的映射关系是无序的,就好比python中的字典,底层用的也是hash,所以也是无序随机的
2.无法对范围查询进行优化
3.排序无法进行优化
二、使用B-tree索引的误区
1.在where条件常用列上加上索引
例如:where cat_id=3 and price>1000;#查询第3个栏目1000元以上的商品
误区:cai_id和price上都加索引,都会使用到该索引
纠正:只能用上cat_id或是price索引,因为都是独立的索引,同时只能用上1个
三、左前缀索引
1.案例
假设某个表有一个联合索引(c1,c2,c3,c4)一下只能使用该联合索引的c1,c2,c3部分
A:where c1=x and c2=x and c4>x and c3=x
B:where c1=x and c2=x and c4=x order by c3
C:where c1=x and c4=x group by c3,c2
D:where c1=x and c5=x order by c2,c3
E:where c1=x and c2=x and c5=? order by c2,c3
2.左前缀索引到底是什么?
现在建立联合索引index(a,b,c),我们来具体分析
语句 | 索引是否发挥作用 |
---|---|
where a=3 | 是,只是用了a列的索引 |
where a=3 and b=5 | 是, 使用了a,b列 |
where a=3 and b=5 and c=4 | 是, 使用了abc |
Where b=3 or where c=4 | 否 |
Where b=3 and where c=4 | a列能发挥索引,c不能 |
Where a=3 and b>10 and c=7 | a 能利用,b能利用, c不能利用 |
同上,where a=3 and b like ‘xxxx%’ and c=7 | a 能利用,b能利用, c不能利用 |
那么问题来了,如何去理解上面索引的使用?
为便于理解,假设ABC各10米长的木板,河面宽30米
全值索引,则木板长10米,like,及范围查询,则木板长6米
自己拼接一下,能否过河对岸,就知道索引能否利用上
如上例中,where a=3 and b>10 and c=7
A板长10米,A列索引发挥作用
A板正常接B板,B列索引发挥作用
B板短了,接不到C板,C列索引不发挥作用
3.解决上述问题
此时,我们刚开始的那个案例,就可以使用我们刚刚讲到的左前缀索引的知识来进行分析了
首先,建立一张测试表
create table t4(c1 tinyint(1) not null default 0,c2 tinyint(1) not null default 0,c3 tinyint(1) not null default 0,c4 tinyint(1) not null default 0,c5 tinyint(1) not null default 0,index c1234(c1,c2,c3,c4));insert into t4 values (1,3,5,6,7),(2,3,9,8,3),(4,3,2,7,5);
对于A选项
c1=x and c2=x and c4>x and c3=x <==等价==> c1=x and c2=x and c3=x and c4>x
因此 c1,c2,c3,c4都能用上
mysql> explain select * from t4 where c1=1 and c2=2 and c4>3 and c3=3 \G*************************** 1. row *************************** id: 1 select_type: SIMPLE table: t4 type: rangepossible_keys: c1234 key: c1234 key_len: 4 #可以看出c1,c2,c3,c4索引都用上
对于B选项
c1=1 and c2=2 and c4=3 order by c3
c1,c2索引用上了,c3是排好序的,因此不用额外排序,而c4没发挥作用
mysql> explain select * from t4 where c1=1 and c2=2 and c4=3 order by c3 \G*************************** 1. row *************************** id: 1 select_type: SIMPLE table: t4 type: refpossible_keys: c1234 key: c1234 key_len: 2 ref: const,const rows: 1 Extra: Using where1 row in set (0.00 sec
对于C选项
只用到c1索引,因为group by c3,c2,无法利用c2,c3索引
mysql> explain select * from t4 where c1=1 and c4=2 group by c3,c2 \G*************************** 1. row *************************** id: 1 select_type: SIMPLE table: t4 type: refpossible_keys: c1234 key: c1234 key_len: 1 #只用到c1,因为先用c4后用c2,c3分组,导致c2,c3索引没发挥作用,c4也接不上 ref: const rows: 1 Extra: Using where; Using temporary; Using filesort1 row in set (0.00 sec
mysql> explain select * from t4 where c1=1 and c4=2 group by c2,c3 \G*************************** 1. row *************************** id: 1 select_type: SIMPLE table: t4 type: refpossible_keys: c1234 key: c1234 key_len: 1 ref: const rows: 1 Extra: Using where1 row in set (0.00 sec)
Using temporary
表示由于排序没有走索引,创建了一个内存临时表
对于D选项
C1确定的基础上,c2是有序的,c2之下c3是有序的,因此c2,c3发挥排序的作用,因此,没用到filesort(文件排序,没用到索引排序)
mysql> explain select * from t4 where c1=1 and c5=2 order by c2,c3 \G *************************** 1. row *************************** id: 1 select_type: SIMPLE table: t4 type: refpossible_keys: c1234 key: c1234 key_len: 1 ref: const rows: 1 Extra: Using where1 row in set (0.00 sec)
对于E选项
这一句等价select * from t4 where c1=1 and c2=3 and c5=2 order by c3;
因为c2的值即是固定的,参与排序时并不考虑
mysql> explain select * from t4 where c1=1 and c2=3 and c5=2 order by c2,c3 \G*************************** 1. row *************************** id: 1 select_type: SIMPLE table: t4 type: refpossible_keys: c1234 key: c1234 key_len: 2 ref: const,const rows: 1 Extra: Using where1 row in set (0.00 sec)
上面就是一个比较经典的左前缀的匹配案例,因此我们在工作中应该在经常使用的列上加索引
四、主键索引解决分页问题
第1页:select * from usr limit 0,10;第2页:select * from usr limit 10,10;第3页:......第2000010页select * from usr limit 2000000,10;越往后查询,需要的时间约长,是因为越往后查,全文扫描查询,会去数据表中扫描查询。mysql> select * from usr limit 2000000,10;+---------+------+--------+--------------------+| id | name | gender | email |+---------+------+--------+--------------------+| 2000000 | jack | m | xxxx2000000@qq.com || 2000001 | jack | m | xxxx2000001@qq.com || 2000002 | jack | m | xxxx2000002@qq.com || 2000003 | jack | m | xxxx2000003@qq.com || 2000004 | jack | m | xxxx2000004@qq.com || 2000005 | jack | m | xxxx2000005@qq.com || 2000006 | jack | m | xxxx2000006@qq.com || 2000007 | jack | m | xxxx2000007@qq.com || 2000008 | jack | m | xxxx2000008@qq.com || 2000009 | jack | m | xxxx2000009@qq.com |+---------+------+--------+--------------------+10 rows in set (1.59 sec)
(1)只有上一页和下一页 做一个记录:记录当前页的最大id或最小id 下一页: select * from usr where id>max_id limit 10; 上一页: select * from usr where idpre_max_id limit (cur_max_id-pre_max_id)*10) as A order by A.id desc limit 10 );mysql> select * from usr where id>=2000000 limit 10;+---------+------+--------+--------------------+| id | name | gender | email |+---------+------+--------+--------------------+| 2000000 | jack | m | xxxx2000000@qq.com || 2000001 | jack | m | xxxx2000001@qq.com || 2000002 | jack | m | xxxx2000002@qq.com || 2000003 | jack | m | xxxx2000003@qq.com || 2000004 | jack | m | xxxx2000004@qq.com || 2000005 | jack | m | xxxx2000005@qq.com || 2000006 | jack | m | xxxx2000006@qq.com || 2000007 | jack | m | xxxx2000007@qq.com || 2000008 | jack | m | xxxx2000008@qq.com || 2000009 | jack | m | xxxx2000009@qq.com |+---------+------+--------+--------------------+10 rows in set (0.00 sec)mysql> select * from usr where id<2000000 order by id desc limit 10;+---------+------+--------+--------------------+| id | name | gender | email |+---------+------+--------+--------------------+| 1999999 | jack | m | xxxx1999999@qq.com || 1999998 | jack | m | xxxx1999998@qq.com || 1999997 | jack | m | xxxx1999997@qq.com || 1999996 | jack | m | xxxx1999996@qq.com || 1999995 | jack | m | xxxx1999995@qq.com || 1999994 | jack | m | xxxx1999994@qq.com || 1999993 | jack | m | xxxx1999993@qq.com || 1999992 | jack | m | xxxx1999992@qq.com || 1999991 | jack | m | xxxx1999991@qq.com || 1999990 | jack | m | xxxx1999990@qq.com |+---------+------+--------+--------------------+10 rows in set (0.01 sec)