获取和分析 AlloyDB 执行计划

您可以获取并分析执行计划,从而找出性能瓶颈并优化 AlloyDB for PostgreSQL 数据库操作。执行计划EXPLAIN 计划详细表示了 AlloyDB 数据库引擎打算如何执行 SQL 查询。执行计划包含一个节点树,其中概述了 AlloyDB 数据库为检索所请求的数据而执行的操作序列,例如表扫描、联接、排序和聚合。此计划中的每个步骤都称为“节点”

执行计划是通过使用 EXPLAIN 命令获得的,该命令会返回 AlloyDB 查询规划器针对给定 SQL 语句生成的计划。查询规划器(也称为优化器)会确定执行给定 SQL 查询的最有效方式。

执行计划包含以下组件:

  • 计划节点:表示查询执行中的不同步骤,例如扫描、联接或排序操作。
  • 执行时间:EXPLAIN 计划包含每个步骤的估计或实际执行时间,有助于您找出数据库瓶颈。
  • 缓冲区使用情况:此图表显示了从磁盘读取的数据量与从缓存读取的数据量,有助于识别磁盘读取问题。
  • 参数设置:该计划会显示在查询执行期间生效的参数设置。

PostgreSQL(以及 AlloyDB)支持以下语句的执行计划:

  • SELECT
  • INSERT
  • UPDATE
  • DECLARE CURSOR
  • CREATE AS
  • CREATE MATERIALIZED VIEW
  • REFRESH MATERIALIZED VIEW
  • EXECUTE

准备工作

您必须拥有 AlloyDB 集群和实例。如需了解详情,请参阅创建集群及其主实例

生成执行计划

您可以通过 psql、pgAdmin 或 DBeaver 等客户端应用生成执行计划。AlloyDB 支持以文本或 JSON 格式生成执行计划。

如需生成执行计划,请按以下步骤操作:

  1. 将 psql 客户端连接到实例
  2. 如需生成文本格式的执行计划,请运行以下命令:

    SET enable_ultra_fast_cache_explain_output TO ON; /* AlloyDB Specific Command */
    EXPLAIN (analyze, verbose, columnar_engine, costs, settings, buffers, wal, timing, summary, format text)
    
  3. 如需生成 JSON 格式的执行计划,请运行以下命令:

    SET enable_ultra_fast_cache_explain_output TO ON; /* AlloyDB Specific Command */
    EXPLAIN (analyze, verbose, columnar_engine, costs, settings, buffers, wal, timing, summary, format json)
    

    EXPLAIN 命令包含所有可用选项(analyzeverbosecolumnar_enginecostssettingsbufferswaltimingsummary),用于以文本或 JSON 格式为指定查询生成详细的执行计划。analyze 选项表示执行查询以提供实际运行时统计信息以及查询规划器的估计值。

查看和分析 EXPLAIN 计划数据

获得执行计划后,您可以查看和分析结果。

默认情况下,EXPLAIN 输出会显示服务器端查询活动。如需测量端到端往返时间,请在 psql 中使用 /timing 选项,并将结果转储到 /dev/null

如需查看您生成的执行计划,请在 SQL 查询之前使用 EXPLAIN 命令。

  • EXPLAIN SELECT...:显示优化器在不运行查询的情况下会选择的计划。
  • EXPLAIN ANALYZE SELECT...:执行查询并显示预测计划和实际执行统计信息,包括实际运行时间和行数。

EXPLAIN,但不进行 ANALYZE

如需显示查询规划器的估计查询费用,请执行不含 ANALYZE 选项的 EXPLAIN 语句。

(postgres@10.3.1.17:5432) [postgres] > EXPLAIN select * from public.index_advisor_test;
                                   QUERY PLAN
---------------------------------------------------------------------------------
 Seq Scan on index_advisor_test  (cost=0.00..1735481.00 rows=100000000 width=27)
 AlloyDB query id: 7588555592527881263
 AlloyDB plan id: 16134093550604823483
(3 rows)

方案输出包含以下数据:

  • cost = 0.00..1735481.00:第一个数字表示检索第一行的费用。第二个数字表示检索最后一行的费用。
  • rows = 100000000:这是查询返回的估计行数。
  • width = 27:这是返回行的估计宽度,有助于您了解访问的块。

ANALYZE 选项

如需显示实际执行统计信息以及执行估计值,请添加 ANALYZE 选项

(postgres@10.3.1.17:5432) [postgres] > EXPLAIN (ANALYZE) select * from public.index_advisor_test;
                                   QUERY PLAN
---------------------------------------------------------------------------------
 Seq Scan on index_advisor_test  (cost=0.00..1735481.00 rows=100000000 width=27) (actual time=0.165..9342.424 rows=100000001 loops=1)
 Planning Time: 0.025 ms
 Execution Time: 13674.794 ms
 AlloyDB query id: 7588555592527881263
 AlloyDB plan id: 16134093550604823483
