SQL优化的一般步骤

通过show status命令了解各种SQL的执行频率
定位执行效率较低的SQL语句,重点select
通过explain分析低效率的SQL
确定问题并采取相应的优化措施

优化措施

show 参数

MySQL客户端连接成功后,通过使用show [session|global] status 命令可以提供服务器状态信息。其中的session来表示当前的连接的统计结果,global来表示自数据库上次启动至今的统计结果。默认是session级别的。

show status like 'Com_%';
show global status like 'Com_%';

下面的例子:
其中Com_XXX表示XXX语句所执行的次数。
-- 查询本次会话

show status like 'Com_XXX'; -- 等效于 show session status like 'Com_XXX'; -- 举例 show session status like 'Com_select';

-- 查询全局

show global status like 'Com_XXX'; -- 举例 show global status like 'Com_select';

重点注意:Com_select,Com_insert,Com_update,Com_delete通过这几个参数,可以容易地了解到当前数据库的应用是以插入更新为主还是以查询操作为主,以及各类的SQL大致的执行比例是多少。
还有几个常用的参数便于用户了解数据库的基本情况。
Connections:试图连接MySQL服务器的次数
Uptime:服务器工作的时间(单位秒)
Slow_queries:慢查询的次数 (默认是慢查询时间10s)

show status like 'Connections';
show status like 'Uptime';
show status like 'Slow_queries';

定位慢查询

可通过开启慢查询日志来找出较慢的SQL

如何查询MySQL的慢查询时间

show variables like 'long_query_time'; -- 未修改的情况下是10

修改MySQL慢查询时间

set long_query_time=1;

默认情况下,MySQL认为10秒才是一个慢查询,这里为了测试,将1秒设置为一个慢查询
set long_query_time=1
这时我们如果出现一条语句执行时间超过1秒时,就会统计到到我们的一个日志中
my.ini的所在目录为:C:\ProgramData\MySQL\MySQL Server 版本号\my.ini
该慢查询日志会放在Data目录下,可需要查看 my.ini 的 datadir=""确定
具体文件名可查看 my.ini 的slow_query_log_file对应的值,低版本的mysql需要通过在开启mysql时使用--log-slow-queries=file_name来配置
在默认情况下,低版本的MySQL不会记录慢查询,需要在启动MySQL时候,指定记录慢查询才可以

bin\mysqld.exe --log-slow-queries=D:/mysql.log

[低版本mysql5.0可以在my.ini指定]
针对 mysql5.5启动慢查询有两种方法

bin\mysqld.exe --safe-mode --slow-query-log

[mysql5.5 可以在my.ini指定]
也可以在my.ini 文件中配置:

[mysqld]
# The TCP/IP Port the MySQL Server will listen on
port=3306
slow-query-log

而在mysql5.6及以上中,默认是启动记录慢查询的,,其中有一个配置项
slow-query-log=1

这时我们如果出现一条语句执行时间超过1秒中,就会统计到日志中

-- 查询哪个部门员工最多,我这边最多的是产品部,所以我用产品部数据进行测试
select d.name, e.count_no_inner count_no_outer from (select dept_no, count(no) count_no_inner from emp group by dept_no) e left join dept d on e.dept_no = d.no order by count_no_outer desc;
UPDATE emp SET dept_no = 1 WHERE no = 100002; -- 25.906sec
SELECT * FROM emp e WHERE dept_no in (SELECT no FROM dept WHERE name='产品部'); -- 秒查
-- 如果最带上ORDER BY e.no,速度就会更慢
-- 本地测试,6.094sec左右
SELECT * FROM emp e WHERE dept_no in (SELECT no FROM dept WHERE name='产品部') ORDER BY e.no;
-- 优化,1.547sec
SELECT * FROM emp e WHERE dept_no = (SELECT no FROM dept WHERE name='产品部') ORDER BY e.no;

explain分析SQL

-- 造数据
update emp set name = 'Jefabc' where no = '';

参考 EXPLAIN详解

语句优化

在查询中不要使用select * 获取列数据【返回更少的数据】
讲解:
1、检索不必要的列会带来额外的系统开销,该省则省,特别是LOB类型的列

优点:

1、减少数据在网络上传输开销

2、减少服务器数据处理开销

3、减少客户端内存占用

4、字段变更时提前发现问题,减少程序BUG

5、如果访问的所有字段刚好在一个索引里面,则可以使用纯索引访问提高性能。

缺点:增加编码工作量

由于会增加一些编码工作量,所以一般需求通过开发规范来要求程序员这么做,否则等项目上线后再整改工作量更大。

如果你的查询表中有大字段或内容较多的字段,如备注信息、文件内容等等,那在查询表时一定要注意这方面的问题,否则可能会带来严重的性能问题。如果表经常要查询并且请求大内容字段的概率很低,我们可以采用分表处理,将一个大表分拆成两个一对一的关系表,将不常用的大内容字段放在一张单独的表中。如一张存储上传文件的表:

