前言

网上有很多关于sql语句优化的文章,我这里想说下为什么这样。。。写sql语句,能够提高查询的效率。

1 sql语句优化原理

要想写出好的sql,就要学会用数据库的方式来思考如何执行sql,那么什么是好的sql,首先要明白数据库是如何执行一个sql,一个事务的。

1.1 数据库执行sql的大致流程

粗略流程,所有关系型数据库都是这几步,具体前后顺序根据不同dbms不同配置下略有小差别,以下过程都需要耗时耗资源:

1.应用程序与数据库服务器建立链接

2.sql发送到数据库,数据库验证是否有执行的权限

3.进入语法解析器,进行词法与语法分析

4.进入优化器生成执行计划,部分dbms会检查是否有可重用的执行计划

5.根据执行计划依次扫描相关表中的行,不在数据缓冲区的走io

6.同时对于被扫描的行可能加锁,同时也可能会被其他sql阻塞

7.扫描的行足够放入查询缓存则开始运算或直接返回,不够则生成临时表,可能消耗io

8.对sql结果进行计算(可能)

9.将计算完成的结果全部写入网络io(可能)

10.如果事务完成则同步事务日志并释放锁,具体方式取决于dbms和当前配置

11.关闭连接(可选)

1.2 如何优化

这么多步骤,每一步都有优化策略,我尽量用简单的语言来描述:

1.应用程序与数据库服务器建立链接:

答:引入数据库连接池,避免每次都与数据库建立连接,提高效率。

2.sql发送到数据库,数据库验证是否有执行的权限

答:没撒好说的。

3.进入语法解析器,进行词法与语法分析

答:也没撒好说的,想要数据库在这里少用点资源就把sql写的简单点,但是差别不大。

4.进入优化器生成执行计划,部分dbms会检查是否有可重用的执行计划

答:任何数据库如何生成执行计划都可以写一本几百页的书,关系型数据库选择走什么执行计划都是基于消耗最小化的思路来的,简单来说就是走什么索引,按什么顺序走表,被扫到的数据行最少。如果你的表结构很复杂,有各种混搭的索引,你的join很多,那执行计划分析的时间就会拉长。所以sql对应的表索引简单,join或子查询少就快,复杂了优化器也会得选择困难症。

5.根据执行计划依次扫描相关表中的行,不在数据缓冲区的走io

答:存储引擎扫描表的性能消耗参考下面的list,消耗从大到小

全表扫描>全索引扫描>部分索引扫描>索引查找>唯一索引/主键查找>常量/null

要走索引对于sql语句也有要求,不能在谓词上作任何运算,扫描行数一般不能超过表的17%左右,这对你数据分布又有要求,比如你查select xxx from human where sex ='man',五五开,还是走扫描。这里我就不展开了,推荐题主一本书《Relational Database Index Design and the Optimizers》

6.同时对于被扫描的行可能加锁,同时也可能会被其他sql阻塞

答:如果扫描的行多,sql执行的时间长,被阻塞的概率就高,阻塞别人的概率也高,然后大家一起等,数据库就hung住了。

7.扫描的行足够放入查询缓存则开始运算或直接返回,不够则生成临时表,可能消耗io

答:一次取的尽量少,这不单指返回服务端的行数,应该从嵌套最深的一个子查询开始算

8.对sql结果进行计算(可能)

答:少用各种复杂的函数啊,count啊,order by啊等等。

9.将计算完成的结果全部写入网络io(可能)

答:请尽量少返回一点数据,如果不行请多次分批。

10.如果事务完成则同步事务日志并释放锁,具体方式取决于dbms和当前配置

这里举两个代表性栗子:

sql渣:

for i in (1-1000):

start transaction;

insert into table values (1);

commit;

end for

sql赞:

start transaction;

for i in (1-1000):

insert into table values (1);

end for

commit;

sql赞爆:

insert into table values (1)()...........()(1000);

首先,sql语法是我临时自创的,这个不是关键,关键在sql渣先生是1000个事务插1000行,日志flush1000次。sql赞先生是一个事务插1000行,事务日志flush1次。sql赞爆最nice。

这个例子我想表达的意思是如果你要用sql做一件事,那就要尽量让这件事占用的事务总时间最少。

第二个例子

sql渣:

update table where id > 0 and id < 1000000;

sql赞:

update table where id > 0 and id < 1000;

update table where id >= 1000 and id < 2000;

update table where id >= 2000 and id < 3000;

....

....

这个例子我想表达的意思是如果你要用sql做一件很大的事,那就尽量让大事化成很多小事。

两个例子好好体会下,一点不矛盾哦。补充一下,这里每个update都是单独事务

11.关闭连接(可选)

答:同1,别每次都关,关了也许还要重连。不关的话记得commit就好了,千万要记得commit啊!

1.3小结

通过好的sql语句:减少访问的数据行、数据量、列数;减少返回的数据量;简化sql语法;减少sql语句中的函数;来实现更少的内存使用,更少的磁盘I/O读写,更快的得到较好的执行计划,以达到提高查询效率的目的。

最后,要学会一种思路:如果我是一个数据库,我会怎么执行一个sql,我喜欢怎么样的sql?

什么样的SQL语句是不好的语句呢:那就是妨碍优化器更好的实现执行逻辑的SQL语句,这类语句包括:

1.where条件里出现各种花样百出的代码,比如函数、运算等。

2.语句过大,大量的表join会导致中间结果集不准确,从而限制优化器选择较好的执行计划。等等.........

3.能写出多好的sql取决于你多了解数据库。

参看链接:链接:https://www.zhihu.com/question/29619558/answer/45805380

作者:宋沄剑

链接:https://www.zhihu.com/question/29619558/answer/45270490

 

