Mysql常见的慢查询优化方式总结

目录
  • 前言
  • (1)数据库中设置SQL慢查询
  • (2)分析慢查询日志
  • (3)常见的慢查询优化
  • 总结

前言

这篇文章主要是就在公司实习的时候,对SQL优化工作作出的一些整理。

在公司实习的时候,导师分配了SQL慢查询优化的任务,任务是这样的:每周从平台中导出生产数据库的慢查询文件进行分析。进行SQL优化的手段也主要是修改SQL写法,或者新增索引。

现在从记录项目中的一点点做起。

(1)数据库中设置SQL慢查询

一、第一步.开启mysql慢查询

方式一:

修改配置文件  在 my.ini 增加几行:  主要是慢查询的定义时间(超过2秒就是慢查询),以及慢查询log日志记录( slow_query_log)

方法二:通过MySQL数据库开启慢查询:

(2)分析慢查询日志

直接分析mysql慢查询日志 ,利用explain关键字可以模拟优化器执行SQL查询语句,来分析sql慢查询语句

例如:执行EXPLAIN SELECT * FROM res_user ORDER BYmodifiedtime LIMIT 0,1000

得到如下结果: 显示结果分析:

table |  type | possible_keys | key |key_len  | ref | rows | Extra  EXPLAIN列的解释:

  • table                 显示这一行的数据是关于哪张表的
  • type                  这是重要的列,显示连接使用了何种类型。从最好到最差的连接类型为const、eq_reg、ref、range、indexhe和ALL
  • rows                显示需要扫描行数
  • key                   使用的索引

(3)常见的慢查询优化

(1)索引没起作用的情况

1. 使用LIKE关键字的查询语句

在使用LIKE关键字进行查询的查询语句中,如果匹配字符串的第一个字符为“%”,索引不会起作用。只有“%”不在第一个位置索引才会起作用。

2. 使用多列索引的查询语句

MySQL可以为多个字段创建索引。一个索引最多可以包括16个字段。对于多列索引,只有查询条件使用了这些字段中的第一个字段时,索引才会被使用。

(2)优化数据库结构

合理的数据库结构不仅可以使数据库占用更小的磁盘空间,而且能够使查询速度更快。数据库结构的设计,需要考虑数据冗余、查询和更新的速度、字段的数据类型是否合理等多方面的内容。

1. 将字段很多的表分解成多个表

对于字段比较多的表,如果有些字段的使用频率很低,可以将这些字段分离出来形成新表。因为当一个表的数据量很大时,会由于使用频率低的字段的存在而变慢。

2. 增加中间表

对于需要经常联合查询的表,可以建立中间表以提高查询效率。通过建立中间表,把需要经常联合查询的数据插入到中间表中,然后将原来的联合查询改为对中间表的查询,以此来提高查询效率。

(3)分解关联查询

将一个大的查询分解为多个小查询是很有必要的。

很多高性能的应用都会对关联查询进行分解,就是可以对每一个表进行一次单表查询,然后将查询结果在应用程序中进行关联,很多场景下这样会更高效,例如:

 SELECT * FROM tag
        JOIN tag_post ON tag_id = tag.id
        JOIN post ON tag_post.post_id = post.id
        WHERE tag.tag = 'mysql';
        分解为:
        SELECT * FROM tag WHERE tag = 'mysql';
        SELECT * FROM tag_post WHERE tag_id = 1234;
        SELECT * FROM post WHERE post.id in (123,456,567);

(4)优化LIMIT分页

在系统中需要分页的操作通常会使用limit加上偏移量的方法实现,同时加上合适的order by 子句。如果有对应的索引,通常效率会不错,否则MySQL需要做大量的文件排序操作。

一个非常令人头疼问题就是当偏移量非常大的时候,例如可能是limit 10000,20这样的查询,这是mysql需要查询10020条然后只返回最后20条,前面的10000条记录都将被舍弃,这样的代价很高。

优化此类查询的一个最简单的方法是尽可能的使用索引覆盖扫描,而不是查询所有的列。然后根据需要做一次关联操作再返回所需的列。对于偏移量很大的时候这样做的效率会得到很大提升。

对于下面的查询:

select id,title from collect limit 90000,10;

该语句存在的最大问题在于limit M,N中偏移量M太大(我们暂不考虑筛选字段上要不要添加索引的影响),导致每次查询都要先从整个表中找到满足条件 的前M条记录,之后舍弃这M条记录并从第M+1条记录开始再依次找到N条满足条件的记录。如果表非常大,且筛选字段没有合适的索引,且M特别大那么这样的代价是非常高的。 试想,如我们下一次的查询能从前一次查询结束后标记的位置开始查找,找到满足条件的100条记录,并记下下一次查询应该开始的位置,以便于下一次查询能直接从该位置 开始,这样就不必每次查询都先从整个表中先找到满足条件的前M条记录,舍弃,在从M+1开始再找到100条满足条件的记录了。

