• mysql索引优化案例


    字符集不一致导致索引无效

    现象

    sql

     explain select DATE_FORMAT(c.closed_at, '%Y-%m-%d') as days, 
        (
                select count(DISTINCT m.chat_uid)
                from module_talk_chat_log_metric m FORCE  INDEX (ix_chat_uid)
                where m.chat_uid = c.uid
                    and m.`engineer_first_log_uid` 
            )
     as noResponseCount
    from module_talk_chat c
    where c.provider_id = 1160 
        and c.deleted = false
        and c.status = 'closed'
        and ((c.created_at >= '2022-10-13'
                and c.created_at <= '2022-10-19 23:59:59')
            or (c.closed_at >= '2022-10-13'
                and c.closed_at <= '2022-10-19 23:59:59'))

    执行计划

    首先我们先看DEPENDENT SUBQUERY原理

    参考:https://www.cnblogs.com/LQBlog/p/10723158.html#autoid-5-3-2

    知道原理我们看外层结果集数,理论上1000多行遍历子查询走索引也不至于很慢

    但是如果没走索引每次遍历子查询都全表扫描性能就会急剧下降

    后来通过对比发现2个表的字段字符集不一致

     将module_talk_chat_log_metric表的字符集修改为utf8mb4

    /* 请确认以下SQL符合您的变更需求,务必确认无误后再提交执行 */
    
    ALTER TABLE `module_talk_chat_log_metric` 
        AVG_ROW_LENGTH=0,
        MODIFY COLUMN `chat_uid` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '会话id' AFTER `provider_id`
    ;

    再看执行计划

    原理

    首先字符集不一致只是表象,真正的原因是隐式转换导致的索引无效

    如果子查询返回的列类型为utf8mb4,父查询后跟着的参数是utf8则会产生隐式类型转换,导致索引失效,反之则不会,原因在于utf8mb4是utf8的超集,兼容前者。

    如果module_talk_chat_log_metric是utf8mb4则不会触发查询字段的隐式转换 可以命中索引

    尽量带上所有条件

    简单描述一下 后面遇到sql再贴 以下只要带上一个表的provider_id 就行,但是尽量都带上 因为给数据库可以根据2个表的条件和索引选择小表做驱动表

     select * from `ticket` t 
     join `ticket_comment` tm on tm.`ticket_id` =t.`id` 
     where tm.`provider_id` =2 and t.`provider_id` =2

    大数据量sum\count sql优化

    场景:查询服务商的容量是否超限制规则

    1个工单=b  1个会话1b   附件则取附件zise

    当数据量有几百万的时候,sum性能会很低 查询需要4秒以上 数据越多则耗时越长

    explain select sum(a.`size`)  size
    from attachment a
    where a.provider_id = 17755
        and (a.deleted = 0
            or a.deleted is null)
            

    1.优化方案

    每天晚上做全量统计并存储记录统计时间

    白天获取服务商使用数量则通过全量统计的数值加上全量统计后的数据

    select sum(a.`size`)  size
    from attachment a
    where a.provider_id = 17755
        and (a.deleted = 0
            or a.deleted is null) and created_at>={同步时间}

    针对历史数据删除则需要用户手动刷新(重复以上操作 并记录新的同步时间)因为考虑到用户针对移除释放空间 都会回来看空间用量,发现没变一般都会主动点击刷新按钮

    方案2

    按年或者月 或者日维护一个数据量.当移除或者修改数据则判断移除数据时间找到制定数据量进行+ - 或许就把当天的进行一次全量?;

    为什么按 年或者月 或者日来拆分 因为如果只使用一个字段 某个时间段错误则全部错误了。。

    埋点可以使用订阅binlog的方式

  • 相关阅读:
    JavaScript操作符instanceof揭秘
    Linux打开txt文件乱码的解决方法
    Working copy locked run svn cleanup not work
    poj 2299 UltraQuickSort 归并排序求解逆序对
    poj 2312 Battle City 优先队列+bfs 或 记忆化广搜
    poj2352 stars 树状数组
    poj 2286 The Rotation Game 迭代加深
    hdu 1800 Flying to the Mars
    poj 3038 Children of the Candy Corn bfs dfs
    hdu 1983 Kaitou Kid The Phantom Thief (2) DFS + BFS
  • 原文地址:https://www.cnblogs.com/LQBlog/p/16807067.html
Copyright © 2020-2023  润新知