在确定查询只是返回需要的数据之后,接下来应该看看查询为了返回结果是否扫描了过多的数据。对于MySQL,最简单的衡量查询开销的三个指标如下:

  1响应时间,2扫描行数,3返回行数

  没有那个指明能够完美的衡量查询的开销,但他们大致反映了MySQL在内存执行查询时需要访问多少数据,并可以大概推算出查询运行的时间。这三个指标都会记录到MySQL的慢日志中,索引检查慢日志记录时找出扫描行过多的查询的好办法。

  1响应时间

  要记住,响应时间只是一个表面上的值。这样说肯能看起来和前面关于响应时间的说法有矛盾?其实并不矛盾,响应时间仍然是最重要的指标。这一点有些复杂,细细道来。

  响应时间是两个部分之和,服务时间和排队时间。服务时间是指数据库处理这个查询真正花了多长时间。排队时间是指服务器为了等等某些资源而没有真正执行查询的时间--可能是等待io的完成,也可能是等待锁,等等。遗憾的是,我们无法把响应时间细分到这些部分,除非有什么办法能够逐个测量上面这些消耗,不过很难做到。一般最常见和重要的是等待io和锁等待,但实际情更加复杂。

  所以在不同类型的应用压力下,响应时间并没有什么一致的规律或者公式。诸如存储引擎的锁(表锁,行锁),高并发资源竞争,硬件响应等诸多因素都会影响响应时间,所以,响应时间既可能是一个问题的结果也可能是一个问题的原因,不同案例情况不同。

  当你看到一个查询的响应时间的时候,首先需要问问自己,这个响应时间是否是一个合理的值。实际上可以使用“快速上限估计”法来gust查询的响应时间。概况的说,了解这个查询需要那些索引以及它的执行计划是什么,然后计算大概需要多少个顺序和随机io,在用其诚意在具体硬件条件下的一侧iodine消耗时间,最后把这些消耗都加起来,就可以获得一个大概参考值来排队当前响应时间是不是一个合理的值。

  2.扫描的行数和返回的行数。

  分析查询时,查看该查询扫描的行数是非常有帮助的。这在一定程度上能够说明该查询找到需要的数据的效率高不高。

  对于找出那些糟糕查询,这个指标可能还不够完美,因为并不是所有的行的访问代价都是相同的。较短的行的访问速度相当快,内存中的行业比磁盘中的行的访问速度要快的多。

  理想的情况下,扫描的行数和返回的行数应该是相同的。但实际上这种美事并不多。例如在做一个关联查询的时候,扫描的行数和对返回的行数的比率通常都很小,一般在1:1和10:1之间,不过有时候这个值也可能非常大。

  3扫描的行数和访问类型。

  在评估查询开销的时候,需要考虑一下从表中找到某一行数据的成本。MySQL有好几种访问方式可以查找并返回一行接口。这些访问方式可能需要访问很多行才能返回一条结果,也有些访问方式可能无需扫描就能返回结果。

  在EXPLAIN语句中的type列反映了访问类型。访问类型有很多种,从全表扫描到索引扫描,范围扫描,唯一索引,常数索引。这里列的这些,速度是从慢到快,扫描的行数也是从多到少。你不需要记住这些访问类型,但需要明明扫描表,扫描索引,范围访问和单值访问的概念。

  如果查询没有办法找到合适的访问类型,那么解决的最好办法通常就是增加一个合适的索引,这也是我们前一章讨论的问题。现在应该明白为什么索引对于查询优化如此重要了。索引让MySQL以最高效,扫描行数最少的方式找到需要的记录。

  SELECT * FROM actor WHERE film_id = 1;

  这个查询将返回10 行数据,从explain的结果可以看出,MySQL在索引idx_fk_film_id上使用了ref访问类型来执行查询。

  EXPLAIN SELECT * FROM film_actor WHERE film_id = 1\G

  id:1
  select type :simple

  type:ref

  table :film_actor

  possible key :****

  key :****

  key len:2

  ref :const

  rows:10

  explain的结果也显示MySQL预估需要访问10行数据。换句话说,查询优化器认为这种访问类型可以高效的完成查询。如果没有合适的索引会怎样呢》、?MySQL就不得不使用一种更糟糕的访问类型,下面我们来看看如果删除对应的索引来运行这个查询:

  ALTER TABLE film_actor DROP FOREIGN KEY fk_fiml_actor_film;

  ALTER TABLE film_actor DROP KEY idx_fk_film_id

  EXPLAIN SELECT * FROM film_actor WHERE film_id=1 \G

  id:1
  select_type:simple

  type:ALL

  table:film_actor

  possible_key:NULL

  kye:NULL;

  key_len:null

  ref :null

  rows:5073

  EXTRA :using where

  

  正如我们预测的,访问类型变成了一个全表扫描,限制MySQL预估需要扫描5073条记录就能完成这个查询。这里的USING WHERE 表示MySQL将通过WHERE 条件来筛选存取引擎返回的记录。

  一般MySQL能够使用如下三种方式使用WHERE 条件,从好到坏依次为:

  1在索引中使用where调价来过滤掉不匹配的记录。这是在存储引擎层完成的。

  2使用索引覆盖扫描(在Extra列中出现USING INDEX )来返回记录,直接从索引中过滤掉不需要的记录并返回命中结果。这是在MySQL服务器层完成的,但无需再回表查询记录。

  3从数据表中返回数据,然后过滤不满足条件的记录(在extra 列中出现using where)。这是在MySQL服务器层完成的,MySQL需要从数据表中读出记录然后过滤。上面这个例子说明了好的索引是多么重要。好的索引可以让查询使用合适的访问类型,尽可能的只扫描需要的数据行。但也不是说增加索引就能让扫描的行数等于返回的行数。例如下面的使用聚合函数COUNT()的查询:

  SELECT actor_id ,COUNT(*) FROM film_actor GROUP BY actor_id

  这个查询需要读取几千行数据,但是仅返回了200行结果。没有什么索引能够让这样的查询减少需要扫描的行数。

  不幸的是,MySQL不会告诉我们生成结果实际上需要扫描多数行数据,而只会告诉我们生成结果时一共扫描了多数行数据。扫描的函数中大部分都很可能被where条件过滤掉的,对最终的结果并没有贡献。在上面的例子中,我们傻叉收益后,看到MySQL需要扫描索引记录然后根据where条件过滤,最终返回10行结果。理解一个查询需要扫描多数行和实际需要使用的行数首先需要理解这个查询背后的逻辑和思想。

  如果发现查询需要大量的数据但值返回少数行,那么通常可以尝试下面的技巧去优化它:

  1使用索引覆盖扫描,把所有需要用的列都放到索引中,这样存储引擎无需回表获取对应的行就可以返回结果了

  2该表库表结构。例如使用单独的汇总表、

  3重写这个查询,然MySQL优化器能够以更优化的方式执行这个查询。