(5 rows)

方案输出包含以下数据:

  • 实际时间(以毫秒为单位)= 0.165..9342.424:这表示返回第一行的实际时间以及返回所有行的总时间。
  • rows = 100000001:这是实际返回的行数。
  • loops = 1:此值对于嵌套循环节点非常重要。如果 loops 大于 1,则显示每个循环的平均时间。
  • 规划时间:0.025 毫秒:表示规划器确定执行路径所用的时间。
  • 执行时间:13674.794 毫秒:这表示规划器确定路径后执行所用的时间。
  • 总执行时间Planning TimeExecution Time 的总和。(0.025 + 13674.794 = 13674.819)

VERBOSE 选项

如需向执行计划添加更多信息,请使用 VERBOSE 选项。在以下示例中,使用 VERBOSE 会向表名称添加架构限定,并显示一个内部查询标识符,您可以使用该标识符将查询与其他监控工具相关联。

(postgres@10.3.1.17:5432) [postgres] > EXPLAIN (ANALYZE,VERBOSE) select * from public.index_advisor_test;
                                   QUERY PLAN
---------------------------------------------------------------------------------
Seq Scan on public.index_advisor_test  (cost=0.00..1735481.00 rows=100000000 width=27) (actual time=0.164..6568.938 rows=100000001 loops=1)
   Output: id, value, product_id, effective_date
 Query Identifier: -5175350694118300766
 Planning Time: 0.027 ms
 Execution Time: 10875.894 ms
 AlloyDB query id: 7588555592527881263
 AlloyDB plan id: 16134093550604823483

方案输出包含以下数据:

  • 输出节点:列出查询中包含的列。如果规划器确定舍弃某些列的成本更高,有时会包含比请求更多的列。
  • 查询标识符:与 pg_stat_statements 对应的 PostgreSQL 标识符。
  • AlloyDB 查询 ID:可用于关联查询洞见信息的 AlloyDB 查询标识符

COLUMNAR ENGINE 选项

如需显示 AlloyDB 列式引擎的相关信息,请添加 COLUMNAR_ENGINE 选项。

如果列式引擎中不存在相应表,请参阅以下执行计划中的列式检查列,了解状态。

(postgres@10.3.1.17:5432) [postgres] > EXPLAIN (ANALYZE,VERBOSE, COLUMNAR_ENGINE) select * from public.index_advisor_test;
                                   QUERY PLAN
---------------------------------------------------------------------------------
Seq Scan on public.index_advisor_test  (cost=0.00..1735481.00 rows=100000000 width=27) (actual time=0.009..6328.154 rows=100000001 loops=1)
   Output: id, value, product_id, effective_date
   Columnar Check: table is not in the columnar store
 Query Identifier: -5175350694118300766
 Planning Time: 0.027 ms
 Execution Time: 10673.310 ms
 AlloyDB query id: 7588555592527881263
 AlloyDB plan id: 16134093550604823483

如果列式引擎中存在相应表,并且使用了列式引擎,则系统会显示自定义扫描,以及有关列式引擎使用情况的统计信息。

(postgres@10.3.1.17:5432) [postgres] > EXPLAIN (ANALYZE,VERBOSE, COLUMNAR_ENGINE) select * from public.index_advisor_test where product_id = 1;
                                   QUERY PLAN
---------------------------------------------------------------------------------
Append  (cost=20.00..27438.78 rows=1166668 width=27) (actual time=0.066..377.029 rows=1000290 loops=1)
   ->  Custom Scan (columnar scan) on public.index_advisor_test  (cost=20.00..27437.66 rows=1166667 width=27) (actual time=0.065..296.904 rows=1000290 loops=1)
         Output: id, value, product_id, effective_date
         Filter: (index_advisor_test.product_id = 1)
         Rows Removed by Columnar Filter: 98999711
         Bytes fetched from storage cache: 774835915
         Columnar cache search mode: native
         Swap-in Time: 92.708 ms
   ->  Seq Scan on public.index_advisor_test  (cost=0.00..1.11 rows=1 width=27) (never executed)
         Output: id, value, product_id, effective_date
         Filter: (index_advisor_test.product_id = 1)
 Query Identifier: -4660018746142248761
 Planning Time: 0.217 ms
 Execution Time: 421.114 ms
 AlloyDB query id: 13855683355620344431
 AlloyDB plan id: 2126918133221480510

方案输出包含以下数据:

  • 查询过滤条件(谓词):显示您使用的过滤条件(如果有)。
  • 列式过滤器移除的行数:表示列式过滤器移除的行数。
  • 从存储缓存中提取的字节数:显示从存储缓存中检索的字节数。
  • 换入时间:如果关系不适合放入内存,则从列式溢出缓存 (SSD) 交换数据所需的时间。

