文档章节

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

迷你卡卡西
 迷你卡卡西
发布于 2015/04/29 12:03
字数 1279
阅读 6
收藏 0
点赞 0
评论 0

场景

我用的数据库是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 > (
            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`
                    )
                )
        )
    )

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

方法如下:

在命令窗口执行 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 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

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

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

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索引的时间差不多

查看执行计划:

image

先提取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倍

执行计划:

image

我们会看到,先提取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

执行计划:

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.cnblogs.com/tangyanbo/p/4462734.html

共有 人打赏支持
迷你卡卡西
粉丝 6
博文 18
码字总数 503
作品 0
大连
高级程序员
一次非常有意思的sql优化经历

场景 我用的数据库是mysql5.6,下面简单的介绍下场景 课程表 create table Course( c_id int PRIMARY KEY, name varchar(10) ) 数据100条 学生表: create table Student( id int PRIMARY KE...

rewiner22 ⋅ 2016/11/30 ⋅ 0

浅谈MySQL SQL优化

本文首发于个人微信公众号《andyqian》,期待你的关注 前言 有好几天没有写文章了,实在不好意思。之前就有朋友希望我写写MySQL优化的文章。我迟迟没有动笔,主要是因为,SQL优化这个东西,很...

andyqian ⋅ 01/30 ⋅ 2

mysql 优化步骤

优化SQL语句的一般步骤: 1. 通过 show status 命令了解各种SQL的执行效率。 show status like 'com%' Comxxx表示每个xxx语句执行的次数,我们通常比较关心的是一下几个参数: Comselect: 执...

nao ⋅ 2015/12/15 ⋅ 0

一次有意思的面试

摘自:http://www.oschina.net/question/2358114_2137986?sort=default&p=1#answers 背景:以前在小公司,技术部水平参差不齐,能力比同部门的人强那么一点,公司给我定位高级工程师。后来,...

shengfq ⋅ 2015/10/20 ⋅ 0

表变量和临时表

表变量存储在内存中,而临时表存储在tempdb中,会涉及到物理IO读写,那么我们是否可以由此得出结论,使用表变量要比使用临时表效率高呢?相信有一部分人会和我有同样的想法,使用表变量的效率...

鱼煎 ⋅ 2015/08/19 ⋅ 0

Sharding-JDBC 1.5.0 正式发布:全新 SQL 解析引擎

经过了 1.5.0.M1-1.5.0.M3 这 3 次里程碑版本的发布,Sharding-JDBC 1.5.0 稳定版终于正式发布。 Sharding-JDBC 1.5.0 版本是一次里程碑式升级,工作量巨大,Sharding-JDBC 截止到 1.4.2 之前...

亮_dangdang ⋅ 2017/07/31 ⋅ 27

公开课发布《轻松学习机器学习算法原理》by晓伟

特邀嘉宾 王晓伟微信号:goodwxw 江湖传言: 知数堂要开新课了,据说就是这位大神, 主讲“大数据”职位必备的职场技能~ 预计近期将启动大数据课程,首期有特别优惠,请认准知数堂! 大牛背景...

n88lpo ⋅ 2017/12/08 ⋅ 0

SQL 语句调优

现有如下SQL: 下面有 N 条查询通过 union all 连接,这些查询的目的是如果数据库存在相同记录就不插入。最终目的是完成一次批量插入。 系统运行发现这种形式的 SQL 非常耗时,求教 SQL 大神...

DevLeon ⋅ 2017/05/16 ⋅ 4

oracle学习路线图

这是本人收藏的一个大师写的,用来提示自己oracle学习路线 1、sql、pl/sql(网上有很多的视频,可以做一个简单的入手,然后看几本书,多做实验) 作为oracle的基本功,需要大家对sql和plsql...

Monument ⋅ 2014/09/25 ⋅ 2

构建高并发&高可用&安全的IT系统-高并发部分

什么是高并发? 狭义来讲就是你的网站/软件同一时间能承受的用户数量有多少 相关指标有 并发数:对网站/软件同时发起的请求数,一般也可代表实际的用户 每秒响应时间:常指一次请求到系统正确...

科技小毛 ⋅ 2017/09/07 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

10个免费的服务器监控工具

监控你的WEB服务器或者WEB主机运行是否正常与健康是非常重要的。你要确保用户始终可以打开你的网站并且网速不慢。服务器监控工具允许你收集和分析有关你的Web服务器的数据。 有许多非常好的服...

李朝强 ⋅ 22分钟前 ⋅ 0

压缩工具之zip-tar

zip 支持目录压缩。使用yum安装zip包,使用yum安装unzip包 zip 1.txt.zip 1.txt #将1.txt文件压缩,新生成的压缩文件为1.txt.zip,原文件保留 zip -r 123.zip 123/ #-r对目录操作。将123/目录...

ZHENG-JY ⋅ 22分钟前 ⋅ 0

Dubbo @Activate注解使用和实现解析

Activate注解标识一个扩展是否被激活和使用,可以放在定义的类上和方法上,dubbo用它在SPI扩张类定义上,标识这个扩展实现激活的条件和时机,先看下定义: /** * Activate * <p/> * ...

哲别0 ⋅ 29分钟前 ⋅ 0

6.5 zip压缩工具 tar打包 打包并压缩

1.tar tar命令格式 [-zjxcvfpP] filename tar -z:表示同时用gzip压缩。 -j:表示同时用bzip2压缩。 -J:表示同时用xz压缩。 -x:表示解包或者解压缩。 -t:表示查看tar包里的文件。 -c:表示建...

oschina130111 ⋅ 31分钟前 ⋅ 0

Linux系统工程狮养成记

如今的社会,随着时代的发展,出现了很多职业,像电子类,计算机类的专业,出现了各种各样的工程师,有算法工程师,java工程师,前端工程师,后台工程师,Linux工程师,运维工程师等等,不同...

六库科技 ⋅ 38分钟前 ⋅ 0

Linux 机器的渗透测试命令备忘表

如下是一份 Linux 机器的渗透测试备忘录,是在后期开发期间或者执行命令注入等操作时的一些典型命令,设计为测试人员进行本地枚举检查之用。 此外,你还可以从这儿(https://gbhackers.com/c...

寰宇01 ⋅ 39分钟前 ⋅ 0

windows 安装java开发环境,配置jdk

下载jdk安装文件 链接:https://pan.baidu.com/s/1UEKPjnAdMqNj612B39Pfsg 密码:ipqx 如果javac无法使用 1,检查环境变量名称中是否有空格。。。,去除后即可 2,将JAVA_HOME替换为原始路径...

阿豪boy ⋅ 41分钟前 ⋅ 0

简析log4j的实现方式

刚加入新公司,对日志的要求比较严格,对此特意花了几天时间看了一下log4j的源码,大概了解了一下log4j的实现方式,总结如下: log4j的实现分为两个步骤:log4j.xml的加载,logger的使用 这里...

zdatbit ⋅ 今天 ⋅ 0

win环境下jdk7与jdk8共存配置

1.jdk安装包 jdk安装包 安装步骤略 2.jdk等配置文件修改 在安装JDK1.8时(本机先安装jdk1.7再安装的jdk1.8),会将java.exe、javaw.exe、javaws.exe三个文件copy到了C:\Windows\System32,这...

泉天下 ⋅ 今天 ⋅ 0

windows profesional 2017 build problem

.net framework .... https://stackoverflow.com/questions/43330915/could-not-load-file-or-assembly-microsoft-build-frameworkvs-2017...

机油战士 ⋅ 今天 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部