T_FILE(ID,FILE_NAME,FILE_SIZE,FILE_TYPE,FILE_CONTENT)

我们可以分拆成两张一对一的关系表:

T_FILE(ID,FILE_NAME,FILE_SIZE,FILE_TYPE)

T_FILECONTENT(ID, FILE_CONTENT)

通过这种分拆,可以大大提少T_FILE表的单条记录及总大小,这样在查询T_FILE时性能会更好,当需要查询FILE_CONTENT字段内容时再访问T_FILECONTENT表。
在select字段中避免不必要的列,连接条件中避免不必要的表【返回更少的数据】
1、如一中的讲解
2、连接条件中包含不必要的表会强制数据库引擎检索和匹配不需要的数据,增加了查询执行时间
不要在子查询中使用count()求和执行存在性检查
1、不要使用

select column_list from table where 0 < (select count(*) from table2 where ...)

2、使用下面的语句代替

sleect column_list from table where exists (select column_list from table2 where ...)

讲解:
使用count()时,数据库不知道你是在做存在性检查,它会计算所有匹配的值,要么会执行全表扫描,要么会扫描最小的非聚集索引;
而使用exists时,数据库就知道你此时是在做存在性检查了,当它发现第一个匹配的值时,就会返回true,并停止查询。类似的,可以使用in或者any代替count()。
使用全文搜索搜索文本数据,取代like搜索
全文搜索始终优于like搜索:
1、全文搜索让你可以实现like不能完成的复杂搜索,如搜索一个单词或一个短语,搜索一个与另一个单词或短语相近的单词或短语,或者是搜索同义词;
2、实现全文搜索比实现like搜索更容易(特别是复杂的搜索);
使用union实现or操作
1、在查询中尽量不要使用or,使用union合并两个不同的查询结果集,这样查询性能会更好;
2、如果不是必须要不同的结果集,使用union all效果会更好,因为它不会对结果集排序。
为大对象使用延迟加载策略
1、在不同的表中存储大对象(如VARCHAR(MAX),Image,Text等),然后在主表中存储这些大对象的引用;
2、在查询中检索所有主表数据,如果需要载入大对象,按需从大对象表中检索大对象。
使用 join 优化子查询

参考JOIN从句

-- 复杂语句
select a.name, (select b.name from test_b b where a.name = b.name) b_name from test_a a;
-- join 优化
select a.name, b.name b_name from test_a a left join test_b b on a.name = b.name; 
other:
因为使用join,MySQL不需要在内存中创建临时表
优化group by 语句
默认情况,MySQL对所有的group by col1,col2进行排序。这与在查询中指定order by col1, col2类似。如果查询中包括group by但用户想要避免排序结果的消耗,则可以使用order by null禁止排序

  • 有索引的字段尽量走有索引的字段
  • 如果想要在含有or的查询语句中利用索引,则or之间的每个条件列都必须用到索引,如果没有索引,则应该考虑增加索引
  • 关联查询多用where条件刷选
  • 少用in,not in,多用exists,not exists,=
  • 少用<>,用> <
  • 能在代码里完成的业务逻辑就尽量不要放在SQL里
  • 尽量让SQL中少出现case、when、then,这样会让逻辑更清楚,让SQL可读性更强
  • 文件、图片等大文件用文件系统存储,不用数据库
  • 不用多说,铁律!!!数据库只存储路径。
  • 集中批量查询【减少数据库交互次数】
  • 不做列运算:SELECT id WHERE age + 1 = 10,任何对列的操作都将导致表扫描,它包括数据库教程函数、计算表达式等等,查询时要尽可能将操作移至等号右边
  • sql语句尽可能简单:一条sql只能在一个cpu运算;大语句拆小语句,减少锁时间;一条大sql可以堵死整个库
  • OR改写成IN:OR的效率是n级别,IN的效率是log(n)级别,in的个数建议控制在200以内
  • 不用函数和触发器,在应用程序实现
  • 避免%xxx式查询
  • 少用JOIN
  • 使用同类型进行比较,比如用'123'和'123'比,123和123比
  • 尽量避免在WHERE子句中使用 != 或 <> 操作符,否则将引擎放弃使用索引而进行全表扫描
  • 对于连续数值,使用BETWEEN不用IN:SELECT id FROM t WHERE num BETWEEN 1 AND 5
  • 列表数据不要拿全表,要使用LIMIT来分页,每页数量也不要太大

tips:新增、删除、修改操作可参考查询操作

