一次翻好多倍的SQL优化过程

一次SQL优化,数据库查询速度提升 60 倍 id为自增主键,val为非唯一索引。为了达到相同的目的,我们一般会改写成如下语句时间相差很明显。为什么会出现上面的结果?我们看一下select*fromtestwhereval=4limit300000,5;查询到索引叶子节点数据。根据叶子节点上的主键值去聚簇索引上查询需要的全部字段值。类似于下面这张图像上面这样,需要查询300005次索引节点,查询300005次聚簇索引的数据,最后再将结果过滤掉前300000条,取出最后5条。... 阅读详情

参考链接:
良许的公众号
一次非常有意思的SQL优化经历

本次案例测试如下:
用的数据库是mysql5.6,下面简单的介绍下场景
课程表

create table Course(
c_id int PRIMARY KEY,
name varchar(10)
)

数据100条。
学生表

create table Student(
id int PRIMARY KEY,
name varchar(10)
)

数据70000条。
学生成绩表

CREATE table SC(
    sc_id int PRIMARY KEY,   
    s_id int,  
    c_id int,  
    score int
)

数据70w条。

查询目的:

查找语文考100分的考生。
查询语句:

select s.* from Student s
where s.s_id in (  
    select s_id   
    from SC sc   
    where sc.c_id = 0 and sc.score = 100 )

执行时间:30248.271s
晕,为什么这么慢,先来查看下查询计划:

EXPLAIN
select s.* from Student s 
  where s.s_id in ( 
    select s_id  
    from SC sc  
    where sc.c_id = 0 and sc.score = 100 )

在这里插入图片描述发现没有用到索引,type全是ALL,那么首先想到的就是建立一个索引,建立索引的字段当然是在where条件的字段。

先给sc表的c_id和score建个索引。

CREATE index sc_c_id_index on SC(c_id);
CREATE index sc_score_index on SC(score);

再次执行上述查询语句,时间为: 1.054s

快了3w多倍,大大缩短了查询时间,看来索引能极大程度的提高查询效率,建索引很有必要,很多时候都忘记建。

索引了,数据量小的的时候压根没感觉,这优化的感觉挺爽。

但是1s的时间还是太长了,还能进行优化吗,仔细看执行计划:
在这里插入图片描述
查看优化后的sql:
方法如下:
在命令窗口执行
在这里插入图片描述

SELECT
    `YSB`.`s`.`s_id` AS `s_id`,  
    `YSB`.`s`.`name` AS `name`
FROM  
    `YSB`.`Student` `s`
WHERE   
    < in_optimizer > (     
        `YSB`.`s`.`s_id` ,< EXISTS > (     
            SELECT          
                1         
            FROM           
                `YSB`.`SC` `sc`    
            WHERE          
                (          
                  (`YSB`.`sc`.`c_id` = 0)                  
                  AND (`YSB`.`sc`.`score` = 100)                 
                  AND (    
                      < CACHE > (`YSB`.`s`.`s_id`) = `YSB`.`sc`.`s_id`                   
                  )    
              )     
      ) 
  )

按照我之前的想法,该sql的执行的顺序应该是先执行子查询。

select s_id
from SC sc 
where sc.c_id = 0 and sc.score = 100

耗时:0.001s

得到如下结果:
在这里插入图片描述然后再执行

select s.* 
from Student s 
where s.s_id in(7,29,5000)

耗时:0.001s
这样就是相当快了啊,Mysql竟然不是先执行里层的查询,而是将sql优化成了exists子句,并出现了EPENDENT SUBQUERY,

mysql是先执行外层查询,再执行里层的查询,这样就要循环70007*8次。
那么改用连接查询呢?

SELECT s.* from
Student s
INNER JOIN SC sc
on sc.s_id = s.s_id
where sc.c_id=0 and sc.score=100

这里为了重新分析连接查询的情况,先暂时删除索引sc_c_id_index,sc_score_index 。
执行时间是:0.057s
效率有所提高,看看执行计划:
在这里插入图片描述这里有连表的情况出现,我猜想是不是要给sc表的s_id建立个索引

CREATE index sc_s_id_index on SC(s_id);
show index from SC

在执行连接查询
时间: 1.076s, 竟然时间还变长了,什么原因?查看执行计划:
在这里插入图片描述

SELECT  
    `YSB`.`s`.`s_id` AS `s_id`,   
    `YSB`.`s`.`name` AS `name`
