跳到主要内容

性能剖析

性能剖析是理解查询性能特征的重要手段。 Goose 内置了多种查询剖析能力,本页进行说明。 如需 EXPLAIN 的高层示例,请参阅 “Inspect Query Plans” 页面

语句

EXPLAIN 语句

查询剖析的第一步通常是查看查询计划。 EXPLAIN 会展示查询计划并说明底层执行过程。

EXPLAIN ANALYZE 语句

查询计划有助于理解性能特征。 但很多场景还需查看各算子的耗时与经过它们的基数。 EXPLAIN ANALYZE 会在格式化输出查询计划的同时执行查询,从而给出真实运行时性能数据。

FORMAT 选项

EXPLAIN [ANALYZE] 支持导出多种格式:

  • text:默认 ASCII-art 样式输出
  • graphviz:输出 DOT,可用 Graphviz 渲染
  • html:输出 HTML,可用 treeflex 渲染
  • json:输出 JSON

通过 FORMAT 指定输出格式:

EXPLAIN (FORMAT html) SELECT 42 AS x;

Pragmas

Goose 支持多种 pragma,用于开启/关闭 profiling 以及控制输出细节级别。

以下 pragma 可通过 PRAGMASET 设置。 也可通过 RESET 加设置名恢复默认值。 更多信息请见 pragmas 页面中的 “Profiling” 小节。

设置说明默认值可选值
enable_profiling, enable_profile开启 profilingquery_treequery_tree, json, query_tree_optimizer, no_output
profiling_coverage设置要剖析的语句范围SELECTSELECT, ALL
profiling_output设置 profiling 输出文件Console文件路径
profiling_mode切换附加优化器/规划器指标standardstandard, detailed
custom_profiling_settings启用或禁用特定指标除 detailed 模式附加指标外全部启用JSON 对象:{"METRIC_NAME": "boolean", ...},见下方 metrics 小节。
disable_profiling, disable_profile关闭 profiling

指标

查询树中有两类节点:QUERY_ROOTOPERATORQUERY_ROOT 是顶层节点,其指标覆盖整个查询。 OPERATOR 节点对应查询计划中的各个算子。 部分指标仅适用于 QUERY_ROOT,部分仅适用于 OPERATOR。 下表给出各指标及其适用节点。

QUERY_NAMEOPERATOR_TYPE 外,其余指标都可单独开关。

MetricReturn typeUnitQueryOperatorDescription
BLOCKED_THREAD_TIMEdoublesecondsThe total time threads are blocked
EXTRA_INFOstringUnique operator metrics
LATENCYdoublesecondsThe total elapsed query execution time
OPERATOR_CARDINALITYuint64absoluteThe cardinality of each operator, i.e., the number of rows it returns to its parent. Operator equivalent of ROWS_RETURNED
OPERATOR_ROWS_SCANNEDuint64absoluteThe total rows scanned by each operator
OPERATOR_TIMINGdoublesecondsThe time taken by each operator. Operator equivalent of LATENCY
OPERATOR_TYPEstringThe name of each operator
QUERY_NAMEstringThe query string
RESULT_SET_SIZEuint64bytesThe size of the result
ROWS_RETURNEDuint64absoluteThe number of rows returned by the query

累计指标

Goose 还支持若干在所有节点可用的累计指标。 在 QUERY_ROOT 中,它们表示整个查询所有算子对应指标的总和。 在 OPERATOR 中,它们表示当前算子及其所有子节点对应指标的递归总和。

累计指标可独立启用,即使底层具体指标被禁用也可以。 下表展示累计指标及其基于的原始指标。

MetricUnitMetric calculated cumulatively
CPU_TIMEsecondsOPERATOR_TIMING
CUMULATIVE_CARDINALITYabsoluteOPERATOR_CARDINALITY
CUMULATIVE_ROWS_SCANNEDabsoluteOPERATOR_ROWS_SCANNED

CPU_TIME 衡量算子耗时总和, 不包含解析、查询规划等其他阶段耗时。 因此某些查询中,QUERY_ROOTLATENCY 可能大于 CPU_TIME

详细 Profiling

profiling_mode 设为 detailed 时,会启用一组仅在 QUERY_ROOT 可见的附加指标, 包括 OPTIMIZERPLANNERPHYSICAL_PLANNER。 这些指标单位为秒,返回类型为 double,且可逐项开关。

Optimizer 指标

QUERY_ROOT 节点中,可查看各optimizer耗时指标。 仅在对应优化器启用时可见。 可通过 goose_optimizers() 表函数查询可用优化器。

每个优化器对应一个指标,命名模板为 OPTIMIZER_⟨OPTIMIZER_NAME⟩。 例如 OPTIMIZER_JOIN_ORDER 对应 JOIN_ORDER 优化器。

此外,还有以下辅助指标:

  • ALL_OPTIMIZERS:启用全部优化器指标,并统计优化器父节点耗时。
  • CUMULATIVE_OPTIMIZER_TIMING:所有优化器指标累计和,无需启用全部优化器指标即可使用。

