[msyql]实战:关于回表的一次查询优化实战

news2024/12/26 12:11:25
  1. 起因与前置环境
  2. 思考与解决方案
    1. 第一个理解与方法——分块分页
    2. 第二个理解与方法——拆分子查询
    3. 第三个理解与方法——拆分子查询+分块分页
  3. 原理浅析与总结
    1. 回表和索引覆盖的浅解
      1. 原理简单说明
      2. MYSQL中回表的实现
    2. 总结与收获

起因与前置环境

目前在职的公司是已经运转挺久的电商类型公司,这个过程中其实因为版本不断迭代和很多历史问题。会出现一些慢sql的情况。而且很多时候其实本来会感觉是不应该出现慢sql的地方莫名其妙就出现慢sql了。这些地方其实最适合我们学习数据库的知识。这一次的优化也证明了底层原理知识真的很重要。

前置环境

各位老板放心,公司真实的数据我都不会放出来的,只是利用自己的服务器数据库模拟数据,代码部分直接语言解析一下就好了。

先放sql脚本:

CREATE TABLE `xm_order_items` (
  `order_item_no` char(50) CHARACTER SET utf8mb3 COLLATE utf8_general_ci NOT NULL COMMENT '订单项号',
  `order_no` char(50) CHARACTER SET utf8mb3 COLLATE utf8_general_ci NOT NULL COMMENT '订单号',
  `product_no` char(50) CHARACTER SET utf8mb3 COLLATE utf8_general_ci DEFAULT NULL COMMENT '产品ID',
  `created_at` datetime NOT NULL COMMENT '创建时间',
  `updated_at` datetime DEFAULT NULL COMMENT '更新时间',
  PRIMARY KEY (`order_item_no`) USING BTREE,
  KEY `xm_items_order_no` (`order_no`) USING BTREE,
  KEY `xm_items_updated_at` (`updated_at`) USING BTREE,
  KEY `xm_items_created_at` (`created_at`) USING BTREE,
  KEY `xm_items_product_no_created_at` (`product_no`,`created_at`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 MAX_ROWS=1000000000 AVG_ROW_LENGTH=15000 ROW_FORMAT=COMPACT COMMENT='订单明细';
在这说一下对应的一个数据量是六百万左右,我是利用navicat直接生成的数据,所以各位也可以用不同的数据类型去直接生成对应数据量的测试数据。而且我们使用crerated_at这个创建时间去去排查,数据量大概是1000~2000 条\天这样吧。

其中,对应的慢sql是:
SELECT
      xoi.order_no AS orderNo, xoi.order_item_no AS orderItemNo
    FROM
      xm_order_items xoi
    WHERE
        xoi.product_no = 'HG-HGRS-0029'
        AND xoi.created_at >= '2022-07-01 00:00:00'
        AND xoi.created_at <= '2022-09-30 23:59:59';
对应的耗时解释:
  1. 起因与前置环境
  2. 思考与解决方案
    1. 第一个理解与方法——分块分页
    2. 第二个理解与方法——拆分子查询
    3. 第三个理解与方法——拆分子查询+分块分页
  3. 原理浅析与总结
    1. 回表和索引覆盖的浅解
      1. 原理简单说明
      2. MYSQL中回表的实现
    2. 总结与收获

起因与前置环境

目前在职的公司是已经运转挺久的电商类型公司,这个过程中其实因为版本不断迭代和很多历史问题。会出现一些慢sql的情况。而且很多时候其实本来会感觉是不应该出现慢sql的地方莫名其妙就出现慢sql了。这些地方其实最适合我们学习数据库的知识。这一次的优化也证明了底层原理知识真的很重要。

前置环境

各位老板放心,公司真实的数据我都不会放出来的,只是利用自己的服务器数据库模拟数据,代码部分直接语言解析一下就好了。

先放sql脚本:

CREATE TABLE `xm_order_items` (
  `order_item_no` char(50) CHARACTER SET utf8mb3 COLLATE utf8_general_ci NOT NULL COMMENT '订单项号',
  `order_no` char(50) CHARACTER SET utf8mb3 COLLATE utf8_general_ci NOT NULL COMMENT '订单号',
  `product_no` char(50) CHARACTER SET utf8mb3 COLLATE utf8_general_ci DEFAULT NULL COMMENT '产品ID',
  `created_at` datetime NOT NULL COMMENT '创建时间',
  `updated_at` datetime DEFAULT NULL COMMENT '更新时间',
  PRIMARY KEY (`order_item_no`) USING BTREE,
  KEY `xm_items_order_no` (`order_no`) USING BTREE,
  KEY `xm_items_updated_at` (`updated_at`) USING BTREE,
  KEY `xm_items_created_at` (`created_at`) USING BTREE,
  KEY `xm_items_product_no_created_at` (`product_no`,`created_at`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 MAX_ROWS=1000000000 AVG_ROW_LENGTH=15000 ROW_FORMAT=COMPACT COMMENT='订单明细';
在这说一下对应的一个数据量是六百万左右,我是利用navicat直接生成的数据,所以各位也可以用不同的数据类型去直接生成对应数据量的测试数据。而且我们使用crerated_at这个创建时间去去排查,数据量大概是1000~2000 条\天这样吧。

其中,对应的慢sql是:
SELECT
      xoi.order_no AS orderNo, xoi.order_item_no AS orderItemNo
    FROM
      xm_order_items xoi
    WHERE
        xoi.product_no = 'HG-HGRS-0029'
        AND xoi.created_at >= '2022-07-01 00:00:00'
        AND xoi.created_at <= '2022-09-30 23:59:59';
对应的耗时解释:

耗时

expalin

思考与解决方案

第一个理解与方法——分块分页

直接从explain可以看出,其实我们已经使用了索引进行查询。作为一个初级程序员的菜鸟。我立刻想到这个在索引上已经没有优化空间。所以我认为这是因为每次获取的数据量太大了,因为是一次性获取三万的数据出来这样。第二个是觉得自己应该是时间跨度太大了。

所以考虑使用java对时间进行分块,比如一周的数据分成一块。然后limit成1000条。这样也能避免一次获取的数据太多的问题。真实数据库的接口能快4倍这样子吧。
SELECT
      xoi.order_no AS orderNo, xoi.order_item_no AS orderItemNo
    FROM
      xm_order_items xoi
    WHERE
        xoi.product_no = 'HG-HGRS-0029'
        AND xoi.created_at >= '2022-07-01 00:00:00'
        AND xoi.created_at <= '2022-07-06 23:59:59';

第二个理解与方法——拆分子查询

第一个方法虽然能优化个几倍的性能。但是事实上的问题还是很明显,而且数据量一直在增长。所以我还是回家偷偷内卷了一段时间,研究了一下性能优化部分的内容。这里主要发现影响到查询效率的是索引覆盖和回表这两个操作。所以考虑了利用java分成两次查询。这样就可以避免回表问题了。
第一次:list = SELECT
  xoi.order_item_no AS orderItemNo
    FROM
      xm_order_items xoi
    WHERE
        xoi.product_no = 'HG-HGRS-0029'
        AND xoi.created_at >= '2022-07-01 00:00:00'
        AND xoi.created_at <= '2022-09-30 23:59:59';

第二次:SELECT
  xoi.order_no AS orderNo 
FROM
  xm_order_items AS xoi 
WHERE
  xoi.order_item_no IN ( list );

第三个理解与方法——拆分子查询+分块分页

最后的方法说是考虑到了后面数据增长的问题,增加了分页,如果时间跨度继续扩大,就进行时间分块的方式。
第一次:list = SELECT
  xoi.order_item_no AS orderItemNo
    FROM
      xm_order_items xoi
    WHERE
        xoi.product_no = 'HG-HGRS-0029'
        AND xoi.created_at >= '2022-07-01 00:00:00'
        AND xoi.created_at <= '2022-09-30 23:59:59';

第二次:SELECT
  xoi.order_no AS orderNo 
FROM
  xm_order_items AS xoi 
WHERE
  xoi.order_item_no IN ( list ) limit 5000;

原理浅析与总结

  1. 回表和索引覆盖的浅解
    1. 原理简单说明

      什么是回表和索引覆盖呢?

      这里和我们使用的mysql中Innodb 引擎中的索引储存方式,可以理解为你构建了一个索引树(非主键)以后。Innodb会生成一个包含了索引的key + 主键 的节点。每次查找数据的时候如果你直接在索引树上可以命中你需要的所有数据,就会直接返回数据。

      但是如果你像本次分享的sql一样product_no的索引没有order_no中的数据。所以下一步需要回表。

      回表其实就是直接使用索引中的主键去再一次查询数据。

  2. 总结与收获
    1. 总结一下,其实这次算是本菜鸟的一次成长吧,真正的研究了一下索引覆盖,回表等mysql中查询相关的知识点。当然不得不承认的是sql的性能优化不能只是单纯的看索引覆盖和回表还有缓冲区之类的挺多东西后面遇到了再分享出来吧。大家有什么想讨论的可以在下面只有留言。

思考与解决方案

第一个理解与方法——分块分页

直接从explain可以看出,其实我们已经使用了索引进行查询。作为一个初级程序员的菜鸟。我立刻想到这个在索引上已经没有优化空间。所以我认为这是因为每次获取的数据量太大了,因为是一次性获取三万的数据出来这样。第二个是觉得自己应该是时间跨度太大了。

所以考虑使用java对时间进行分块,比如一周的数据分成一块。然后limit成1000条。这样也能避免一次获取的数据太多的问题。真实数据库的接口能快4倍这样子吧。
SELECT
      xoi.order_no AS orderNo, xoi.order_item_no AS orderItemNo
    FROM
      xm_order_items xoi
    WHERE
        xoi.product_no = 'HG-HGRS-0029'
        AND xoi.created_at >= '2022-07-01 00:00:00'
        AND xoi.created_at <= '2022-07-06 23:59:59';

第二个理解与方法——拆分子查询

第一个方法虽然能优化个几倍的性能。但是事实上的问题还是很明显,而且数据量一直在增长。所以我还是回家偷偷内卷了一段时间,研究了一下性能优化部分的内容。这里主要发现影响到查询效率的是索引覆盖和回表这两个操作。所以考虑了利用java分成两次查询。这样就可以避免回表问题了。
第一次:list = SELECT
  xoi.order_item_no AS orderItemNo
    FROM
      xm_order_items xoi
    WHERE
        xoi.product_no = 'HG-HGRS-0029'
        AND xoi.created_at >= '2022-07-01 00:00:00'
        AND xoi.created_at <= '2022-09-30 23:59:59';

第二次:SELECT
  xoi.order_no AS orderNo 
FROM
  xm_order_items AS xoi 
WHERE
  xoi.order_item_no IN ( list );

第三个理解与方法——拆分子查询+分块分页

最后的方法说是考虑到了后面数据增长的问题,增加了分页,如果时间跨度继续扩大,就进行时间分块的方式。
第一次:list = SELECT
  xoi.order_item_no AS orderItemNo
    FROM
      xm_order_items xoi
    WHERE
        xoi.product_no = 'HG-HGRS-0029'
        AND xoi.created_at >= '2022-07-01 00:00:00'
        AND xoi.created_at <= '2022-09-30 23:59:59';

第二次:SELECT
  xoi.order_no AS orderNo 
FROM
  xm_order_items AS xoi 
WHERE
  xoi.order_item_no IN ( list ) limit 5000;

原理浅析与总结

  1. 回表和索引覆盖的浅解
    1. 原理简单说明

      什么是回表和索引覆盖呢?

      这里和我们使用的mysql中Innodb 引擎中的索引储存方式,可以理解为你构建了一个索引树(非主键)以后。Innodb会生成一个包含了索引的key + 主键 的节点。每次查找数据的时候如果你直接在索引树上可以命中你需要的所有数据,就会直接返回数据。

      但是如果你像本次分享的sql一样product_no的索引没有order_no中的数据。所以下一步需要回表。

      回表其实就是直接使用索引中的主键去再一次查询数据。

  2. 总结与收获
    1. 总结一下,其实这次算是本菜鸟的一次成长吧,真正的研究了一下索引覆盖,回表等mysql中查询相关的知识点。当然不得不承认的是sql的性能优化不能只是单纯的看索引覆盖和回表还有缓冲区之类的挺多东西后面遇到了再分享出来吧。大家有什么想讨论的可以在下面只有留言。

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

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

相关文章

leetcode 343. 整数拆分(动态规划)

题目链接&#xff1a;343. 整数拆分 动态规划 (1) 确定 dpdpdp 数组下标含义&#xff1a; dp[i]dp[i]dp[i]: 将 iii 拆分为至少两个正整数之后的最大乘积&#xff1b; (2) 确定递推公式&#xff1a; 当 i≥2i \ge 2i≥2 时, 设 jjj 是 iii 拆分出来的第一个正整数&#xff0c…

1990-2021年全国30省城镇登记失业率

1、时间&#xff1a;1990-2021年 2、来源&#xff1a;整理自统计NJ 3、数据说明&#xff1a; 包括全国30个省份&#xff0c;不包括西藏&#xff0c;其中北京、天津、辽宁、吉林、江苏、浙江、湖南、四川、新疆2021年数据存在缺失&#xff0c; 内含原始数据&#xff0c;线性…

猿如意开发工具|python3.7

文章目录 一、猿如意是什么&#xff1f;一、猿如意的下载安装使用二、使用猿如意下载安装python3.7总结前言 对于程序猿来说&#xff0c;辅助开发工具箱是非常重要的&#xff0c;可以方便广大的开发者们。今天我就介绍一款非常好用的开发工具箱-猿如意。 一、猿如意是什么&…

大数据必学Java基础(一百零八):过滤器的生命周期

文章目录 过滤器的生命周期 一、构造方法 二、初始化方法 三、拦截请求方法

用R语言实现神经网络预测股票实例

神经网络是一种基于现有数据创建预测的计算系统。最近我们被客户要求撰写关于神经网络的研究报告&#xff0c;包括一些图形和统计输出。 如何构建神经网络&#xff1f; 神经网络包括&#xff1a; 输入层&#xff1a;根据现有数据获取输入的层隐藏层&#xff1a;使用反向传播…

基于PHP+MySQL动漫周边商城销售网站的开发与设计

随着时代的发展,人们对动漫周边产品的关注度越来越高,尤其是对当代的年轻人来说,对一些动漫的手办和玩具等商品都非常的热爱。但是当下时长上的动漫周边产品销售网站还很少,这对钟爱动漫周边产品的来说是一件很痛苦的事情,明明知道一件出现了这些相关产品,但是没有渠道能够购买…

【简单、实用】kubernetes的etcd备份与恢复实现恢复集群配置

学习目标 内容 提示:由于牵涉概念过多,本章主要讲解具体的备份恢复,其他概述 官网:https://kubernetes.io/zh-cn/docs/tasks/administer-cluster/configure-upgrade-etcd/#backing-up-an-etcd-cluster 一. etcd的工作原理 可将其分成两层次:Http层请求、接收消息;剩下的…

家电专用降压DC-DC方案PL8310

PL8310是一个单片36V, 1A降压开关监管机构。PL8310集成了一个36V 250mΩ高侧和一个36V, 140mΩ低侧mosfet提供1A持续负载电流超过4.5V至36V宽工作输入电压带33V输入过电压保护。峰值电流模式控制速度快瞬态响应和逐周电流限制。PL8310具有可配置的线路下降补偿&#xff0c;可配…

CenterNet算法代码剖析

目录 一、图片预处理 1、cv读取原始图片 2、读取图片的中心点 3、计算仿射变化2*3的矩阵 4、基于双线性插值的仿射变化&#xff0c;将原始图片映射到dst图片 5、将原始图片的值归一化到0~1之间 6、使用样本集的mean和std再进行z-score归一化 7、计算特征图的大小&#…

linux mailxdingding机器人报警

前言&#xff1a;采用devops的思想来确认做本文内容目的 作为 <用户角色> 我想要 <结果> 以便于 <目的> 作为运维人员&#xff0c;我想要服务器故障时候能够进行报警&#xff0c;以便于即使处理服务器故障、保障服务器稳定运行 两种方式 邮箱 客户端授权码 …

Kafka - 10 Kafka副本 | 分区副本分配 | 手动调整分区副本 | Leader Partition 负载平衡 | 增加副本因子

文章目录1. 分区副本分配2. 手动调整分区副本3. Leader Partition 负载平衡4. 增加副本因子1. 分区副本分配 如果 kafka 服务器只有 4 个节点&#xff0c;那么设置 kafka 的分区数大于服务器台数&#xff0c;在 kafka底层如何分配存储副本呢&#xff1f; ① 创建 16 分区&…

[附源码]计算机毕业设计springboot高校学生宿舍管理系统

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

HashMap(2)-----哈希表

自己实现一个哈希表 class Node { int data;String val;Node next;public Node(int data,String val){ this.valval;this.datadata;} } class myhashtable { Node arr1[];Node headnull;Node tailnull;int count0;private double load0.75;public myhashtable() {this…

ESIM:Enhanced LSTM for Natural Language Inference

原文链接&#xff1a;https://aclanthology.org/P17-1152.pdf 概述 对于自然语言推理任务&#xff0c;Bowman等人在2015年提出了一个大数据集&#xff0c;大多数工作就开始使用神经网络来对该任务进行训练。但作者认为序列模型的潜力还没有完全被挖掘&#xff0c;因此提出了一个…

自建网上商城平台该如何做好运营?

现在很多企业都在自建网上商城系统&#xff0c;但很多都以为建好商城上线就万事大吉了。其实&#xff0c;自建网上商城系统只是一个开始&#xff0c;后期的运营才最重要。如果经营不好&#xff0c;这个商城就白做了&#xff0c;今天小编给大家整理了几个网上商城平台运营方向&a…

[附源码]计算机毕业设计springboot港口集团仓库管理系统

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

【python】list 删除列表中某个元素的3种方法;附加删除numpy数组中的指定索引元素的方法

方法 python中关于删除list中的某个元素&#xff0c;一般有三种方法: remove、pop、del实例 1.remove: 删除单个元素&#xff0c;删除首个符合条件的元素&#xff0c;按值删除 2.pop: 删除单个或多个元素&#xff0c;按位删除(根据索引删除) 3.del&#xff1a;它是根据索…

校内评奖评优|基于Springboot+Vue实现高校评优管理系统

作者主页&#xff1a;编程指南针 作者简介&#xff1a;Java领域优质创作者、CSDN博客专家 、掘金特邀作者、多年架构师设计经验、腾讯课堂常驻讲师 主要内容&#xff1a;Java项目、毕业设计、简历模板、学习资料、面试题库、技术互助 收藏点赞不迷路 关注作者有好处 文末获取源…

[附源码]计算机毕业设计SpringBoot海南与东北的美食文化差异及做法的研究展示平台

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

新型超导Fluxonium量子比特正加速量子计算机的创建

量子处理器的一部分&#xff08;图片来源&#xff1a;网络&#xff09; 来自国立科技大学MISIS和鲍曼莫斯科国立技术大学的俄罗斯科学家是世界上最早使用超导Fluxonium量子比特实现双量子比特操作的科学家之一。Fluxonium具有更长的生命周期和更高的操作精度&#xff0c;因此它…