当前位置: 首页 > article >正文

MySQL查询语句优化

SQL脚本

-- ----------------------------
-- Table structure for entrust
-- ----------------------------
DROP TABLE IF EXISTS `entrust`;
CREATE TABLE `entrust`  (
  `id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键ID',
  `contract_id` varchar(50)  NOT NULL COMMENT '合同id',
  `entrust_code` varchar(50)  NOT NULL COMMENT '外协编号',
  `entrust_name` varchar(50)  NOT NULL COMMENT '外协名称',
  `entrust_info` json NOT NULL COMMENT '外协扩展信息',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 69  COMMENT = '外协' ROW_FORMAT = Dynamic;

-- ----------------------------
-- Records of entrust
-- ----------------------------
INSERT INTO `entrust` VALUES (11, '1', 'WX_001', 'HT001-设计外协', '{\"sign_status\": 1, \"entrust_type\": 1}');
INSERT INTO `entrust` VALUES (12, '2', 'WX_002', 'HT002-设计外协', '{\"sign_status\": 1, \"entrust_type\": 1}');
INSERT INTO `entrust` VALUES (13, '3', 'WX_003', 'HT003-设计外协', '{\"sign_status\": 1, \"entrust_type\": 1}');
INSERT INTO `entrust` VALUES (14, '4', 'WX_004', 'HT004-设计外协', '{\"sign_status\": 1, \"entrust_type\": 1}');
INSERT INTO `entrust` VALUES (16, '1', 'WX_001', 'HT001-勘察外协', '{\"sign_status\": 1, \"entrust_type\": 1}');
INSERT INTO `entrust` VALUES (17, '2', 'WX_002', 'HT002-勘察外协', '{\"sign_status\": 1, \"entrust_type\": 1}');
INSERT INTO `entrust` VALUES (18, '3', 'WX_003', 'HT003-勘察外协', '{\"sign_status\": 1, \"entrust_type\": 1}');
INSERT INTO `entrust` VALUES (19, '4', 'WX_004', 'HT004-勘察外协', '{\"sign_status\": 1, \"entrust_type\": 1}');
INSERT INTO `entrust` VALUES (23, '1', 'WX_001', 'HT001-物探外协', '{\"sign_status\": 1, \"entrust_type\": 1}');
INSERT INTO `entrust` VALUES (24, '2', 'WX_002', 'HT002-物探外协', '{\"sign_status\": 1, \"entrust_type\": 1}');
INSERT INTO `entrust` VALUES (25, '3', 'WX_003', 'HT003-物探外协', '{\"sign_status\": 1, \"entrust_type\": 1}');
INSERT INTO `entrust` VALUES (26, '4', 'WX_004', 'HT004-物探外协', '{\"sign_status\": 1, \"entrust_type\": 1}');
INSERT INTO `entrust` VALUES (27, '1', 'WX_001', 'HT001-测绘外协', '{\"sign_status\": 2, \"entrust_type\": 1}');
INSERT INTO `entrust` VALUES (28, '2', 'WX_002', 'HT002-测绘外协', '{\"sign_status\": 1, \"entrust_type\": 1}');
INSERT INTO `entrust` VALUES (29, '3', 'WX_003', 'HT003-测绘外协', '{\"sign_status\": 1, \"entrust_type\": 1}');
INSERT INTO `entrust` VALUES (30, '4', 'WX_004', 'HT004-测绘外协', '{\"sign_status\": 1, \"entrust_type\": 1}');
INSERT INTO `entrust` VALUES (38, '1', 'WX_001', 'HT001-劳务外协', '{\"sign_status\": 2, \"entrust_type\": 1}');
INSERT INTO `entrust` VALUES (39, '2', 'WX_002', 'HT002-劳务外协', '{\"sign_status\": 1, \"entrust_type\": 1}');
INSERT INTO `entrust` VALUES (40, '3', 'WX_003', 'HT003-劳务外协', '{\"sign_status\": 2, \"entrust_type\": 1}');
INSERT INTO `entrust` VALUES (41, '4', 'WX_004', 'HT004-劳务外协', '{\"sign_status\": 1, \"entrust_type\": 1}');

-- ----------------------------
-- Table structure for contract
-- ----------------------------
DROP TABLE IF EXISTS `contract`;
CREATE TABLE `contract`  (
  `id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键ID',
  `contract_code` varchar(50)  NOT NULL COMMENT '合同编号',
  `contract_name` varchar(50)  NOT NULL COMMENT '合同名称',
  `create_time` datetime NOT NULL COMMENT '创建时间',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 11112  COMMENT = '合同' ROW_FORMAT = Dynamic;

-- ----------------------------
-- Records of contract
-- ----------------------------
INSERT INTO `contract` VALUES (1, 'HT001', 'HT001-1', '2024-05-15 00:00:00');
INSERT INTO `contract` VALUES (2, 'HT002', 'HT002-1', '2024-05-15 00:00:00');
INSERT INTO `contract` VALUES (3, 'HT003', 'HT003-1', '2024-05-15 00:00:00');
INSERT INTO `contract` VALUES (4, 'HT004', 'HT004-1', '2024-05-15 08:55:49');

要求优化下方的MySQL语句

-- 优化下面的SQL
-- Sql说明:查询合同 id (1,3)下签订状态(sign_status)等于 2 的外协(entrust)信息
-- 要求: 所有字段都走索引
-- 提示: 可以新增字段,但不能把 contract_name 冗余到 entrust 表直接改成单表查询

SELECT
	e.*,
	c.contract_name 
FROM
	contract c
	JOIN entrust e ON c.id = e.contract_id AND e.entrust_info LIKE '%"sign_status": 2%' 
WHERE
	c.id IN ( 1, 3 );

思路分析

  1. 避免使用 LIKE,LIKE 操作符在 JSON 字段上通常不会利用索引,因此我们可以使用 JSON 函数来直接访问 entrust_info 中的 sign_status 字段
  2. 使用 JSON 函数, MySQL 提供了 JSON 函数,比如 JSON_EXTRACT() 可以直接提取 JSON 数据中的字段,这样可以提高查询效率
  3. 使用 JOIN 代替子查询:通过将子查询转换为 JOIN,可以提高性能,因为这样可以减少查询的复杂性
  4. 为 签订状态(sign_status)添加索引

参考答案

1. 使用 JSON 函数代替子查询
--  1. 避免使用 LIKE, LIKE 操作符在 JSON 字段上通常不会利用索引,因此我们可以使用 JSON 函数来直接访问 entrust_info 中的 sign_status 字段 
--  2. 使用 JSON 函数, MySQL 提供了 JSON 函数,比如 JSON_EXTRACT() 可以直接提取 JSON 数据中的字段,这样可以提高查询效率 
--  3. 使用 JOIN 代替子查询:通过将子查询转换为 JOIN,可以提高性能,因为这样可以减少查询的复杂性。
--  基于以上优化思路,以下是重写后的 SQL 查询:
SELECT
    e.*,
    c.contract_name 
FROM
    contract c
JOIN
    entrust e ON c.id = e.contract_id 
WHERE
    c.id IN (1, 3)
    AND JSON_UNQUOTE(JSON_EXTRACT(e.entrust_info, '$.sign_status')) = '2';	
  1. JSON_EXTRACT() 使用该函数提取 entrust_info 中的 sign_status 字段的值
  2. JSON_UNQUOTE() 将提取的 JSON 值转换为普通字符串,以便进行比较
  3. JOIN 结构 保持原有的 JOIN 结构,确保能够获取到合同名称
2. 索引优化
-- 索引建议: 
-- 为了确保所有字段都走索引,建议在 entrust 表的 entrust_info 字段上创建一个虚拟列,并为该虚拟列创建索引。可以按照以下步骤进行:
 
-- 1. 添加虚拟列
ALTER TABLE entrust ADD COLUMN sign_status INT GENERATED ALWAYS AS (JSON_UNQUOTE(JSON_EXTRACT(entrust_info, '$.sign_status'))) VIRTUAL;

-- 2. 创建索引
CREATE INDEX idx_sign_status ON entrust (sign_status);
3. 最终SQL结果
SELECT
    e.*,
    c.contract_name 
FROM
    contract c
JOIN
    entrust e ON c.id = e.contract_id 
WHERE
    c.id IN (1, 3)
    AND e.sign_status = 2;

http://www.kler.cn/a/322395.html

相关文章:

  • 面试题: Spring中的事务是如何实现的?
  • Python设计模式详解之5 —— 原型模式
  • 自动化生成测试用例:利用OpenAI提升电商网站测试覆盖率
  • 讯飞、阿里云、腾讯云:Android 语音合成服务对比选择
  • TON商城与Telegram App:生态融合与去中心化未来的精彩碰撞
  • 智慧社区平台系统提升物业管理效率与居民生活质量
  • DataGrip远程连接Hive
  • Python中列表常用方法
  • C语言 15 预处理
  • vue3 TagInput 实现
  • 监控易监测对象及指标之:Kubernetes(K8s)集群的全方位监控策略
  • webpack与vite读取base64图片
  • django开发流程1
  • manim中实现文字换行和设置字体格式
  • MySQL篇(日志)
  • blender设置背景图怎么添加?blender云渲染选择
  • 学Python再学C++是走弯路?
  • centos7 yum 更新 nginx 到最新版本 1.26
  • 【Kotlin 集合概述】可变参数vararg、中缀函数infix以及解构声明(二十)
  • MySQL record 07 part
  • 自动化办公-Python-os模块的使用
  • 标准 I/O
  • 西门子6ES7414-4HM14-0AB0 CPU模块的优缺点
  • 最佳植树距离 - 华为OD统一考试(E卷)
  • 记录Mac编译Android源码踩过的坑
  • offset、client 和 scroll【JavaScript】