SQL查询效率优化方案

1.速度慢原因:

  1. 数据库扫描数据行数过多(和表行数多少有一定关系)
  2. SQL写法不科学导致的索引失效,出现1.1描述;

2.慢的问题点:

  1. 使用“*”,数据库高频访问时,数据库需要额外解析“*”,浪费时间;
  2. 数据库查询字段未建立索引,导致全表数据扫描;
  3. 字段已建立索引,但SQL写法导致索引无法使用,如下示例:
    1.  模糊查询:name like ‘%张’ or name like ‘_张’;
    2.  模糊查询:score != 80;
    3.  范围查询:name in (‘张三’,‘李四’);
    4.  索引字段运算:where score+10 = 100;
    5.  子查询中使用:group by子句
    6.  联合索引:index(name,score),查询:where score=80;
    7.  隐式转换:where name=12315;
    8.  Null直接参与比较:where name=null;

3.优化方案:

  1. 使用明确的列名查询:select u.id,u.name from user u;
  2. 建立合理的索引,主键约束、外键约束自带索引,优先在主键上查询;
  3. 替换的SQL写法:
    1.  模糊查询(like):视情况解决,一般是搜索引擎;
    2.  模糊查询(!=):视情况解决,可采用排除法;
    3.  范围查询(in):改用exists;
    4.  索引字段运算:where score = 100–10;
    5.  子查询(group by):视情况解决,可考虑临时表;
    6.  联合索引(name_score):拆分索引或查询name;
    7.  隐式转换:改为where name=‘12315‘;保持类型一致;
    8.  Null直接参与比较:改为where name is null;

4.特殊说明:

  1. Group by子句是我们常见的导致效率低下的原因,解决办法视情况不同而不同,下边举一个实际的例子对比下:
  2. 用户表user:uid主键,name姓名
  3. 分数表user_score:usid主键,uid用户表外键,item科目,score分数
  4. 两张表分别是用户表user和用户分数表user_score,现在统计算每个用户的总分。

方法1:

SELECT 
  u.uid,
  u.name,
  (SELECT 
    SUM(score) 
  FROM
    user_score 
  WHERE uid = u.uid) sumScore 
FROM
  USER u ;

方法2:

SELECT 
  u.uid,
  u.name,
  SUM(us.score) sumScore 
FROM
  USER u 
  LEFT JOIN user_score us 
    ON us.uid = u.uid 
GROUP BY u.uid,
  u.name ;

方法3:

SELECT 
  u.uid,
  u.name,
  s.score sumScore 
FROM
  USER u 
  LEFT JOIN 
    (SELECT 
      uid,
      SUM(score) score 
    FROM
      user_score 
    GROUP BY uid) s 
    ON u.uid = s.uid ;

此三种方法,方法1查询速度会明显优于方法2以及方法3。方法2使用了group by语句。方法3使用了group by子句,导致子句查询出来的结果会存入缓存,在缓存中进行查询时left join无法引用索引。

方法4:

SELECT 
  u.uid,
  u.name,
  s.sumScore 
FROM
  (SELECT 
    us.uid,
    SUM(us.score) sumScore 
  FROM
    user_score us 
  GROUP BY us.uid) s 
  LEFT JOIN USER u 
    ON u.uid = s.uid ;

方法4(效率略优于方法3,差异基本可忽略,也是常被遗忘的方法)。

解释说明:
如果有100个学生,200条学分(每人2条):

方法1  数据行扫描数:
最低是:100user+100*1 SUM=200次,
最高是:100user+100*1 SUM=200次;

方法2  数据行扫描数:
最低是:100user+100groupby+100*1 SUM=300次,
最高是:100user+100groupby+100*1 SUM=300次;

方法3  数据行扫描数:
最低是:100user+200groupby+100*1 leftjoin=400次,
最高是:100user+200groupby +100*100 leftjoin=13000次;

有最高和最低是因为可能第一次查询就匹配到,也可能扫描到最后才匹配到数据。

5.索引的建立原则:

  1. 索引会影响物理表插入和删除效率,并非越多越好,每张表索引尽量不超过3个;
  2. 尽量不要在长文本字段建立索引,索引字段长度尽量不超过32位;
  3. 如果已经建立了a_b的联合索引,则无需再在a字段上建立索引;

6.视图创建原则:

  1. 视图尽量不要嵌套,逻辑视图本身不支持索引,嵌套后查询时间基本上是级数级增长,数据库本身也无法对此种查询做优化;
  2. 如确实需要嵌套,尽量建立物理视图,但建立物理视图会导致服务器本身压力增大,磁盘消耗增多,物理视图依赖的物理表的插入和删除等效率受到影响;

转载请注明出处:BestEternity亲笔。

猜你喜欢

转载自blog.csdn.net/BestEternity/article/details/88669283