索引一文带你你搞懂索引如何优化( 二 )


5、不能使用索引中范围条件右边的列(范围列可以用到索引) , 范围列之后列的索引全失效

  • 范围条件有:&lt、&lt=、&gt、&gt=、between等 。
  • 索引最多用于一个范围列 , 如果查询条件中有两个范围列则无法全用到索引 。
  • 假如有联合索引 (empno、title、fromdate) , 那么下面的 SQL 中 emp_no 可以用到索引 , 而title 和 from_date 则使用不到索引 。
select * fromemployees.titles where emp_no &lt 10010" and title="Senior Engineer"and from_date between "1986-01-01" and "1986-12-31"
6、不要在索引列上面做任何操作(计算、函数) , 否则会导致索引失效而转向全表扫描
  • 例如下面的 SQL 语句 , 即使 date 上建立了索引 , 也会全表扫描:
select* fromdoc where YEAR(create_time) &lt= "2016"
  • 可优化为值计算 , 如下:
select* fromdoc wherecreate_time &lt= "2016-01-01"
  • 比如下面的 SQL 语句:
select* from order where date&lt = CURDATE();
  • 可以优化为:
select* from order where date&lt = "2018-01-2412:00:00"
7、强制类型转换会全表扫描
  • 字符串类型不加单引号会导致索引失效 , 因为mysql会自己做类型转换,相当于在索引列上进行了操作 。
  • 如果 phone 字段是 varchar 类型 , 则下面的 SQL 不能命中索引 。
select* from user wherephone=13800001234
  • 可以优化为:
select* from user wherephone="13800001234"
8、更新十分频繁、数据区分度不高的列不宜建立索引
  • 更新会变更 B+ 树 , 更新频繁的字段建立索引会大大降低数据库性能 。
  • “性别”这种区分度不大的属性 , 建立索引是没有什么意义的 , 不能有效过滤数据 , 性能与全表扫描类似 。
  • 一般区分度在80%以上的时候就可以建立索引 , 区分度可以使用 count(distinct(列名))/count(*) 来计算 。
9、利用覆盖索引来进行查询操作 , 避免回表 , 减少select * 的使用
  • 覆盖索引:查询的列和所建立的索引的列个数相同 , 字段相同 。
  • 被查询的列 , 数据能从索引中取得 , 而不用通过行定位符 row-locator 再到 row 上获取 , 即“被查询列要被所建的索引覆盖” , 这能够加速查询速度 。
  • 例如登录业务需求 , SQL语句如下 。
Selectuid, login_time from user wherelogin_name=? andpasswd=?
  • 可以建立(login_name, passwd, login_time)的联合索引 , 由于 login_time 已经建立在索引中了 , 被查询的 uid 和 login_time 就不用去 row 上获取数据了 , 从而加速查询 。
10、索引不会包含有NULL值的列
  • 只要列中包含有NULL值都将不会被包含在索引中 , 复合索引中只要有一列含有NULL值 , 那么这一列对于此复合索引就是无效的 。 所以我们在数据库设计时 , 尽量使用not null约束以及默认值 。
11、is null, is not null无法使用索引 12、如果有order by、group by的场景 , 请注意利用索引的有序性
  1. order by 最后的字段是组合索引的一部分 , 并且放在索引组合顺序的最后 , 避免出现file_sort 的情况 , 影响查询性能 。
  • 例如对于语句 where a=? and b=? order by c , 可以建立联合索引(a,b,c) 。
  1. 如果索引中有范围查找 , 那么索引有序性无法利用 , 如WHERE a&gt10 ORDER BY b , 索引(a,b)无法排序 。


    推荐阅读