FROM   
    `YSB`.`Student` `s`
JOIN `YSB`.`SC` `sc`
WHERE  
    (     
        (         
            `YSB`.`sc`.`s_id` = `YSB`.`s`.`s_id`       
        )   
        AND (`YSB`.`sc`.`score` = 100)    
        AND (`YSB`.`sc`.`c_id` = 0)  
    )

回到前面的执行计划:
在这里插入图片描述这里是先做的where条件过滤,再做连表,执行计划还不是固定的,那么我们先看下标准的sql执行顺序:
在这里插入图片描述
正常情况下是先join再进行where过滤,但是我们这里的情况,如果先join,将会有70w条数据发送join做操,因此先执行where 。

过滤是明智方案,现在为了排除mysql的查询优化,我自己写一条优化后的sql 。

SELECT   
    s.*
FROM   
    (     
        SELECT      
            *     
        FROM       
            SC sc   
        WHERE       
            sc.c_id = 0    
        AND sc.score = 100  
    ) t
INNER JOIN Student s ON t.s_id = s.s_id

即先执行sc表的过滤,再进行表连接,执行时间为:0.054s 。

和之前没有建s_id索引的时间差不多。
查看执行计划:
在这里插入图片描述
先提取sc再连表,这样效率就高多了,现在的问题是提取sc的时候出现了扫描表,那么现在可以明确需要建立相关索引。

CREATE index sc_c_id_index on SC(c_id);
CREATE index sc_score_index on SC(score);

再执行查询:

SELECT   
    s.*
FROM   
    (    
        SELECT     
            *    
        FROM      
            SC sc    
        WHERE        
            sc.c_id = 0    
        AND sc.score = 100   
    ) t
INNER JOIN Student s ON t.s_id = s.s_id

执行时间为:0.001s,这个时间相当靠谱,快了50倍。
在这里插入图片描述我们会看到,先提取sc,再连表,都用到了索引。

那么再来执行下sql。

SELECT s.* from
Student s
INNER JOIN SC sc
on sc.s_id = s.s_id
where sc.c_id=0 and sc.score=100

执行时间0.001s

执行计划:
在这里插入图片描述这里是mysql进行了查询语句优化,先执行了where过滤,再执行连接操作,且都用到了索引。

总结
1 mysql嵌套子查询效率确实比较低
2 可以将其优化成连接查询
3 连接表时,可以先用where条件对表进行过滤,然后做表连接
(虽然mysql会对连表语句做优化)
4 建立合适的索引,必要时建立多列联合索引
5 学会分析sql执行计划,mysql会对sql进行优化,所以分析执行计划很重要

索引优化
上面讲到子查询的优化,以及如何建立索引,而且在多个字段索引时,分别对字段建立了单个索引。

后面发现其实建立联合索引效率会更高,尤其是在数据量较大,单个列区分度不高的情况下。

单列索引
查询语句如下:

select * from user_test_copy where sex = 2 and type = 2 and age = 10
CREATE index user_test_index_sex on user_test_copy(sex);
CREATE index user_test_index_type on user_test_copy(type);
CREATE index user_test_index_age on user_test_copy(age);

分别对sex,type,age字段做了索引,数据量为300w,查询时间:0.415s执行计划:
在这里插入图片描述发现 type=index_merge

这是mysql对多个单列索引的优化,对结果集采用intersect并集操作

多列索引
我们可以在这3个列上建立多列索引,将表copy一份以便做测试

create index user_test_index_sex_type_age on user_test(sex,type,age);
select * from user_test where sex = 2 and type = 2 and age = 10

执行时间:0.032s,快了10多倍,且多列索引的区分度越高,提高的速度也越多

执行计划:
在这里插入图片描述
最左前缀

多列索引还有最左前缀的特性:

执行一下语句:

select * from user_test where sex = 2
select * from user_test where sex = 2 and type = 2
select * from user_test where sex = 2 and age = 10

都会使用到索引,即索引的第一个字段sex要出现在where条件中

索引覆盖
就是查询的列都建立了索引,这样在获取结果集的时候不用再去磁盘获取其它列的数据,直接返回索引数据即可

select sex,type,age from user_test where sex = 2 and type = 2 and age = 10

排序

select * from user_test where sex = 2 and type = 2 ORDER BY user_name

