MySQL 如何分析查询性能

查询优化、索引优化和表设计优化是环环相扣的。如果你有丰富的编写MySQL查询语句的经验,你就会知道如何设计表和索引来支持有效的查询。同样的,知晓表设计同样有助于了解表结构如何对查询语句产生影响。因此,即便表设计和索引都设计得很好,但如果查询语句写得很糟糕,那查询的性能也会很糟糕。

在尝试编写快速的查询语句前,务必记住快速都是基于响应时间进行评估的。查询语句是一组由多个子任务组成的大任务,每一个子任务都会消耗时间。为了优化查询,我们需要尽可能地减少子任务的数量,或者让子任务执行得更快。 注:有些时候我们也需要考虑查询对系统其他查询的影响,在这种情况下,还需要尽可能地减少资源消耗。 _ 通常,我们可以认为查询的生命周期贯穿于客户端到服务端的整个交互时序图中,包括了查询语句解析、查询计划、执行过程和数据返回到客户端。执行是查询过程中最为重要的一环,包括了从存储引擎获取数据行而发起的大量调用,以及获取数据后的处理,例如分组和排序。

当完成所有这些任务后,查询还会在网络传错、CPU处理、数据统计和策略规划、等待锁、从存储引擎获取数据行的操作中消耗时间。这些调用会在内存操作、CPU操作和I/O操作中消耗时间。在每一种情况中,如果这些操作被滥用、执行次数过多、或过慢,就会导致额外的时间开销。查询优化的目标是避免这些情况——通过消除或减少操作,或者让操作运行更快。

需要注意的是,我们没法绘制一个精确的查询生命周期图,我们的目的是展示理解查询生命周期的重要性,并思考这些环节的耗时。有了这个基础,就能够着手去优化查询语句。

慢查询基础:优化数据获取

查询性能差的最基础的原因是处理了太多的数据。有些查询必须从大量数据中进行筛选,这种情况就没法优化。但这是不太正常的情况。大部分糟糕的查询可以通过访问更少的数据进行优化。下面的两个步骤对分析性能差的查询十分有用:

  1. 找出应用是不是获取了你需要之外的数据。通常这意味着应用获取了太多的数据行或数据列。
  2. 找出MySQL服务器是不是分析了超过需要的行。

检查是否向数据库请求了不必要的数据

有些查询会向数据库服务器请求所需要的数据,然后将这些数据丢弃。这会增加MySQL服务器的工作、加重网络负荷、消耗更多内存和应用服务器的CPU资源。下面是一些典型的错误:

  1. 获取不需要的数据行:一个常见的误区是假设MySQL只提供需要的结果,而不是计算和返回全部的结果集。通常这种错误发生在熟悉其他数据库系统的人身上。这些开发者习惯于使用返回很多行的SELECT语句,然后从中取出前N行,之后不再使用返回的结果集(例如从一个资讯网站获取最近的100篇文章,然后在前端仅仅展示其中的10条)。他们会认为MySQL在拿到10行数据后就会停止查询,而实际MySQL会获取完整的数据集合。然后,客户端或获取全部的数据再将其中的大部分丢弃。最佳的解决方案是在查询中加上LIMIT条件。
  2. 在一个多表联合查询终获取全部列:如果你需要获取恐龙时代这部电影的全部演员,不要像下面那样写你的SQL语句:
SELECT * FROM sakila.actor
INNER JOIN sakila.file_actor USING(actor_id)
INNER JOIN sakila.file USING (film_id)
WHERE sakila.film.title = 'Academy Dinosaur';

这会返回参与联合查询的三张表的全部列。更好的做法是,像下面那样写:

SELECT sakila.actor.* FROM sakila.actor
INNER JOIN sakila.file_actor USING(actor_id)
INNER JOIN sakila.file USING (film_id)
WHERE sakila.film.title = 'Academy Dinosaur';
  1. 获取全部数据列:在你看到SELECT *这样的查询时,一定要保持怀疑:真的需要全部的列吗?很可能不是的。获取全部的数据列会让覆盖索引失效、增加I/O负担、内存消耗和CPU负荷。有些DBA直接因为这个禁用SELECT *,并且可以减少人员修改表的列后引发的问题。当然,请求不必要的数据并不总是糟糕。在调查中发现,这种方式可以简化开发工作,因为这样可以提高代码的复用性。只要你知道这会影响性能,那会是一个正当的理由。同样的,如果在应用中使用了某些缓存机制,也会提高缓存的命中率。获取和缓存全部对象可以通过运行多个获取部分对象的独立的查询来处理会更好。
  2. 重复获取相同数据:如果粗心的话,很容易在应用中编写获取相同数据的代码。例如,如果你要在评论列表中展示用户个人信息中的头像,你可能再每一条评论都获取一次。更有效的方式是第一次获取后缓存起来直接在评论列表使用。

