Mysql慢sql优化案例

一 问题描述

生产有一个这样的慢sql:

SELECT DISTINCT

  m1.meetingid AS meetingid,

  m1.starttime AS START,

  m1.endtime AS END,

m1.title AS title,

j.userid AS uid,

j.type AS TYPE,

m1.cuserid AS cuserid

FROM

  MEETINGINFO m1

  INNER JOIN JOININFO j

    ON (m1.meetingid = j.meetingid)

    AND (

      m1.cuserid IN (192379)

      OR j.userid IN (192379)

    )

    AND m1.dostatus IN (2, 4)

ORDER BY m1.starttime DESC

LIMIT 0, 10

查询需要2.3秒。

MEETINGINFO有三十万条数据,JOININFO有将近98万条数据。

执行计划如下:

 

二 优化思路

看到查询条件里有m1.cuserid IN (192379),却选择了starttime这个索引来扫描m1,遂查询下该列上是否有索引:

SHOW INDEXES FROM MEETINGINFO #看到没有相关索引

再看下该列是否适合创建索引:

 

重复率不算高,还可以。

尝试在该列上创建索引:

CREATE INDEX ind_cuserid ON MEETINGINFO(cuserid);

发现执行计划依然没选择走该索引,原因有二:

① cuserid是varchar类型的,而sql里192379是数值类型,发生数据类型转换,会导致索引失效

② OR j.userid IN (192379)里的OR会导致无法走索引,需要用UNION ALL来代替OR。

三 解决办法

改写sql:

SELECT DISTINCT   aa.meetingid,aa.start,aa.end,aa.title,aa.uid,aa.type,aa.cuserid 
FROM
  (SELECT 
    m1.meetingid AS meetingid,
    m1.starttime AS START,
    m1.endtime AS  END,
  m1.title AS title,
  j.userid AS uid,
  j.type AS TYPE,
  m1.cuserid AS cuserid 
  FROM
    MEETINGINFO m1 
    INNER JOIN JOININFO j 
      ON (m1.meetingid = j.meetingid) 
      AND (m1.cuserid IN ('192379')) 
      AND m1.dostatus IN (2, 4) 
  UNION  ALL 
  (SELECT 
    m1.meetingid AS meetingid,
    m1.starttime AS START,
    m1.endtime AS 
  END,
  m1.title AS title,
  j.userid AS uid,
  j.type AS TYPE,
  m1.cuserid AS cuserid 
  FROM
    MEETINGINFO m1 
    INNER JOIN JOININFO j 
      ON (m1.meetingid = j.meetingid) 
      AND j.userid IN ('192379') 
      AND m1.dostatus IN (2, 4)
    )
  ) aa 
ORDER BY aa.start DESC LIMIT 0,10 

查询时间从2秒多降到了0.02秒。

执行计划如下:

 

 

MySQL中的复杂SQL优化通常涉及以下几个方面: 1. **查询重构**:避免使用子查询和联接操作过多的嵌套,可以尝试将复杂的条件转换成JOIN,或者通过临时表进行存储过程处理。 2. **索引选择**:针对经常用于WHERE子句的列创建合适的索引,如覆盖索引(只包含所需的列),复合索引等,这能大大提高查询速度。 3. **避免全表扫描**:尽量减少对数据表的全表扫描,特别是大数据集,应该利用好分区、分片等技术。 4. **使用EXPLAIN分析语句**:在执行复杂SQL之前,先使用EXPLAIN查看其执行计划,理解哪些部分可能会成为性能瓶颈。 5. **缓存优化**:开启MySQL的InnoDB的行级缓存或者设置合适的查询缓存策略,减少磁盘I/O。 6. **表分区**:对于时间序列数据或大范围值的数据,可以考虑水平或垂直分区,提高查询效率。 7. **数据库设计优化**:合理的设计数据库模式,比如减少冗余,使用合适的数据类型,降低数据复制的成本。 8. **批量处理**:对于大量数据的操作,可以考虑分批处理,而不是一次性加载到内存中。 **案例示例**:假设有一个用户表`users`和订单表`orders`,关联通过`user_id`字段。如果你发现查询所有用户的订单信息很,可以首先检查是否有正确的联合索引(`user_id`),如果没有,添加一个索引。然后,如果查询频繁且结果需要进一步处理,可能需要提取最常见的查询并作为视图存在,以便复用。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值