MySQL是否在扫描额外的记录的更多相关文章

  1. MYSQl 全表扫描以及查询性能

    MYSQl 全表扫描以及查询性能 -- 本文章仅用于学习,记录 一. Mysql在一些情况下全表检索比索引查询更快: 1.表格数据很少,使用全表检索会比使用索引检索更快.一般当表格总数据小于10行并且 ...

  2. mysql插入数据与删除重复记录的几个例子(收藏)

    mysql插入数据与删除重复记录的几个例子 12-26shell脚本实现mysql数据的批量插入 12-26mysql循环语句插入数据的例子 12-26mysql批量插入数据(insert into ...

  3. MySQL查询数据表中数据记录(包括多表查询)

    MySQL查询数据表中数据记录(包括多表查询) 在MySQL中创建数据库的目的是为了使用其中的数据. 使用select查询语句可以从数据库中把数据查询出来. select语句的语法格式如下: sele ...

  4. mysql中根据一个字段相同记录写递增序号,如序号结果,如何实现?

      mysql中根据一个字段相同记录写递增序号,如序号结果,如何实现? mysql中实现方式如下: select merchantId, NameCn, send_date, deliver_name ...

  5. Web开发入门经典:使用PHP6、Apache和MySQL 中文pdf扫描版​

    通过学习本书,读者很快就能明白为什么PHP.Apache和MySQL会迅速成为开发动态网站最流行的方式,本书将为读者理解这3个核心组件如何独立工作和协同工作奠定良好的基础,引导读者充分利用它们提供的各 ...

  6. php MySQL使用rand函数随机取记录(转)

    php MySQL使用rand函数随机取记录 如何在mysql中使用随机数, 如何写一个语句能一下更新几百条MYSQL数据! 需要测试MYSQL数据库,里面有一个上万条数据的数据库,如何写一个PHP文 ...

  7. MySQL使用INSERT插入多条记录

    MySQL使用INSERT插入多条记录,应该如何操作呢?下面就为您详细介绍MySQL使用INSERT插入多条记录的实现方法,供您参考. 看到这个标题也许大家会问,这有什么好说的,调用多次INSERT语 ...

  8. 12 | 为什么我的MySQL会“抖”一下? 学习记录

    <MySQL实战45讲>12 | 为什么我的MySQL会“抖”一下? 学习记录 http://naotu.baidu.com/file/15aa54cab2fa882c6a2a1dd52e ...

  9. MySQL按时间统计每个小时记录数

    MySQL按时间统计每个小时记录数 方案1: ? 1 2 3 4 5 6 7 SELECT  @rownum := @rownum + 1 AS ID,         CONCAT((CASE WH ...

随机推荐

  1. Python使用Pygame.mixer播放音乐

    Python使用Pygame.mixer播放音乐 frequency这里是调频率... 播放网络中的音频: #!/usr/bin/env python # -*- coding: utf-8 -*- ...

  2. angular2 学习笔记 ( Component 组件)

    refer : https://angular.cn/docs/ts/latest/guide/template-syntax.html https://angular.cn/docs/ts/late ...

  3. LeetCode——Two Sum

    Given an array of integers, find two numbers such that they add up to a specific target number. The ...

  4. 《SDN核心技术剖析和实战指南》3.1控制器核心技术读书笔记

    在SDN的架构中,控制器可以说是SDN的核心,它负责对底层转发设备的控制以及向上层应用提供可编程性的北向接口.从实现上看,主要分三个层面来考虑,南向接口技术,北向接口技术以及东西向的可扩展性能力.下面 ...

  5. [转载]使用uiautomator做UI测试

    这个只是单纯的mark一下.还没有认真去研究.鉴于最近也不会做手机的自动化测试,所以留作以后参考吧. 转自: http://blog.chengyunfeng.com/?p=504 在Android ...

  6. ip地址中的网络号,主机号

    当前使用的IP地址有4个字节(32bit)组成,即IPV4编码方式.每个IP地址包括两部分:网络号和主机号.当分配给主机号的二进制位越多,则能标识的主机数就越多,相应地能标识的网络数就越少,反之同理. ...

  7. HTTP学习实验8-windows添加telnet功能

    Windows 添加telnet功能: 控制面板->(查看方式:小图标)->程序和功能->打开或关闭Windows功能->Telnet客户端 Telnet 设置: 打开cmd, ...

  8. java vm内存设置

    1.普通java应用程序,使用java命令运行,  java -Xms1024m -Xmx1024m -XX:MaxNewSize=256m  -XX:MaxPermSize=256m -jar 2. ...

  9. Python 列表(list)、字典(dict)、字符串(string)常用基本操作小结

    创建列表 sample_list = ['a',1,('a','b')] Python 列表操作 sample_list = ['a','b',0,1,3] 得到列表中的某一个值 value_star ...

  10. CF380C Sereja and Brackets [想法+线段树]

    题意: 给出一串括号 给出一些询问,问某个区间[l,r]内的能合法匹配的括号数有多少个 分析: 我们能够实现处理两个数组 sum[i] 1....i中已经能匹配的右括号的数目 left[i] 1... ...