MySQL五千万大表查询优化实战

news2024/11/19 8:27:39

背景

DBA同事在钉钉发了两张告警截图,作为“始作俑者”的我很心虚,因为刚才是我在管理后台查询数据,结果很久都没出来,并且用多个维度查了N次

问题分析

这是当天上线的功能,完事我立马锁定SQL然后开启排查

# 原SQL,此为分页接口中count部分
SELECT
	COUNT( 1 ) 
FROM
	shop_day_statistics a
	LEFT JOIN (
	SELECT
		shop_id shop_id,
		statistics_time,
		merchant_id,
		GROUP_CONCAT( CONCAT_ws( '-', service_id, service_name ) SEPARATOR ',' ) AS service_name,
		sum( profit_amount ) profit_amount 
	FROM
		service_day_statistics 
	GROUP BY
		shop_id,
		statistics_time 
	) s ON s.shop_id = a.shop_id
	
	AND a.statistics_time = s.statistics_time 
WHERE
	a.statistics_time BETWEEN '2023-09-05 00:00:00.0' 
	AND '2024-10-22 00:00:00.0' 
	AND a.shop_id = 999999;
    
# SQL解释
此SQL中有两张表:shop_day_statistics(5800W)、service_day_statistics(30多万)
下面将用A表来替代shop_day_statistics,B表来替代service_day_statistics
A表与B表的关系是一对多,因业务的需要,故之前在一条SQL上查询得出

