使用查询配置文件分析查询

查询配置文件(可通过 Classic Console 获取)提供查询的执行详细信息。对于选定的查询,它提供了查询处理计划的主要组件的图形表示形式,其中包含每个组件的统计信息,以及整个查询的详细信息和统计信息。

本主题内容:

简介

何时使用查询配置文件

查询配置文件是用于了解查询机制的强大工具。每当您想要或需要了解有关特定查询的性能或行为的更多信息时,都可以使用它。它旨在帮助您发现 SQL 查询表达式中的典型错误,以识别潜在的性能瓶颈和改进机会。

有关各个查询的其他高级信息可以在 Worksheets Worksheet 选项卡History History 选项卡 页面的各个列中查看。

如何访问查询配置文件

从查询的详细信息页面访问查询配置文件。因此,您可以从显示 Query ID 列的任何页面访问查询配置文件,并且可以点击查询 IDs,具体如下:

  • Worksheets Worksheet 选项卡

  • History History 选项卡

备注

如果这些页面上未显示 Query ID 列,请点击页面上某个列标题旁边的下拉列表,然后在 Columns 列表中选择 Query ID

要访问查询的配置文件,请执行以下操作:

  1. History History 选项卡Worksheets Worksheet 选项卡 页面中,点击 ID。

  2. 将显示查询的详细信息页面:

    ../_images/ui-profile-detail.png
  3. 点击 Profile 选项卡。

  4. 如果查询具有配置文件,则会显示该配置文件(请参阅下方屏幕截图)。

查询配置文件接口

在本主题中,我们将使用连接两个表的基本示例 SQL 查询:

select sum(j)
from x join y using (i)
where j > 300
and i < (select avg(j) from x);
Copy

以下屏幕截图显示了此查询的配置文件:

../_images/ui-profile-step1.png

该接口由以下主要元素组成:

步骤:

如果查询是分多个步骤处理的,则可以在每个步骤之间切换。

运算符树:

中间窗格显示所选步骤的所有操作符节点的图形表示,包括每个操作符节点之间的关系。

节点列表:

中间窗格包括按执行时间划分的运算符节点的可折叠列表。

概述:

右窗格显示查询配置文件的概述。选择运算符节点时,显示将更改为运算符详细信息。

步骤

查询通常分多个步骤进行处理。例如,我们的示例查询分 2 个步骤处理:

  • 第 1 步:计算 x.j 列的平均值。

  • 第 2 步:使用此中间结果来计算最终查询结果。

查询配置文件在单独的面板中显示每个处理步骤。您可以通过点击相应的步骤在面板之间切换。对于示例查询,点击 Step 2 会将视图更改为:

../_images/ui-profile-step2.png

运算符树

