前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >技术译文 | MySQL 8.1 和 8.2 中 EXPLAIN 的新玩法

技术译文 | MySQL 8.1 和 8.2 中 EXPLAIN 的新玩法

作者头像
爱可生开源社区
发布2024-01-04 12:52:41
1360
发布2024-01-04 12:52:41
举报

作者:Magnus Brevik

本文来源:https://dev.mysql.com/blog-archive/,爱可生开源社区翻译。

本文约 900 字,预计阅读需要 3 分钟。

1EXPLAIN INTO

从 MySQL 8.1 开始 EXPLAIN 引入了 INTO 子句,它允许将 EXPLAIN 查询的输出存储在用户变量中,而不是将其返回给客户端。目前仅支持 JSON 格式,但这对于大多数用例来说应该足够了。

EXPLAIN 的输出存储在用户变量之后,就可以将它当成 JSON 对象操作。这使您能够以编程方式直接从 EXPLAIN中提取、操作和存储数据到数据库中。

举个例子:

代码语言:javascript
复制
mysql> SELECT name, quantity FROM orders JOIN items ON orders.item_id = items.id;
+-------------+----------+
| name        | quantity |
+-------------+----------+
| Screwdriver |       23 |
| Screwdriver |        1 |
| Locket      |       17 |
| Armoire     |       42 |
| Armoire     |       16 |
+-------------+----------+

如果只对此次查询的开销成本感兴趣,可以先将查询定义为为 @explain_output

代码语言:javascript
复制
mysql> EXPLAIN FORMAT=JSON INTO @explain_output SELECT name, quantity FROM orders JOIN items ON orders.item_id = items.id;
Query OK, 0 rows affected (0,00 sec)

现在,从这个 EXPLAIN 中得到的唯一输出是“Query OK”。如果我们想查看完整的 EXPLAIN 输出,我们可以选择 @explain_output,但是完整的 JSON 输出会占用很大的空间,而且我只对开销(cost )感兴趣。为了从 JSON 对象中提取,只需使用 MySQL 的 JSON 函数对指定的 JSON 对象处理即可。

代码语言:javascript
复制
mysql> SELECT JSON_EXTRACT(@explain_output, "$.query_block.cost_info.query_cost") AS query_cost;
+------------+
| query_cost |
+------------+
| "1.60"     |
+------------+

2EXPLAIN SCHEMA

从 MySQL 8.2 开始 EXPLAIN 引入了 FOR SCHEMA 子句。它允许在当前 SCHEMA 之外的其他 SCHEMA 中执行 EXPLAIN 查询。这使得创建一个存储过程 PROCEDURE 来解释每个 SCHEMA 中最常运行的查询并收集有关它们的统计信息成为可能。

如果当前的 SCHEMA 与我们要查询的表所在的 SCHEMA 不同,我们可以

代码语言:javascript
复制
mysql> USE statistics;
mysql> EXPLAIN FORMAT=TREE FOR SCHEMA customer1 SELECT name, quantity FROM orders JOIN items ON orders.item_id = items.id;
-> Nested loop inner join  (cost=2.3 rows=5)
    -> Table scan on items  (cost=0.55 rows=3)
    -> Index lookup on orders using fk_item_id (item_id=items.id)  (cost=0.472 rows=1.67)

这对于大多数 EXPLAIN 使用的情况可能不太有用,但是如果我们有多个具有相同表结构的 SCHEMA,并且想要一次性收集所有 SCHEMA 的统计信息,我们可以创建一个存储过程 PROCEDURE 来为我们做到这一点:

代码语言:javascript
复制
DELIMITER |
CREATE PROCEDURE explain_query_for_schema(IN schema_name VARCHAR(64), IN query VARCHAR(1000))
BEGIN
    SET @explain_stmt = CONCAT("EXPLAIN FORMAT=JSON INTO @explain_output FOR SCHEMA ", schema_name, " ", query);
    PREPARE stmt FROM @explain_stmt;
    EXECUTE stmt;
    INSERT INTO explain_outputs (schema_name, query, explain_output) VALUES (schema_name, query, @explain_output);
END |

CREATE PROCEDURE explain_query_for_all_schemas(IN query VARCHAR(1000))
BEGIN
    DECLARE done BOOLEAN DEFAULT FALSE;
    DECLARE schema_name VARCHAR(64);
    DECLARE cur_schema_names CURSOR FOR SELECT schema_name_table.schema_name FROM schema_name_table;
    DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
    OPEN cur_schema_names;

    explain_loop: LOOP
        FETCH cur_schema_names INTO schema_name;
        IF done THEN
            LEAVE explain_loop;
        END IF;
        CALL explain_query_for_schema(schema_name, query);
    END LOOP;
    CLOSE cur_schema_names;
END |
DELIMITER ;

SET @query = "SELECT name, quantity FROM orders JOIN items ON orders.item_id = items.id";
CALL explain_query_for_all_schemas(@query);

SELECT schema_name, query, JSON_EXTRACT(explain_output, "$.query_block.cost_info.query_cost") AS query_cost, created_at FROM explain_outputs;
+-------------+---------------------------------------------------------------------------+------------+---------------------+
| schema_name | query                                                                     | query_cost | created_at          |
+-------------+---------------------------------------------------------------------------+------------+---------------------+
| customer1   | SELECT name, quantity FROM orders JOIN items ON orders.item_id = items.id | "2.30"     | 2023-11-14 20:56:47 |
| customer2   | SELECT name, quantity FROM orders JOIN items ON orders.item_id = items.id | "0.70"     | 2023-11-14 20:56:47 |
| customer3   | SELECT name, quantity FROM orders JOIN items ON orders.item_id = items.id | "9.10"     | 2023-11-14 20:56:47 |
+-------------+---------------------------------------------------------------------------+------------+---------------------+

就是这样。EXPLAIN 的两个相对简单的扩展乍一看可能并不重要,但使存储过程能够以编程方式处理 EXPLAIN 输出。我们自己将其用于 《使用 MySQL Autopilot Indexing 删除索引猜测值》[1] 这个案例中,其中 EXPLAIN INTOEXPLAIN FOR SCHEMA 对于收集数据以建议更好的索引至关重要。我们希望它对您和我们一样有用。

如果您想了解更多信息,这些都记录在 MySQL EXPLAIN 文档[2] 中。

参考资料

[1]

MySQL Autopilot Indexing: https://blogs.oracle.com/mysql/post/removing-the-index-guesstimate-with-mysql-autopilot-indexing

[2]

explain: https://dev.mysql.com/doc/refman/8.2/en/explain.html

本文原文:https://dev.mysql.com/blog-archive/explain-into-and-explain-for-schema-in-mysql-81-and-82/

本文关键字:#MySQL 8# #优化器# #翻译#

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2024-01-02,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 爱可生开源社区 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1EXPLAIN INTO
  • 2EXPLAIN SCHEMA
    • 参考资料
    相关产品与服务
    对象存储
    对象存储(Cloud Object Storage,COS)是由腾讯云推出的无目录层次结构、无数据格式限制,可容纳海量数据且支持 HTTP/HTTPS 协议访问的分布式存储服务。腾讯云 COS 的存储桶空间无容量上限,无需分区管理,适用于 CDN 数据分发、数据万象处理或大数据计算与分析的数据湖等多种场景。
    领券
    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档