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

原文:一次非常有意思的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条

学生成绩表SC

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 )

image

发现没有用到索引,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的时间还是太长了,还能进行优化吗,仔细看执行计划:

image

查看优化后的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 > (SELECT1FROM`YSB`.`SC` `sc`WHERE((`YSB`.`sc`.`c_id` = 0)AND (`YSB`.`sc`.`score` = 100)AND (< CACHE > (`YSB`.`s`.`s_id`) = `YSB`.`sc`.`s_id`))))

补充:这里有网友问怎么查看优化后的语句

方法如下:

在命令窗口执行 image

image

有type=all

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

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

耗时:0.001s

得到如下结果:

image

然后再执行

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

耗时:0.001s

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

mysql是先执行外层查询,再执行里层的查询,这样就要循环70007*11=770077次。

那么改用连接查询呢?

SELECT s.* from Student sINNER JOIN SC scon sc.s_id = s.s_idwhere sc.c_id=0 and sc.score=100

这里为了重新分析连接查询的情况,先暂时删除索引sc_c_id_index,sc_score_index

执行时间是:0.057s

效率有所提高,看看执行计划:

image

这里有连表的情况出现,我猜想是不是要给sc表的s_id建立个索引

CREATE index sc_s_id_index on SC(s_id);

show index from SC

image

在执行连接查询

时间: 1.076s,竟然时间还变长了,什么原因?查看执行计划:

image

优化后的查询语句为:

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条件过滤

回到前面的执行计划:

image

这里是先做的where条件过滤,再做连表,执行计划还不是固定的,那么我们先看下标准的sql执行顺序:

image

正常情况下是先join再where过滤,但是我们这里的情况,如果先join,将会有70w条数据发送join做操,因此先执行where

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

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

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

和之前没有建s_id索引的时间差不多

查看执行计划:

image

先提取sc再连表,这样效率就高多了,现在的问题是提取sc的时候出现了扫描表,那么现在可以明确需要建立相关索引

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

再执行查询:

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

执行时间为:0.001s,这个时间相当靠谱,快了50倍

执行计划:

image

我们会看到,先提取sc,再连表,都用到了索引。

那么再来执行下sql

SELECT s.* from Student sINNER JOIN SC scon sc.s_id = s.s_idwhere sc.c_id=0 and sc.score=100

执行时间0.001s

执行计划:

image

这里是mysql进行了查询语句优化,先执行了where过滤,再执行连接操作,且都用到了索引。

总结:

1.mysql嵌套子查询效率确实比较低

2.可以将其优化成连接查询

3.连接表时,可以先用where条件对表进行过滤,然后做表连接

(虽然mysql会对连表语句做优化)

4.建立合适的索引

5.学会分析sql执行计划,mysql会对sql进行优化,所以分析执行计划很重要

由于时间问题,这篇文章先写到这里,后续再分享其他的sql优化经历。

 

执行计划参考:

http://www.cnblogs.com/ggjucheng/archive/2012/11/11/2765237.html

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

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

相关文章

Go Out Otherwise Shut Up

Shut Up For Ever! Work ,Work, Right Now! 下面盗用一下PLMM的格言给自己Add Oil。 a za a za fighting! Forge Ahead,Never Retreat! 这两句还是蛮有气势的&#xff0c;哈哈。 转载于:https://www.cnblogs.com/Farseer1215/archive/2005/05/07/150413.html

setCharacterEncoding和setContentType

request.setCharacterEncoding&#xff08;&#xff09;是设置从request中取得的值或从数据库中取出的值 response.setContentType("text/html;charsetgb2312")是设置页面中为中文编码 前者是设置动态文字&#xff08;参数&#xff0c;数据库&#xff09;&#xff0c…

LeetCode—239. 滑动窗口最大值(困难)

239. 滑动窗口最大值&#xff08;困难&#xff09; 题目描述&#xff1a; 给你一个整数数组 nums&#xff0c;有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。 返回滑动窗口中的最大值 。 …

intellij idea搭建springboot

intellij idea2018.3创建springboot项目1.new > spring initilizer > web > spring web initializer运行项目方法一&#xff1a;导航板上的命令台图标&#xff0c;输入命令&#xff1a;mvn springboot:run,即可看到running,浏览器测试控制器方法&#xff0c;这种方法暂…

logstash

http://www.cnblogs.com/fangjian0423/p/logstash-elasticsearch-build.html http://chenlinux.com/2013/07/11/howto-filter-count-in-logstash/

连连看路径求解的算法

这是路径求解的算法做一个简单的介绍,适合入门者;首先是 x to x ,这个是横向比较直连然后是 y to y ,这个是竖向比较直连然后是 1个折点算法很简单;比如7x3的000100000000000000001p1 是 3,0p2 是 6,2那么折点是000100x0000000000x001折点1是 6,0 ,折点2是 3,2注意这个值和p1,p…

LeetCode—240. 搜索二维矩阵 II

