慢sql问题解决,sql优化,数据库(mysql)

文章目录

1、count效率比较

  • 所以结论是:按照效率排序的话,count(字段)<count(主键 id)<count(1)=count(*)
  • 所以我建议你,尽量使用 count(*)或count(1)。

2、作者遇到的慢sql问题

2.1、使用排序导致变慢问题

  • 表的数据大概为100万条

  • 问题原因:使用create_time字段排序,但是create_time字段没有增加索引导致速度变慢

  • 原执行速度 2.6秒

    sql 复制代码
    #导致原因
    order by create_time
  • 解决方式给字段create_time 增加一个索引,执行速度从2秒变成0.031

    sql 复制代码
    alter table 'system_log' 
    add index 'idx_create_time'

2.2、使用LEFT JOIN 导致索引失效的问题

  • 小表sys_user(用户表)

  • 大表system_log (系统日志表),默认system_log.create_time 已经创建了普通索引

  • 问题原因:索引在大表上,使用left join导致大表的索引失效

  • 原执行速度2.6秒

    sql 复制代码
    #导致原因
    from sys_user
    left join system_log on sys_user.id=system_log.user_id
    order by system_log.create_time
  • 解决办法一:使用 inner join,执行速度0.031秒

    sql 复制代码
    from sys_user
    inner join system_log on sys_user.id=system_log.user_id
    order by system_log.create_time
  • 解决办法二:使用大表驱动小表,执行速度0.033秒

    sql 复制代码
    from system_log 
    left join sys_user on sys_user.id=system_log.user_id
    order by system_log.create_time

2.3、子查询导致索引失效

  • rds数据库(mysql的一种),recode_table表记录数5亿,org_table表记录数4万

  • 原执行速度超时(60秒以上)

    sql 复制代码
    SELECT cu.org_no as orgNo,
           org.org_short_name as orgName,
           round(sum(qty) /10000, 2)  as aValue,
           cast(round((sum(qty) -sum(qty_corrprd)) / sum(qty_corrprd) *100, 2)  as decimal(22, 2)) as cValue
      FROM `org_table` org
      left join recode_table cu on cu.org_no= org.org_no
       and cu.time_period= '01'
       and cu.ind_cls in ('0101', '0202', '0303')
       and cu.stat_date between '20240801'
       and '20240810'
     where org.prnt_org_no= '11101'
     group by org.org_no,
             org.org_name,
             org.org_short_name
    sql 复制代码
    #等价于
    SELECT cu.org_no as orgNo,
           org.org_short_name as orgName,
           round(sum(qty) /10000, 2)  as aValue,
           cast(round((sum(qty) -sum(qty_corrprd)) / sum(qty_corrprd) *100, 2)  as decimal(22, 2)) as cValue
    from org_table org
    left join(
    select cu.org_no, qty, qty_corrprd
      from recode_table cu
     where cu.time_period= '01'
       and cu.ind_cls in('0101', '0202', '0303')
       and cu.stat_date between '20240801'
       and '20240810'
    ) cu on cu.org_no= org.org_no
    where org.prnt_org_no= '11101'
    group by org.org_no,
             org.org_name,
             org.org_short_name
  • 解决方式一:把条件都放到where中,执行速度2.5s

    sql 复制代码
    #搜索的结果会有略微差异,org_table关联不上的结果会消失
    SELECT cu.org_no as orgNo,
           org.org_short_name as orgName,
           round(sum(qty)  /10000, 2) as aValue,
           cast(round((sum(qty)  -sum(qty_corrprd))  / sum(qty_corrprd)  *100, 2) as decimal(22, 2))  as cValue
      FROM `org_table` org
       join recode_table cu on cu.org_no= org.org_no
     where cu.time_period= '01'
       and cu.ind_cls in('0101', '0202', '0303')
       and cu.stat_date between '20240801'
       and '20240810'
       and org.prnt_org_no= '11101'
     group by org.org_no,
             org.org_name,
             org.org_short_name
  • 解决方式二:把条件都放到where中,同时外层再重复关联org_table表执行速度2.5s

    sql 复制代码
    #多嵌套了一层非常难看,但是可以解决org_table关联结果不丢失的问题
    select org.org_no as orgNo,
           org.org_short_name as orgName,
           a.aValue as aValue,
           a.cValue as cValue
      FROM org_table org
    left join 
    (
    SELECT cu.org_no as orgNo,
           org.org_short_name as orgName,
           round(sum(qty) /10000, 2)  as aValue,
           cast(round((sum(qty) -sum(qty_corrprd)) / sum(qty_corrprd) *100, 2)  as decimal(22, 2)) as cValue
      FROM `org_table` org
      inner join recode_table cu on cu.org_no= org.org_no
     where cu.time_period= '01'
       and cu.ind_cls in ('0101', '0202', '0303')
       and cu.stat_date between '20240801'
       and '20240810'
       and org.prnt_org_no= '11101'
     group by org.org_no,
             org.org_name,
             org.org_short_name
    ) as a on a.orgNo= org.org_no
     where org.prnt_org_no= '11101'	 
  • 解决方法三:使用union 强制让子查询走索引,执行速度0.2s

    sql 复制代码
    SELECT cu.org_no as orgNo,
           org.org_short_name as orgName,
           round(sum(qty) /10000, 2)  as aValue,
           cast(round((sum(qty) -sum(qty_corrprd)) / sum(qty_corrprd) *100, 2)  as decimal(22, 2)) as cValue
    from org_table org
    left join(
    select cu.org_no, qty, qty_corrprd
      from recode_table cu
     where cu.time_period= '01'
       and cu.ind_cls in('0101', '0202', '0303')
       and cu.stat_date between '20240801'
       and '20240810'
    union
    select null,null,null
    ) cu on cu.org_no= org.org_no
    where org.prnt_org_no= '11101'
    group by org.org_no,
             org.org_name,
             org.org_short_name

