# SQL 语句的优化

主要围绕如何使用索引展开

  • 不要把 select 子句写成 select *

    1. 返回结果集数量太多了
    2. 需要先读取表结构,换成字段名称
  • 谨慎使用模糊查询

    select ename from t_emp where ename like '%S%'
    
    1

    「%」在左边,无法使用左前缀索引查询。

  • 对 order by 排序的字段设置索引

    索引是二叉树机制,索引建立就是有序的了,所以不用做额外的排序计算

  • 少用 is null 和 is not null

    会让 mysql 跳过索引,进行全表查询。

    null 值无法进行排序,所以不会记录在二叉树里,所以与 null 值有关的判定都不会走索引。

    -- 查询奖金不为空的数据
    select ename from t_emp where comm is not null;
    -- 可以改写成
    select ename from t_emp where comm >= 0
    -- 还可以对 comm 设置非空约束,使用 -1 表示没有奖金。
    
    1
    2
    3
    4
    5
  • 尽量少用 != 运算符

    无法利用二叉树机制。就无法走索引了。

    selecet ename from t_emp where deptno != 20;
    -- 可以改写成
    selecet ename from t_emp where deptno > 20 and deptno < 20;
    
    1
    2
    3
  • 尽量少用 OR 运算索引

    同样会让索引失效, OR 之前的会走索引,之后的就无法走索引了

    -- =20 走索引,=30 无法走索引
    select ename from t_emp where deptno = 20 or deptno=30;
    
    -- 可以改写为两个 sql
    select ename from t_emp where deptno = 20
    union all
    select ename from t_emp where deptno = 30;
    
    1
    2
    3
    4
    5
    6
    7
  • 尽量少用 in 和 not int 运算符

    在某些情况下使用 in 能走索引,参考 mysql 高性能一书

    也可以将 in 改写成 union 关联多个拆分开的查询

  • 避免条件语句中的数据类型转换

    select ename from t_emp where deptno='20'
    
    1

    在我们的苦衷 deptno 是整数类型,这里写了字符串类型,mysql 需要先转换类型,再匹配,这会影响执行速度

  • 在表达式左侧使用 运算符和函数 都会让索引失效

    -- 查询年薪超过 12 万的员工
    select ename from t_emp where salary * 12 > 100000;
    -- 可以改写为
    select ename from t_emp where salary > 100000 / 12;
    
    -- 查询 2000 年以后入职的员工
    select ename from t_emp where year(hiredate) >= 2000;
    -- 可以改写为
    select ename from t_emp where year >= '2000-01-01 00:00:00';
    
    1
    2
    3
    4
    5
    6
    7
    8
    9