今天项目遇到一个问题:就是在公司test环境中执行sql查询语句很快,也就几百毫秒,但是放到sit环境中测试就要延迟至少1分钟左右。

网上找了很多原因,大多数都是说索引问题,我看了索引没问题,又重新建立索引散列值保证其有效,但是还是不行;

原因:test环境中数据量很少,也就100多条,索引的散列有效值也是100多,但是sit环境中有近4000条数据,自己本身的sql语句中又有子查询+join外连接。我在想是不是sql语句写的有些复杂导致执行变慢。

解决:sql语句优化,尽量不用子查询,我将子查询换成了join外连接查询,完美解决,但是网上的资料对我也有一定帮助,对mysql有进一步的了解。

优化方案1


最近客户提出某些业务查询数据的速度特别慢,而且这种情况来的比较突然。

情况:
1.系统最近没有更新
2.数据库结构没有更改
3.没有大量增加过数据

分析:
1.应用服务器问题:尝试把慢的业务的SQL语句取出到mysql命令行执行,速度依然很慢
2.VPN问题:把业务系统数据导出,再导入到本地数据库运行,速度很快,没有出现上述问题

陷入困境,求教于DBA,DBA也很茫然,查看进程,每次执行那些SQL语句进程占用CPU都非常高;没有错误的日志;MYSQL也运行了2个多月没重启过;硬盘也检查过OK的,也怀疑是raid有问题。

查了这么多也没有找到原因,包括mysql和应用服务器都重启过了。

最后DBA说用Analyze Table的方法看看。

语句是:
ANALYZE TABLE MYTABLE;

运行后,问题解决,速度恢复正常。

MySQL 的在优化SQL语句时,首先需要收集一些相关信息,其中就包括表的cardinality(可以翻译为“散列程度”),它表示某个索引对应的列包含多少个不同的值——如果cardinality大大少于数据的实际散列程度,那么索引就基本失效了。
我们可以使用SHOW INDEX语句来查看索引的散列程度。

TABLE         KEY_NAME       COLUMN_NAME CARDINALITY
------- -------- ----------- -----------
MYTABLE   PRIMARY          ORG_ID_FK                   10

此时可以看到,MYTABLE 数据有几百,但是CARDINALITY只有10,可见CARDINALITY大大少于数据量,因此这个索引基本起不到作用,例如当查询语句对这个字段用到join连接时,由于索引的失效,查询就会变得很慢。

在使用了ANALYZE TABLE后cardinality被增大到了500,因此查询的性能得到了提高。

优化方案2


  • 避免使用select *
  • 其他数据库中使用count(1)或count(列) 代替 count(*),而mysql数据库中count(*)经过优化后,效率与前两种基本一样.
  • 创建表时尽量时 char 代替 varchar:char表示定长最多可以放255字符,varchar表示变长最多可以存放65532个字符
  • 表的字段顺序固定长度的字段优先
  • 组合索引代替多个单列索引(经常使用多个条件查询时)
  • 使用连接(JOIN)来代替子查询(Sub-Queries)
  • 不要有超过4个以上的表连接(JOIN)
  • 优先执行那些能够大量减少结果的连接。
  • 连表时注意条件类型需一致
  • 索引散列值不适合建索引,例:性别不适合

例子:

- like '%xx'
select * from tb1 where name like '%cn';
- 使用函数
select * from tb1 where reverse(name) = 'wupeiqi';
- or
select * from tb1 where nid = 1 or email = 'seven@live.com';
特别的:当or条件中有未建立索引的列才失效,以下会走索引
select * from tb1 where nid = 1 or name = 'seven';
select * from tb1 where nid = 1 or email = 'seven@live.com' and name = 'alex'
- 类型不一致
如果列是字符串类型,传入条件是必须用引号引起来,不然...
select * from tb1 where name = 999;
- !=
select * from tb1 where name != 'alex'
特别的:如果是主键,则还是会走索引
select * from tb1 where nid != 123
- >
select * from tb1 where name > 'alex'
特别的:如果是主键或索引是整数类型,则还是会走索引
select * from tb1 where nid > 123
select * from tb1 where num > 123
- order by
select email from tb1 order by name desc;
当根据索引排序时候,选择的映射如果不是索引,则不走索引
特别的:如果对主键排序,则还是走索引:
select * from tb1 order by nid desc; - 组合索引最左前缀
如果组合索引为:(name,email)
name and email -- 使用索引
name -- 使用索引
email -- 不使用索引