检查MySQL是不是处理了过多的数据

一旦确定了查询语句没有获取不必要的数据,就可以查找那些在返回结果前处理过多数据的查询。在MySQL中,最简单的查询消耗标准是:

  1. 响应时间
  2. 处理的数据行数量
  3. 返回的数据行数量

这些标准没有一个是完美的查询性能评估手段,但它们大致反映了MySQL执行查询语句时在内部处理过程中获取的数据量和查询运行的速度。这三个标准都在慢查询日志中记录,因此从慢查询日志中去发现数据处理过多的查询是查询优化的最佳实践方式。

响应时间 首先,注意查询响应时间是我们看到的一个表象。实际上,响应时间比我们想象的要更为复杂。响应时间由两部分组成:服务时间和队列时间。服务时间是服务端实际处理查询的时间。队列时间是服务端并没有真正执行查询的那部分时间——它在等待某些资源,例如I/O操作的完成、行锁释放等等。问题在于,你没法准确将响应时间拆分成这两部分——除非你能够单独测量这两部分的时间,而这是很难做到的。最常见和最重要的情形是I/O阻塞和等待锁,但不是百分之百都是这样。

结果就是,响应时间在不同负荷情况下并不是一成不变的。其他的因素,例如存储引擎锁、高并发和硬件都会影响响应时间。因此,当检查响应时间的时候,首先要决定这个响应时间是不是仅仅是这个查询引起的。可以通过计算查询的快速上限估计(QUBE)方法来评估其响应时间:通过检查查询计划和使用的索引,来决定需要的顺序和随机I/O访问操作,然后乘以机器的硬件执行每次操作的时间来评估。通过将全部的时间求和可以评估查询响应慢是因为查询本身引起的还是其他原因。

处理和返回的数据行数量 在分析查询语句时,思考处理行的数量十分有用,因为这样可以直观地知道查询是如何获取我们所需的数据。然而,这对查找糟糕的查询并不是完美的测量工具。并不是所有的行访问都是一致的。更少的行访问速度更快,而从内存中获取数据行比在磁盘获取要快很多。

理想情况下,处理的数据行和返回的数据行是相等的,但是实际上很少会这样。例如,使用联合索引构建返回行时,服务端必须从多个行中获取数据以产生返回的行数据。处理的数据行和返回的数据行的比例通常很小,在1:1到10:1之间,但有时候可能是更大的数量级。

数据行处理和获取类型

当思考查询的代价时,可以考虑从数据表获取单独一行的代价。MySQL使用多种获取方法去查找和返回一行数据。有些需要处理多行,而有些则可能不需要检查直接得到返回结果。

获取数据的方法在EXPLAIN输出结果的type列。包括了全表扫描、索引扫描、范围扫描、唯一索引查找和常量。由于数据读取量依次减少,因此上述的每一种方法都比它之前的要快。我们不需要记住获取类型,但需要理解其中的基本概念。

如果没有好的获取类型,最佳解决问题的方式是增加一个合适的索引。索引使得MySQL检查更少的数据,从而更有效地查询数据行。例如,以下面的简单查询为例:

EXPLAIN SELECT * FROM sakila.film_actor WHERE file_id=1;

这个查询会返回10行数据,然后EXPLAIN指令显示了MySQL在idx_fk_film_id索引上使用了ref类型执行查询语句。

***********************1. row************************
id: 1
select_type: SIMPLE
table:film_actor
type: ref
possile)keys: idx_fk_film_id
key: idx_fk_film_id
key_len: 2
ref: const
rows: 10
Extra:

EXPLAIN指令显示MySQL估计仅仅需要获取10行完成查询。换言之,查询优化器知道如何选择获取类型来让查询更有效。如果查询没有合适的索引会怎么样?MySQL必须使用次优的获取类型,当删除掉表索引后再来看结果。

ALTER TABLE sakila.film_actor DROP FOREIGN KEY fk_film_actor_film;
ALTER TABLE sakila.film_actor DROP DROP KEY idx_fk_film_id;
EXPLAIN SELECT * FROM sakila.film_actor WHERE file_id=1;
***********************1. row************************
id: 1
select_type: SIMPLE
table:film_actor
type: ALL
possile)keys: NULL
key: NULL
key_len: NULL
ref: NULL
rows: 5073
Extra: Using where