查询SQL优化的更多相关文章

  1. 树形查询SQL优化一例

    上周五一哥们发了条SQL,让我看看,代码如下: SELECT COUNT(1) FROM (select m.sheet_id from cpm_main_sheet_history m, cpm_s ...

  2. 1 min 数据查询 SQL 优化

    问题 前几天线上数据库 IOPS 飙升,一直居高不下,最近并没有升级.遂查看数据库正在执行的 SQL 语句,发现有个查询离线设备的语句极其缓慢. 探寻原因 SELECT o.* FROM ( SELE ...

  3. oracle查询SQL优化相当重要

    如果表中的时间字段是索引,那么时间字段不要使用函数,函数会使索引失效. 例如: select * from mytable where trunc(createtime)=trunc(sysdate) ...

  4. Mysql 分页查询sql优化

    先查下数据表的总条数: SELECT COUNT(id) FROM ts_translation_send_address 执行分页界SQL 查看使用时间2.210s SELECT * FROM ts ...

  5. mysql联合查询sql优化

    我们在使用mysql数据库时,经常会使用到mysql的联合查询,联合查询分为内连接和外连接,内连接查询结果是联合的表都存在匹配才会有结果,外连接则根据驱动表是否存在匹配来生成结果集. 这里使用mysq ...

  6. 数据库的规范和SQL优化技巧总结

    现总结工作与学习中关于数据库的规范设计与优化技巧 1.规范背景与目的 MySQL数据库与 Oracle. SQL Server 等数据库相比,有其内核上的优势与劣势.我们在使用MySQL数据库的时候需 ...

  7. 【MySQL】SQL优化系列之 in与range 查询

    首先我们来说下in()这种方式的查询 在<高性能MySQL>里面提及用in这种方式可以有效的替代一定的range查询,提升查询效率,因为在一条索引里面,range字段后面的部分是不生效的. ...

  8. SQL 查询性能优化----解决书签查找

    先来看看什么是书签查找: 当优化器所选择的非聚簇索引只包含查询请求的一部分字段时,就需要一个查找(lookup)来检索其他字段来满足请求.对一个有聚簇索引的表来说是一个键查找(key lookup), ...

  9. 提高SQL查询效率(SQL优化)

    要提高SQL查询效率where语句条件的先后次序应如何写 http://blog.csdn.net/sforiz/article/details/5345359   我们要做到不但会写SQL,还要做到 ...

随机推荐

  1. unity抗锯齿(Antialiasing)

    目前知道的有两种方式,下面依次介绍 一.系统菜单设置法. 这样只能简单去锯齿,要想效果特别明显,看下面的脚本吧. 二.为摄像机挂上一个去锯齿的系统脚本 导入后Assets资源下多了一个包 找到这个脚本 ...

  2. P1075 质因数分解

    P1075 质因数分解 题目描述 已知正整数 n 是两个不同的质数的乘积,试求出两者中较大的那个质数. 输入输出格式 输入格式: 一个正整数 n . 输出格式: 一个正整数 p ,即较大的那个质数. ...

  3. Java基础-线程操作共享数据的安全问题

    Java基础-线程操作共享数据的安全问题 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.引发线程安全问题 如果有多个线程在同时运行,而这些线程可能会同时运行这段代码.程序每次运 ...

  4. 科学计算三维可视化---TVTK管线与数据加载(可视化管线和图像管线了解)

    一:TVTK的管线 使用管线技术将TVTK中各个对象穿连起来,几乎所有渲染引擎都会提到管线技术 在TVTK中,每个对象只需要实现相对简单的任务,整个管线则能根据用户的需求,实现复杂的数据可视化处理. ...

  5. bzoj千题计划132:bzoj1189: [HNOI2007]紧急疏散evacuate

    http://www.lydsy.com/JudgeOnline/problem.php?id=1189 二分答案 源点向人连边,流量为1 门拆为mid个点,同一个门的第j个点向第j+1个点连边,流量 ...

  6. 俞昆20155335《网络对抗》MSF基础应用

  7. 【leetcode 简单】 第九十九题 字符串相加

    给定两个字符串形式的非负整数 num1 和num2 ,计算它们的和. 注意: num1 和num2 的长度都小于 5100. num1 和num2 都只包含数字 0-9. num1 和num2 都不包 ...

  8. php Only variables should be passed by reference 报错问题

    这个错误是变量引用引起的非致命错误,可修改php.ini文件的error_reporting = E_ALL & E_NOTICE 使其屏蔽此错误

  9. 【数据库】软件安全测试之SQL注入

    这些年我们发现越来越多的公司开始注重安全测试了,为什么?因为安全测试可以在某种程度上可以排查掉你项目的一些安全漏洞,这样你的系统上线后才会相对安全,才有可能尽量避免来自外部的攻击.每一年互联网都会发生 ...

  10. 【译】第六篇 SQL Server代理深入作业步骤工作流

    本篇文章是SQL Server代理系列的第六篇,详细内容请参考原文. 正如这一系列的前几篇所述,SQL Server代理作业是由一系列的作业步骤组成,每个步骤由一个独立的类型去执行.每个作业步骤在技术 ...