表结构:
DROP TABLE IF EXISTS `shop_day_statistics`;
CREATE TABLE `shop_day_statistics`  (
  `id` bigint NOT NULL AUTO_INCREMENT COMMENT 'id',
  `statistics_time` date NOT NULL COMMENT '统计日期',
  `group_id` bigint NULL DEFAULT NULL COMMENT '代理商ID',
  `group_name` varchar(70) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '代理商名称',
  `shop_id` bigint NULL DEFAULT NULL COMMENT '门店ID',
  `shop_name` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '门店名称',
  `merchant_id` bigint NULL DEFAULT NULL COMMENT '商户ID',
  `merchant_name` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '商户名称',
  `employee_id` bigint NULL DEFAULT NULL COMMENT '员工ID',
  `employee_name` varchar(45) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '员工名称',
  PRIMARY KEY (`id`) USING BTREE,
  INDEX `idx_groupid_time`(`group_id` ASC, `statistics_time` ASC) USING BTREE,
  INDEX `idx_merchantid_time`(`merchant_id` ASC, `statistics_time` ASC) USING BTREE,
  INDEX `idx_statistics_time`(`statistics_time` ASC) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '门店日收益统计' ROW_FORMAT = DYNAMIC;

DROP TABLE IF EXISTS `service_day_statistics`;
CREATE TABLE `service_day_statistics`  (
  `id` bigint NOT NULL AUTO_INCREMENT COMMENT 'id',
  `statistics_time` date NOT NULL COMMENT '统计日期',
  `shop_id` bigint NULL DEFAULT NULL COMMENT '门店ID',
  `shop_name` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '门店名称',
  `merchant_id` bigint NULL DEFAULT NULL COMMENT '商户ID',
  `merchant_name` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '商户名称',
  `service_id` bigint NULL DEFAULT NULL COMMENT '服务商id',
  `service_name` varchar(45) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '服务商名称',
  `profit_amount` bigint NULL DEFAULT NULL COMMENT '服务商收益金额',
  `gmt_create` datetime NOT NULL COMMENT '创建时间',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '服务商日收益统计' ROW_FORMAT = DYNAMIC;

SQL解析


从上图可以了解到几个点

  1. 内层的联表是ALL,也很慢,虽然只有三十多万数据,时间也去到了一秒
  2. 外层A表是ALL,全表扫描非常慢

依次改造

  1. 子查询中是没有带任何条件的,故在B表中新增两个参数:group_id,group_name,并为A B表关联的字段增加索引,在后续查询中将外层的条件(门店商户代理商ID)尽可能的加到子查询中,这样能直接命中索引,无需对B进行全表扫描
  2. 外层A表根据shop_id、statistics_time建立联合索引(shop_id必须放前面,区分度更加高)

改造后SQL及其执行计划

SELECT
	COUNT( 1 ) 
FROM
	shop_day_statistics a
	LEFT JOIN (
	SELECT
		shop_id shop_id,
		statistics_time,
		merchant_id,
		GROUP_CONCAT( CONCAT_ws( '-', service_id, service_name ) SEPARATOR ',' ) AS service_name,
		sum( profit_amount ) profit_amount 
	FROM
		service_day_statistics 
	WHERE
		statistics_time BETWEEN '2023-09-05 00:00:00.0' 
		AND '2024-10-22 00:00:00.0' 
		AND shop_id = 99999 
	GROUP BY
		shop_id,
		statistics_time 
	) s ON s.shop_id = a.shop_id 
	AND a.statistics_time = s.statistics_time 
WHERE
	a.statistics_time BETWEEN '2023-09-05 00:00:00.0' 
	AND '2024-10-22 00:00:00.0' 
	AND a.shop_id = 99999;

到这个时候就爽了吗,从执行计划上看确实如此,但是我们忽视了这个功能是在web页面上操作的,而操作员可以任何额外条件都不输(只有时间),那执行计划又将非常难看

前端限制

限制管理后台使用人员的操作来达到我们预期的执行计划

  1. 默认任何额外条件不输入时仅允许7天跨度查询
  2. 输入代理商/门店/商户ID(这几个字段都与统计时间有做联合索引)后,时间将会允许拉长跨度进行查询

写到最后

对于一个SQL的优化我感触比较深的是:不能仅从SQL本身去进行优化,而需要结合具体的业务进行权衡从而选择一个合适的方案进行优化,目前项目也到高速上升期,出现了很多大表,未来系统将会有更多的问题,当然这即是问题也是挑战,加油!!!

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

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

相关文章

系统性能优化

在程序员的职业生涯中,解决当前系统问题,优化性能,是走向高阶的必经之路。如果一辈子做着后台开发,写着CRUD,QPS低于10,那确实没必要去做性能优化,因为根本用不上。性能优化范围很广&#xff0c…

排序|插入排序|希尔排序|直接选择排序|堆排序的实现即特性(C)

插入排序 基本思想 直接插入排序是一种简单的插入排序法,其基本思想是: 把待排序的记录按其关键码值的大小逐个插入到一个已经排好序的有序序列中,直到所有的记录插入完为止,得到一个新的有序序列 。 单趟 当插入第 i ( i ≤ 1…

人数识别 人员超员识别系统 作业区域超员预警系统 ai#YOLO视觉

在当今复杂的生产作业与社会管理场景中,人员管理的精准性和高效性变得愈发重要。人数识别、人员超员识别系统、作业区域超员预警系统以及特殊岗位人员达标监测等,都是保障安全生产、提高运营效率和维护社会秩序的关键要素。随着人工智能(AI)技术的飞速发…

【Python实例】Python读取并绘制nc数据

【Python实例】Python读取并绘制nc数据 准备:安装netCDF库等读取nc数据相关信息绘制图形利用basemap绘图 参考 准备:安装netCDF库等 以【1960-2020年中国1km分辨率月降水数据集】中2020年降水为例。 先在Panopoly中查看数据属性,如下&#…

单细胞转录组 —— kb-python 原始数据处理

单细胞转录组 —— kb-python 原始数据处理 前言 kallisto|bustools 是一种用于预处理 scRNA-seq 数据的工作流程。 数据预处理步骤包括: 将 reads 与其来源细胞关联起来;根据唯一分子标识符(UMI)对 reads 进行去重&#xff1…

西门子S7-200 SMART高速计数器指令向导

在 Micro/WIN SMART 中的命令菜单中选择 Tools(工具)> Wizards(向导)中选择 High Speed Counter(高速计数器向导) ,也可以在项目树中选择 Wizards(向导)文件夹中的 Hi…

下载相应版本的PyTorch

1、前置条件 下载某个版本的Python,本文涉及的Python版本为3.10 2、查看该Python版本可以下载的whl文件格式 pip debug --verbose 从上图可以发现python3.10可以下载格式为cp310-cp310-win_amd64的whl文件 PyTorch各稳定版本下载链接:https://downloa…

GNN与Transformer创新结合!模型性能起飞!

近年来,图神经网络(GNN)和Transformer模型因其在处理复杂数据结构和序列依赖性方面的卓越表现而受到广泛关注。这种优势使得将GNN与Transformer结合成为图表示学习领域的一个新兴且充满潜力的研究方向。通过结合这两种模型,我们不…

软考下午题1-数据流图

问题一:求实体的名称 例题: 1.提问方式-如问题1 从子图(0层数据流图)找比较快 外部实体可以是 人、物体、系统 在子图中找到加工,与文章中加工文字相对应,继续读文章,可以找到实体 E1-巴士列表文件 E2-机械师 E3-会…

《深度学习》LSTM 长短期记忆网络 结构及原理解析

目录 一、关于LSTM网络 1、什么是LSTM网络 举例: 2、RNN网络的结构 3、Tanh双曲正切函数 二、LSTM网络结构 1、遗忘门 1)功能 2)步骤 2、输入门 1)功能 2)步骤 3、输出门 1)功能 2)步骤…

