面试官:给你一段有问题的SQL,如何优化?

news2025/1/11 11:03:13

大家好,我是飘渺!

我在面试的时候很喜欢问候选人这样一个问题:“你在项目中遇到过慢查询问题吗?你是怎么做SQL优化的?”

很多时候,候选人会直接跟我说他们在编写SQL时会遵循的一些常用技巧,比如:

  • 合理使用索引

  • 使用UNION ALL替代UNION

  • 不要使用select * 写法

  • JOIN字段建议建立索引

  • 避免复杂SQL语句

这里不能说完全错误,因为这些技巧确实可以提高SQL运行效率;但是也不能说完全正确,毕竟我是想问他具体怎么是做SQL优化的。

接下来我问他,我这里有一段复杂的SQL,你可以动手帮我优化一下吗?到这一步的时候就有很多候选人做不好打了退堂鼓。他们有很扎实的理论知识,但是动手能力却差点火候。

今天这篇文章就从实战的角度出发,带大家走一遍SQL优化的真实流程。

找出有问题的SQL?

在实际开发中要判断一段SQL有没有问题可以从两方面来判断:

1、系统层面

  • CPU消耗严重

  • IO等待严重

  • 页面响应时间过长

  • 应用的日志出现超时等错误

2、SQL语句层面

  • 冗长

  • 执行时间过长

  • 从全表扫描获取数据

  • 执行计划中的rows、cost很大

冗长的SQL都好理解,一段SQL太长阅读性肯定会差,出现问题的频率肯定会更高。更进一步判断SQL问题就必须得从执行计划入手,如下所示:

9db7dbb03e2546eff30ec7edf7d138fb.png

执行计划告诉我们本次查询走了全表扫描Type=ALL,rows很大(9950400)基本可以判断这是一段"有味道"的SQL。

查看SQL执行计划?

找到了有问题的SQL就要确定优化方案,那究竟从何处下手呢?这里必须要通过执行计划来观察。

执行计划会告诉你哪些地方效率低,哪里可以需要优化。我们以MYSQL为例,看看执行计划是什么。(每个数据库的执行计划都不一样,需要自行了解)

explain select * from xxx

当使用explain sql后会看到执行计划

b8fa0ef1e22c227ad8fc6a1df9c20a9f.png

执行计划中几个重要字段的解释说明,大家需要记住

字段解释
id每个被独立执行的操作标识,标识对象被操作的顺序,id值越大,先被执行,如果相同,执行顺序从上到下
select_type查询中每个select 字句的类型
table被操作的对象名称,通常是表名,但有其他格式
partitions匹配的分区信息(对于非分区表值为NULL)
type连接操作的类型
possible_keys可能用到的索引
key优化器实际使用的索引(最重要的列) 从最好到最差的连接类型为consteq_regrefrangeindexALL。当出现ALL时表示当前SQL出现了“坏味道”
key_len被优化器选定的索引键长度,单位是字节
ref表示本行被操作对象的参照对象,无参照对象为NULL
rows查询执行所扫描的元组个数(对于innodb,此值为估计值)
filtered条件表上数据被过滤的元组个数百分比
extra执行计划的重要补充信息,当此列出现Using filesort , Using temporary 字样时就要小心了,很可能SQL语句需要优化

通过执行计划我们就可以确定优化方案,优化一处后再回过头来观察执行计划,如此往复循环直到找到最优目标为止。

下面给出一段有问题的SQL具体操作一下。

SQL优化案例

慢查询

1、表结构如下:

CREATE TABLE `a`
(
    `id`          int(11) NOT NULLAUTO_INCREMENT,
    `seller_id`   bigint(20)                                       DEFAULT NULL,
    `seller_name` varchar(100) CHARACTER SET utf8 COLLATE utf8_bin DEFAULT NULL,
    `gmt_create`  varchar(30)                                      DEFAULT NULL,
    PRIMARY KEY (`id`)
);
CREATE TABLE `b`
(
    `id`          int(11) NOT NULLAUTO_INCREMENT,
    `seller_name` varchar(100) DEFAULT NULL,
    `user_id`     varchar(50)  DEFAULT NULL,
    `user_name`   varchar(100) DEFAULT NULL,
    `sales`       bigint(20)   DEFAULT NULL,
    `gmt_create`  varchar(30)  DEFAULT NULL,
    PRIMARY KEY (`id`)
);
CREATE TABLE `c`
(
    `id`         int(11) NOT NULLAUTO_INCREMENT,
    `user_id`    varchar(50)  DEFAULT NULL,
    `order_id`   varchar(100) DEFAULT NULL,
    `state`      bigint(20)   DEFAULT NULL,
    `gmt_create` varchar(30)  DEFAULT NULL,
    PRIMARY KEY (`id`)
);

2、有问题的查询SQL

select a.seller_id,
       a.seller_name,
       b.user_name,
       c.state
from a,
     b,
     c
where a.seller_name = b.seller_name
  and b.user_id = c.user_id
  and c.user_id = 17
  and a.gmt_create
    BETWEEN DATE_ADD(NOW(), INTERVAL – 600 MINUTE)
    AND DATE_ADD(NOW(), INTERVAL 600 MINUTE)
order by a.gmt_create;

a,b,c 三张表关联,查询用户17 在当前时间前后10个小时的订单情况,并根据订单创建时间升序排列

优化步骤

1、先查看各表数据量

6fd2f2fd6c083fcf1284321980f40ad2.png

2、查看原执行时间,总耗时0.21s

05329f6628d6493f597b5d47331bfded.png

3、查看原执行计划

b8b98f52bdd7593e89aefbb1c084866a.png

4、通过观察执行计划和SQL语句,确定初步优化方案

  • SQL中 where条件字段类型要跟表结构一致,表中 user_id 为varchar(50)类型,实际SQL用的int类型,存在隐式转换,也未添加索引。将b和c表 user_id 字段改成int类型。

  • 因存在b表和c表关联,将b和c表 user_id创建索引

  • 因存在a表和b表关联,将a和b表 seller_name字段创建索引

  • 利用复合索引消除临时表和排序

初步优化的SQL:

alter table b modify `user_id` int(10) DEFAULT NULL;
alter table c modify `user_id` int(10) DEFAULT NULL;
alter table c add index `idx_user_id`(`user_id`);
alter table b add index `idx_user_id_sell_name`(`user_id`,`seller_name`);
alter table a add index `idx_sellname_gmt_sellid`(`gmt_create`,`seller_name`,`seller_id`);

查看优化后的执行时间

8c807df63031ec0a65d09f4cf0a4489b.png

初步优化后执行速度提升了20倍,是否还能继续优化呢?

5、继续查看优化后的执行计划

55bb6f99f2aae2d8cae8d932ee9b1bd0.png

这里只看到查询需要扫描的元素比较大,不过还看到了有两处告警信息,直接查看告警信息

show warnings
c193fdae6d3e3306aa3c8b4ab54e637a.png

Cannot use range access on index ‘idx_sellname_gmt_sellid’ due to type or collation conversion on field ‘get_create’,这句话是告诉你由于gmt_create列发生了类型转换所以无法走索引。

查看SQL建表语句发现gmt_create字段被设计成了varchar类型,在SQL查询时需要转化成时间格式做查询,确实不能走索引。

所以需要调整一下gmt_create字段格式

alter table a modify "gmt_create" datetime DEFAULT NULL;

6、修改字段后再来查看执行时间

f63690bed4258e14ebb397a3b0d81626.png

执行速度非常完美。

7、再观察优化后的执行计划

58a69aed6a4638279e8919e932ed254f.png

可以看到执行计划也很完美,至此SQL优化结束。

SQL优化小结

这里给大家总结一下优化SQL的套路,再也不怕面试官问你怎么做SQL优化的啦。

  1. 查看执行计划 explain

  2. 如果有告警信息,查看告警信息 show warnings;

  3. 查看SQL涉及的表结构和索引信息

  4. 根据执行计划,思考可能的优化点

  5. 按照可能的优化点执行表结构变更、增加索引、SQL改写等操作

  6. 查看优化后的执行时间和执行计划

  7. 如果优化效果不明显,重复第四步操作