该树提供了构成查询的运算符节点的图形表示形式,以及连接每个运算符的链接:

  • 运算符是查询的功能构建基块。负责数据管理和处理的不同方面,包括数据访问、转换和更新。树中的每个运算符节点都包含一些基本属性:

    <Type> [#]:

    运算符类型和 ID 编号。ID 可用于唯一标识查询配置文件中的运算符(例如上面屏幕截图中的 Aggregate [5]Join [11] )。

    有关所有类型的说明,请参阅下方的 运算符类型

    百分比:

    此运算符在查询步骤中消耗的时间比例(例如, Aggregate [5]25%)。此信息也反映在运算符节点底部的橙色条中,以便于直观地识别性能关键型运算符。

    标签:

    特定于运算符的附加信息(例如 Aggregate [5]SUM(X.J))。

  • 链接表示在每个运算符节点之间流动的数据。每个链接提供已处理的记录数(例如,从 Join [11]Aggregate [5]41.95M)。

备注

如果使用触摸屏并且未显示操作树,则触摸屏的触摸事件界面可能会受到干扰。有关暂时禁用该界面的说明,请参阅 Snowflake 社区论坛中的讨论: 查询配置文件窗口显示概述,但不显示查询树。 (https://community.snowflake.com/s/question/0D50Z00007OfRQrSAN/query-profile-window-shows-the-overview-but-does-not-show-the-query-tree-does-anyone-have-the-same-issue-and-how-did-you-solve-it-thanks) 。

按执行时间划分的运算符节点

该运算符树面板中的可折叠面板按执行时间降序列出节点,使用户能够根据执行时间快速找到成本最高的运算符节点。该面板列出了持续时间占查询执行总计时间的 1% 或更长时间的所有节点(如果查询是在多个处理步骤中执行的,则为所显示查询步骤的执行时间)。

点击列表中的节点会使运算符树在所选节点上居中。

以下屏幕截图显示了点击 汇总 [5] 运算符后的面板:

../_images/ui-profile-nodes-by-execution-time.png

配置文件概述/运算符详细信息

右侧的概述/详细信息面板提供有关左侧树中所选组件(运算符和链接)的信息。显示的信息取决于是否选择了运算符树中的节点:

  • 最初,树中没有选择任何节点,因此面板显示当前步骤的概述信息。

  • 通过点击节点选择组件时,面板将显示该组件的信息。

备注

点击节点后,要返回到步骤级概述信息,只需通过点击运算符树周围的任何空白区域来取消选择该节点即可。

概述/详细信息面板分为 3 个部分:

执行时间:

提供有关哪些处理任务占用了查询时间的信息(请参阅下文中的 查询/运算符详细信息)。此外,对于步骤级信息,将显示给定步骤的状态及其执行时间。

统计信息:

提供有关各种统计信息的详细信息(请参阅下文中的 查询/运算符详细信息)。

属性:

提供特定于组件的信息(请参阅下文中的 运算符类型)。

以下屏幕截图显示了点击 加入 [11]* 运算符后的详细信息:

../_images/ui-profile-operator.png

运算符类型

以下各部分提供了最常见的运算符类型及其属性的列表。

数据访问和运算符生成

TableScan:

表示对单个表的访问。属性:

  • 完整表名称 – 访问表的名称,包括数据库和架构。

  • – 已扫描列的列表

  • 表别名 – 使用的表别名(如果存在)

  • 提取的变体路径 – 从 VARIANT 列中提取的路径列表

ValuesClause:

随 VALUES 子句提供的值列表。属性:

  • 值数 – 生成值数。

  • – 生成值列表。

生成器:

使用 TABLE(GENERATOR(...)) 结构生成记录。属性:

  • rowCount – 所提供的 rowCount 参数。

  • timeLimit – 所提供的 timeLimit 参数。

ExternalScan:

表示对存储在暂存区对象中的数据的访问。可以是直接从暂存区扫描数据的查询的一部分,也可以用于数据加载 COPY 查询。属性:

  • 暂存区名称 – 读取数据来源暂存区的名称。

  • 暂存区类型 – 暂存区的类型(例如 TABLE STAGE)。

InternalObject:

表示对内部数据对象(例如 Information Schema 表或上一个查询的结果)的访问。属性:

  • 对象名称 – 访问对象的名称或类型。

数据处理运算符

筛选器:

表示筛选记录的操作。属性:

  • 筛选条件 – 用于执行筛选的条件。

联接:

在给定条件下组合两个输入。属性:

  • 连接类型 – 联接类型(例如 INNER、LEFT OUTER 等)。

  • 相等连接条件 – 对于使用相同基础条件的联接,此条件列出了用于联接元素的表达式。

  • 附加联接条件 – 某些联接使用包含基于非相同的谓词的条件。这些联接列在此处。

备注

非相同的联接谓词可能会导致处理速度明显变慢,应尽可能避免使用。

汇总:

对输入进行分组并计算聚合函数。可以表示 SQL 结构,例如 GROUP BY 和 SELECT DISTINCT 等。属性:

  • 分组键 – 如果使用 GROUP BY,则列出分组所依据的表达式。

  • 聚合函数 – 每个汇总组已计算的函数列表,例如 SUM。

GroupingSets:

表示 GROUPING SETS、ROLLUP 和 CUBE 等结构。属性:

  • 分组密钥集 – 分组集列表

  • 聚合函数 – 每个组已计算的函数列表,例如 SUM。

WindowFunction:

计算窗口函数。属性:

  • 窗口函数 – 已计算窗口函数的列表。

排序:

对给定表达式的输入进行排序。属性:

  • 排序键 – 定义排序顺序的表达式。

SortWithLimit:

排序后生成输入序列的一部分,通常是 SQL 中的 ORDER BY ... LIMIT ... OFFSET ... 构造的结果。属性:

  • 排序键 – 定义排序顺序的表达式。

  • 行数 – 生成的行数。

  • 偏移 – 生成的元组在已排列序列中的发出位置。

展平:

处理 VARIANT 记录,可能在指定路径上展平记录。属性:

  • 输入 – 用于展平数据的输入表达式。

JoinFilter:

特殊筛选操作,用于移除识别为可能不符合查询计划中进一步联接条件的元组。属性:

  • 原始联接 ID – 用于标识可筛选掉的元组的联接。

UnionAll:

连接两个输入。属性:无。

ExternalFunction:

表示外部函数执行的处理。

DML 运算符

插入:

通过 INSERT 或 COPY 操作将记录添加到表中。属性:

  • 输入表达式 – 插入了哪些表达式。

  • 完整表名 – 记录添加到的单个目标表的名称。

  • 完整表名 – 添加记录的多个目标表的名称。

删除:

从表中移除记录。属性:

  • 完整表名称 – 删除记录的表的名称。

更新:

更新表中的记录。属性:

  • 完整的表名称 – 更新的表的名称。

合并:

对表执行 MERGE 操作。属性:

  • 完整的表名称 – 更新的表的名称。

卸载:

表示将数据从表导出到暂存区中的文件的 COPY 操作。属性:

  • 位置 – 保存数据的暂存区的名称。

元数据运算符

某些查询包含的步骤是纯元数据/目录操作,而不是数据处理操作。这些步骤由单个运算符组成。一些例子包括:

DDL 和事务命令:

用于创建或修改对象、会话、事务等。通常,这些查询不由虚拟仓库处理,并且最终会生成与匹配 SQL 语句对应的单步配置文件。例如:

CREATE DATABASE | SCHEMA | ...

ALTER DATABASE | SCHEMA | TABLE | SESSION | ...

DROP DATABASE | SCHEMA | TABLE | ...

COMMIT

表创建命令:

用于创建表的 DDL 命令。例如:

CREATE TABLE

与其他 DDL 命令类似,这些查询会生成单步配置文件;但是,它们也可以是多步骤配置文件的一部分,例如在 CTAS 语句中使用时。例如:

CREATE TABLE ...AS SELECT ...

查询结果重用:

重用上一个查询结果的查询。

基于元数据的结果:

纯粹根据元数据计算结果,不访问任何数据的查询。这些查询不由虚拟仓库处理。例如:

SELECT COUNT(*) FROM ...

SELECT CURRENT_DATABASE()

其他运算符

结果:

返回查询结果。属性:

  • 表达式列表 – 生成的表达式。

查询/运算符详细信息

为了帮助您分析查询性能,详细信息面板提供了两类分析信息:

  • 执行时间,细分为类别

  • 详细统计

此外,还为每个运算符提供了属性(请参阅本主题的 _运算符类型)。

执行时间

执行时间提供有关查询处理期间“时间花费在何处”的信息。花费的时间可以分为以下几类,按以下顺序显示:

  • Processing – CPU 在数据处理上花费的时间。

  • Local Disk IO – 本地磁盘访问阻止处理的时间。

  • Remote Disk IO – 远程磁盘访问阻止处理的时间。

  • Network Communication – 处理等待网络数据传输的时间。

  • Synchronization – 参与进程之间的各种同步活动。

  • Initialization – 设置查询处理所花费的时间。

统计信息

详细信息窗格中所提供的信息的主要来源是各种统计信息,这些统计信息分为以下部分:

  • IO – 有关查询期间执行的输入输出操作的信息:

    • 扫描进度 – 到目前为止为给定表扫描的数据百分比。

    • 扫描的字节数 – 到目前为止扫描的字节数。

    • 从缓存扫描的百分比 – 从本地磁盘缓存扫描的数据所占的百分比。

    • 写入的字节数 – 写入的字节数(例如,加载到表中时)。

    • 写入结果的字节数 – 写入结果对象的字节数。例如,select * from . . . 将生成一组表格格式的结果,表示所选内容中的每个字段。通常,结果对象表示作为查询结果生成的任何内容,写入结果的字节数 表示返回结果的大小。

    • 从结果读取的字节数 – 从结果对象读取的字节数。

    • 扫描的外部字节数 – 从外部对象(例如暂存区)读取的字节数。

  • DML – 数据操作语言 (DML) 查询的统计信息:

    • 插入的行数 – 插入到表(或多个表)中的行数。

    • 更新的行数 – 表中更新的行数。

    • 删除的行数 – 从表中删除的行数。

    • 卸载的行数 – 数据导出期间卸载的行数。

  • Pruning – 有关表修剪效果的信息:

    • 已扫描的分区 – 目前为止扫描的分区数。

    • 分区总数 – 给定表中的分区总数。

  • Spilling – 关于在中间结果无法完全放入内存的运算中磁盘使用情况信息:

    • 溢出到本地存储的字节数 – 溢出到本地磁盘的数据量。

    • 溢出到远程存储的字节数 – 溢出到远程磁盘的数据量。

  • Network – 网络通信:

    • 通过网络发送的字节数 – 通过网络发送的数据量。

  • External Functions – 有关外部函数调用的信息:

    对于 SQL 语句调用的每个外部函数,显示以下统计信息。如果同一 SQL 语句多次调用同一函数,则会汇总统计信息。

    • 总调用次数 – 调用外部函数的次数。(这可能与 SQL 语句文本中的外部函数调用次数不同,原因可能是行被划分为的批次数量、重试次数[如果存在暂时性的网络问题]等)

    • 发送的行数 – 发送到外部函数的行数。

    • 接收的行数 – 从外部函数接收的行数。

    • 发送的字节数(x-区域)– 发送到外部函数的字节数。如果标签包含“(x-区域)”,则数据将会跨区域发送(可能会影响计费)。

    • 接收的字节数(x-区域)– 从外部函数接收的字节数。如果标签包含“(x-区域)”,则数据将会跨区域发送(可能会影响计费)。

    • 由于暂时性错误而重试 – 由于暂时性错误而重试的次数。

    • 每次调用的平均延迟 – Snowflake 发送数据和接收返回数据之间的每次调用花费的平均时间。

    • HTTP 4xx 错误 – 返回 4xx 状态代码的 HTTP 请求总数。

    • HTTP 5xx 错误 – 返回 5xx 状态代码的 HTTP 请求总数。

    • 每次成功调用的延迟(平均)– 成功 HTTP 请求的平均延迟。

    • 平均限制延迟开销 – 由限制 (HTTP 429) 产生的减速导致的,每个成功请求的平均开销。

    • 由于限制而重试的批次 – 由于 HTTP 429 错误而重试的批次数。

    • 每次成功调用的延迟 (P50) – 成功 HTTP 请求的第 50 个百分位延迟。在所有成功请求中,有 50% 的请求完成时间少于此时间。

    • 每次成功调用的延迟 (P90) – 成功 HTTP 请求的第 90 个百分位延迟。在所有成功请求中,有 90% 的请求完成时间少于此时间。

    • 每次成功调用的延迟 (P95) – 成功 HTTP 请求的第 95 个百分位延迟。在所有成功请求中,有 95% 的请求完成时间少于此时间。

    • 每次成功调用的延迟 (P99) – 成功 HTTP 请求的第 99 个百分位延迟。在所有成功请求中,有 99% 的请求完成时间少于此时间。

  • Extension Functions – 有关调用扩展函数的信息:

    • Java UDF 处理程序加载时间 – Java UDF 处理程序的加载时间长短。

    • Java UDF 处理程序调用总数 – Java UDF 处理程序的调用次数。

    • Java UDF 处理程序执行时间上限 – 执行 Java UDF 处理程序的最长时间。

    • 平均 Java UDF 处理程序执行时间 – 执行 Java UDF 处理程序的平均时间。

    • Java UDTF process() 调用数 – Java UDTF 过程方法 的调用次数。

    • Java UDTF process() 执行时间 – 执行 Java UDTF 过程的时间长短。

    • Java UDTF process() 平均执行时间 – 执行 Java UDTF 过程的平均时间。

    • Java UDTF 的构造函数调用数 – Java UDTF 构造函数 的调用次数。

    • Java UDTF 的构造函数执行时间 – 执行 Java UDTF 构造函数的时间长短。

    • Java UDTF 的构造函数平均执行时间 – 执行 Java UDTF 构造函数的平均时间。

    • Java UDTF endPartition() 调用数 – 调用 Java UDTF endPartition 方法 的次数。

    • Java UDTF endPartition() 执行时间 – 执行 Java UDTF endPartition 方法的时间长短。

    • Java UDTF endPartition() 平均执行时间 – 执行 Java UDTF endPartition 方法的平均时间。

    • Java UDF 依赖项下载时间上限 – 下载 Java UDF 依赖项的最长时间。

    • JVM 内存使用量上限 – JVM 报告的峰值内存使用量。

    • Java UDF 内联代码编译时间(以毫秒为单位)– Java UDF 内联代码的编译时间。

    • Python UDF 处理程序调用总数 – Python UDF 处理程序的调用次数。

    • Python UDF 处理程序总执行时间 – Python UDF 处理程序的总执行时间。

    • Python UDF 处理程序平均执行时间 – 执行 Python UDF 处理程序的平均时间。

    • Python 沙盒内存使用量上限 – Python 沙盒环境的内存使用量峰值。

    • Python 环境创建平均时间:下载和安装包 – 创建 Python 环境的平均时间,包括下载和安装包。

    • Conda 求解器时间 – 运行 Conda 求解器对 Python 包求解的时间长短。

    • Conda 环境创建时间 – 创建 Python 环境的时间长短。

    • Python UDF 初始化时间 – 初始化 Python UDF 的时间长短。

    • 为 UDFs 读取的外部文件字节数 – 为 UDFs 读取的外部文件字节数。

    • 为 UDFs 访问的外部文件数 – 为 UDFs 访问的外部文件数。

    如果字段的值(例如“由于暂时性错误而重试”)为零,则不会显示该字段。

在 Snowflake Native App 中编辑的查询配置文件信息

在以下上下文中,Snowflake Native App Framework 编辑 查询配置文件 中的信息:

  • 在安装或升级应用程序时运行的查询。

  • 源自应用程序所拥有的存储过程的查询。

  • 包含应用程序所拥有的非安全视图或函数的查询。

对于以上任何类型的查询,Snowsight 都会将查询配置文件数据合并到单个空节点中,而不是显示完整的查询配置文件树。

查询配置文件识别的常见查询问题

本部分描述一些可以使用查询配置文件识别和解决的问题。

“爆炸”联接

SQL 用户常犯的错误之一是在不提供联接条件的情况下联接表(导致“笛卡尔积”),或者提供一个表中的记录与另一个表中的多个记录匹配的条件。对于此类查询,Join 运算符生成的元组明显多于消耗的元组数量(通常为数量级)。

这可以通过查看 Join 运算符生成的记录数量来观察,Join 运算符消耗大量时间通常也会反映这一点。

以下示例显示了以数百条记录为单位的输入,但以数十万条记录为单位的输出:

SELECT tt1.c1, tt1.c2
FROM tt1
JOIN tt2 ON tt1.c1 = tt2.c1
 AND tt1.c2 = tt2.c2;
Copy
../_images/ui-profile-issues-exploding-joins.png

UNION(无 ALL)

在 SQL 中,可以将两组数据与 UNION 或 UNION ALL 结构组合在一起。它们之间的区别在于,UNION ALL 只是简单地连接输入,而 UNION 在执行同样操作的同时,也会消除重复数据。

一个常见的错误是在 UNION ALL 的语义足够时使用 UNION。这些查询在查询配置文件中显示为 UnionAll 运算符,顶部附带一个额外的 Aggregate 运算符(用来消除重复数据)。

查询太大而无法放入内存

对于某些操作(例如,大型数据集的重复消除),用于执行操作的计算资源的可用内存量可能不足以保存中间结果。因此,查询处理引擎会开始将数据 溢出 到本地磁盘。如果本地磁盘空间不足,则溢出的数据将保存到远程磁盘。

这种溢出可能会对查询性能产生深远影响(尤其是在因为溢出而使用远程磁盘时)。为了缓解这种情况,我们建议:

  • 使用更大的仓库(有效地增加操作的可用内存/本地磁盘空间),以及/或者

  • 以较小的批次处理数据。

修剪效率低下

Snowflake 会收集有关数据的丰富统计信息,从而根据查询筛选器避免读取表中不必要的部分。但是,要使此设置生效,需要将数据存储顺序与查询筛选器属性相关联。

通过比较 TableScan 运算符中的 扫描分区分区总数 统计信息,可以观察到修剪的效率。如果前者只是后者的一小部分,说明修剪是有效的。如果情况不是这样,则表明修剪没有效果。

当然,修剪只能对实际筛选掉大量数据的查询有所帮助。如果修剪统计信息未显示数据减少,但 TableScan 上面有一个 Filter 运算符可以筛选掉许多记录,则这可能表明其他数据组织对此查询有益。

有关修剪的更多信息,请参阅 了解 Snowflake 表结构

通过 Snowflake Native App 编辑的查询配置文件数据

在以下上下文中,Snowflake Native App Framework 编辑 查询配置文件 中的信息:

  • 在安装或升级应用程序时运行的查询。

  • 源自应用程序所拥有的存储过程的查询。

  • 包含应用程序所拥有的非安全视图或函数的查询。

对于以上任何类型的查询,Snowsight 都会将查询配置文件数据合并到单个空节点中,而不是显示完整的查询配置文件树。

语言: 中文