方法一:虑筛选字段(title)上加索引

title字段加索引  (此效率如何未加验证)

方法二:先查询出主键id值

select id,title from collect where id>=(select id from collect order by id limit 90000,1) limit 10;

原理:先查询出90000条数据对应的主键id的值,然后直接通过该id的值直接查询该id后面的数据。

方法三:“关延迟联”

如果这个表非常大,那么这个查询可以改写成如下的方式:

Select news.id, news.description from news inner join (select id from news order by title limit 50000,5) as myNew using(id);

这里的“关延迟联”将大大提升查询的效率,它让MySQL扫描尽可能少的页面,获取需要的记录后再根据关联列回原表查询需要的所有列。这个技术也可以用在优化关联查询中的limit。

方法四:建立复合索引 acct_id和create_time

select * from acct_trans_log WHERE  acct_id = 3095  order by create_time desc limit 0,10

注意sql查询慢的原因都是:引起filesort

(5)分析具体的SQL语句  1、两个表选哪个为驱动表,表面是可以以数据量的大小作为依据,但是实际经验最好交给mysql查询优化器自己去判断。   例如:  select * from a where id in (select id from b );

对于这条sql语句它的执行计划其实并不是先查询出b表的所有id,然后再与a表的id进行比较。
mysql会把in子查询转换成exists相关子查询,所以它实际等同于这条sql语句:select * from a where exists(select * from b where b.id=a.id );

而exists相关子查询的执行原理是: 循环取出a表的每一条记录与b表进行比较,比较的条件是a.id=b.id . 看a表的每条记录的id是否在b表存在,如果存在就行返回a表的这条记录。

exists查询有什么弊端?

由exists执行原理可知,a表(外表)使用不了索引,必须全表扫描,因为是拿a表的数据到b表查。而且必须得使用a表的数据到b表中查(外表到里表中),顺序是固定死的。

如何优化?

建索引。但是由上面分析可知,要建索引只能在b表的id字段建,不能在a表的id上,mysql利用不上。

这样优化够了吗?还差一些。

由于exists查询它的执行计划只能拿着a表的数据到b表查(外表到里表中),虽然可以在b表的id字段建索引来提高查询效率。
但是并不能反过来拿着b表的数据到a表查,exists子查询的查询顺序是固定死的。

为什么要反过来?

因为首先可以肯定的是反过来的结果也是一样的。这样就又引出了一个更细致的疑问:在双方两个表的id字段上都建有索引时,到底是a表查b表的效率高,还是b表查a表的效率高?

该如何进一步优化?

把查询修改成inner join连接查询:select * from a inner join b on a.id=b.id; (但是仅此还不够,接着往下看)

为什么不用left join 和 right join?

这时候表之间的连接的顺序就被固定住了,比如左连接就是必须先查左表全表扫描,然后一条一条的到另外表去查询,右连接同理。仍然不是最好的选择。

为什么使用inner join就可以?

inner join中的两张表,如: a inner join b,但实际执行的顺序是跟写法的顺序没有半毛钱关系的,最终执行也可能会是b连接a,顺序不是固定死的。如果on条件字段有索引的情况下,同样可以使用上索引。

那我们又怎么能知道a和b什么样的执行顺序效率更高?

你不知道,我也不知道。谁知道?mysql自己知道。让mysql自己去判断(查询优化器)。具体表的连接顺序和使用索引情况,mysql查询优化器会对每种情况做出成本评估,最终选择最优的那个做为执行计划。

在inner join的连接中,mysql会自己评估使用a表查b表的效率高还是b表查a表高,如果两个表都建有索引的情况下,mysql同样会评估使用a表条件字段上的索引效率高还是b表的。

利用explain字段查看执行时运用到的key(索引)

而我们要做的就是:把两个表的连接条件的两个字段都各自建立上索引,然后explain 一下,查看执行计划,看mysql到底利用了哪个索引,最后再把没有使用索引的表的字段索引给去掉就行了。

总结

