一般只会为单个索引生成扫描区间,对于多个搜索条件,查询优化器会根据不同的搜索条件判断不同的扫描区间的执行成本,最后选择成本更小的扫描区间对应的索引执行查询操作
索引的代价(缺点)
- 空间代价:每建立一个索引,都要建立一个二叉树,占用存储空间
- 时间代价:对数据进行增删改操作,需要维护对应的B+树索引,破坏节点和记录的排序,需要额外的时间进行页分裂、页面回收等操作。除此之外,在执行查询语句前,需要生成一个执行计划,生成执行计划时需要计算不同索引执行查询时所需成本,索引建的多,会导致成本分析过程耗时太多,影响查询语句的执行性能。
如何正确使用索引
- 扫描区间:待扫描记录所在的区间
- 边界条件:形成扫描区间的搜索条件
select * from single_table where id >= 10001 and id <= 20002
边界条件:id >= 10001 and id <= 20002
扫描区间:待扫描记录id值所在的区间
如果想使用某个索引来执行查询,但又不能通过搜索条件形成合适的扫描区间减少需要扫描的记录数量时,则不考虑使用这个索引执行查询
根据搜索条件,减少待扫描记录的所在区间
在执行查询时,查询优化器会对SQL语句的执行成本进行分析,决定是采用【全表扫描】还是【二级索引+回表】
key1是普通二级索引,采用全表扫描+filesort的方式执行查询
explain select * from single_table order by key1
key1是普通二级索引,采用二级索引+回表的方式执行查询
explain select * from single_table order by key1 limit 10
索引条件下推(Index Condition Pushdown, ICP)
使用联合索引idx_key_part(a,b,c)执行查询时,假设搜索条件是a和c,根据搜索条件a可以形成扫描区间,每当从扫描区间获取一条二级索引记录时,先判断这个二级索引记录是否满足搜索条件c,如果满足,就不需要执行回表操作,减少回表操作带来的性能损耗。
只为搜索、排序或分组的列创建索引
考虑索引列不重复的个数
避免太多的回表次数
索引列的类型尽量小
数据类型越小,索引占用的空间越少,一个数据页可以存放更多的记录,一次页面I/O可以将更多的记录加载到内存中,读写效率也会更高。对于主键来说,更加能节省空间,因为聚集索引和二级索引都要存储记录的主键值。
为列前缀建立索引
为字符串建立列前缀(假如为字符串前10个字符建立索引),因为字符串越长,索引占用的存储空间越大。
覆盖索引
最好查询列只包含所有列
索引列以列名的形式在搜索条件中单独出现
索引列不要有计算操作
explain select * from single_table where key2 * 2 < 4
MySQL不会简化key2 * 2 < 4表达式,
直接认为搜索条件不能形成合适的扫描区间减少需要扫描的记录数,
因此该查询语句直接全表扫描
新插入的记录主键依次递增
避免页分裂带来的性能损耗