SQL性能优化,书写高质量SQL语句

  1. limit分页优化
    当偏移量特别大时,limit效率会非常低。
    SELECT id FROM A LIMIT 1000,10 很快
    SELECT id FROM A LIMIT 90000,10 很慢
    方案一:
    select id from A order by id limit 90000,10;
    如果我们结合order by使用。很快,0.04秒就OK。因为使用了id主键做索引!当然,是否能够使用索引还需要根据业务逻辑来定,这里只是为了提醒大家,在分页的时候还需谨慎使用!
    方案二:
    select id from A order by id between 90000 and 90010;

  2. 利用limit1、top1取得一行
    有些业务逻辑进行查询操作时 (特别是在根据某一字段DESC取最大一笔) 可以使用limit 1 或者top 1 来终止 [数据库索引] 继续扫描整个表或索引。
    反例
    SELECT id FROM A LIKE ‘abc%’
    正例
    SELECT id FROM A LIKE ‘abc%’ limit 1

  3. 任何情况都不要用select * from table,用具体的字段列表替换 " * " ,不要返回用不到的字段避免全盘扫描!
    反例
    SELECT * FROM A
    正例
    SELECT id FROM A

  4. 批量插入优化
    反例
    INSERT into person(name,age) values(‘A’, 24)
    INSERT into person(name, age) values(‘B’, 24)
    INSERT into person(name,age) values(‘C’, 24)
    正例
    INSERT into person(name, age) values(‘A’, 24), (‘B’, 24), (‘C’, 24)
    sql语句的优化主要在于对索引的正确使用,而我们在开发中经常犯的错误便是对表进行全盘扫描,一来影响性能,而来耗费时间!

  5. like语句的优化
    反例
    SELECT id FROM A WHERE name like ‘%abc%’
    由于abc前面用了”%”,因此该查询必然走全表查询,除非必要(模糊查询需要包含abc),否则不要在关键词前加%
    正例
    SELECT id FROM A WHERE name like ‘abc%’

  6. where子句使用or的优化
    通常使用unionall或union的方式替换“or”会得到更好的效果。 where子句中使用了or关键字索引将被放弃使用。
    反例
    SELECT id FROM A WHERE num=10 or num=20
    正例
    SELECT id FROM A WHERE num=10 union all SELECT id FROM A WHERE num=20

  7. where子句中使用IS NULL 或 IS NOT NULL 的优化
    反例
    SELECT id FROM A WHERE num IS NULL
    在where子句中使用ISNULL或ISNOTNULL判断,索引将被放弃使用,会进行全表查询。
    正例
    优化成num上设置默认值0,确保表中num没有null值IS NULL的用法在实际业务场景下SQL使用率极高,我们应注意避免全表扫描
    SELECT id FROM A WHERE num=0

  8. where子句中对字段进行表达式操作的优化
    不要在where子句中的="左边进行函数、算数运算或其他表达式运算,否则系统将可能无法正确使用索引。

    • SELECT id FROM A WHERE datediff(day, createdate, ‘2022-01-01’)=0
      优化为
      SELECT id FROM A WHERE createdate>=‘2019-11-30’ and createdate<‘2022-01-01’

    • SELECT id FROM A WHERE year(addate)<2020
      优化为
      SELECT id FROMAwhereaddate<‘2020-01-01’

  9. 排序的索引问题
    mysql查询只是用一个索引,因此如果where子句中已经使用了索引的话,那么order by中的列是不会使用索引。因此数据库默认排序可以符合要求情况下不要使用排序操作;尽量不要包含多个列的排序,如果需要最好给这些列创建复合索引。

  10. 尽量用union all 替换 union
    union和unionall的差异主要是前者需要将两个(或者多个)结果集合并后再进行唯一性过滤操作,这就会涉及到排序,增加大量的 cpu运算,加大资源消耗及延迟。所以当我们可以确认不可能出现重复结果集或者不在乎重复结果集的时候,尽量使用unionall而不是 union

  11. Inner join 和 left join、right join、子查询

  • 第一:innerjoin内连接也叫等值连接是,left/rightjoin是外连接。
    SELECT A.id, A.name, B.id, B.name FROM A LEFT JOIN B ON A.id=B.id;
    SELECT A.id, A.name, B.id, B.name FROM A RIGHT JOIN ON B A.id=B.id;
    SELECT A.id, A.name, B.id, B.name FROM A INNER JOIN ON A.id =B.id;
    经过来之多方面的证实inner join性能比较快,因为inner join是等值连接,或许返回的行数比较少。但是我们要记得有些语句隐形的用到了等值连接,如:
    SELECT A.id A.name, B.id, B.name FROM A, B WHERE A.id=B.id;
    推荐:能用inner join连接尽量使用inner join连接
    反例
    mysql是先对外表A执行全表查询,然后根据uuid逐次执行子查询,如果外层表是一个很大的表,我们可以想象查询性能会表现比这个更加糟糕。
    Select * from A where exists(select * from B where id>=3000 and A.uuid=B.uuid);
    执行时间:2s左右
    正例
    Select * from A inner join B ON A.uuid=B.uuid where b.uuid>=3000;
    执行时间:1s不到

  • 第二:使用JOIN时候,应该用小的结果驱动大的结果
    left join左边表结果尽量小,如果有条件应该放到左边先处理,right join同理反向。如:
    反例
    Select * from A left join B A.id=B.ref_id where A.id>10
    正例
    select * from(select * from A where id>10) T1 left join B on T1.id=B.ref_id;

海投无果?不知道如何上岸?想进大厂?身份解决?我们都可以为你解决与提供专业的职场辅导。

关于我们:
我们是位于旧金山湾区的一家求职咨询公司:
1、我们帮你找到硅谷本地CPT/OPT/OPT Extension 的工作机会
2、实习保录项目,协定时间内无offer全额退款
3、项目包括:简历精修 + Mock Interviews + Project Portfolio + 第三人称介绍 + 自我介绍视频录制
4、签约、准备材料,最快3-5个工作日 拿到offer
5、81%高实习转正率 ,强资源企业优先推荐+全美百余家全职岗位内推。
(欢迎添加微信 mtg_cz