到此这篇关于Mysql常见的慢查询优化方式的文章就介绍到这了,更多相关Mysql慢查询优化内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • MySQL慢查询优化之慢查询日志分析的实例教程

    数据库响应慢问题最多的就是查询了.现在大部分数据库都提供了性能分析的帮助手段.例如Oracle中会帮你直接找出慢的语句,并且提供优化方案.在MySQL中就要自己开启慢日志记录加以分析(记录可以保存在表或者文件中,默认是保存在文件中,我们系统使用的就是默认方式). 先看看MySQL慢查询日志里面的记录长什么样的: Time Id Command Argument # Time: 141010 9:33:57 # User@Host: root[root] @ localhost [] Id: 1

  • MySQL优化方案之开启慢查询日志

    目录 前言 设置慢查询日志 测试 附:日志分析工具mysqldumpslow 总结 前言 本方案只适应于小的项目.项目未上线或者紧急情况下可采用这种方式,一旦开启慢日志查询会增加数据库的压力,所以一般采用后台对数据操作时间写入日志文件中,每一周定时进行清除日志 mysql优化方案:开启慢查询日志(查询sql执行超过一秒以上sql等等) 开启慢查询日志:可以让MySQL记录下查询超过指定时间的语句,通过定位分析性能的瓶颈,才能更好的优化数据库系统的性能. 参数说明: slow_query_log

  • MySQL慢查询优化解决问题

    目录 1. MySQL慢查询介绍 2.发现问题(主动/被动) 3.找到原因-对症下药 1.  MySQL慢查询介绍 MySQL的慢查询日志是MySQL提供的一种日志记录,它用来记录在MySQL中响应时间超过阀值的语句,具体指运行时间超过long_query_time值的SQL,则会被记录到慢查询日志中.long_query_time的默认值为10,意思是运行10S以上的语句.默认情况下,Mysql数据库并不启动慢查询日志,需要我们手动来设置这个参数,当然,如果不是调优需要的话,一般不建议启动该参

  • 简单谈谈MySQL优化利器-慢查询

    慢查询 首先,无论进行何种优化,开启慢查询都算是前置条件.慢查询机制,将记录过慢的查询语句(事件),从而为DB维护人员提供优化目标. 检查慢查询是否开启 通过show variables like 'slow_query_log'这条语句,可以找到慢查询的状态(On/Off). 开启慢查询 本文使用的MySQL版本:MariaDB - 10.1.19,请注意,不同版本的MySQL存在差异. 在[mysqld]下加入: [mysqld] port= 3306 slow-query-log=1 #

  • Mysql慢查询优化方法及优化原则

    1.日期大小的比较,传到xml中的日期格式要符合'yyyy-MM-dd',这样才能走索引,如:'yyyy'改为'yyyy-MM-dd','yyyy-MM'改为'yyyy-MM-dd'[这样MYSQL会转换为日期类型] 2.条件语句中无论是等于.还是大于小于,WHERE左侧的条件查询字段不要使用函数或表达式或数学运算 3.WHERE条件语句尝试着调整字段的顺序提升查询速度,如把索引字段放在最前面.把查询命中率高的字段置前等 4.保证优化SQL前后其查询结果是一致的 5.在查询的时候通过将EXPLA

  • MySQL优化教程之慢查询日志实践

    一.慢查询日志概念 对于SQL和索引的优化问题,我们会使用explain去分析SQL语句.但是真正的企业级项目有成千上万条SQL,我们不可能从头开始一条一条explain去分析.我们从什么地方可以获取那些运行时间长,耗性能的SQL?? 我们可以打开慢查询日志: 根据具体的业务和并发量来预估一个时间上限(20ms.100ms),设置好后开启业务,压测后打开慢查询日志,就会看到超过执行时间的SQL,然后使用explain分析这些耗时的SQL语句 步骤如下: 打开慢查询日志开关slow_query_l

  • 安装MySQL常见的三种方式

    目录 安装MySQL的方式常见的有三种: rpm包形式 通用二进制形式 源码编译 1,rpm包形式 (1) 操作系统发行商提供的 (2) MySQL官方提供的(版本更新,修复了更多常见BUG)www.mysql.com/downloads 关于MySQL中rpm包类型的介绍: MySQL-client         客户端组件  MySQL-debuginfo      调试MySQL的组件  MySQL-devel          想针对于MySQL编译安装PHP等依赖于MySQL的组件包

  • MySQL 百万级数据的4种查询优化方式

    一.limit越往后越慢的原因 当我们使用limit来对数据进行分页操作的时,会发现:查看前几页的时候,发现速度非常快,比如 limit 200,25,瞬间就出来了.但是越往后,速度就越慢,特别是百万条之后,卡到不行,那这个是什么原理呢.先看一下我们翻页翻到后面时,查询的sql是怎样的: select * from t_name where c_name1='xxx' order by c_name2 limit 2000000,25; 这种查询的慢,其实是因为limit后面的偏移量太大导致的.

  • MySQL索引介绍及优化方式

    目录 一.导致sql执行慢的原因 二.分析原因时,一定要找切入点 三.什么是索引? 四.Explain分析 1.id 2.select_type 3.table 4.type(★) 5.possible_key 6.key(★) 7.key_len 8.ref(★) 9.rows(★) 10.extra 五.优化案例 六.是否需要创建索引? 一.导致sql执行慢的原因 硬件条件限制: io吞吐量小,形成瓶颈(读取磁盘数据) 网络传输速度慢 内存不足(读取磁盘数据加载到内存) 程序设计方面: 没有

  • Mysql使用索引实现查询优化

    索引的目的在于提高查询效率,可以类比字典,如果要查"mysql"这个单词,我们肯定需要定位到m字母,然后从下往下找到y字母,再找到剩下的sql.如果没有索引,那么你可能需要把所有单词看一遍才能找到你想要的. 1.索引的优点 假设你拥有三个未索引的表t1.t2和t3,每个表都分别包含数据列i1.i2和i3,并且每个表都包含了1000条数据行,其序号从1到1000.查找某些值匹配的数据行组合的查询可能如下所示: SELECT t1.i1, t2.i2, t3.i3 FROM t1, t2,

  • Python操作MySQL数据库的两种方式实例分析【pymysql和pandas】

    本文实例讲述了Python操作MySQL数据库的两种方式.分享给大家供大家参考,具体如下: 第一种 使用pymysql 代码如下: import pymysql #打开数据库连接 db=pymysql.connect(host='1.1.1.1',port=3306,user='root',passwd='123123',db='test',charset='utf8') cursor=db.cursor()#使用cursor()方法获取操作游标 sql = "select * from tes

  • PHP连接MySQL数据库的三种方式实例分析【mysql、mysqli、pdo】

    本文实例讲述了PHP连接MySQL数据库的三种方式.分享给大家供大家参考,具体如下: PHP与MySQL的连接有三种API接口,分别是:PHP的MySQL扩展 .PHP的mysqli扩展 .PHP数据对象(PDO) ,下面针对以上三种连接方式做下总结,以备在不同场景下选出最优方案. PHP的MySQL扩展是设计开发允许php应用与MySQL数据库交互的早期扩展.MySQL扩展提供了一个面向过程的接口,并且是针对MySQL4.1.3或者更早版本设计的.因此这个扩展虽然可以与MySQL4.1.3或更

  • MySQL 常见的数据表设计误区汇总

    误区一:过多的数据列 MySQL 存储引擎的 API 是按照行缓冲区方式从服务端和存储引擎复制数据.服务端将缓冲区数据解码成数据列.然而,将行缓冲区的格式转换为数据行数据结构的列可能会代价很高.MyISAM 固定使用与服务端匹配的行格式,因此无需转换.然而,MyISAM 的可变行格式以及 InnoDB 的行格式总是需要进行转换.转换的代价依赖于列的数量.如果当数据表的列超过上百列的时候,会引起很高的 CPU 资源消耗--即便是使用到的列很少.曾经看过一篇文章,指的是一个多语言的解决方案,直接简单

  • Mysql大数据量查询优化思路详析

    目录 1. 千万级别日志查询的优化 2. 几百万黑名单库的查询优化 3. Mybatis批量插入处理问题 项目场景: Mysql大表查询优化,理论上千万级别以下的数据量Mysql单表查询性能处理都是可以的. 问题描述: 在我们线上环境中,出现了mysql几千万级别的日志查询.几百万级别的黑名单库查询分页查询及条件查询都慢的问题,针对Mysql表优化做了一些优化处理. 原因分析:首先说一下日志查询,在Mysql中如果索引加的比较合适,走索引情况下千万级别查询不会超过一秒,Mysql查询的速度和检索

  • MySQL常见优化方案汇总

    目录 思考sql优化的几个地方,我把他做了个分类,方便理解 key_len计算方式简单介绍 一.优化点1:字段优化 覆盖索引尽量用 二.优化点2:where优化 1.尽量全值匹配 2.最佳左前缀法则 3.范围条件放最后 4.不在索引列上做任何操作 5.不等于要甚用 6.Null/Not null有影响 7.Like 查询要当心 like 8.字符类型加引号 三.优化3 1.OR 改 UNION 效率高 mysql优化是我们日常工作经常遇到的问题,今天给大家说下MySQL常见的几种优化方案. 注:

  • MySQL常见的脚本语句格式参考指南

    目录 表整体(TABLE )操作 表字段(COLUMN )操作 表索引(INDEX )操作 表数据操作 FUNCTION 函数操作 PROCEDURE 存储过程操作 附录 总结 表整体(TABLE )操作 针对数据库的表进行新增操作,考虑到脚本可重复执行,有以下两种方案 使用TRYADDTABLE存储过程 CALL TRYADDTABLE('ACT_GE_PROPERTY', 'CREATE TABLE ACT_GE_PROPERTY ( NAME_ varchar(128) CHARACTER

随机推荐