时间:0.139s

在排序字段上建立索引会提高排序的效率

create index user_name_index on user_test(user_name)

最后附上一些sql调优的总结,以后有时间再深入研究

1 列类型尽量定义成数值类型,且长度尽可能短,如主键和外键,类型 字段等等

2 建立单列索引

3 根据需要建立多列联合索引
当单个列过滤之后还有很多数据,那么索引的效率将会比较低,即列的区分度较低,
那么如果在多个列上建立索引,那么多个列的区分度就大多了,将会有显著的效率提高。

4 根据业务场景建立覆盖索引
只查询业务需要的字段,如果这些字段被索引覆盖,将极大的提高查询效率

5 多表连接的字段上需要建立索引 这样可以极大的提高表连接的效率

6 where条件字段上需要建立索引

7 排序字段上需要建立索引

8 分组字段上需要建立索引

9 Where条件上不要使用运算函数,以免索引失效

mysql查询sql计划_MySQL 查询计划 总结

数据库执行计划的局限性:

EXPLAIN不会告诉你关于触发器、存储过程的信息或用户自定义函数对查询的影响情况;

EXPLAIN不考虑各种Cache(通常人们所说的Cache就是指缓存SRAM。 SRAM叫静态内存,“静态”指的是当我们将一笔数据写入SRAM后,除非重新写入新数据或关闭电源,否则写入的数据保持不变);

EXPLAIN不能显示MySQL在执行查询时所作的优化工作;

部分统计信息是估算的,并非精确值;

EXPALIN只能解释SELECT操作,其他操作要重写为SELECT后查看执行计划。(mysql5.6的版本已经支持直接查看)

一张图告诉你SQL使用inner join,left join 等

数据库优化的8大方案

Mysql leftjoin一对多关系导致sum数据翻倍 解决方案 使用 leftjoin 的时候会导致 t_01 的数据出现多次,再对 t_01 使用 sum 时,会有 sum 数据翻倍的情况。 阅读详情

相关推荐

SQL语句|查询结果翻了4倍,如何修复?

🏆本文收录于专栏,主要记录项目实战过程中所遇到的Bug或因后果及提供真实有效的解决方案,希望能够助你一臂之力,帮你早日登顶实现财富自由🚀;同时,欢迎大家!持续更新中,up!up!up!!

**My Coding Family** 853

MySQL Left Join左连接后对数据做SUM汇总处理时出现数据倍数增长问题(左连接SUM数据重复问题)【已解决】

展示的数据内容是同事提供,表名,列名的命名不规范,表结构设计的也不合理 切记不可使用拼音,这里我是为了解决同事的问题(表结构同事测试写的,我就没修改) 今天写项目时,需要将一个车辆的所有费用做汇总处理,包括加油费和保险事故等等 刚开始使用左连接,然后对加油表和保险表的费用一栏用SUM进行处理,代码如下: select b.id,b.plate_number,SUM( bx.pay_money),SUM(o.money) from base b left join baoxian bx on b.id=b.

小刘爱搬砖 1万+

详解卷积神经网络(CNN)

卷积神经网络(Convolutional Neural Network, CNN)是一种前馈神经网络,它的人工神经元可以响应一部分覆盖范围内的周围单元,对于大型图像处理有出色表现。

qq_25762497的博客 25万+

一次非常有意思的 SQL 优化经历

原文出处: 风过无痕-唐   欢迎分享原创到伯乐头条 我用的数据库是mysql5.6,下面简单的介绍下场景 课程表 1 2 3 4 create table Course( c_id int PRIMARY KEY, name varchar(10) ) 数据100条 学生表:

lijunlinlijunlin的专栏 735

AMBA-CHI协议详解(十五)

Write transactions事务描述以及请求属性,cache line状态转换。

Crazzy_M的博客 650

LVGL iPhone Duo 开合过渡

环境:LVGL 9.x(需要软件模糊),窗口建议 1280×800。界面文案英文(默认 Montserrat 无 CJK)。

摸鱼专家 149

Mysql一对多关系leftjoin导致sum数据翻倍的解决方案