在看、点赞、转发,是对我最大的鼓励。您的支持就是我坚持下去的最大动力!

另外我的 知识星球 开通了,点击 知识星球 获取限量40元优惠券加入,每天不到3毛钱。目前更新了SpringCloud alibaba开发实战、Kubernetes云原生实战、分库分表实战、设计模式实战、一起学DDD 等,还有每周的送书活动等着你....

0f3154e0db0f44b85a512a5045c3b13b.png

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

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

相关文章

【力扣(LeetCode)】【MySQL】【185.部门工资前三高的所有员工】

学习时间: 2023年3月1日 题目描述: 题解分享: # 作 者 : 繁 华 倾 夏# 力扣(LeetCode):185. 部门工资前三高的所有员工# MySQL 数据库selectd.Name as Department, e1.Name as Employee, e1.Salary fromEmployee e1joinDepartment d on …

数据结构初阶 -- 顺序表

数据结构初阶 链表的讲解 目录 一. 线性表 1.1 定义 1.2 特点 二. 顺序表 2.1 定义 2.2 代码 2.3 功能需求 2.4 静态顺序表的特点以及缺点 2.5 动态的顺序表 2.6 动态顺序表接口的实现 三. 代码 头文件 主文件 一. 线性表 1.1 定义 线性表(linear li…

【算法】Tire字符串

作者:指针不指南吗 专栏:算法篇 🐾或许会很慢,但是不可以停下🐾 文章目录1.Trie的基本思想1.1什么是Trie1.2字符串条件1.3如何存储字符串1.4如何查找字符串2.Trie的代码实现2.1怎么用数组建树2.2完整代码1.Trie的基本思…

柔性电路板的优点、分类和发展方向

柔性电路板是pcb电路板的一种,又称为软板、柔性印刷电路板,主要是由柔性基材制作而成的一种具有高可靠性、高可挠性的印刷电路板,具有厚度薄、可弯曲、配线密度高、重量轻、灵活度高等特点,主要用在手机、电脑、数码相机、家用电器…

CSGO社区服搭建服务器架设游戏服务端教程

CSGO社区服搭建服务器架设游戏服务端教程 我是艾西,上一篇说了搭建CSGO服务器需要准备服务器以及安装好所需要的环境,那么今天说一下CSGO社区私人服务器怎么搭建游戏服务端 搭建CSGO服务器比较简单,Valve开发者社区wiki也给出了安装指导&…

仓库管理如何实现扫码出入库?

仓库实现扫描出入库管理具体应该怎么做?以下方参考模板为例,可以点击打开配合阅读: 参考模板:通用仓库管理(官方)① 库存卡设计: 此表单主要用于代替传统纸质库存卡的记录功能,货物…

【备战面试】每日10道面试题打卡-Day1

本篇总结的是Java基础知识相关的面试题,后续也会更新其他相关内容 文章目录1、JVM、JRE和JDK的关系?2、Java语言有哪些特点?3、Java和C的区别有哪些?4、Java有哪些数据类型?5、访问修饰符 public、private、protected&…

企业如何实现精细化人员管理?五大业务场景值得关注

近年来,随着大数据、人工智能和云计算等信息技术不断升级与渗透,处在数字化变革的劳动力密集型企业希望利用更加智能化的劳动力管理软件,帮助企业实现规范化的管理。 面对企业劳动力管理理念的变化,以及数字化转型的发展渗透&…

Puppeteer项目结构梳理

最近接触了一个个人感觉很奈斯的项目,故记录思路如下: puppeteer项目梳理: 入口文件 run.js 入口命令 node run.js YourConfig.json 1、我们可以在自己的config.json里面设置好 ①、登录的用户名密码;aws或其它服务器的access等id,accessKey…

二叉树的性质(概念/特性/存储结构)

目录1 二叉树的定义及主要特性1.1 二叉树的定义1.2 特殊二叉树1.2.1 满二叉树1.2.2 完全二叉树1.2.3 二叉排序树1.2.4 平衡二叉树1.3 二叉树的性质1.3.1 非空二叉树上的叶结点数1.3.2 非空二叉树第k层结点数1.3.3 高度为h的二叉树至多结点数1.3.4 完全二叉树结点与双亲的关系1.…

电子价格标签-系统结构

一、V2.4基站软件电子标签 接收PC下达的操作指令,解析后再通过RF发送给电子标签,接收路由器发送的数据信息并解析,更新数据。 1. 2.1寸电子价签 2. 2.9寸电子价签 ​ 3. 4.2寸电子价签 ​ 4. 7.5寸电子价签 ​ 5. 10.2寸电子价签 二、V4…

当审稿人回复这些审稿意见时,其实是在暗示你这些细节需要注意

当我们翘首以盼SCI论文投稿的审稿决定时。心情往往是复杂的,想收到审稿决定又担心收到的是不好的审稿决定。不管审稿结论如何,我们首先要明白的是那几个简短字母的审稿决定对我们来说,意味着什么。只有这样才有可能既不妄自菲薄也不杞人忧天。…

Intel CSME 简述

SME 算是 Intel X86 PC 上最神秘的部分了,本文根据 us-19-Hasarfaty-Behind-The-Scenes-Of-Intel-Security-And-Manageability-Engine 一文写成。讲述内容无法证伪,各位随便听听即可,了解这些能够帮助BIOS 工程师更好的理解一些操作的实现。文章基于 Intel 第八代第九代CPU(…

springCloud之seata

一、Seata是什么 Seata 是一款开源的分布式事务解决方案,致力于提供高性能和简单易用的分布式事务服务。Seata 将为用户提供了 AT、TCC、SAGA 和 XA 事务模式,为用户打造一站式的分布式解决方案。 官方文档 https://seata.io/zh-cn/docs/overview/wha…

发现新大陆——原来软件开发根本不需要会编码(看我10分钟应用上线)

目录 一、前言 二、官网基础功能及搭建 三、体验过程 01、连接数据源 02、设计表单 03、流程设计 04、图表呈现 05、组织架构设置 五、效率评价 六、小结 一、前言 众所周知,每家公司在发展过程中都需要构建大量的内部系统, 如运营使用的用户…

数据结构与算法基础-学习-14-线性表之串

一、串的定义由0-n个字符组成的有限序列。(n>0)二、串的相关术语1、子串串中任意个连续字符组成的子序列成为该串的子串。2、主串包含子串的串成为主串。3、字符位置字符在序列中的序号为该字符在串中的位置。4、子串位置子串第一个字符在主串中的位置…

Docker----------Docker轻量级可视化工具Portainer/监控之 CAdvisor+InfluxDB+Granfana

1.是什么 Portainer 是一款轻量级的应用,它提供了图形化界面,用于方便地管理Docker环境,包括单机环境和集群环境。 2 官网 官网 https://www.portainer.io/ https://docs.portainer.io/v/ce-2.9/start/install/server/docker/linux 3.…

【数电基础】——时序逻辑电路

目录 1.大纲 2.时序逻辑电路的特点 3.时序逻辑电路的一般形式 4.时序逻辑电路的描述方法 5.同步时序逻辑电路 6.异步时序逻辑电路 7.同步时序逻辑电路的分析方法(上升沿触发的D触发器) 8.同步时序逻辑电路的分析方法(脉冲触发的JK触发…

Grafana邮件及告警配置

之前部署过服务器的监控组件程序,本在部署时也进行邮件及告警配置,但未进行文档整理,在这儿进行展示。之前用过Grafana的7.*的版本,在进行邮件配置还比较OK,但在配置告警时,太繁琐,还要自己去写…

Java数据结构LinkedList单链表和双链表模拟实现及相关OJ题秒AC总结知识点

本篇文章主要讲述LinkedList链表中从初识到深入相关总结,常见OJ题秒AC,望各位大佬喜欢 一、单链表 1.1链表的概念及结构 1.2无头单向非循环链表模拟实现 1.3测试模拟代码 1.4链表相关面试OJ题 1.4.1 删除链表中等于给定值 val 的所有节点 1.4.2 反转…