记一次生产慢sql索引优化及思考

记一次生产慢sql索引优化及思考

问题重现

  • 夜黑风高的某一晚,突然收到一条运营后台数据库慢sql的报警,耗时竟然达到了60s。
  • img
  • 看了一下,还好不是很频繁,内心会更加从容排查问题,应该是特定条件下没有走到索引导致,如果频繁出现慢查询,可能会将数据库连接池打满,导致数据库不可用,从而导致应用不可用。

问题排查

  • 报警自带定位慢sql语句,这个是很早就上线的一条sql语句,下面对sql语句进行了简化:
  • select * from xxx where gear_id=xxx and examine=xxx order by id desc limit 10,这是个简单的根据流量池gear_id查询,按照主键id倒序进行分页查询10条数据的语句。
  • 在examine=2时查询速度很快,但是在examine=3时,查询速度极慢,然后分别在不同的examine下查看执行计划,得到的执行计划都是一致的
  • img
  • 查看执行计划,发现possible_keys中有idx_gear_id索引,但是实际用到的key却是PRIMARY,并且extra中明确用了where条件进行数据过滤。到现在就明白了这个sql是在主键聚簇索引上进行扫描,然后用where语句条件进行过滤,时间耗费在这了。
  • 这个也解释了为什么examine在不同状态下的耗时不一样,取决于where过滤扫描的行数,扫描行数越多,执行越慢,但同一个问题是都没走到我们已有的索引idx_gear_id。
  • 当单表数量较小时,无论有没有索引,或者走主键索引扫描或者普通索引都很快,很容易忽略这些问题,此时的表现就是你好,我好,大家好,然后随着数据量的增大,当达到千万级别或者亿级时,慢查询的问题就凸显出来了。

原理剖析

  • 为什么mysql会选择这个不合适的主键聚簇索引?
  • 以常用的InnoDb存储引擎为例,看一下聚簇索引和非聚簇索引查询区别:
  • 聚簇索引:通常就是按照每张表的主键构造一颗B+树,叶子节点中存放的就是整张表的行记录数据,即数据和主键都在索引上
  • 非聚簇索引:表的二级索引字段(比如唯一索引,联合索引等)构造的一颗B+树,叶子节点存储的是Key字段+主键值,即非聚集索引的叶节仍然是索引节点,但它有一个指向最终数据索引的指针。
  • 聚簇索引查询原理:
  • img
  • 非聚簇索引查询原理(二级索引查询):
  • img
  • 由以上的索引数据结构可以看出,因为聚簇索引将索引和数据保存在同一个B+树中,因此通常从聚簇索引中获取数据比非聚簇索引更快,而非聚簇索引在获取到叶子节点的主键后,需要再次查询主键索引,即回表查询行记录数据。当然如果查询的列只是索引字段,比如查询姓名和年龄,可以创建联合索引,即索引存储的内容即为需要查询的内容,这种查询速度往往比主键索引更快,这种索引查询又称为覆盖索引。

什么是回表?

  • 将以上的索引数据映射成常见的用户表user的索引为例,上面的聚簇索引就是以id字段为主键的索引,name字段为非聚簇索引,还有age等其他表字段是非索引字段,示例sql:select * from user where id = 1; 这条 SQL 语句就不需要回表。原因是根据主键的查询方式,则只需要搜索 id聚簇索引这棵 B+ 树,就可以查到对应的数据。
  • 但当我们使用非聚簇索引 name 这个索引来查询 name = b 的记录时就要用到回表。原因是通过 name 这个二级索引查询方式,则需要先搜索 name 索引树,然后得到主键 id,即PK的值为 1,再到主键id聚簇索引树再搜索一次。这种根据二级索引查询到主键id,再根据主键id查询主键聚簇索引的过程就称为回表。
  • 回到为什么mysql会选择这个不合适的主键聚簇索引问题本身,mysql执行器认为使用二级索引查出来的数据太多了,还需要基于磁盘做临时存储进行排序,然后排序取出10条,然后进行回表查询字段,性能可能会很差,所以采用了直接采用了按顺序扫描主键聚簇索引,和where条件gear_id=xxx and examine=xxx进行对比,最多放10条即可,这种情况就是数量小的时候没问题,但是当数据量大的时候,就需要一直扫描所有的数据,直到查到符合where条件的10条数据为止,同时耗时也急剧增长。

