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. Python之paramiko模块和SQL连接API

    堡垒机前戏 开发堡垒机之前,先来学习Python的paramiko模块,该模块机遇SSH用于连接远程服务器并执行相关操作 SSHClient 用于连接远程服务器并执行基本命令 基于用户名密码连接: i ...

  2. 一篇很棒的 MySQL 触发器学习教程

    一.触发器概念 触发器(trigger):监视某种情况,并触发某种操作,它是提供给程序员和数据分析员来保证数据完整性的一种方法,它是与表事件相关的特殊的存储过程,它的执行不是由程序调用,也不是手工启动 ...

  3. 蓝桥杯 方格填数 DFS 全排列 next_permutation用法

    如下的10个格子(参看[图1.jpg]) 填入0~9的数字.要求:连续的两个数字不能相邻.(左右.上下.对角都算相邻) 一共有多少种可能的填数方案? 请填写表示方案数目的整数.注意:你提交的应该是一个 ...

  4. jetty 热部署

    1,在pom.xml文件中配置jetty插件的参数:scanIntervalSeconds <plugin> <groupId>org.mortbay.jetty</gr ...

  5. CodeForces 816C 思维

    On the way to school, Karen became fixated on the puzzle game on her phone! The game is played as fo ...

  6. Django连接mysql常见错误

    1045, "Access denied for user 'root'@'localhost' (using password: YES)" 数据库的密码或用户名不对,查看set ...

  7. Linux日志文件/var/log详解

    更多内容推荐微信公众号,欢迎关注: 如果愿意在Linux环境方面花费些时间,首先就应该知道日志文件的所在位置以及它们包含的内容.在系统运行正常的情况下学习了解这些不同的日志文件有助于你在遇到紧急情况时 ...

  8. 正在载入中......loading页面的几种方法

    网页加载过程中提示“载入中…”,特别是使用动画效果,可以一个“等待”的温馨提示,用户体验很不错.下面介绍几种方法. 第一种: 原理就是,在网页载入时在页面最中间打入一个层上面显示,"网页正在 ...

  9. G - Pandaland HDU - 6005 (找最小环)

    题目链接:https://cn.vjudge.net/contest/275153#problem/G 具体思路: 我们可以按照暴力的方法进行做 , 我们可以枚举每一条边,将这条边的权值设置为inf, ...

  10. Servlet笔记4--ServletConfig接口和ServletContext接口

    ServletConfig接口: ServletContext接口: 代码详解: (1)web.xml配置文件: <?xml version="1.0" encoding=& ...