如同预期的那样,获取类型变成了全表扫描(ALL),MySQL估计需要处理5073行数据才能完成查询。在Extra列中的Using where显示MySQL服务器使用了WHERE条件来丢弃存储引擎读取的其他不符合条件的数据。通常,MySQL会在下面三种方式中使用WHERE条件,效果依次是从好到差:

  1. 通过索引查找操作去除不匹配的数据行,这发生在存储引擎层;
  2. 使用覆盖索引(在Extra列显示是Using index)去避免数据行访问,并在获取到结果后将不符合条件的数据过滤掉。这发生在服务器层,但不需要从数据表读取数据行。
  3. 从数据表获取数据行,然后在过滤掉不匹配的数据(在Extra列显示为Using where)。这发生在服务器层,并且需要在过滤数据前从数据表读取数据行。

下面的例子演示了有好的索引的重要性。好的索引有助于使用好的数据获取类型并且只需要处理所需要的数据行。然而,添加索引并不总是意味着MySQL获取和返回的数据行是一致的。例如,下面的COUNT()聚合方法。

SELECT actor_id, COUNT(*) FROM sakila.film_actor GROUP BY actor_id;

这个查询只返回200行,但是在构建返回结果集前需要读取数千行数据。这种查询语句,即便有索引也无法减少需要的处理的数据行数。

不幸的是,MySQL并不会告知获取了多少行来构建返回结果集,它仅仅告知获取的总行数。很多行通过WHERE条件过滤掉了,而对返回结果集没有任何作用。在前面的例子中,移除sakila.film_actor索引后,查询获取了数据表的全部行,但是只从中取了10条数据作为结果集返回。理解服务器获取的数据行数量和返回的数据行数量有助于理解查询本身。 如果发现了需要获取大量数据行而只是在结果使用很少的行,可以通过下面的方式修复这个问题:

  1. 使用覆盖索引,这使得存储引擎不需要获取完整的数据行(直接从索引中获取)。
  2. 修改查询表,一个例子是构建汇总表来查询统计数据。
  3. 重写复杂的查询语句,使得MySQL查询优化器能够以更优的方式执行。

以上就是MySQL 如何分析查询性能的详细内容,更多关于MySQL 分析查询性能的资料请关注我们其它相关文章!

(0)