优化方案3


查询计划

1,语法格式

explain + 查询SQL - 用于显示SQL执行信息参数,根据参考信息可以进行SQL优化

2,执行计划让mysql预估执行操作一般正确

mysql> explain select * from tb2;
+----+-------------+-------+------+---------------+------+---------+------+------+-------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+---------------+------+---------+------+------+-------+
| 1 | SIMPLE | tb2 | ALL | NULL | NULL | NULL | NULL | 2 | NULL |
+----+-------------+-------+------+---------------+------+---------+------+------+-------+
1 row in set (0.00 sec)  
type : 查询计划的连接类型, 有多个参数,先从最佳类型到最差类型介绍

性能: null > system/const > eq_ref > ref > ref_or_null > index_merge >  range > index >  all

慢:
explain select * from userinfo where email='alex';
type: ALL(全表扫描)
特别的: select * from userinfo limit 1;
快:
explain select * from userinfo where name='alex';
type: ref(走索引) ③EXPLAIN 参数详解:http://www.cnblogs.com/wangfengming/articles/8275448.html
id
查询顺序标识
如:mysql> explain select * from (select nid,name from tb1 where nid < 10) as B;
+----+-------------+------------+-------+---------------+---------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+------------+-------+---------------+---------+---------+------+------+-------------+
| 1 | PRIMARY | <derived2> | ALL | NULL | NULL | NULL | NULL | 9 | NULL |
| 2 | DERIVED | tb1 | range | PRIMARY | PRIMARY | 8 | NULL | 9 | Using where |
+----+-------------+------------+-------+---------------+---------+---------+------+------+-------------+
特别的:如果使用union连接气值可能为null select_type
查询类型
SIMPLE 简单查询
PRIMARY 最外层查询
SUBQUERY 映射为子查询
DERIVED 子查询
UNION 联合
UNION RESULT 使用联合的结果
...
table
正在访问的表名 type
查询时的访问方式,性能:all < index < range < index_merge < ref_or_null < ref < eq_ref < system/const
ALL 全表扫描,对于数据表从头到尾找一遍
select * from tb1;
特别的:如果有limit限制,则找到之后就不在继续向下扫描
select * from tb1 where email = 'seven@live.com'
select * from tb1 where email = 'seven@live.com' limit 1;
虽然上述两个语句都会进行全表扫描,第二句使用了limit,则找到一个后就不再继续扫描。 INDEX 全索引扫描,对索引从头到尾找一遍
select nid from tb1; RANGE 对索引列进行范围查找
select * from tb1 where name < 'alex';
PS:
between and
in
> >= < <= 操作
注意:!= 和 > 符号 INDEX_MERGE 合并索引,使用多个单列索引搜索
select * from tb1 where name = 'alex' or nid in (11,22,33); REF 根据索引查找一个或多个值
select * from tb1 where name = 'seven'; EQ_REF 连接时使用primary key 或 unique类型
select tb2.nid,tb1.name from tb2 left join tb1 on tb2.nid = tb1.nid; CONST 常量
表最多有一个匹配行,因为仅有一行,在这行的列值可被优化器剩余部分认为是常数,const表很快,因为它们只读取一次。
select nid from tb1 where nid = 2 ; SYSTEM 系统
表仅有一行(=系统表)。这是const联接类型的一个特例。
select * from (select nid from tb1 where nid = 1) as A;
possible_keys
可能使用的索引 key
真实使用的 key_len
MySQL中使用索引字节长度 rows
mysql估计为了找到所需的行而要读取的行数 ------ 只是预估值 extra
该列包含MySQL解决查询的详细信息
“Using index”
此值表示mysql将使用覆盖索引,以避免访问表。不要把覆盖索引和index访问类型弄混了。
“Using where”
这意味着mysql服务器将在存储引擎检索行后再进行过滤,许多where条件里涉及索引中的列,当(并且如果)它读取索引时,就能被存储引擎检验,因此不是所有带where子句的查询都会显示“Using where”。有时“Using where”的出现就是一个暗示:查询可受益于不同的索引。
“Using temporary”
这意味着mysql在对查询结果排序时会使用一个临时表。
“Using filesort”
这意味着mysql会对结果使用一个外部索引排序,而不是按索引次序从表里读取行。mysql有两种文件排序算法,这两种排序方式都可以在内存或者磁盘上完成,explain不会告诉你mysql将使用哪一种文件排序,也不会告诉你排序会在内存里还是磁盘上完成。
“Range checked for each record(index map: N)”
这个意味着没有好用的索引,新的索引将在联接的每一行上重新估算,N是显示在possible_keys列中索引的位图,并且是冗余的。

