SQL语句优化方案及MySQL数据库优化

本文主要分析了数据库查询速度慢的原因,如扫描数据行数过多、SQL写法不科学致索引失效等。指出数据库语句查询慢的问题点,如使用“*”、未建索引等。并给出数据库语句及其他优化方案,还介绍了索引和视图的创建原则以及MySQL数据库的优化方法。

1.速度慢原因

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

2.数据库语句查询慢的问题点

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

3.数据库语句优化方案

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

4.其他优化方案

  1. 如果有like话,尽量避免%xxx%两侧都有%的条件,单侧%可以使用索引,多侧不可以。
  2. 应尽量避免在where子句中使用 != 或 <> 操作符,否则将导致引擎放弃使用索引而进行全表扫描。
  3. 应尽量避免在where子句中使用or来连接条件,否则将导致引擎放弃使用索引而进行全表扫描。
  4. 应尽量避免在where子句中对字段进行null值判断,否则将导致引擎放弃使用索引而进行全表扫描。
  5. in 和 not in 也要慎用,否则会导致全表扫描。
  6. 对查询进行优化,应尽量避免全表扫描,首先应考虑在whereorder by涉及的列上建立索引
  7. 根据查询条件,如果查询条件不止一个时,使用组合索引。
  8. 在查询条件表达式的左侧尽量不要使用函数,否则索引失效。

5.特殊说明

  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次;

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

6.索引的建立原则

  1. 索引并非越多越好,索引固然可以提高相应的select 查询的效率,但会影响物理表insert 插入、update 修改和delete删除效率,因为insert或update时有可能会重建索引,所以怎样建索引需要慎重考虑。每张表索引尽量不超过3个;
  2. 尽量不要在长文本字段建立索引,索引字段长度尽量不超过32位;
  3. 如果已经建立了a_b的联合索引,则无需再在a字段上建立索引;
  4. 建立索引时字段不能有null值;

7.视图创建原则

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

8.MySQL数据库优化

  1. EXPLAIN 你的 SELECT 查询;
  2. 当只要一行数据时使用 LIMIT 1;
  3. 使用 ENUM 而不是 VARCHAR;
  4. 固定长度的表会更快;
  5. 分库分表

 

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

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值