案例: 数据表: 群表(team)和 群标签关系表 (team_tag_relation) 关系:一个群对应多个标签 team表中有群人数字段,当leftjoin群标签关系表时,如果某个群拥有3个标签,则该群的数据会出现3次,导致进行sum(群人数)会sum多次,即群人数会翻3倍,造成数据错误。 解决方案: 避免直接将两个表进行leftjoin 先处理群标签关系表(team_tag_relation),将多条数据聚合为一条,sql如下: select team_id, GROUP_CONCAT(t

m0_47005349的博客 9786

QT如何使用CTK插件搭建应用程序框架?

CTK框架,QT框架,插件系统

cs821984831的博客 735

Mysql一对多关系leftjoin到导致sum数据翻倍解决方案

Mysql一对多关系leftjoin到导致sum数据翻倍-解决方案

陆柒捌的博客 1917

超详细教程YoloV8官方推荐免费数据集网站Roboflow一键导出Voc、COCO、Yolo、Csv等格式

YoloV8官方推荐了一个数据集网站,就是Roboflow。Roboflow是一个数据集管理平台,提供了免费的数据集,同时也支持上传自己的数据集进行格式转换。使用Roboflow,开发者可以方便地获取所需格式的数据集,无需手动转换格式。此外,Roboflow还提供了多种数据预处理、数据增强等功能,可帮助开发者更好地优化训练数据

Snu77的博客 2万+

S7-1200PLC与昆仑通态触摸屏以太网通信的具体方法和步骤(图文)

S7-1200PLC与昆仑通态触摸屏以太网通信的具体方法和步骤(图文)

Robot_PLC_HMI_Automation 1万+

一次复杂的SQL优化过程

一、背景 这个复杂的查询SQL语句,已经进行语法优化,写入应用程序中,且不希望修改代码,实现执行速度大幅度提升。 查询语句中,使用了用户自定义函数,多个视图嵌套,代码逻辑复杂,运行时长过长。 分析方向,基于查询计划,定位耗时较多的节点,通过改变调用对象,实现优化查询性能。 二、查询语句,优化前后的计划 SQL语句如下: analyse; explain (analyse ,buffers ,verbose ,costs ,timing ) with t as (select.

lyu1026的博客 5469

西门子S7-1200PLC与FANUC机器人进行PROFINET IO通信的具体方法和步骤详解

西门子S7-1200PLC与FANUC机器人进行PROFINET IO通信的具体方法和步骤详解

Robot_PLC_HMI_Automation 1万+

PostgreSQL SQL优化用兵法,优化后提高 140倍速度

开头还是介绍一下群,如果感兴趣PolarDB ,MongoDB ,MySQL ,PostgreSQL ,Redis, OceanBase, Sql Server等有问题,有需求都可以加群群内有各大数据库行业大咖,可以解决你的问题。加群请联系 liuaustin3 ,(共2720人左右 1 + 2 + 3 + 4 +5 + 6 + 7 + 8 +9)(1 2 3 4 5 6群均已爆满,7群430+,...

sql server的专栏 1189

从业务角色到工作台:一步步创建 SAP Fiori Launchpad Space 与 Page

SAP S/4HANA Launchpad 配置优化指南:从业务角色出发构建高效工作台 本文针对S/4HANA项目中用户普遍反映的"入口难找"问题,提出基于Spaces和Pages的系统化解决方案。通过"以工作岗位为中心"的设计理念,将Launchpad信息架构重构为:一个业务角色对应一个Space,每个Space包含1-5个Page,Page内按任务划分2-5个Section,每个Section放置3-7个Tiles。文章详细阐述了从Business Role入手配

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 224

精雕软件(JDpaint) 5.5 绿色版

精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版

MySQL SQL优化过程

本文旨在深入探讨MySQL SQL优化的过程,从基础概念到高级技巧,通过多个代码示例,帮助初学者和有经验的开发者掌握SQL优化的核心策略。通过上述步骤和技巧,你可以逐步提升自己的SQL技能,使你的应用在面对日益增长的数据量时仍然保持高性能。希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。一个做过前端开发的产品经理,经历过睿智产品的折磨导致脱发之后,励志要翻身农奴把歌唱,数据库的性能会随数据量增长而变化,定期执行查询分析和优化是必要的。

一个做过前端开发的产品经理,经历过睿智产品的折磨导致脱发之后,励志要翻身"农奴"把歌唱,一边打入敌人内部一边持续提升自己,为我们广大开发同胞谋福祉,坚决抵制睿智产品折磨我们码农兄弟! 946

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

一次SQL优化过程

一次SQL优化过程 场景 第一步:发现问题 一个页面列表接口,耗时 6.98s。 我认为一个前端接口耗时超过1s就是耍流氓。 第二步:定位问题 使用arthas神器打印接口耗时。arthas的部署及使用方法可以参见: arthas独家心得 如果不会使用arthas的开发,我不认为他是一个高级开发。 可见问题在 mapper那里出问题了,我一直猜想是拉列表后因为循环拉取详情导致的慢,看来我的经验不对,所以碰到问题,先从本质核实问题的原因,是程序员解决问题的第一步,而不是瞎猜,惊慌失措。 第三步:找出问题,

八角塘塘主的博客 777

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

win10 跳过U8环境检测的IE WebControls.rar

win10 安装u8的时候 提示IE WebControls 不通过,这个工具可以欺骗u8的检查。 跳过U8环境检测的IE WebControls。提示导入失败后,重新检测通过。

记录一次sql优化过程

对于我这种刚刚进入DBA行业的人来说sql优化是一件很难的事情。所以今天看了一下别人优化的过程顺手记录的一笔。 SELECT DISTINCT vi.policy_no FROM odsdata.policy_extend_info ei, policy_vehicle_info vi, policy_base_info bi, od

xionglang7的专栏 1101

记录一次老项目的优化过程

最近着手了部门一个几年前的的性能优化,分析之后我发现:大量接口直接查询某个表中的所有数据、没有使用分页查询,导致返回的数据量过大,降低了接口响应速度和前端渲染速度(甚至教师预约界面的渲染会让整个电脑都顿时变得卡顿),返回了大量不必要的数据筛选条件不足一些数据在前端处理、收集结果集(比如前端接收到所有课程的数据之后,逻辑处理出已结束的课程的结果集 然后在一个页面中渲染,降低了性能)

Hazehacker的博客 935

记录一次spark sql的优化过程

记录一次spark sql优化的过程

xiaoluobutou的专栏 388

Presto在车好多的实践

本文作者:车好多大数据OLAP团队-王培Presto 简介1.简介Presto 最初是由 Facebook 开发的一个分布式 SQL 执行引擎, 它被设计为用来专门进行高速、实时的数据分...

过往记忆大数据 6198

MySQL六:SQL优化、视图、存储过程

视图(View)是一种虚拟存在的表。视图中的数据并不在数据库中实际存在,行和列数据来自定义视图的查询中使用的表,并且是在使用视图时动态生成的。通俗的讲,视图只保存了查询的SQL逻辑,不保存查询结果(没有保存这张表,虚拟表)。所以我们在创建视图的时候,主要的工作就落在创建这条SQL查询语句上。存储过程是事先经过编译并存储在数据库中的一段 SQL 语句的集合,调用存储过程可以简化应用开发人员的很多工作,减少数据在数据库和应用服务器之间的传输,对于提高数据处理的效率是有好处的。

XiaoyuEr_6688的博客 2342

工作记录二: 记录一次简单的SQL优化过程

在工作时, 和同事一起遇到了一个关于SQL优化方面的问题, 现在记录如下 项目描述 项目分析思路 首先F12进入开发者模式, 查看最费时的请求 然后利用resultful风格接口工具集( RestfulToolkit ) : 用于将前端请求的url与后端的controller对应. 安装后的快捷键( Ctrl+\ ) 对应的controller方法如下,可以看到该方法将requ...

时间静止 2355

记一次JPA分页查询的SQL优化过程

JPA分页查询,在单表查询以及数据量不大的情况下,非常容易写,也利于后面的维护,但是效率却达不到预期

weixin_40733384的博客 1882

记一次Sql优化过程

这几天在写一个存储过程,反复优化了几次,从最开始的7分钟左右,优化到最后的几秒,并且这个过程中我的导师帮我指点了很多问题,这些指点都是非常宝贵的,独乐乐不如众乐乐,一起来分享这次的优化过程吧。 这个存过程的需求是这样的,抓取某个时间段内的订单明细,然后计算并汇总到某表即可。 于是乎,我写出第一版的存储过程,代码如下: /******************************...

weixin_33711647的博客 162
上一篇: 超时放弃订单怎么实现(几种方案)
下一篇: 多线程快速处理List集合(结合线程池的使用)
凌晨里的无聊人
博客等级 码龄8年 2320粉丝 206原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

凌晨里的无聊人

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值