优化方案4


大数据量分页优化

1,简单粗暴,不允许查询靠后的数据【优先选择】

2,在查询下一页时把上一页的行id作为参数传递给客户端程序,即

select * from tb1 where id>3000000 limit 10; 

还有一种方式,比如100页的10条数据

select * from tb1 where id>100*10 limit 10;

3,延迟关联

我们在来分析一下这条语句为什么慢,玄机就处在这个 * 里面,这个表除了id主键肯定还有其他字段, 因为select * 所以mysql在沿着id主键走的时候要回行拿数据,走一下拿一下数据,如果把语句改成

select id from tb1 limit 3000000,10;

你会发现时间缩短了一半;然后我们再拿id分别去取10条数据就行了;

select table.* from tb1 inner join ( select id from tb1 limit 3000000,10 ) as tmp on tmp.id=table.id;

慢查询日志


1、概念

将mysql服务器中影响数据库性能的相关SQL语句记录到日志文件,通过对这些特殊的SQL语句分析,改进以达到提高数据库性能的目的。

2、慢查询日志参数

long_query_time     :  设定慢查询的阀值,超出设定值的SQL即被记录到慢查询日志,缺省值为10s
slow_query_log : 指定是否开启慢查询日志
log_slow_queries : 指定是否开启慢查询日志(该参数已经被slow_query_log取代,做兼容性保留)
slow_query_log_file : 指定慢日志文件存放位置,可以为空,系统会给一个缺省的文件host_name-slow.log
log_queries_not_using_indexes: 如果值设置为ON,则会记录所有没有利用索引的查询.

3、查看MySQL慢日志信息

#.查询慢日志配置信息 :
show variables like '%query%';
#.修改配置信息
set global slow_query_log = on;

4、查看不使用索引参数状态

# 显示参数  
show variables like '%log_queries_not_using_indexes';
# 开启状态
set global log_queries_not_using_indexes  = on;

5、查看慢日志显示的方式

#查看慢日志记录的方式
show variables like '%log_output%'; #设置慢日志在文件和表中同时记录
set global log_output='FILE,TABLE';

6、测试慢查询日志

#查询时间超过10秒就会记录到慢查询日志中
select sleep(3) FROM user ; #查看表中的日志
select * from mysql.slow_log;

char与varchar的区别:https://www.cnblogs.com/webph/p/6679815.html

参考文章:https://www.cnblogs.com/hanbowen/p/9569149.html

