SQL语句优化

news2025/1/16 15:59:46

当表中有百万数据的时候,我们要怎么去查询数据,平时写的sql也许就会很慢了。

SQL的执行顺序

SELECT
DISTINCT <select_list>
FROM <left_table>
<join_type> JOIN <right_table>
ON <join_condition>
WHERE<where_condition>
GROUP BY <cgroup_by_list>
HAVING <having_condition>
ORDER BY <order_by_condition>
LIMIT <limit_number>

执行顺序:

  • FROM <表名># 选取表,将多个表数据通过笛卡尔积变成一个表。

  • ON <筛选条件> # 对笛卡尔积的虚表进行筛选

  • JOIN <join, left join, right join...>

  • <join 表> #指定join,用于添加数据到on之后的虚表中,例如leftjoin会将左表的剩余数据添加到虚表中

  • WHERE <where条件> #对上述虚表进行筛选

  • GROUP BY <分组条件> # 分组

  • <SUM() 等聚合函数> #用于having子句进行判断,在书写上这类聚合函数是写在having判断里面的

  • HAVING <分组筛选> # 对分组后的结果进行聚合筛选

  • SELECT <返回数据列表> #返回的单列必须在group by子句中,聚合函数除

  • DISTINCT 数据除重

  • ORDER BY 排序条件> # 排序

  • LIMIT <行数限制>

几个SQL优化技巧

这里总结了几种优化sql的小技巧

我准备了一百万的数据,表如下:

