索引
索引的目的是加速查找,在MysQL中,指定建立索引,会为这个表的某些列建立额外的索引文件,通过索引文件可以快速查找到内容.
索引文件是一种特殊的数据结构,在MySQL里一般有两种,一种是哈希表,一种是Btree.索引文件建立之后,表如果被改动,索引文件也会被改动,因此提高了查询性能,但降低了修改表的性能.
索引类型 | |
普通索引 | 加速查询 |
唯一索引 | 加速查询而且不能重复,可以为Null |
主键索引 | 加速查询和唯一约束(不可含null) |
组合索引 | 建立索引的时候将n个列组合成一个索引 |
索引都可以在创建表的时候建立,也可以在之后添加索引,组合索引则必须单独创立:
# 建立索引 CREATE TABLE in1( nid INT NOT NULL AUTO_INCREMENT PRIMARY KEY, # 主键写在其后表示建立主键索引,也可以单独一行 PRIMARY KEY(nid) 来建立 name varchar(32) NOT NULL, email varchar(64) NOT NULL, extra TEXT INDEX ix_name (name) # 建立普通索引 UNIQUE ix_name (name) # 建立唯一索引 ) CREATE INDEX index_name ON table_name(column_name); # 建立普通索引 CREATE INDEX ix_name_email ON in3(name,email); # 建立组合索引 CREATE UNIQUE INDEX 索引名 ON 表名(列名) # 建立唯一索引 ALTER TABLE 表名 ADD PRIMARY KEY(列名); # 主键需要用到ALTER,而不是CREATE命令 # 对于text和blob的索引,一定要加上长度,写法为列名(长度),表示对开头的多少个字符进行索引,如果不加,MySQL会报错, CREATE INDEX ix_extra ON in1(extra(32)); # 删除索引 drop index_name on table_name; # 删除普通索引 drop unique index 索引名 on 表名 # 删除唯一索引 alter table 表名 drop primary key # 删除主键索引
对于组合索引,要注意,索引的列名对于索引命中是有关系的,如果建立的时候是(name,email,age)之类建立组合索引,则遵循左前缀优先的策略才能让索引命中,即按照顺序从左侧搜索起: 例如: 按照 name -> email -> age 的条件语句是可以的,直接用email作为条件,或者email -> age,都不会进行组合索引查找
索引覆盖与索引合并
索引覆盖:直接通过索引文件就可以取到查询结果,而不用再去数据库中寻找,比如查询主键的id
索引合并,指两个列分别建立了索引,然后通过 where con1 and con2 两个条件来查询,这种情况叫做索引合并.索引合并的效率低于组合索引
索引未命中
虽然建立了索引,但一些查询,依然不会使用索引,主要有如下情况:
索引未命中的情况 | |
like '%xx' | 不会使用索引 |
使用某些超出索引范围的函数 | select * from tb1 where reverse(name) = 'wupeiqi'; |
or | 如果or内的任意一列没有编制索引,则失效 |
类型不一致 | 类型不一致的时候有时候会自动转换类型,此时无法走索引 |
!= | 判定不等于时不会走索引,但如果是主键还是会走索引 |
大于或者小于 | 也不会走索引,但如果是主键而且是整数,还是会走索引 |
order by | 如果排序的列没有编制索引,则不会走索引,即使查询的列有索引也没用.但如果是主键,还是会走索引 |
一些注意事项
- 避免使用SELECT
- 用count(1)或者count(列)来代替count(*)
- 如果知道长度,用char代替vachar,将变长部分放到最后
- 组合索引代替多个单列索引(经常使用多个条件查询时)
- 尽量让使用索引针对局部创建,比如只针对数据的不同部分
- 使用连接(JOIN)来代替子查询(Sub-Queries)
- 连表时注意条件类型需一致,类型转换效率很低下
- 如果散列值很少,而且大量重复,不适合做索引,比如性别
查看执行方式
MySQL提供了一种方式可以查看语句将如何被解释和执行的,可以用来调优.会以表格的形式展示要如何运行这个SQL语句.详细情况见此:mysql explain执行计划详解
分页性能
limit命令会直接扫描数据库,按行弄过来,所以在大量显示的时候,性能不高,有如下解决方案:
限定数据总数,比如在生成页面的时候,只取数据库的最开始100行,分成10页,如果想要查询,通过其他的方法,这样保证了页面展示不会性能低下
通过索引覆盖,但依然性能低下
解决方案是做一个记录,记录当前页的最大和最小ID,以及分页的大小.注意,不能用between and,因为很可能id不连续.然后将取出来的记录传回来之后,在页面中进行展示.可以配合Python程序,获取用户需要查询的页数,以及每页显示的内容,作为变量传入MySQL,然后用LIMIT进行分页.