解决问题

  • 为了快速解决问题,可以采用强制索引force index,即在写sql语句时指定使用具体的索引
  • sql示例 :select * from xxx force index (idx_gear_id) where gear_id=xxx and examine=3 order by id desc limit 10,强制使用idx_gear_id这个索引。
  • 以下为使用强制索引的执行计划:
  • img
  • 可以看到实际使用的索引key就是idx_gear_id,执行耗时在几百毫秒,运营后台的业务人员完全可接受。

长期优化

  • 由于表的数据越来越多,查询条件错综复杂,还有用json字段查询问题,决定将数据异构到es查询,将json字段打平,es天然支持复杂的查询条件,查询响应更快。

  • es数据同步方案:

  • img

  • 在ES数据同步链路中,通过京东科技中间件DTS监听数据库的binlog,将索引字段(查询条件字段)及业务唯一id写入ES。

  • 在业务运营查询时,根据复杂的查询条件,先去ES查询,将业务唯一id查出,再根据业务唯一id去DB中查询业务明细数据,同时解决了业务查询的复杂性和查询性能。

    转载自:https://juejin.cn/post/7313242116770709530

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/742972.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

[论文精读]Dynamic Coarse-to-Fine Learning for Oriented Tiny Object Detection

论文网址:[2304.08876] 用于定向微小目标检测的动态粗到细学习 (arxiv.org) 论文代码:https://github.com/ChaselTsui/mmrotate-dcfl 英文是纯手打的!论文原文的summarizing and paraphrasing。可能会出现难以避免的拼写错误和语法错误&…

支付模块-基于消息队列发送支付通知消息

消息队列发送支付通知消息 需求分析 订单服务作为通用服务,在订单支付成功后需要将支付结果异步通知给其他对接的微服务,微服务收到支付结果根据订单的类型去更新自己的业务数据 技术方案 使用消息队列进行异步通知需要保证消息的可靠性即生产端将消息…

深入了解 大语言模型(LLM)微调方法

引言 众所周知,大语言模型(LLM)正在飞速发展,各行业都有了自己的大模型。其中,大模型微调技术在此过程中起到了非常关键的作用,它提升了模型的生成效率和适应性,使其能够在多样化的应用场景中发挥更大的价值。 那么&…

服务器命令

服务器命令 服务器命令top查看任务 服务器命令 top查看任务 、ps 命令 ps 命令是最基本同时也是非常强大的进程查看命令。使用该命令可以确定有哪些进程正在运行和它所运行的状态、进程是否结束、进程有没有僵死、哪些进程占用了过多的资源等。总之大部分信息都是可以通过执行…

pytorch模型转onnx格式,编写符号函数实现torch算子接口和onnx算子的映射,新建简单算子--模型部署记录整理

对于深度学习模型来说,模型部署指让训练好的模型在特定环境中运行的过程。相比于软件部署,模型部署会面临更多的难题: 运行模型所需的环境难以配置。深度学习模型通常是由一些框架编写,比如 PyTorch、TensorFlow。由于框架规模、依…

掌握Go语言:深入encoding/gob包的高效数据序列化

掌握Go语言:深入encoding/gob包的高效数据序列化 引言理解Gob和它的使用场景Gob的概念和设计目标Gob的适用场景和优势 开始使用Gob基本的Gob编码和解码示例代码编码(序列化)解码(反序列化) Gob编码高级应用自定义类型的…

【Java语言】遍历List元素时删除集合中的元素

目录 前言 实现方式 1.普通实现 1.1 使用【for循环】 方式 1.2 使用【迭代器】方式 2.jdk1.8新增功能实现 2.1 使用【lambda表达式】方式 2.2 使用【stream流】方式 注意事项 1. 使用【for循环】 方式 2. 不能使用增强for遍历修改元素 总结 前言 分享几种从List中移…

基于 K8s 容器集群的容灾架构与方案

作者:庄宇 在设计系统架构时,我们必须假设任何组件和任何基础设施可能会在任何时间失效,例如:自然灾害,电力中断,网络中断,错误的系统变更等。为了应对挑战,我们必须设计合适的容灾…

在centos8中部署Tomcat和Jenkins