数据库mysql之慢查询优化的更多相关文章

  1. MySql学习(六) —— 数据库优化理论(二) —— 查询优化技术

    逻辑查询优化包括的技术 1)子查询优化  2)视图重写  3)等价谓词重写  4)条件简化  5)外连接消除  6)嵌套连接消除  7)连接消除  8)语义优化 9)非SPJ优化 一.子查询优化 1. ...

  2. 数据库MySQL 之 索引原理与慢查询优化

    数据库MySQL 之 索引原理与慢查询优化 浏览目录 索引介绍方法类型 聚合索引辅助索引 测试索引 正确使用索引 组合索引 注意事项 查询计划 慢查询日志 大数据量分页优化 一.索引介绍方法类型 1. ...

  3. mysql系列八、mysql数据库优化、慢查询优化、执行计划分析

    mysql的性能优化无法一蹴而就,必须一步一步慢慢来,从各个方面进行优化,最终性能就会有大的提升. 一.介绍 对mysql优化是一个综合性的技术,主要包括 表的设计合理化(符合3NF) 添加适当索引( ...

  4. MySQL的limit查询优化

    MySQL的limit查询优化以下的文章主要是对MySQL limit查询优化的具体内容的介绍,我们大家都知道MySQL数据库的优化是相当重要的.其他最为常用也是最为需要优化的就是limit.MySQ ...

  5. 数据库MySQL学习笔记高级篇

    数据库MySQL学习笔记高级篇 写在前面 学习链接:数据库 MySQL 视频教程全集 1. mysql的架构介绍 mysql简介 概述 高级Mysql 完整的mysql优化需要很深的功底,大公司甚至有 ...

  6. MySQL实验 子查询优化双参数limit

    MySQL实验 子查询优化双参数limit 没想到双参数limit还有优化的余地,为了亲眼见到,今天来亲自实验一下.   实验准备 使用MySQL官方的大数据库employees进行实验,导入该示例库 ...

  7. MySQL 5.6查询优化器新特性的“BUG” eq_range_index_dive_limit

    本文转自 http://www.imysql.cn 最近碰到一个慢SQL问题,解决过程有点小曲折,和大家分享下. SQL本身不复杂,表结构.索引也比较简单,不过个别字段存在于多个索引中. CREATE ...

  8. MYSQL添加新用户 MYSQL为用户创建数据库 MYSQL为新用户分配权限

    1.新建用户 //登录MYSQL @>mysql -u root -p @>密码 //创建用户 mysql> insert into mysql.user(Host,User,Pas ...

  9. Robot Framework-DatabaseLibrary数据库(MySql)

    Robot Framework-Mac版本安装 Robot Framework-Windows版本安装 Robot Framework-工具简介及入门使用 Robot Framework-Databa ...

随机推荐

  1. c++11 function_typetraits备忘

    function traits. 获取函数或成员函数的返回类型,参数类型,参数长度,类类型. 函数参数列表推断基于typelist:http://www.cnblogs.com/flytrace/p/ ...

  2. JDK / JRE zip

    Server JRE与JRE的区别: Server JRE一般用于服务器上安装,只有64bit版本,不会安装浏览器插件.自动更新,有监视工具.没有Java Fx和其他开发工具:有安装程序,只是一压缩目 ...

  3. Can't parse message of type "gazebo.msgs.Packet" because it is missing required fields: stamp, type

    在gazebo的仿真环境中,采用强化学习HER算法训练baxter执行reach.slide和pick and place任务. 运行HER算法,此时尚未启动gazebo仿真环境,出现如下报错: [l ...

  4. NodeJS入门教学

    http://v.baidu.com/v?word=Node.JS+%2B+MongoDB&ct=301989888&rn=27&pn=0&db=0&s=0&a ...

  5. 使用gitbook plugin

    使用gitbook plugin. { "title": "xx doc", "author": "morya", &q ...

  6. tkinter 写一个简易的ide

    简易IDE 基于tkinter的简易ide,参考文档和Baidu的资料制作的,过程中遇到了很多问题,也学到了很多知识. 功能: 1.菜单栏 2.编辑功能 open save... 3.快捷键  ctr ...

  7. bitbucket 上公钥SSH key如何add key并进行项目运用

    前提:从sourcetree 添加项目时老是拉取不下来,查到原因是应为bitbucket需要SSH key公钥 目的:公钥相当于你在任何一台电脑只要有公钥授权就可以随时提交代码到服务器 原因: 1.很 ...

  8. JVM-字节码

  9. Java虚拟机-JVM各种参数配置大全详细

      usr/local/jdk/bin/java -Dresin.home=/usr/local/resin -server -Xms1800M -Xmx1800M -Xmn300M -Xss512K ...

  10. 3.1链表----链表(Linked List)入门

    在分析链表之前,我们先来对之前的动态数组.栈.队列总结一下: (1)底层依托于静态数组 (2)依靠resize解决固定容量问题 (3)是一种假的的动态数据结构 1.什么是链表 可以从以下两个部分来理解 ...