0
点赞
收藏
分享

微信扫一扫

MySQL 优化之执行SQL成本

吴陆奇 2022-02-13 阅读 53

EXPLAIN 升级版 EXPLAIN FORMAT=JSON SQL


一、demo 表介绍

CREATE TABLE IF NOT EXISTS {TABLE_NAME} (
  `id` varchar(32) NOT NULL,
  `time_recorded` datetime(0) NOT NULL,
  `time_updated` datetime(0) NOT NULL,
  `key1_column` int(11) NULL,
  `key2_column` int(11) NOT NULL,
  `key3_column` varchar(255) NOT NULL,
  `key4_column` varchar(255) NULL,
  `key5_column` varchar(255) NOT NULL,
  PRIMARY KEY (`id`),
  INDEX `index_key1`(`key1_column`),
  UNIQUE KEY `UK_key2`(`key2_column`),
  INDEX `key_column`(`key3_column`,`key4_column`,`key5_column`)
) ENGINE = InnoDB;

test_model数据量487623
test_model数据量

test_model2数据量1001
test_model2数据量

二、例句 SQL EXPLAIN

EXPLAIN例句
从EXPLAIN 中我们可得知SQL执行大体情况,唯独不清楚执行成本(// TODO 以后更EXPLAIN各字段解释博客),这些可以通过EXPLAIN 升级版 "EXPLAIN FORMAT=JSON"得到

三、例句 SQL , EXPLAIN FORMAT=JSON

# 执行SQL
EXPLAIN FORMAT=JSON SELECT * FROM test_model INNER JOIN test_model2 ON test_model.key2_column = test_model2.key2_column WHERE test_model.time_updated < "2022-02-13 15:13:56";
# 得到json数据:
{
  "query_block": {
    "select_id": 1, # 对应EXPLAIN id列
    "cost_info": { 
      "query_cost": "1419.40" # 查询整个语句,执行成本预计时间
    },
    "nested_loop": [ # 采用嵌到循环连接算法执行查询
    # 以下是参与嵌套循环连接算法的各个表的信息
      {
        "table": {
          "table_name": "test_model2", # 驱动表, 对应EXPLAIN table字段
          "access_type": "ALL", # 访问方法为ALL, 对应EXPLAIN type字段
          "possible_keys": [ # 可能使用的索引,对应EXPLAIN possible_keys字段
            "UK_key2"
          ],
          "rows_examined_per_scan": 1001, # 查询一次test_model2表大致需要扫描数据量
          "rows_produced_per_join": 1001, # 驱动表的扇出预计数量
          "filtered": "100.00", # condition filtering代表的百分比
          "cost_info": {
            "read_cost": "18.00", # IO成本 + 检查rows*(1-filter)条记录的CPU成本
            "eval_cost": "200.20", # 检查rows * filter条记录的成本
            "prefix_cost": "218.20", # 检查驱动表test_model2单独成本 read_cost + eval_cost
            "data_read_per_join": "805K" # 表示在此次查询中需要读取的数据量
          },
          "used_columns": [ # 执行查询中涉及的列
            "id",
            "time_recorded",
            "time_updated",
            "key1_column",
            "key2_column",
            "key3_column",
            "key4_column",
            "key5_column"
          ]
        }
      },
      {
        "table": {
          "table_name": "test_model", # 被驱动表, 对应EXPLAIN table字段
          "access_type": "eq_ref", # 对应EXPLAIN type字段
          "possible_keys": [ # 可能使用的索引,对应EXPLAIN possible_keys字段
            "UK_key2"
          ],
          "key": "UK_key2", # 实际使用的索引
          "used_key_parts": [ # 使用到的索引列
            "key2_column"
          ],
          "key_length": "4", # key length
          "ref": [ # 索引列进行等值匹配的对象,对应:test_model.key2_column = test_model2.key2_column
            "test_demo.test_model2.key2_column"
          ],
          "rows_examined_per_scan": 1, # 查询一次test_model大致需要扫描一条记录
          "rows_produced_per_join": 333, # 被驱动表test_model的扇出是968(由于后边没有多余的连接所以也没啥用)
          "filtered": "33.33", # condition filtering代表百分比
          "cost_info": { 
            "read_cost": "1001.00", # read_cost 和 eval_cost 是访问多次累加起来的指
            "eval_cost": "66.73",
            "prefix_cost": "1419.40", # 整个连接查询预计的成本也就是单词查询test_demo2和多次查询test_demo的成本和
            "data_read_per_join": "268k" # 表示在查询中需要读取的数据量
          },
          "used_columns": [
            "id",
            "time_recorded",
            "time_updated",
            "key1_column",
            "key2_column",
            "key3_column",
            "key4_column",
            "key5_column"
          ],
          "attached_condition": "(`test_demo`.`test_model`.`time_updated` < '2022-02-13 15:13:56')" # 对test_model表访问时,针对单表查询的条件
        }
      }
    ]
  }
}

总结

可以通过"EXPLAIN FORMAT=JSON" 找出SQL执行成本

参考资料: 《MySQL是怎样运行的》

举报

相关推荐

0 条评论