240. 搜索二维矩阵 II 题目描述&#xff1a; 编写一个高效的算法来搜索 m x n 矩阵 matrix 中的一个目标值 target 。该矩阵具有以下特性&#xff1a; 每行的元素从左到右升序排列。 每列的元素从上到下升序排列。 考察重点&#xff1a;简单的二维矩阵搜索 func SearchMatr…

Android开发:什么是IBinder

上回书简单描述了进程间传递类对象的原理&#xff0c;这回在讲Parcel之前&#xff0c;先要讲一个东西&#xff1a;IBinder。IBinder是什么呢&#xff1f;首先要明白&#xff0c;Android的远程调用&#xff08;就是跨进程调用&#xff09;就是通过IBinder实现的&#xff0c;下面…

Debug调试

先设置断点&#xff0c;然后Debug调试 step into&#xff1a;进入子函数step over&#xff1a;越过子函数&#xff0c;但子函数会执行step return&#xff1a;跳出子函数转载于:https://www.cnblogs.com/android-for-dh/p/4482519.html

python matplotlib绘图大全(散点图、柱状图、饼图、极坐标图、热量图、三维图以及热图)...

//2019.7.14晚matplotlib七种常见图像输出编程大全 七种图形汇总输出如下&#xff1a; import numpy as np #导入数据结构nmupy模块import matplotlib.pyplot as plt #导入matplotlib图像输出模块plt.rcParams["font.sans-serif"]["SimHei"] #输出图像的标…

Java入门需掌握的30个基本概念[转]

Java的白皮书为我们提出了Java语言的11个关键特性(1)Easy:Java的语法比C的相对简单&#xff0c;另一个方面就是Java能使软件在很小的机器上运行&#xff0c;基础解释其和类库的支持的大小约为40kb&#xff0c;增加基本的标准库和线程支持的内存需要增加125kb。(2)分布式:Java带…

LeetCode—241. 为运算表达式设计优先级

241. 为运算表达式设计优先级 题目描述&#xff1a; 给你一个由数字和运算符组成的字符串 expression &#xff0c;按不同优先级组合数字和运算符&#xff0c;计算并返回所有可能组合的结果。你可以按任意顺序 返回答案。 考察重点&#xff1a;(递归分治) 以符号位分割为左右…

报错:不是可以识别的内置函数名称

!!创建函数的时候不需要加dbo.&#xff0c;但在访问的时候&#xff0c;标量函数要加.dbo的 自己写完的函数&#xff0c;调用后报错提示&#xff1a;不是可以识别的内置函数名称 例&#xff1a;SELECT JS_ID A.ID, JSHM A.JSHM, JS_MC A.JS_MC, XY_DM …

C++右值引用与转移语义

std::forwad? C11 中定义的 T&& 的推导规则为&#xff1a; 右值实参为右值引用&#xff0c;左值实参仍然为左值引用。 参考&#xff1a; 右值引用与转移语义转载于:https://www.cnblogs.com/glensblog/p/11098359.html

gltail安装

是基于Ruby,所以服务器需要安装有ruby,国内需要把ruby的源改为淘宝的 Centos上 yum groupinstall "Development Tools" yum -y install freeglut libX11-devel mesa-libGL-devel perl-Time-HiRes freeglut-devel readline-devel libffi-devel libtool bison libxml…

微软获得O/R映射技术专利 业界担忧阻碍技术进展

一组微软员工申报了O/R映射技术的专利。 该专利将对业界现有的O/R映射产品造成怎样的影响目前尚不清楚&#xff0c;但有业界专家担忧微软将借此专利打压竞争对手。 这份专利档案是被网友无意间在专利信息查询网站FreshPatents.com上找到的&#xff0c;点此可以浏览原文。该专利…

Linux下安装Perl模块

# perl -MCPAN -e install Time::HiRes# perl -MCPAN -e install File::Tail# perl -MCPAN -e install Date::Parse# perl -MCPAN -e install Net::Netmask转载于:https://www.cnblogs.com/nwf5d/archive/2011/06/07/2074259.html

LeetCode—260. 只出现一次的数字 III

260. 只出现一次的数字 III 题目描述&#xff1a; 给定一个整数数组 nums&#xff0c;其中恰好有两个元素只出现一次&#xff0c;其余所有元素均出现两次。 找出只出现一次的那两个元素。你可以按 任意顺序 返回答案。 进阶&#xff1a;你的算法应该具有线性时间复杂度。你能否…

keras中接口

接口文档 https://keras-cn.readthedocs.io/en/latest/layers/merge/转载于:https://www.cnblogs.com/charlie7/p/11190102.html

【活动】畅想云端加油站,赢iPad

2019独角兽企业重金招聘Python工程师标准>>> 中石化联手阿里云升级石油化工业务&#xff0c;已运行2月 中石化的“互联网”战略正在不断深化。4月20日消息&#xff0c;中石化与阿里云共同宣布&#xff0c;双方将展开技术合作&#xff0c;借助阿里巴巴在云计算、大数…