使用查询配置文件分析查询¶
查询配置文件(可通过 Classic Console 获取)提供查询的执行详细信息。对于选定的查询,它提供了查询处理计划的主要组件的图形表示形式,其中包含每个组件的统计信息,以及整个查询的详细信息和统计信息。
本主题内容:
简介¶
何时使用查询配置文件¶
查询配置文件是用于了解查询机制的强大工具。每当您想要或需要了解有关特定查询的性能或行为的更多信息时,都可以使用它。它旨在帮助您发现 SQL 查询表达式中的典型错误,以识别潜在的性能瓶颈和改进机会。
如何访问查询配置文件¶
从查询的详细信息页面访问查询配置文件。因此,您可以从显示 Query ID 列的任何页面访问查询配置文件,并且可以点击查询 IDs,具体如下:
备注
如果这些页面上未显示 Query ID 列,请点击页面上某个列标题旁边的下拉列表,然后在 Columns 列表中选择 Query ID。
要访问查询的配置文件,请执行以下操作:
查询配置文件接口¶
在本主题中,我们将使用连接两个表的基本示例 SQL 查询:
select sum(j)
from x join y using (i)
where j > 300
and i < (select avg(j) from x);
以下屏幕截图显示了此查询的配置文件:
该接口由以下主要元素组成:
- 步骤:
如果查询是分多个步骤处理的,则可以在每个步骤之间切换。
- 运算符树:
中间窗格显示所选步骤的所有操作符节点的图形表示,包括每个操作符节点之间的关系。
- 节点列表:
中间窗格包括按执行时间划分的运算符节点的可折叠列表。
- 概述:
右窗格显示查询配置文件的概述。选择运算符节点时,显示将更改为运算符详细信息。
步骤¶
查询通常分多个步骤进行处理。例如,我们的示例查询分 2 个步骤处理:
第 1 步:计算
x.j
列的平均值。第 2 步:使用此中间结果来计算最终查询结果。
查询配置文件在单独的面板中显示每个处理步骤。您可以通过点击相应的步骤在面板之间切换。对于示例查询,点击 Step 2 会将视图更改为:
运算符树¶
该树提供了构成查询的运算符节点的图形表示形式,以及连接每个运算符的链接:
运算符是查询的功能构建基块。负责数据管理和处理的不同方面,包括数据访问、转换和更新。树中的每个运算符节点都包含一些基本属性:
- <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] 运算符后的面板:
配置文件概述/运算符详细信息¶
右侧的概述/详细信息面板提供有关左侧树中所选组件(运算符和链接)的信息。显示的信息取决于是否选择了运算符树中的节点:
最初,树中没有选择任何节点,因此面板显示当前步骤的概述信息。
通过点击节点选择组件时,面板将显示该组件的信息。
备注
点击节点后,要返回到步骤级概述信息,只需通过点击运算符树周围的任何空白区域来取消选择该节点即可。
概述/详细信息面板分为 3 个部分:
- 执行时间:
提供有关哪些处理任务占用了查询时间的信息(请参阅下文中的 查询/运算符详细信息)。此外,对于步骤级信息,将显示给定步骤的状态及其执行时间。
- 统计信息:
提供有关各种统计信息的详细信息(请参阅下文中的 查询/运算符详细信息)。
- 属性:
提供特定于组件的信息(请参阅下文中的 运算符类型)。
以下屏幕截图显示了点击 加入 [11]* 运算符后的详细信息:
运算符类型¶
以下各部分提供了最常见的运算符类型及其属性的列表。
数据访问和运算符生成¶
- 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;
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 都会将查询配置文件数据合并到单个空节点中,而不是显示完整的查询配置文件树。