斯坦福 CS229 I 机器学习 I 构建大型语言模型 (LLMs)

1. Pretraining -> GPT3 1.1. Task & loss 1.1.1. 训练 LLMs 时的关键点 对于 LLMs 的训练来说,Architecture(架构)、Training algorithm/loss(训练算法/损失函数)、Data(数据)、Evalu…

3D看车如何实现?有哪些功能特点和优势?

3D看车是一种创新的汽车展示方式,它利用三维建模和虚拟现实技术,将汽车以更真实、更立体的形式呈现在消费者面前。 一、3D看车的实现方式 1、三维建模: 通过三维建模技术,按照1:1的比例还原汽车外观,包括车身线条、细…

uniapp学习(003-2 vue3学习 Part.2)

零基础入门uniapp Vue3组合式API版本到咸虾米壁纸项目实战,开发打包微信小程序、抖音小程序、H5、安卓APP客户端等 总时长 23:40:00 共116P 此文章包含第15p-第p20的内容 文章目录 事件监听以及组件内置事件处理自定义模板快速创建uniapp条件渲染 v-if和v-elsev-e…

骨传导耳机哪个牌子好?五大选购妙计带你精准入手优质骨传导耳机!

随着骨传导耳机市场的蓬勃发展,此产品凭借优秀的佩戴体验以及可降低听力损伤等优点引起了广泛的关注。然而,随着热度提高,市面上开始出现了许多品牌,这些品牌实力技术各不相同,甚至其中还有一些劣质机型,这…

国内经典多模态大模型工作1——Qwen-VL系列(Qwen-VL、Qwen2-VL解读)

Qwen-VL 论文标题:《Qwen-VL: A Versatile Vision-Language Model for Understanding, Localization, Text Reading, and Beyond》 论文链接:https://arxiv.org/pdf/2308.12966.pdf 项目:https://github.com/QwenLM/Qwen-VL/tree/master 模…

如何构建某一行业的知识图谱

构建一个行业的知识图谱是一个系统而复杂的过程,它涉及到数据收集、处理、分析等多个环节。以下是构建行业知识图谱的基本步骤: 1. 需求分析: - 明确构建知识图谱的目的和应用场景,比如是用于辅助决策、市场分析、产品推荐等。…

【python机器学习】线性回归 拟合 欠拟合与过拟合 以及波士顿房价预估案例

文章目录 线性回归之波士顿房价预测案例 欠拟合与过拟合线性回归API 介绍:波士顿房价预测数据属性:机器学习代码实现 拟合 过拟合 欠拟合 模拟 及处理方法(正则化处理)导包定义函数表示欠拟合定义函数表示拟合定义函数表示过拟合 正则化处理过拟合L1正则化L2正则化 线性回归之波…

李沐 X动手学深度学习 数据操作+数据预处理 学习笔记(无代码,纯理论部分)

数据结构介绍 机器学习和神经网络最主要的的数据结构:N维数组0维数组:标量,eg:1.0(是一个浮点数,可能表示一个类别)1维数组:向量,eg:[1.0, 2.7, 3.4](特征向量&#xf…

Java中System类和RunTime类的Api

目录 System 类 1)out 2)err 3)in 4)currentTimeMillis() 5)nanoTime() 6)arraycopy(Object 要从里面复制东西的数组, int 要从里面复制东西数组的索引起始位置, Object 获得复制元素的数组, int 获得复制元素数组的起始索引, int 要复制东西的个数) 7)gc() 8)exit(int status)…

Miniconda 入门级使用教程

前言 Miniconda是一个更小的Anaconda发行版(Anaconda是一个包含大量预装数据科学和机器学习库的Python发行版),它只包含conda包管理器和Python以及其必要的库。Miniconda的目的是提供一个更轻量级的选项来安装和运行conda环境,同…