“设置”选项

如需显示规划器使用的任何非默认会话、数据库或全局设置,请添加 SETTINGS 选项。

(postgres@10.3.1.17:5432) [postgres] > EXPLAIN (ANALYZE,VERBOSE, COLUMNAR_ENGINE,COSTS,SETTINGS) select * from public.index_advisor_test;

                                   QUERY PLAN
---------------------------------------------------------------------------------
Seq Scan on public.index_advisor_test  (cost=0.00..1735481.00 rows=100000000 width=27) (actual time=0.007..6366.249 rows=100000001 loops=1)
   Output: id, value, product_id, effective_date
   Columnar Check: table is not in the columnar store
 Settings: effective_cache_size = '19690120kB', random_page_cost = '1.1', work_mem = '256MB'
 Query Identifier: -5175350694118300766
 Planning Time: 0.027 ms
 Execution Time: 10727.068 ms
 AlloyDB query id: 7588555592527881263
 AlloyDB plan id: 16134093550604823483

BUFFERS 选项

如需显示有关数据源的信息,请使用 BUFFERS 关键字。BUFFERS 数量会从所有步骤累积,而不仅仅是计划中的特定步骤。

(postgres@10.3.1.17:5432) [postgres] > EXPLAIN (ANALYZE,VERBOSE, COLUMNAR_ENGINE,COSTS,SETTINGS, BUFFERS) select * from public.effective_io_concurrency_test;

                                   QUERY PLAN
---------------------------------------------------------------------------------
Seq Scan on public.effective_io_concurrency_test  (cost=0.00..1844356.96 rows=100058296 width=31) (actual time=0.111..10007.193 rows=100000001 loops=1)
   Output: id, value, product_id, effective_date
   Buffers: shared hit=1185 read=842625 dirtied=1, ultra fast cache hit=842625
   I/O Timings: shared read=2588.597
   Columnar Check: table is not in the columnar store
 Settings: effective_cache_size = '19690120kB', random_page_cost = '1.1', work_mem = '256MB'
 Query Identifier: -5987221491374921441
 Planning:
   Buffers: shared hit=58 read=2, ultra fast cache hit=2
   I/O Timings: shared read=0.215
 Planning Time: 0.410 ms
 Execution Time: 14825.271 ms
 AlloyDB query id: 12754549874439071326
 AlloyDB plan id: 13656575252012920931

缓冲区信息包括以下内容:

  • 共享命中:在 PostgreSQL 的主共享缓冲区缓存中找到的 8kB 数据块的数量。
  • 共享读取:从操作系统读取的 8kB 数据块的数量。这通常表示磁盘 I/O。
  • dirtied:查询更改的之前未修改的块数(可见性地图更改)。
  • 写入:在查询处理期间,此后端从缓存中逐出的之前已脏的块的数量,通常是由于提示位或可见性映射发生变化,并已刷新到磁盘。
  • 超快缓存命中:从超快缓存中检索的块数。
  • I/O Timings:任何磁盘或 SSD I/O 的时长(以毫秒为单位)。
  • 规划:规划阶段的缓冲活动,例如从目录表中读取元数据或统计信息。
  • 规划期间花费在 I/O 上的时间:如果需要从磁盘读取任何元数据,则会显示 I/O 时间。

WAL 选项

如需提供有关预写式日志记录 (WAL) 活动的信息,请使用 WAL 选项。

(postgres@10.3.1.17:5432) [postgres] > EXPLAIN (ANALYZE,VERBOSE, COLUMNAR_ENGINE,COSTS,SETTINGS, BUFFERS, WAL) select * from public.effective_io_concurrency_test;

                                   QUERY PLAN
---------------------------------------------------------------------------------
Seq Scan on public.effective_io_concurrency_test  (cost=0.00..1844356.96 rows=100058296 width=31) (actual time=0.010..10147.314 rows=100000001 loops=1)
   Output: id, value, product_id, effective_date
   Buffers: shared hit=1185 read=842625 dirtied=1, ultra fast cache hit=842625
   I/O Timings: shared read=2590.410
   WAL: records=18 bytes=5178
   Columnar Check: table is not in the columnar store
 Settings: effective_cache_size = '19690120kB', random_page_cost = '1.1', work_mem = '256MB'
 Query Identifier: -5987221491374921441
 Planning Time: 0.030 ms
 Execution Time: 15033.004 ms
 AlloyDB query id: 12754549874439071326
 AlloyDB plan id: 13656575252012920931

WAL 信息包括以下内容:

  • WAL 记录:为保持一致性而读取的 WAL 记录数。
  • WAL 字节数:为保持一致性而从 WAL 读取的字节数。
  • 已修改但尚未检查点的记录:表示已修改但尚未检查点的记录。

后续步骤