查询SQL优化
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优化的更多相关文章
- 树形查询SQL优化一例
上周五一哥们发了条SQL,让我看看,代码如下: SELECT COUNT(1) FROM (select m.sheet_id from cpm_main_sheet_history m, cpm_s ...
- 1 min 数据查询 SQL 优化
问题 前几天线上数据库 IOPS 飙升,一直居高不下,最近并没有升级.遂查看数据库正在执行的 SQL 语句,发现有个查询离线设备的语句极其缓慢. 探寻原因 SELECT o.* FROM ( SELE ...
- oracle查询SQL优化相当重要
如果表中的时间字段是索引,那么时间字段不要使用函数,函数会使索引失效. 例如: select * from mytable where trunc(createtime)=trunc(sysdate) ...
- Mysql 分页查询sql优化
先查下数据表的总条数: SELECT COUNT(id) FROM ts_translation_send_address 执行分页界SQL 查看使用时间2.210s SELECT * FROM ts ...
- mysql联合查询sql优化
我们在使用mysql数据库时,经常会使用到mysql的联合查询,联合查询分为内连接和外连接,内连接查询结果是联合的表都存在匹配才会有结果,外连接则根据驱动表是否存在匹配来生成结果集. 这里使用mysq ...
- 数据库的规范和SQL优化技巧总结
现总结工作与学习中关于数据库的规范设计与优化技巧 1.规范背景与目的 MySQL数据库与 Oracle. SQL Server 等数据库相比,有其内核上的优势与劣势.我们在使用MySQL数据库的时候需 ...
- 【MySQL】SQL优化系列之 in与range 查询
首先我们来说下in()这种方式的查询 在<高性能MySQL>里面提及用in这种方式可以有效的替代一定的range查询,提升查询效率,因为在一条索引里面,range字段后面的部分是不生效的. ...
- SQL 查询性能优化----解决书签查找
先来看看什么是书签查找: 当优化器所选择的非聚簇索引只包含查询请求的一部分字段时,就需要一个查找(lookup)来检索其他字段来满足请求.对一个有聚簇索引的表来说是一个键查找(key lookup), ...
- 提高SQL查询效率(SQL优化)
要提高SQL查询效率where语句条件的先后次序应如何写 http://blog.csdn.net/sforiz/article/details/5345359 我们要做到不但会写SQL,还要做到 ...
随机推荐
- P1558 色板游戏
P1558 色板游戏 题目背景 阿宝上学了,今天老师拿来了一块很长的涂色板. 题目描述 色板长度为L,L是一个正整数,所以我们可以均匀地将它划分成L块1厘米长的小方格.并从左到右标记为1, 2, .. ...
- 安装MySQL5.7由于 Redistributable导致失败
今天上午安装MySQL5.7时一直提示 1: Action 10:59:21: INSTALL. 1: 1: MySQL Server 5.7 2: {F08E9C75-A42E-4962-8760- ...
- 笔记 oracle 创建主键自增长
笔记 (1) 创建表 create table test( id number(18,2) primary key, -- 主键(unique+not null) name varchar2(100) ...
- mongodb 跟踪SQL语句及慢查询收集
有个需求:跟踪mongodb的SQL语句及慢查询收集 第一步:通过mongodb自带函数可以查看在一段时间内DML语句的运行次数. 在bin目录下面运行 ./mongostat -port 端口号 ...
- 最小割 D. Behind the Wall Samara University ACM ICPC 2016-2017 Quarterfinal Qualification Contest
题目链接:http://codeforces.com/gym/101149/problem/D 题目大意: 堡垒受到攻击.堡垒是n*m的矩阵,矩阵里刚开始都是平地,然后那个数值表示在当前平地上建一面墙 ...
- SQL语句(十五)视图
视图 实际上是一个查询语句, 如果将子查询保存为视图, 就可以将子查询的结果当作数据表使用 从而来简化查询语句 引言 例1 查询参加"数据库技术"课程的考试的学生学号.姓名.班级. ...
- 兼容firefox,ie,谷歌,阻止浏览器冒泡事件,Firefox不支持event解决方法
兼容firefox,ie,谷歌,阻止浏览器冒泡事件,Firefox不支持event解决方法 // 获取事件function getEvent(){ if(window.event) {return w ...
- java反射三种获得类类型的方法
public class Test { public static void main(String[] args) { Test t=new Test();//所有的类都是Class类的实例(类类型 ...
- 44、File类简介
使用File类创建文件夹 File类在java.io包下,看名字应该可以猜到,这个类是跟文件夹操作有关,下面使用File类中的方法在硬盘中创建文件夹. package com.sutaoyu.file ...
- Ubuntu 增加全新硬盘 分区及开机自动挂载
安装新的硬盘后.可以安装Gparted, 或者从live cd启动,然后用Gparted工具对硬盘进行分区.然后进入系统,启动Disks, 找到对应硬盘, 选择Edit Mount Options, ...