参考链接:tomcat安装和部署jenkins_jenkins和tomcat-CSDN博客 1、进入centos中 /usr/local 目录文件下 [rootlocalhost webapps]# cd /usr/local2、使用通过wget命令下下载tomcat或者直接在官网下载centos版本的包后移动到centos中的local路径下 3、下载tomcat按…

VUE3内置组件Transition的学习使用

更多ruoyi-nbcio功能请看演示系统 gitee源代码地址 前后端代码: https://gitee.com/nbacheng/ruoyi-nbcio 演示地址:RuoYi-Nbcio后台管理系统 更多nbcio-boot功能请看演示系统RuoYi-Nbcio亿事达企业管理平台 gitee源代码地址 后端代码:…

详解Postman使用

简介: 1.简介 PostMan,一款接口调试工具。 特点: 可以保留接口请求的历史记录 可以使用测试集Collections有效管理组织接口 可以在团队之间同步接口数据 1.简介 PostMan,一款接口调试工具。 特点: 可以保留接口请求…

从0到1入门C++编程——12 演讲比赛流程管理系统

文章目录 一、创建类并显示菜单二、退出管理系统三、开始演讲比赛四、查看往届记录五、清空比赛记录六、案例源代码 演讲比赛流程管理系统 比赛规则:演讲比赛共有12个人参加,比赛分两轮进行,第一轮为淘汰赛,第二轮为决赛。每名选手…

HTML万字学习总结

html文本标签特殊符号图片音频与视频超链接表单列表表格语义标签(布局) html文本标签 标签简介根目录规定文档相关的配置信息&#xff08;元数据元素表示文档的内容表示那些不能由其它 HTML 元相关元素&#xff08;(<base>、<link>, <script>、<style>…

今日AI:GPT-4.5意外曝光可能6月发布、UP主借AI识别情绪播放量186万、全球首个AI程序员诞生

欢迎来到【今日AI】栏目!这里是你每天探索人工智能世界的指南&#xff0c;每天我们为你呈现AI领域的热点内容&#xff0c;聚焦开发者&#xff0c;助你洞悉技术趋势、了解创新AI产品应用。 新鲜AI产品点击了解:AIbase - 智能匹配最适合您的AI产品和网站 &#x1f4e2;一分钟速…

如何拆解技术瓶颈的难点

以大化小的思路 解决一个一个小问题从而解决最终问题 三段论&#xff1a; 抽象能力 职责领域划分 分层构建解决方案 案例&#xff1a;全局分布式事务的解决方案 抽象能力&#xff1a;全局分布式 是由一个个小的事务组合而成的&#xff0c;其中一个分布式事务出现问题&#xff…

探索考古文字场景,基于YOLOv8全系列【n/s/m/l/x】参数模型开发构建文本考古场景下的甲骨文字符图像检测识别系统

甲骨文是一种非常历史悠久的古老文字&#xff0c;在前面我们基本上很少有涉及这块的内容&#xff0c;最近正好在做文字相关的项目开发研究&#xff0c;就想着基于甲骨文的场景来开发对应的检测识别系统&#xff0c;在前文中我们基于YOLOv5、YOLOv7和YOLOv9开发构建了在仿真数据…

激活函数Mish

paper&#xff1a;Mish: A Self Regularized Non-Monotonic Activation Function official implementation&#xff1a;https://github.com/digantamisra98/Mish 背景 在早期文献中&#xff0c;Sigmoid和TanH激活函数被广泛使用&#xff0c;随后在深度神经网络中失效。相比于…

Springboot的配置文件及其优先级

配置文件 内置配置文件 配置文件的作用&#xff1a;修改SpringBoot自动配置的默认值&#xff1b;SpringBoot在底层都给我们自动配置好&#xff1b;SpringBoot使用一个全局的配置文件&#xff0c;配置文件名是固定的&#xff1a; application.propertiesapplication.yml 以上…

网络建设与运维培训介绍和能力介绍

1.开过的发票 3.培训获奖的证书 4合同签署 5.实训设备

[ThinkPHP]Arr返回1

$detailId (int)Arr::get($detail, null); var_dump($detailId); 打印结果&#xff1a;int(1) 原因&#xff1a; vendor/topthink/think-helper/src/helper/Arr.php