3、explain命令介绍

  • explain使用方法及结果分析

  • explain命令可以查看执行计划,在你需要执行的sql语句前面加explain即可

  • filtered越小代表索引的优化效果越好,定位到需要的记录速度越快

  • 例如

    sql 复制代码
    explain select * from `order` where code='002';
  • 执行计划包含列的含义

4、阿里云rds数据库(mysql的一种)主键索引查询很慢问题

  • where的查询条件也在索引上,但是单表查询的速度非常慢
  • 解决方式:添加多个单字段索引,原本主键字段为date、org_code、type,建3个索引,每个索引对应一个字段
  • 原速度10s,加完之后0.05s
  • 为什么添加单字段索引会变快,这个问题作者也没想通

参考文档

相关推荐
松涛和鸣26 分钟前
72、IMX6ULL驱动实战:设备树(DTS/DTB)+ GPIO子系统+Platform总线
linux·服务器·arm开发·数据库·单片机
likangbinlxa44 分钟前
【Oracle11g SQL详解】UPDATE 和 DELETE 操作的正确使用
数据库·sql
r i c k1 小时前
数据库系统学习笔记
数据库·笔记·学习
野犬寒鸦1 小时前
从零起步学习JVM || 第一章:类加载器与双亲委派机制模型详解
java·jvm·数据库·后端·学习
IvorySQL2 小时前
PostgreSQL 分区表的 ALTER TABLE 语句执行机制解析
数据库·postgresql·开源
·云扬·2 小时前
MySQL 8.0 Redo Log 归档与禁用实战指南
android·数据库·mysql
野生技术架构师2 小时前
SQL语句性能优化分析及解决方案
android·sql·性能优化
IT邦德2 小时前
Oracle 26ai DataGuard 搭建(RAC到单机)
数据库·oracle
惊讶的猫3 小时前
redis分片集群
数据库·redis·缓存·分片集群·海量数据存储·高并发写