百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 编程字典 > 正文

mysql explain format=json 详解

toyiye 2024-06-27 00:59 14 浏览 0 评论

explain format=json 可以打印详细地执行计划成本,下面两个示例将告诉你如何查看成本输出,以及如何计算成本。

表结构如下:

mysql> show create table sbtest1\G
*************************** 1. row ***************************
       Table: sbtest1
Create Table: CREATE TABLE `sbtest1` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `k` int(11) NOT NULL DEFAULT '0',
  `c` char(120) COLLATE utf8mb4_bin NOT NULL DEFAULT '',
  `pad` varchar(90) COLLATE utf8mb4_bin DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4316190 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin

##注意sbtest3无主键
mysql> show create table sbtest3\G
*************************** 1. row ***************************
       Table: sbtest3
Create Table: CREATE TABLE `sbtest3` (
  `id` int(11) NOT NULL,
  `k` int(11) NOT NULL DEFAULT '0',
  `c` char(120) COLLATE utf8mb4_bin NOT NULL DEFAULT '',
  `pad` varchar(66) COLLATE utf8mb4_bin DEFAULT NULL,
  KEY `k_3` (`k`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin

示例1

mysql> explain format=json select * from sbtest3 where id<100 and k<200\G
*************************** 1. row ***************************
EXPLAIN: {
  "query_block": {
    "select_id": 1,
    "cost_info": {
      "query_cost": "26.21"            ##查询总成本
    },
    "table": {
      "table_name": "sbtest3",        ##表名
      "access_type": "range",         ##访问数据的方式是range,即索引范围查找
      "possible_keys": [
        "k_3"
      ],
      "key": "k_3",                   ##使用索引
      "used_key_parts": [
        "k"
      ],
      "key_length": "4",
      "rows_examined_per_scan": 18,   ##扫描 k_3 索引的行数:18(满足特定条件时使用index dive可得到真实行数)
      "rows_produced_per_join": 5,    ##扇出。在扫描索引后估算满足id<100条件的行数:5
      "filtered": "33.33",            ##在扫描索引后估算满足其他条件id<100的数据行占扫描行数的比重
      "index_condition": "(`sbtest`.`sbtest3`.`k` < 200)",     ##索引条件
      "cost_info": {
        "read_cost": "25.01",         ##这里包含了所有的IO成本+部分CPU成本
        "eval_cost": "1.20",          ##部分CPU成本:rows_produced_per_join*成本常数
        "prefix_cost": "26.21",       ##read_cost+eval_cost
        "data_read_per_join": "4K"
      },
      "used_columns": [
        "id",
        "k",
        "c",
        "pad"
      ],
      "attached_condition": "(`sbtest`.`sbtest3`.`id` < 100)"
    }
  }
}


rows_produced_per_join

字面意思是每次连接产生的行,这里是个单表查询,无所谓连接,估计是为了统一所以这样命名了(因为SQL有可能是连接查询,这样就不必再取一个名字)。从单表查询来看,这个就是预估的最终满足条件的行数,即 rows_examined_per_scan*filtered,18*33.33%四舍五入应该是 6 才对,这里是向下取整所以显示5。这个值也叫做扇出。

eval_cost

这个很简单,就是计算扇出的CPU成本。应用条件 k<200 时,需要扫描索引 18 行记录,这里18是精确值(index dive),然后优化器用了一种叫启发式规则(heuristic)的算法估算出其中满足条件 id<100 的比例为 33.33%,进行 18*33.33% 次计算的CPU成本等于 18*33.33%*0.2=1.2,这里 0.2 是成本常数(即 row_evaluate_cost )。
简化公示:eval_cost=rows_examined_per_scan*filtered*成本常数,由于 rows_produced_per_join 其实等于 rows_examined_per_scan*filtered,再简化可以得出:eval_cost=rows_produced_per_join*成本常数

注意:计算成本时扇出数准确来说应该用 rows_examined_per_scan*filtered 表示, rows_produced_per_join 是对其向下取整的

read_cost

这里包含了所有的IO成本+(CPU成本-eval_cost)。我们先看下这个SQL的总成本应该怎么算:
访问二级索引 k_3 的成本:

  • IO成本=1*1.0
    查询优化器粗暴的认为读取索引的一个范围区间的I/O成本和读取一个页面是相同的,这个SQL中 k 字段的筛选范围只有1个:k < 200,而读取一个页面的IO成本为1.0(即 io_block_read_cost);
  • CPU成本=18*0.2
    从 k 索引中取出 18行数据后,实际还要再计算一遍,每行计算的成本为 0.2。

然后因为 select * 以及 where id<100 需要的数据都不在索引 k_3 中,所以还需要回表,回表成本:

  • IO成本=18*1.0
    从索引中取出满足 k<200 的数据一共是 18 行,所以=18*1.0;
  • CPU成本=18*0.2
    从这18行完整的数据中计算满足 id<100 的数据,所以也需要计算 18 次。这里拆成了两部分:18*(66.67%+33.33%)*0.2,eval_cost 是其中 18*33.33%*0.2 的部分,即扇出的那部分。

总成本=1*1.0+18*0.2+18*1+18*0.2=26.2。

示例2

mysql> explain format=json select t1.id from sbtest1 t1 join sbtest3 t3 \
on t1.id=t3.id and t3.k<200 and t3.id<100\G
*************************** 1. row ***************************
EXPLAIN: {
  "query_block": {
    "select_id": 1,
    "cost_info": {
      "query_cost": "33.41"                      ##查询总成本
    },
    "nested_loop": [                            ##join算法:NLJ
      {
        "table": {
          "table_name": "t3",                   ##t3是驱动表
          "access_type": "range",               ##访问数据的方式是range,即索引范围查找
          "possible_keys": [
            "k_3"
          ],
          "key": "k_3",                         ##使用的索引:k_3
          "used_key_parts": [                   ##索引字段:k
            "k"
          ],
          "key_length": "4",
          "rows_examined_per_scan": 18,         ##k_3索引扫描行数:18
          "rows_produced_per_join": 5,          ##扇出。18*33.33% 向下取整了所以是5,实际算eval_cost时应该四舍五入得6
          "filtered": "33.33",                  ##(估算值)扫描索引18行后,满足条件id<200的数据占扫描行数的比例,即驱动表扇出
          "index_condition": "(`sbtest`.`t3`.`k` < 200)",
          "cost_info": {
            "read_cost": "25.01",              ##这里包含了所有的IO成本+部分CPU成本
            "eval_cost": "1.20",               ##部分CPU成本:rows_produced_per_join*成本常数
            "prefix_cost": "26.21",            ##驱动表的总成本:read_cost+eval_cost
            "data_read_per_join": "4K"
          },
          "used_columns": [
            "id",
            "k"
          ],
          "attached_condition": "(`sbtest`.`t3`.`id` < 100)"
        }
      },
      {
        "table": {
          "table_name": "t1",                  ##t1为被驱动表
          "access_type": "eq_ref",             ##关联查询时访问驱动表方式是通过主键或唯一索引的等值查询
          "possible_keys": [
            "PRIMARY"
          ],
          "key": "PRIMARY",                    ##使用索引为主键
          "used_key_parts": [                  ##索引字段为id
            "id"
          ],
          "key_length": "4",
          "ref": [
            "sbtest.t3.id"
          ],
          "rows_examined_per_scan": 1,         ##关联查询时,每次扫描被驱动表1行数据(使用主键)
          "rows_produced_per_join": 5,         ##被驱动表t1的扇出,即估算的满足join条件的行数
          "filtered": "100.00",                ##关联查询后,(估算)满足join条件的行数占被驱动表t1总扫描行数的比例
          "using_index": true,                 ##t1总扫描行数=rows_examined_per_scan*驱动表扇出数=1*6=6
          "cost_info": {                      
            "read_cost": "6.00",               ##t1表总的IO成本:驱动表扇出数*单次查询被驱动表的IO成本=6*1*1.0=6
            "eval_cost": "1.20",               ##部分CPU成本:rows_produced_per_join*成本常数=6*0.2
            "prefix_cost": "33.41",            ##查询总成本=驱动表的总成本+被驱动表的(read_cost+eval_cost)
            "data_read_per_join": "5K"
          },
          "used_columns": [
            "id"
          ]
        }
      }
    ]
  }
}


eval_cost 是部分CPU成本,但是由于 filtered=100%,另一部分成本 rows_examined_per_scan*(1-filtered)*成本常数=0,所以 eval_cost 就相当于全部的CPU成本了。

join查询的总成本计算公式简化:连接查询总成本 = 访问驱动表的成本 + 访问被驱动表的成本。explain 执行计划详解1 中有解释 filtered 在关联查询中的重要性。

在上面示例中:访问驱动表的成本=26.21,被驱动表的成本=6+1.2=7.2
总成本=26.21+7.2=33.41

注意

被驱动表的 read_cost+eval_cost 不等于被驱动表的总成本,除非 filtered 等于100%。可以简化被驱动表的总成本计算公式:被驱动表的总成本= read_cost + eval_cost/filtered



感谢原作者:https://www.jianshu.com/p/f93b13323058


相关推荐

为何越来越多的编程语言使用JSON(为什么编程)

JSON是JavascriptObjectNotation的缩写,意思是Javascript对象表示法,是一种易于人类阅读和对编程友好的文本数据传递方法,是JavaScript语言规范定义的一个子...

何时在数据库中使用 JSON(数据库用json格式存储)

在本文中,您将了解何时应考虑将JSON数据类型添加到表中以及何时应避免使用它们。每天?分享?最新?软件?开发?,Devops,敏捷?,测试?以及?项目?管理?最新?,最热门?的?文章?,每天?花?...

MySQL 从零开始:05 数据类型(mysql数据类型有哪些,并举例)

前面的讲解中已经接触到了表的创建,表的创建是对字段的声明,比如:上述语句声明了字段的名称、类型、所占空间、默认值和是否可以为空等信息。其中的int、varchar、char和decimal都...

JSON对象花样进阶(json格式对象)

一、引言在现代Web开发中,JSON(JavaScriptObjectNotation)已经成为数据交换的标准格式。无论是从前端向后端发送数据,还是从后端接收数据,JSON都是不可或缺的一部分。...

深入理解 JSON 和 Form-data(json和formdata提交区别)

在讨论现代网络开发与API设计的语境下,理解客户端和服务器间如何有效且可靠地交换数据变得尤为关键。这里,特别值得关注的是两种主流数据格式:...

JSON 语法(json 语法 priority)

JSON语法是JavaScript语法的子集。JSON语法规则JSON语法是JavaScript对象表示法语法的子集。数据在名称/值对中数据由逗号分隔花括号保存对象方括号保存数组JS...

JSON语法详解(json的语法规则)

JSON语法规则JSON语法是JavaScript对象表示法语法的子集。数据在名称/值对中数据由逗号分隔大括号保存对象中括号保存数组注意:json的key是字符串,且必须是双引号,不能是单引号...

MySQL JSON数据类型操作(mysql的json)

概述mysql自5.7.8版本开始,就支持了json结构的数据存储和查询,这表明了mysql也在不断的学习和增加nosql数据库的有点。但mysql毕竟是关系型数据库,在处理json这种非结构化的数据...

JSON的数据模式(json数据格式示例)

像XML模式一样,JSON数据格式也有Schema,这是一个基于JSON格式的规范。JSON模式也以JSON格式编写。它用于验证JSON数据。JSON模式示例以下代码显示了基本的JSON模式。{"...

前端学习——JSON格式详解(后端json格式)

JSON(JavaScriptObjectNotation)是一种轻量级的数据交换格式。易于人阅读和编写。同时也易于机器解析和生成。它基于JavaScriptProgrammingLa...

什么是 JSON:详解 JSON 及其优势(什么叫json)

现在程序员还有谁不知道JSON吗?无论对于前端还是后端,JSON都是一种常见的数据格式。那么JSON到底是什么呢?JSON的定义...

PostgreSQL JSON 类型:处理结构化数据

PostgreSQL提供JSON类型,以存储结构化数据。JSON是一种开放的数据格式,可用于存储各种类型的值。什么是JSON类型?JSON类型表示JSON(JavaScriptO...

JavaScript:JSON、三种包装类(javascript 包)

JOSN:我们希望可以将一个对象在不同的语言中进行传递,以达到通信的目的,最佳方式就是将一个对象转换为字符串的形式JSON(JavaScriptObjectNotation)-JS的对象表示法...

Python数据分析 只要1分钟 教你玩转JSON 全程干货

Json简介:Json,全名JavaScriptObjectNotation,JSON(JavaScriptObjectNotation(记号、标记))是一种轻量级的数据交换格式。它基于J...

比较一下JSON与XML两种数据格式?(json和xml哪个好)

JSON(JavaScriptObjectNotation)和XML(eXtensibleMarkupLanguage)是在日常开发中比较常用的两种数据格式,它们主要的作用就是用来进行数据的传...

取消回复欢迎 发表评论:

请填写验证码