sql语句优化原理的更多相关文章

  1. mysql--------大数据量分页sql语句优化

    分页程序原理很简单,这里就不多说了,本篇文章主要说的是在数据表记录量比较大的情况下,如何将分页SQL做到更优化,让MySQL执行的更快的方法. 一般的情况下,我们的分页SQL语句是这样的: ,; 以上 ...

  2. SQL系列 - SQL语句优化个人总结

    关于SQL语句优化方法 有些是通用的(如避免Select *): 有些不同的数据库管理系统有所区别(如Where子句顺序): 然后必须根据实际环境进行调优,因为即使是相同的数据库和表,在数据量或其他环 ...

  3. Oracle SQL语句优化34条

    非常好用的SQL语句优化34条 1)选择最有效率的表名顺序(只在基于规则的优化器中有效): ORACLE 的解析器按照从右到左的顺序处理FROM子句中的表名,FROM子句中写在最后的表(基础表 dri ...

  4. php面试专题---MySQL常用SQL语句优化

    php面试专题---MySQL常用SQL语句优化 一.总结 一句话总结: 原理,万变不离其宗:其实SQL语句优化的过程中,无非就是对mysql的执行计划理解,以及B+树索引的理解,其实只要我们理解执行 ...

  5. 优化数据库的方法及SQL语句优化的原则

    优化数据库的方法: 1.关键字段建立索引. 2.使用存储过程,它使SQL变得更加灵活和高效. 3.备份数据库和清除垃圾数据. 4.SQL语句语法的优化.(可以用Sybase的SQL Expert,可惜 ...

  6. oracle之sql语句优化

    oracle之sql语句优化 sql语句的优化 1.在where子句中使用 is null 或 is not null 时,oracle优化器就不能使用索引了. 2.对于有连接的列,即使最有一个是静态 ...

  7. 数据库 基于索引的SQL语句优化之降龙十八掌(转)

    一篇挺不错的关于SQL语句优化的文章,因不知原始出处,故未作引用说明! 1 前言      客服业务受到SQL语句的影响非常大,在规模比较大的局点,往往因为一个小的SQL语句不够优化,导致数据库性能急 ...

  8. 数据库的优化(表优化和sql语句优化)

    在这里主要是分为表设计优化和sql语句优化两方面来实现. 首先的是表设计优化: 1.数据行的长度不要超过8020字节.如果是超过这个长度的话这条数据会占用两行,减低查询的效率. 2.能用数字类型就不要 ...

  9. MySQL常用SQL语句优化

    推荐阅读这篇博文,索引说的非常详细到位:http://blog.linezing.com/?p=798#nav-3-2 在数据库日常维护中,最常做的事情就是SQL语句优化,因为这个才是影响性能的最主要 ...

随机推荐

  1. UiPath 中 List 集合的实例化与使用

    >>>跳过BB,空降正文<<< 目录 前言 正文 1. 创建 List 变量 2. 实例化 List 变量 3. 集合的使用 后记 前言 大家好呀,我是 白墨,一个 ...

  2. LeetCode:322. 零钱兑换

    链接:https://leetcode-cn.com/problems/coin-change/ 标签:动态规划.完全背包问题.广度优先搜索 题目 给定不同面额的硬币 coins 和一个总金额 amo ...

  3. java并发编程JUC第十一篇:如何在线程之间进行对等数据交换

    java.util.concurrent.Exchanger可以用来进行数据交换,或者被称为"数据交换器".两个线程可以使用Exchanger交换数据,下图用来说明Exchange ...

  4. NoSQL:如何使用NoSQL架构构建实时广告系统

    JDNoSQL平台是什么 JDNoSQL平台是一个分布式面向列的KeyValue毫秒级存储服务,存储结构化数据和非机构化数据,支持随机读写与更新,灵活的动态列机制,架构上支持水平扩容,提供高并发.低延 ...

  5. JVM学习第一篇思考:一个Java代码是怎么运行起来的-上篇

    JVM学习第一篇思考:一个Java代码是怎么运行起来的-上篇 作为一个使用Java语言开发的程序员,我们都知道,要想运行Java程序至少需要安装JRE(安装JDK也没问题).我们也知道我们Java程序 ...

  6. MIT6.828 Lab2 内存管理

    Lab2 0. 任务介绍 你将编写一个内存管理代码.主要分为两大部分.分别对物理内存和虚拟内存的管理. 对于物理内存,每次分配内存分配器会为你分配4096bytes.也称为一个页(在大部分操作系统中一 ...

  7. css--flex弹性布局详解和使用

    前言 前端开发最基础的能力是根据 ui 设计稿迅速还原页面,拿到设计稿不要急于写代码,首先要对页面进行分析,对页面的整体布局有个大概的了解,然后先实现一个整体的布局,再把布局拆分成逐个小模块,逐个去实 ...

  8. HTTP Cookies知识-查看、发送、获取、返回

    我最新最全的文章都在南瓜慢说 www.pkslow.com,欢迎大家来喝茶! 1 简介 HTTP Cookies是服务器发送到用户浏览器并保存在本地的一小块数据,它会在浏览器下次向同一服务器再发起请求 ...

  9. go语言结构体内存对齐

    cpu要想从内存读取数据,需要通过地址总线,把地址传输给内存,内存准备好数据,输出到数据总线,交给cpu,如果地址总线只有8根,那这个地址就只有8位可以表示[0,255]256个地址,因为表示不了更多 ...

  10. 97、配置yum源仓库服务器

    (服务端(双(外,内)网卡)--客户端(内网)) YUM主要用于自动安装.升级rpm软件包,它能自动查找并解决rpm包之间的依赖关系.要成功的使用YUM工具安装更新软件或系统, 就需要有一个包含各种r ...