Planner 指标

planner 负责生成逻辑计划。目前 Goose 提供两项 planner 指标:

  • PLANNER:从已解析 SQL 节点生成逻辑计划的耗时。
  • PLANNER_BINDING:逻辑计划绑定耗时。

Physical Planner 指标

physical planner 负责从逻辑计划生成物理计划。 支持以下指标:

  • PHYSICAL_PLANNER:生成物理计划总耗时。
  • PHYSICAL_PLANNER_COLUMN_BINDING:将逻辑列绑定到物理列的耗时。
  • PHYSICAL_PLANNER_RESOLVE_TYPES:将逻辑类型解析到物理类型的耗时。
  • PHYSICAL_PLANNER_CREATE_PLAN:创建物理计划阶段耗时。

自定义指标示例

以下示例展示如何启用自定义 profiling 并将输出设为 json。 第一个示例中我们启用 profiling 并输出到文件, 只开启 EXTRA_INFOOPERATOR_CARDINALITYOPERATOR_TIMING

CREATE TABLE students (name VARCHAR, sid INTEGER);
CREATE TABLE exams (eid INTEGER, subject VARCHAR, sid INTEGER);
INSERT INTO students VALUES ('Mark', 1), ('Joe', 2), ('Matthew', 3);
INSERT INTO exams VALUES (10, 'Physics', 1), (20, 'Chemistry', 2), (30, 'Literature', 3);

PRAGMA enable_profiling = 'json';
PRAGMA profiling_output = '/path/to/file.json';

PRAGMA custom_profiling_settings = '{"CPU_TIME": "false", "EXTRA_INFO": "true", "OPERATOR_CARDINALITY": "true", "OPERATOR_TIMING": "true"}';

SELECT name
FROM students
JOIN exams USING (sid)
WHERE name LIKE 'Ma%';

执行查询后文件内容如下:

{
"extra_info": {},
"query_name": "SELECT name\nFROM students\nJOIN exams USING (sid)\nWHERE name LIKE 'Ma%';",
"children": [
{
"operator_timing": 0.000001,
"operator_cardinality": 2,
"operator_type": "PROJECTION",
"extra_info": {
"Projections": "name",
"Estimated Cardinality": "1"
},
"children": [
{
"extra_info": {
"Join Type": "INNER",
"Conditions": "sid = sid",
"Build Min": "1",
"Build Max": "3",
"Estimated Cardinality": "1"
},
"operator_cardinality": 2,
"operator_type": "HASH_JOIN",
"operator_timing": 0.00023899999999999998,
"children": [
...

第二个示例会在输出中增加 detailed 指标。

PRAGMA profiling_mode = 'detailed';

SELECT name
FROM students
JOIN exams USING (sid)
WHERE name LIKE 'Ma%';

输出文件内容如下:

{
"all_optimizers": 0.001413,
"cumulative_optimizer_timing": 0.0014120000000000003,
"planner": 0.000873,
"planner_binding": 0.000869,
"physical_planner": 0.000236,
"physical_planner_column_binding": 0.000005,
"physical_planner_resolve_types": 0.000001,
"physical_planner_create_plan": 0.000226,
"optimizer_expression_rewriter": 0.000029,
"optimizer_filter_pullup": 0.000002,
"optimizer_filter_pushdown": 0.000102,
...
"optimizer_column_lifetime": 0.000009999999999999999,
"rows_returned": 2,
"latency": 0.003708,
"cumulative_rows_scanned": 6,
"cumulative_cardinality": 11,
"extra_info": {},
"cpu_time": 0.000095,
"optimizer_build_side_probe_side": 0.000017,
"result_set_size": 32,
"blocked_thread_time": 0.0,
"query_name": "SELECT name\nFROM students\nJOIN exams USING (sid)\nWHERE name LIKE 'Ma%';",
"children": [
{
"operator_timing": 0.000001,
"operator_rows_scanned": 0,
"cumulative_rows_scanned": 6,
"operator_cardinality": 2,
"operator_type": "PROJECTION",
"cumulative_cardinality": 11,
"extra_info": {
"Projections": "name",
"Estimated Cardinality": "1"
},
"result_set_size": 32,
"cpu_time": 0.000095,
"children": [
...

查询图

profiling 输出也可以渲染为查询图。 查询图会可视化展示查询计划中的算子及其关系。 查询计划需先以 json 格式输出到文件。 随后可用 Python 脚本将其渲染为查询图。 该脚本依赖已安装的 goose Python 模块。 它会生成 HTML 文件并在浏览器中打开。

python -m goose.query_graph /path/to/file.json

查询计划中的记号

在查询计划中,hash join 采用如下约定: join 的 probe side 为左操作数,build side 为右操作数。

查询计划中的 join 算子会标明使用的 join 类型:

  • 内连接记为 INNER
  • 左/右外连接分别记为 LEFT / RIGHT
  • 全外连接记为 FULL

提示:如需可视化查询计划,可使用Goose execution plan visualizer(由图宾根大学数据库系统研究组开发)。