索引的使用
以下内容基于MySQL的InnoDB引擎
1、索引可以有效提高查询效率,如果一个 SQL 查询比较慢,一般是索引使用不当。
2、InnoDB使用B+树索引模型,每一个索引对应一颗B+树;
3、主键索引:PRIMARY KEY,不为空,不重复。
- 主键索引存的是整行数据,也即在seelct查询中,找到主键之后,才能获取到该条记录上的其他所有字段的数据。也叫聚簇索引;
- 非主键索引,存的是主键的值,也叫二级索引。也即通过select查询到非主键索引对应的主键索引值,再去主键索引上取其他字段的数据,回到主键索引树搜索的过程,叫回表;
Tips: 一般情况下新增一列ID列,为其添加自增主键索引(NOT NULL PRIMARY KEY AUTO_INCREMENT),此可以减少非主键索引在存储主键值时占用的空间;
- 对于
count(主键 id)
来说,InnoDB 引擎会遍历整张表,把每一行的 id 值都取出来,按行累加; - 对于
count(1)
来说,InnoDB 引擎遍历整张表,但不取值,按行累加;
count(1)
执行得要比count(主键 id)
快,因为从引擎返回 id 会涉及到解析数据行,以及拷贝字段值的操作。
- 对于
count(字段)
来说:如果这个“字段”是定义为 not null,一行行地从记录里面读出这个字段,按行累加;如果这个“字段”定义允许为 null,那么还要把值取出来再判断一下,不是 null 才累加; -
count(*)
专门做了优化,不取值,count(*)
肯定不是 null,按行累加。
- 等值查询,使用HASH索引;
- 范围查询,使用BTREE索引;
- 如要优化存储空间,可限制索引长度(但是会损失区分度,增加扫描次数,也就是时间成本),EX:
add index index_name(field_name(6))
;在设定索引长度时,可预先设定区分度损失比例,比如5%,也即DISTINCT field_name为100的话,DISTINCT field_name(6)应为100 * 0.95 = 95。损失度是具体情况而定。另外区分度很小的字段,没必要加索引,加了相当于没加。
- order by的字段,如果没有合适的索引,就要放到内存甚至磁盘中去排序了,比较费资源时间;
- 可以考虑在常用的WHERE筛选和排序的字段上添加联合索引,比如这个查询
select city,name,age from t where city='杭州' order by name limit 1000;
,可以设置联合索引(杭州
,name
),使让这俩字段有序排列,免去了再次排序的过程;
- 比如
WHERE TIMESTAMPDIFF(DAY,day_id,'2021-01-01') > 90
,这时day_id字段的索引用不上。应把函数消掉,换算到逻辑符的右边;
- 隐式类型转换;
- 隐士编码转换;
隐式转换会导致InnoDB引擎对字段偷偷使用函数,导致索引失效,应采取和7类似的做法;
- 有可能是表被锁了,在等待;
- 或者表太大,但是查询的字段没索引;