相关推荐

  • MySQL查询中LIMIT的大offset导致性能低下浅析

    前言 我们大家都知道,mysql查询使用select命令,配合limit,offset参数可以读取指定范围的记录,但是offset过大影响查询性能的原因及优化方法 我们在业务系统中难免少不了分页的需求.想到分页的时候,大家肯定会想到使用SQL中的LIMIT来实现.但是,如果不正确的使用LIMIT会导致性能问题(SQL执行得很慢.有可能会拖垮服务器),也会被领导批的:所以,我们来看看如何正确地使用LIMIT. 下面话不多说了,来一起看看详细的介绍吧 LIMIT OFFSET, ROW_COUNT

  • 通过MySQL慢查询优化MySQL性能的方法讲解

    随着访问量的上升,MySQL数据库的压力就越大,几乎大部分使用MySQL架构的web应用在数据库上都会出现性能问题,通过mysql慢查询日志跟踪有问题的查询非常有用,可以分析出当前程序里有很耗费资源的sql语句. 慢查询日志我们可以通过my.cnf文件设置开启,下面先来看一下相关参数的意义 log-slow-queries <slow_query_log_file> 存放slow query日志的文件.你必须保证mysql server进程mysqld_safe进程用户对该文件有w权限. lo

  • MySQL中distinct语句去查询重复记录及相关的性能讨论

    在 MySQL 查询中,可能会包含重复值.这并不成问题,不过,有时您也许希望仅仅列出不同(distinct)的值. 关键词 DISTINCT 用于返回唯一不同的值,就是去重啦.用法也很简单: SELECT DISTINCT * FROM tableName DISTINCT 这个关键字来过滤掉多余的重复记录只保留一条. 另外,如果要对某个字段去重,可以试下: SELECT *, COUNT(DISTINCT nowamagic) FROM table GROUP BY nowamagic 这个用

  • MySQL查询随机数据的4种方法和性能对比

    下面从以下四种方案分析各自的优缺点.方案一: 复制代码 代码如下: SELECT * FROM `table` ORDER BY RAND() LIMIT 0,1; 这种方法的问题就是非常慢.原因是因为MySQL会创建一张零时表来保存所有的结果集,然后给每个结果一个随机索引,然后再排序并返回.有几个方法可以让它快起来.基本思想就是先获取一个随机数,然后使用这个随机数来获取指定的行.由于所有的行都有一个唯一的id,我们将只取最小和最大id之间的随机数,然后获取id为这个数行.为了让这个方法当id不

  • 详解MySQL的limit用法和分页查询语句的性能分析

    limit用法 在我们使用查询语句的时候,经常要返回前几条或者中间某几行数据,这个时候怎么办呢?不用担心,mysql已经为我们提供了这样一个功能. SELECT * FROM table LIMIT [offset,] rows | rows OFFSET offset LIMIT 子句可以被用于强制 SELECT 语句返回指定的记录数.LIMIT 接受一个或两个数字参数.参数必须是一个整数常量.如果给定两个参数,第一个参数指定第一个返回记录行的偏移量,第二个参数指定返回记录行的最大数目.初始记

  • MySQL数据库查询性能优化策略

    优化查询 使用Explain语句分析查询语句 Explain 用来分析 SELECT 查询语句,开发人员可以通过分析 Explain 结果来优化查询语句. 通过对查询语句的分析,可以了解查询语句的执行情况,找出查询语句执行的瓶颈,从而优化查询语句. 使用索引查询 MySql中提高性能的一个最有效的方式就是对数据表设计合理的索引. 索引提供了高效访问数据的方法,并且加快查询速度. 如果查询时没有使用索引,那么查询语句将扫描表中所有的记录.在数据量大的时候,这样查询速度会很慢. 使用索引进行查询,查

  • 如何提高MySQL Limit查询性能的方法详解

    在MySQL数据库操作中,我们在做一些查询的时候总希望能避免数据库引擎做全表扫描,因为全表扫描时间长,而且其中大部分扫描对客户端而言是没有意义的.其实我们可以使用Limit关键字来避免全表扫描的情况,从而提高效率. 有个几千万条记录的表 on MySQL 5.0.x,现在要读出其中几十万万条左右的记录.常用方法,依次循环: select * from mytable where index_col = xxx limit offset, limit; 经验:如果没有blob/text字段,单行记

  • MySQL 查询速度慢与性能差的原因与解决方法

    一.什么影响了数据库查询速度 1.1 影响数据库查询速度的四个因素 1.2 风险分析 QPS: QueriesPerSecond意思是"每秒查询率",是一台服务器每秒能够相应的查询次数,是对一个特定的查询服务器在规定时间内所处理流量多少的衡量标准. TPS: 是 TransactionsPerSecond的缩写,也就是事务数/秒.它是软件测试结果的测量单位.客户机在发送请求时开始计时,收到服务器响应后结束计时,以此来计算使用的时间和完成的事务个数. Tips: 最好不要在主库上数据库备

  • 大幅优化MySQL查询性能的奇技淫巧

    回顾 MySQL / InnoDB 的改善历史.你能很容易发现.在MySQL 5.6稳定版本中从来没有在read-only 这么快的提速,它很容易搞懂,以及在read-only(RO)有着良好的扩张性.也很期待它在read+write(RW)上达到一个较高水平.(特别是在读取数据是数据库主要工作的时候) 然而.我们对于RO在 MySQL 5.6的表现也十分的高兴,在5.7这个版本中,主要工作集中在 read+write (RW)上, 因为在大数据的处理上还没能达到我们的期望.但是RW依赖RO下.

  • MySQL 如何分析查询性能

    查询优化.索引优化和表设计优化是环环相扣的.如果你有丰富的编写MySQL查询语句的经验,你就会知道如何设计表和索引来支持有效的查询.同样的,知晓表设计同样有助于了解表结构如何对查询语句产生影响.因此,即便表设计和索引都设计得很好,但如果查询语句写得很糟糕,那查询的性能也会很糟糕. 在尝试编写快速的查询语句前,务必记住快速都是基于响应时间进行评估的.查询语句是一组由多个子任务组成的大任务,每一个子任务都会消耗时间.为了优化查询,我们需要尽可能地减少子任务的数量,或者让子任务执行得更快. 注:有些时

  • MySQL使用profile查询性能的操作教程

    MYSQL的profiling功能要在Mysql版本5.0.37以上才能使用. 查看profile是否开启 mysql> show variables like '%profil%'; +------------------------+-------+ | Variable_name | Value | +------------------------+-------+ | profiling | OFF | --开启SQL语句剖析功能 | profiling_history_size |

  • MySQL查询性能优化索引下推

    目录 前言 1. 索引下推的作用 2. 案例实践 3. 索引下推配置 4. 索引下推原理剖析 5. 索引下推应用范围 前言 前面已经讲了MySQL的其他查询性能优化方式,没看过可以去了解一下: MySQL查询性能优化七种方式索引潜水 MySQL查询性能优化武器之链路追踪 今天要讲的是MySQL的另一种查询性能优化方式 — 索引下推(Index Condition Pushdown,简称ICP),是MySQL5.6版本增加的特性. 1. 索引下推的作用 主要作用有两个: 减少回表查询的次数 减少存

  • MySQL数据库查询性能优化的4个技巧干货

    目录 前言 SQL的执行频率 慢查询日志 show profiles详情分析 explain执行计划 1.ID参数 2.select_type参数 3.type参数 前言 MySQL性能优化是一个老生常谈的问题,无论是在实际工作中还是面试中,都不可避免遇到相应的场景,下面博主就总结一些能够帮助大家解决这个问题的小技巧. SQL优化之前需要确认哪些SQL需要优化,这时就需要引起SQL性能分析工具,主要优化的是查询语句. SQL的执行频率 SQL性能优化一般是针对查询语句,所以在定位是否需要优化之前

  • MySQL查询性能优化武器之链路追踪

    目录 前言 1. 查看optimizer trace配置 2. 开启optimizer trace 3. 线上问题复现 3. 使用optimizer trace 前言 MySQL优化器可以生成Explain执行计划,我们可以通过执行计划查看是否使用了索引,使用了哪种索引? 但是到底为什么会使用这个索引,我们却无从得知. 好在MySQL提供了一个好用的分析工具 — optimizer trace(优化器追踪),可以帮助我们查看优化器生成执行计划的整个过程,以及做出的各种决策,包括访问表的方法.各种

  • MySQL常用慢查询分析工具详解

    目录 引言 1.调优工具mysqldumpslow 1.1调优工具常用设置 1.2 调优工具常用命令 1.3 慢日志文件分析 2. 调优工具show profile 引言 在日常的业务开发中MySQL 出现慢查询是很常见的 大部分情况下会分为两种情况: 1.业务增长太快 2.要么就是SQL 写的太xx了 所以对慢查询 SQL 进行分析和优化很重要其中 mysqldumpslow 是 MySQL 服务自带的一款很好的分析调优工具 1.调优工具mysqldumpslow 1.1调优工具常用设置 1.

  • 详解MySql的慢查询分析及开启慢查询日志

    我最近也在研究MySQL性能优化的路上,那么今天也算个学习笔记吧! 在小伙伴们开发的项目中,对于MySQL排查问题找出性能瓶颈来说,最容易发现并解决的问题就是MYSQL的慢查询以及没有得用索引的查询. 接下来教大家如何开启MySQL5.0版本以上的慢查询日志记录: OK,一起开始找出mysql中执行起来不"爽"的SQL语句吧. 首先,我们通过mysql命令进入mysql命令行中: [root@yunuo_vm ~]# mysql -u root -p Enter password: W

  • mysql关联子查询的一种优化方法分析

    本文实例讲述了mysql关联子查询的一种优化方法.分享给大家供大家参考,具体如下: 很多时候,在mysql上实现的子查询的性能较差,这听起来实在有点难过.特别有时候,用到IN()子查询语句时,对于上了某种数量级的表来说,耗时多的难以估计.本人mysql知识所涉不深,只能慢慢摸透个中玄机了. 假设有这样的一个exists查询语句: select * from table1 where exists (select * from table2 where id>=30000 and table1.u

  • mysql详细分析讲解子查询的使用

    出现在其他语句中的 select 语句,称为子查询或内查询:外部的查询语句,称为主查询或 外查询 . -- 子查询 -- 查询的条件来自于另一查询的结果 SELECT * FROM t_user WHERE number=(SELECT number FROM t_user WHERE NAME='张三') 当然子查询也有类型,分为以下几种 : 标量子查询(结果集只有一行一列) 列子查询(结果集只有一列多行) 行子查询(结果集有一行多列)(较少) 表子查询(结果集一般为多行多列) 这里我们以新建

随机推荐