CREATE TABLE `test_import_export` (
  `seckill_id` bigint(20) NOT NULL AUTO_INCREMENT,
  `order_id` varchar(51) NOT NULL COMMENT '订单id',
  `user_id` int(20) NOT NULL,
  `goods_id` int(11) NOT NULL,
  `msg` varchar(64) DEFAULT NULL,
  PRIMARY KEY (`seckill_id`),
  UNIQUE KEY `uidx_so_oid` (`order_id`) USING BTREE,
  UNIQUE KEY `uidx_so_id` (`seckill_id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

1.写清楚需要查询的字段

select * from test_import_export;  -- 消耗2.006s

这个语句会查询所有字段,如果我们不需要字段比较长,比如msg这个字段,那这种写法就会增加查询时长。使用select *可能造成以下问题:

  • 性能问题

  • 维护问题

  • 查询结果不确定:当查询中存在多个表时,使用SELECT * 很容易造成列名冲突,导致查询结果不确定。

  • 冗余数据

select seckill_id,order_id,user_id,goods_id from test_import_export;  -- 0.712s

少查了msg字段后,可以看出快了不少。

2.避免索引失效的场景

2.1 使用in范围太大

in的范围太大会导致索引失效,not in 也会导致索引失效。

EXPLAIN select seckill_id,order_id,user_id,goods_id from test_import_export where order_id in (
    "share_of_sean_240001","share_of_sean_240002", ... -- 后面跟10000万条
)
EXPLAIN select seckill_id,order_id,user_id,goods_id from test_import_export where order_id not in (
    "share_of_sean_999982","share_of_sean_999983","share_of_sean_999984","share_of_sean_999985","share_of_sean_999986"
)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0jJIViOD-1693295196299)(file://d:\Pictures\mdpic\2023-08-28-16-46-14-image.png?msec=1693267693120)]

分析上面两个语句不会使用到索引,使用范围不大的in可以使用索引

EXPLAIN select seckill_id,order_id,user_id,goods_id from test_import_export where order_id in (
"share_of_sean_999982","share_of_sean_999983","share_of_sean_999984","share_of_sean_999985","share_of_sean_999986"
)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JcOiwc3I-1693295196300)(file://d:\Pictures\mdpic\2023-08-28-16-46-31-image.png?msec=1693267693120)]

如果使用in,需要限制in的数量。

但是使用>,<,BETWEEN ... AND ...这样的范围查找是可以使用索引的(无论范围多大),因为B+数的叶子节点已经排好序了,这样可以很容易的锁定范围。但是in里边的数据不确定,如果范围太大,优化器会分析,如果觉得全表扫描更快,就直接使用全表扫描。

解决办法将大量的in条件进行分页。然后再将结果组合起来。

2.2 前缀模糊查询

EXPLAIN 
select seckill_id,order_id,user_id,goods_id from test_import_export where order_id like '%_11';

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WyXuWy8n-1693295196300)(file://d:\Pictures\mdpic\2023-08-28-20-41-43-image.png?msec=1693267693120)]

前缀模糊查询会导致索引失效,导致全表扫描

EXPLAIN 
select seckill_id,order_id,user_id,goods_id from test_import_export where order_id like '11_%';

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nA7FnqFL-1693295196300)(file://d:\Pictures\mdpic\2023-08-28-20-39-52-image.png?msec=1693267693120)]

非前缀模糊查询则会使用到索引

2.3 数据区分度不大

select seckill_id,order_id,user_id,goods_id from test_import_export where `status` = 1 

如果在status字段上加索引,没有效果,因为索引是B+树,本来就是通过索引来进行排序增加检索速度,只有几个枚举值,自然也不需要索引就能很快检索。

2.4 在属性上计算(或使用函数,或隐式类型转换)不能使用索引

以下我就不贴出运行结果,直接解释原因。

EXPLAIN
select seckill_id,order_id,user_id,goods_id from test_import_export where seckill_id + 1 = 10;

因为索引保存的是索引字段的原始值,而不是 id+1(包括其他函数和表达式计算)计算之后的值,所以无法走索引。

这个解释似乎有些牵强,那为什么MySql不转换成 id = 10-1,我查过这个问题,觉得最好的解释是因为MySql不太想去实现这个逻辑,因为表达式和函数太多了,如果需要全部实现,显得代码太过臃肿。就需要程序员自己去注意这个问题。

对索引隐式类型转换

EXPLAIN
select seckill_id,order_id,user_id,goods_id from test_import_export where seckill_id = "71222593";

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Il1539OZ-1693295196300)(file://d:\Pictures\mdpic\2023-08-28-22-06-33-image.png?msec=1693267693121)]

数字 = 字符串,这种比较方式会使用索引。

EXPLAIN
select seckill_id,order_id,user_id,goods_id from test_import_export where order_id = 17;

字符串 = 数字,这种不会使用到索引。

原因是MySQL 在遇到字符串和数字比较的时候,会自动把字符串转为数字,然后再进行比较

相当于对order_i使用了函数:

EXPLAIN
select seckill_id,order_id,user_id,goods_id from test_import_export where CAST(order_id AS signed int)  = 17;

而第一种方式,相当于在右测使用了函数,自然能用到索引。

2.5 联合索引非最左匹配

联合索引在B+树中的存储方式如下图

在这里插入图片描述

其中c1是主键,联合索引c2,c3,c4。它首先根据联合索引第一列的值排序,如果第一列的值相等再根据第二列的值排序,以此类推。

联合索引需要遵循最左匹配原则,也就是按照最左优先的方式进行匹配。

如果创建了(a, b, c)三个联合索引

第一种情况:以下查询可以用到索引:

  • where a=1;

  • where a=1 and b=2 and c=3;

  • where a=1 and b=2;

其中a,b,c的顺序不重要,MySql会进行优化。

第二种情况:但是以下查询,则不会走索引:

  • where b=2;
  • where c=3;
  • where b=2 and c=3;

第三种情况:比较特殊:

  • where a = 1 and c = 3

    这种情况属于索引截断a能使用到索引,c不能。

    在5.5版本,前面a会走索引,在联合索引找到主键值后,回表查询出数据,然后对比c字段的值。

    5.6版本后,有一个索引下推功能,可以在索引遍历过程中,对索引中包含的字段先做判断,直接过滤掉不满足条件的记录,减少回表次数。

    什么是索引下推:五分钟搞懂MySQL索引下推

    大概原理是:截断的字段会被下推到存储引擎层进行条件判断(因为 c 字段的值是在 (a, b, c) 联合索引里的),然后过滤出符合条件的数据后再返回给 Server 层。由于在引擎层就过滤掉大量的数据,无需再回表读取数据来进行判断,减少回表次数,从而提升了性能。

第一,第二种情况体现了最左匹配原则,因为联合索引是按a,b,c依此排序,在a相同的情况下,对b排序,在b相同的情况下,对c排序。如果直接找b,根据树的特点就不能依据顺序快速定位b的位置。

2.6 使用OR

or两边,只要有一个不是索引,就会导致索引失效,原因很简单,如果有一边不是索引,那另一天即使有索引还是需要去匹配没有索引的一边是否符合条件,任然需要全表扫描。

解决办法是可以使用in代替or。或者分别查询在应用层面拼接。

3.慎用UNION关键字

在使用UNION执行完SQL后,会帮我们获取所有数据并去掉重复的数据,性能的损耗就在这里,而UNION ALL和UNION相反,帮我们获取所有数据但会保留重复的数据。

-- 2.5s
EXPLAIN
select seckill_id, order_id, user_id, goods_id from test_import_export where status = '0'
UNION
select seckill_id, order_id, user_id, goods_id from test_import_export where status = '1';

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Yg2w9TkO-1693295196301)(file://d:\Pictures\mdpic\2023-08-29-14-39-09-image.png?msec=1693291149492)]

UNION会产生一张临时表,大致是用来去重的

-- 1.2s
EXPLAIN
select seckill_id, order_id, user_id, goods_id from test_import_export where status = '0'
UNION ALL
select seckill_id, order_id, user_id, goods_id from test_import_export where status = '1';

更换成union all执行时间上能快很多。

解决方法可以把两个语句拆开分别查(这里可以用多线程),然后将查询结果组合到一起。避免用unionunion all

4.小表驱动大表

加入表user_info,为小表(数据量不大),如下:

CREATE TABLE `user_info` (
  `user_id` bigint(20) NOT NULL AUTO_INCREMENT,
  `name` varchar(50) DEFAULT NULL,
  `sex` tinyint(2) DEFAULT NULL,
  PRIMARY KEY (`user_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

有几种小表驱动大表的形式:

select user_id from test_import_export where user_id in 
(select user_id from user_info where user_id = 20)

5.分页查询优化

分页查询优化的方式主要有两种:

  • 最大id查询法。将上一次查询出的最大id传入,取每页数目的数据量。查询速度在ms级别

    select * from test_import_export where seckill_id > 44212577 ORDER BY seckill_id ASC
    limit 20;
    
  • 子查询方式。先分页查询出符合条件和分页的第一条id,然后取id>=的数据

    
    -- 子查询方式,1千万秒级别
    
    select * from test_import_export 
    where seckill_id >= ( select seckill_id from test_import_export limit 990000,1) limit 10;
    

以上两种方式都只适合不排序的情况。如果需要排序,则需要给排序加上索引,用索引字段来代替id字段比较:

select * from test_import_export 
where user_id >= ( select user_id from test_import_export limit 990000,1) limit 10;

6.优化select count

优化select count,只能从应用层面优化。

  • 加缓存(redis)

参考博客:

面试官:聊聊索引失效?失效的原因是什么? - 小林coding - 博客园

五分钟搞懂MySQL索引下推

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

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

相关文章

经济大环境不好是你给自己找的理由吗?

最近很多自媒体博主都在说的一个现象&#xff0c;就是今年的经济形势比口罩那几年都要难过&#xff0c;全球的经济都面临打的挑战&#xff0c;就业岗位的缺失&#xff0c;22-35岁的青年失业率攀升很多人都在痛苦的边缘挣扎。 我国灵活就业人数已超2亿&#xff0c;平台经济快速发…

在ros中利用串口serial发布fdilink的gps话题

文章目录 介绍FDILink通讯协议数据帧组成数据包 数据处理打开串口在头文件中定义参数串口读取 代码运用依赖&#xff1a;使用&#xff1a; 源码 介绍 DETA100系列 是一个提供 GNSS/INS & AHRS 系统的模组&#xff0c;在最苛刻的条件下提供准确的位置、速度、加速度和姿态数…

国标GB28181安防监控视频平台EasyGBS新功能:批量绑定角色与取消设备

国标GB28181协议视频平台EasyGBS是基于国标GB28181协议的视频云服务平台&#xff0c;支持多路设备同时接入&#xff0c;并对多平台、多终端分发出RTSP、RTMP、FLV、HLS、WebRTC等格式的视频流。国标视频监控平台可提供视频监控直播、云端录像、云存储、检索回放、智能告警、语音…

多线程(额外扩展)(面试会用)

1 线程状态 1.1 状态介绍 当线程被创建并启动以后&#xff0c;它既不是一启动就进入了执行状态&#xff0c;也不是一直处于执行状态。线程对象在不同的时期有不同的状态。那么Java中的线程存在哪几种状态呢&#xff1f;Java中的线程 状态被定义在了java.lang.Thread.State枚…

中央发文:提高青年人才资助比例, 放宽学历、年龄限制 (附2023国自然资助比例统计)~

8 月 27 日&#xff0c;中共中央办公厅、国务院办公厅印发《关于进一步加强青年科技人才培养和使用的若干措施》&#xff08;以下简称《若干措施》&#xff09;&#xff0c;明确提出包括提高国家自然科学基金对青年科技人才的资助比例&#xff0c;放宽学历、年龄限制等措施&…

五、多表查询-4.5子查询-表子查询

一、概述 子查询返回的结果是多行多列&#xff0c;这种子查询称为表子查询。 常用的操作符&#xff1a;in 经常出现在from之后 二、演示 【例1】查询与“鹿掌客”、“宋院桥”的职位和薪资相同的员工信息 1、查询与“鹿掌客”、“宋院桥”的职位和薪资 返回的结果是一个表…

请问现在开融资融券账户交易佣金利率最低是多少?怎么开户!

请问现在开融资融券账户交易佣金利率最低是多少&#xff1f;怎么开户&#xff01; 融资融资利率没有最低的说法&#xff0c;利率一般都是相对的&#xff0c;融资融券的利率通常约为6%以上&#xff0c;当然这个也会根据市场货币的政策有所变动&#xff0c;比如现在的的货币政策…

极智嘉(Geek+)再获重磅荣誉,持续力领跑智慧物流行业发展

近日&#xff0c;全球仓储机器人引领者极智嘉(Geek)再度传来好消息&#xff0c;凭借着全球化的专业服务能力和稳健增长的亮眼海外成绩&#xff0c;一举荣登“2023出海品牌服务商”价值榜&#xff0c;成为唯一登榜的物流机器人企业。 作为率先出海的物流机器人企业&#xff0c…

如何在VR头显端实现低延迟的RTSP或RTMP播放

技术背景 VR&#xff08;虚拟现实技术&#xff09;给我们带来身临其境的视觉体验&#xff0c;广泛的应用于城市规划、教育培训、工业仿真、房地产、水利电力、室内设计、文旅、军事等众多领域&#xff0c;常用的行业比如&#xff1a; 教育行业&#xff1a;VR头显可以用于教育…

成都瀚网科技:抖店怎么上精选联盟?

在抖音电商平台上&#xff0c;选定的联盟是一个非常重要的入口。对于商家来说&#xff0c;能够进入选定的联盟意味着更多的曝光度和流量&#xff0c;从而获得更好的销售机会。那么&#xff0c;抖店是如何进入精选联盟的呢&#xff1f; 1、抖店如何加入特色联盟&#xff1f; 提供…

arm版Linux下安装es集群

背景&#xff1a;由于生产上网络没通&#xff0c;没办法&#xff0c;只能自己安装一个es集群的测试环境了&#xff0c;我的电脑是Mac M2&#xff0c;安装的Linux是centos7&#xff0c;也是arm版的。 第一步&#xff1a;查看自己Linux系统的版本 命令&#xff1a;uname -a 例如…

用Kubernetes(k8s)的ingress部署https应用

用Kubernetes的ingress部署https应用 环境准备Ingress安装域名证书准备 部署应用通过ingress暴露应用根据ssl证书生成对应的secret创建ingress暴露部署的应用确认自己安装了ingress创建ingress 访问你暴露的应用 环境准备 Ingress安装 我之前有一片文章写的是用ingress暴露应…

揭秘:企业在线帮助中心的一些技巧秘密!

企业在线帮助中心是现代企业为了提供更好的客户服务而建立的一个重要渠道。它可以帮助客户解决问题、获取产品信息和技术支持。在这篇文章中&#xff0c;我将揭秘一些企业在线帮助中心的技巧秘密&#xff0c;希望能够帮助企业提供更好的客户服务。 一、清晰的导航结构 一个清…

js删除字符串中的指定字符串

1. 使用 replace() 方法 replace() 将字符串中的指定子字符串替换为新的字符串。 如果删除指定的子字符串&#xff0c;可以将它替换为空字符串。 var str "Hello, World!";var substringToRemove "World";var newStr str.replace(substringToRemove, &q…

太阳能景观凉亭

丰富的太阳辐射能是重要的能源&#xff0c;是取之不尽、用之不竭的、无污染、廉价、人类能够自由利用的能源。太阳能每秒钟到达地面的能量高达80万千瓦&#xff0c;假如把地球表面0.1%的太阳能转为电能&#xff0c;转变率5%&#xff0c;每年发电量可达5.61012千瓦小时&#xff…

Oatpp编译使用Windows版本----windows搭建http服务器

来源&#xff1a;微信公众号「编程学习基地」 文章目录 一、Oatpp 编译下载源码cmake构建工程Configue配置x64Generate构建项目 VS2019编译项目 二、Oatpp搭建http服务器VS2019创建空项目导入oatpp项目配置 一、Oatpp 编译 下载源码 下载源码&#xff1a;https://github.com…

装备一台ubuntu

问题&#xff1a;linux在执行ifconfig时出现 Command ‘ifconfig‘ not found ,but can be installed with: 这种情况解决方案&#xff08;参考&#xff09; 描述&#xff1a; 1、安装好linux后想查一下ip地址&#xff0c;一查出现了这种情况 2、执行了这个命令&#xff0c;出…

如何使用CSS实现一个带有动画效果的进度条?

聚沙成塔每天进步一点点 ⭐ 专栏简介⭐ HTML 结构&#xff1a;⭐ CSS 样式&#xff1a;⭐ 写在最后 ⭐ 专栏简介 前端入门之旅&#xff1a;探索Web开发的奇妙世界 记得点击上方或者右侧链接订阅本专栏哦 几何带你启航前端之旅 欢迎来到前端入门之旅&#xff01;这个专栏是为那…

Android开发基础之服务Service

尽可能简单理解Android开发四大组件中的服务Service&#xff0c;用简单的例子和语言。 概念 长期在后台运行&#xff0c;与用户没有交互&#xff0c;比如音乐&#xff0c;可以在后台播放&#xff0c;同时可以去看书&#xff0c;浏览新闻等 配置 由于Service也是四大组件之…

2.2 概念模型

思维导图&#xff1a; 学习目标&#xff1a; 学习数据库的概念模型涉及对抽象思维和具体实践的结合。我会采取以下策略来有效学习&#xff1a; 1. **基础理论学习**&#xff1a; - 阅读经典教材和参考书籍&#xff0c;理解关键概念如实体、属性、关系等。 - 观看在线课…