Azure SQL 数据仓库上的简单性能测试
Simple Performance Test on Azure SQL Data Warehouse
我们正在努力将现有应用程序移植到 Azure SQL 数据仓库。为了更好的理解Azure SQL数据仓库的performance/workload管理characteristics/capabilities,我设置了一个我认为很简单的测试
我加载了一个静态 table,我们公司的日历,包含大约 20k 行(即,对于并行数据仓库来说非常小)。然后,我使用如下模式生成了单个 table 的所有可能查询:
SELECT current_timestamp,COUNT(1) FROM
( SELECT C1, ..., Cn , COUNT(1) AS _A_ROW_COUNT
FROM schema.view_to_table GROUP BY C1, ..., Cn) DER
给定:
- DWU 设置为 1000。
- 启动了 35 个并发线程。
- 运行small_rc 中的所有线程。 (即,每个查询使用 1 个槽。)
- 在初始连接中使用 sqlcmd,然后在每个 SELECT
之后提交
- 运行 在通过 Express 路由连接的非 Azure VM 上。选择外部 SELECT COUNT() 结构以确保网络流量最小。
- 堆的使用 table 提供了比默认列存储更好的结果(正如预期的那样)。 (需要用聚簇索引测试。)
- Table按主键列分布
Background/Biases - 我使用过许多其他 MPP 数据库。
结果
- 查询在 10 到 20 秒内完成 运行,这比我对这种简单工作的预期要长得多。
- 当我提交每个线程时,我在每个新线程之间睡觉。初始查询 运行 快得多,随着线程数增加到 35,平均 运行 次急剧下降。
如何理解存在的瓶颈?
当然,我会在其他 DWU 设置下重新运行 测试,看看它是否会影响专门的 small_rc 工作负载。
附录 - 示例查询计划
<?xml version="1.0" encoding="utf-8"?>
<dsql_query number_nodes="10" number_distributions="60" number_distributions_per_node="6">
<sql>SELECT current_timestamp,COUNT(1) FROM ( SELECT GREGORIAN_DATE, WM_MONTH, MON_MULT, FRI_MULT , COUNT(1) AS _A_ROW_COUNT FROM AR_WM_VM.CALENDAR_DAY GROUP BY GREGORIAN_DATE, WM_MONTH, MON_MULT, FRI_MULT) DER</sql>
<dsql_operations total_cost="0.260568" total_number_operations="8">
<dsql_operation operation_type="RND_ID">
<identifier>TEMP_ID_21523</identifier>
</dsql_operation>
<dsql_operation operation_type="ON">
<location permanent="false" distribution="AllDistributions" />
<sql_operations>
<sql_operation type="statement">CREATE TABLE [tempdb].[dbo].[TEMP_ID_21523] ([col] DATE ) WITH(DATA_COMPRESSION=PAGE);</sql_operation>
</sql_operations>
</dsql_operation>
<dsql_operation operation_type="SHUFFLE_MOVE">
<operation_cost cost="0.258648" accumulative_cost="0.258648" average_rowsize="3" output_rows="2155.4" GroupNumber="76" />
<source_statement>SELECT [T1_1].[col] AS [col]
FROM (SELECT dateadd(dd, CAST ((364) AS INT), [T2_1].[calendar_date]) AS [col]
FROM [db_ARdev1].[AR_CORE_DIM_TABLES].[calendar_dim] AS T2_1) AS T1_1</source_statement>
<destination_table>[TEMP_ID_21523]</destination_table>
<shuffle_columns>col;</shuffle_columns>
</dsql_operation>
<dsql_operation operation_type="ON">
<location permanent="false" distribution="Control" />
<sql_operations>
<sql_operation type="statement">CREATE TABLE [tempdb].[QTables].[QTable_3ff26b5253004eec9d9ca50492bab1e2] ([col] BIGINT ) WITH(DATA_COMPRESSION=PAGE);</sql_operation>
</sql_operations>
</dsql_operation>
<dsql_operation operation_type="PARTITION_MOVE">
<operation_cost cost="0.00192" accumulative_cost="0.260568" average_rowsize="8" output_rows="1" GroupNumber="93" />
<location distribution="AllDistributions" />
<source_statement>SELECT [T1_1].[col] AS [col]
FROM (SELECT COUNT_BIG(CAST ((1) AS INT)) AS [col]
FROM (SELECT 0 AS [col]
FROM [tempdb].[dbo].[TEMP_ID_21523] AS T3_1
INNER JOIN
(SELECT CASE
WHEN ([T4_1].[wm_week_day_nbr] = CAST ((3) AS SMALLINT)) THEN CAST ((1) AS INT)
ELSE CAST ((0) AS INT)
END AS [col],
CASE
WHEN ([T4_1].[wm_week_day_nbr] = CAST ((7) AS SMALLINT)) THEN CAST ((1) AS INT)
ELSE CAST ((0) AS INT)
END AS [col1],
[T4_1].[calendar_date] AS [calendar_date],
[T4_1].[fiscal_month_nbr] AS [fiscal_month_nbr]
FROM [db_ARdev1].[AR_CORE_DIM_TABLES].[calendar_dim] AS T4_1) AS T3_2
ON ([T3_2].[calendar_date] = [T3_1].[col])
GROUP BY [T3_2].[calendar_date], [T3_2].[fiscal_month_nbr], [T3_2].[col], [T3_2].[col1]) AS T2_1
GROUP BY [T2_1].[col]) AS T1_1</source_statement>
<destination>Control</destination>
<destination_table>[QTable_3ff26b5253004eec9d9ca50492bab1e2]</destination_table>
</dsql_operation>
<dsql_operation operation_type="ON">
<location permanent="false" distribution="AllDistributions" />
<sql_operations>
<sql_operation type="statement">DROP TABLE [tempdb].[dbo].[TEMP_ID_21523]</sql_operation>
</sql_operations>
</dsql_operation>
<dsql_operation operation_type="RETURN">
<location distribution="Control" />
<select>SELECT [T1_1].[col1] AS [col],
[T1_1].[col] AS [col1]
FROM (SELECT CONVERT (INT, [T2_1].[col], 0) AS [col],
isnull(CONVERT (DATETIME, N'2016-10-03 13:04:34.203', 0), CONVERT (DATETIME, N'2016-10-03 13:04:34.203', 0)) AS [col1]
FROM (SELECT ISNULL([T3_1].[col], CONVERT (BIGINT, 0, 0)) AS [col]
FROM (SELECT SUM([T4_1].[col]) AS [col]
FROM [tempdb].[QTables].[QTable_3ff26b5253004eec9d9ca50492bab1e2] AS T4_1) AS T3_1) AS T2_1) AS T1_1</select>
</dsql_operation>
<dsql_operation operation_type="ON">
<location permanent="false" distribution="Control" />
<sql_operations>
<sql_operation type="statement">DROP TABLE [tempdb].[QTables].[QTable_3ff26b5253004eec9d9ca50492bab1e2]</sql_operation>
</sql_operations>
</dsql_operation>
</dsql_operations>
</dsql_query>
在 DWU 1000,您将获得 32 个最大并发查询和 40 个并发槽,因此您的一些查询将不得不排队。
您做出了哪些索引和分发选择?这个 table 很小,所以它听起来更适合聚集索引而不是聚集列存储(默认值)。还要确保您已经创建了统计信息。
您从哪里调用 sqlcmd,例如 Azure VM,所以它 "closer" 到 DW,或者从您的笔记本电脑,在这种情况下您可能正在等待网络往返。
查看并发 DMV:sys.dm_pdw_exec_requests
查看等待 DMV:sys.dm_pdw_waits
这个 recent answer 看起来也很有用。
我已经对您的示例 EXPLAIN
计划进行了注释。在 SSMS 中打开行号或在诸如 Sublime 文本之类的内容中查看以获得最佳效果:
- 第 3 行是正在分析的查询。
- 第 4 行将计划中的操作或步骤总数列为 8。每个操作都保存在 XML.
中的 dsql_operation 元素中
- 第 5 行开始操作 1,
RND_ID
,或 RandomIdOperation。此操作只是为查询计划中使用的临时对象创建一个唯一名称。标识符是 TEMP_ID_21523.
- 第 8 行开始操作 2,
ON
,或 OnOperation。这对数据库或对象执行操作。此特定步骤在第 9 行指定的所有节点上创建一个临时 table [TEMP_ID_21523]。在所有节点上创建临时 table 的 DDL 在第 11 行。此临时 table 只有一列,称为 'col' 数据类型 DATE。
- 第 14 行是操作 3,称为
SHUFFLE_MOVE
或 ShuffleMoveOperation 的数据移动服务 (DMS) 操作。 SHUFFLE_MOVE 重新分发已分发的 table。
- 第 16 行给出了 SHUFFLE_MOVE 中使用的语句。它将数据从 table [AR_CORE_DIM_TABLES].[calendar_dim] 的计算列移动到临时 table [TEMP_ID_21523],我们知道它存在于所有节点。
- 第 22 行开始下一个操作 4,另一个
ON
,或 OnOperation。此操作在控制节点上创建另一个 temp table,具有一个 BIGINT 列。此 table 的 DDL 在第 25 行提供。
- 第 28 行开始操作 5,一个
PARTITION_MOVE
,或 PartitionMoveOperation。此 DMS 操作将数据从分布式 table 移动到控制节点上的单个 table。该操作用于控制节点上的聚合操作。此特定步骤将数据从所有节点上存在的 temp table [TEMP_ID_21523] 移动到控制节点上的目标 temp table [QTable_3ff2...]。
- 第 31 到 49 行列出了用于执行此操作的 SQL。
- 第 53 行开始操作 6,另一个
ON
,或 OnOperation。此步骤删除存在于所有节点上的临时 table [TEMP_ID_21523]。
- 第 59 行开始第 7 个操作,共 8 个操作,
RETURN
或 ReturnOperation。该操作发生在控制节点上,将查询结果从控制节点发送给提交查询的用户。返回的 SQL 显示在第 61-67 行中。
- 第 69 行开始最后一个操作 8 of 8,另一个
ON
,或 OnOperation。此特定步骤会删除控制节点上存在的温度 table [QTable_3ff2...]。
对于您的查询,PARTITION_MOVE
或 SHUFFLE_MOVE
步骤最有可能导致性能问题,提高性能需要删除或改进它们。
为了更进一步,我需要了解 table [AR_CORE_DIM_TABLES].[calendar_dim] 和视图 [AR_WM_VM].[ 的 DDL。 CALENDAR_DAY GROUP] 这样我就可以计算出分布以及是否使用了任何计算列。
此注释基于 APS 帮助文件部分中有关 EXPLAIN
计划和 Understanding Query Plans
的类似注释,其中一些文本是从中复制的。我已经根据你的计划进行了调整。
我们正在努力将现有应用程序移植到 Azure SQL 数据仓库。为了更好的理解Azure SQL数据仓库的performance/workload管理characteristics/capabilities,我设置了一个我认为很简单的测试
我加载了一个静态 table,我们公司的日历,包含大约 20k 行(即,对于并行数据仓库来说非常小)。然后,我使用如下模式生成了单个 table 的所有可能查询:
SELECT current_timestamp,COUNT(1) FROM
( SELECT C1, ..., Cn , COUNT(1) AS _A_ROW_COUNT
FROM schema.view_to_table GROUP BY C1, ..., Cn) DER
给定:
- DWU 设置为 1000。
- 启动了 35 个并发线程。
- 运行small_rc 中的所有线程。 (即,每个查询使用 1 个槽。)
- 在初始连接中使用 sqlcmd,然后在每个 SELECT 之后提交
- 运行 在通过 Express 路由连接的非 Azure VM 上。选择外部 SELECT COUNT() 结构以确保网络流量最小。
- 堆的使用 table 提供了比默认列存储更好的结果(正如预期的那样)。 (需要用聚簇索引测试。)
- Table按主键列分布
Background/Biases - 我使用过许多其他 MPP 数据库。
结果
- 查询在 10 到 20 秒内完成 运行,这比我对这种简单工作的预期要长得多。
- 当我提交每个线程时,我在每个新线程之间睡觉。初始查询 运行 快得多,随着线程数增加到 35,平均 运行 次急剧下降。
如何理解存在的瓶颈?
当然,我会在其他 DWU 设置下重新运行 测试,看看它是否会影响专门的 small_rc 工作负载。
附录 - 示例查询计划
<?xml version="1.0" encoding="utf-8"?>
<dsql_query number_nodes="10" number_distributions="60" number_distributions_per_node="6">
<sql>SELECT current_timestamp,COUNT(1) FROM ( SELECT GREGORIAN_DATE, WM_MONTH, MON_MULT, FRI_MULT , COUNT(1) AS _A_ROW_COUNT FROM AR_WM_VM.CALENDAR_DAY GROUP BY GREGORIAN_DATE, WM_MONTH, MON_MULT, FRI_MULT) DER</sql>
<dsql_operations total_cost="0.260568" total_number_operations="8">
<dsql_operation operation_type="RND_ID">
<identifier>TEMP_ID_21523</identifier>
</dsql_operation>
<dsql_operation operation_type="ON">
<location permanent="false" distribution="AllDistributions" />
<sql_operations>
<sql_operation type="statement">CREATE TABLE [tempdb].[dbo].[TEMP_ID_21523] ([col] DATE ) WITH(DATA_COMPRESSION=PAGE);</sql_operation>
</sql_operations>
</dsql_operation>
<dsql_operation operation_type="SHUFFLE_MOVE">
<operation_cost cost="0.258648" accumulative_cost="0.258648" average_rowsize="3" output_rows="2155.4" GroupNumber="76" />
<source_statement>SELECT [T1_1].[col] AS [col]
FROM (SELECT dateadd(dd, CAST ((364) AS INT), [T2_1].[calendar_date]) AS [col]
FROM [db_ARdev1].[AR_CORE_DIM_TABLES].[calendar_dim] AS T2_1) AS T1_1</source_statement>
<destination_table>[TEMP_ID_21523]</destination_table>
<shuffle_columns>col;</shuffle_columns>
</dsql_operation>
<dsql_operation operation_type="ON">
<location permanent="false" distribution="Control" />
<sql_operations>
<sql_operation type="statement">CREATE TABLE [tempdb].[QTables].[QTable_3ff26b5253004eec9d9ca50492bab1e2] ([col] BIGINT ) WITH(DATA_COMPRESSION=PAGE);</sql_operation>
</sql_operations>
</dsql_operation>
<dsql_operation operation_type="PARTITION_MOVE">
<operation_cost cost="0.00192" accumulative_cost="0.260568" average_rowsize="8" output_rows="1" GroupNumber="93" />
<location distribution="AllDistributions" />
<source_statement>SELECT [T1_1].[col] AS [col]
FROM (SELECT COUNT_BIG(CAST ((1) AS INT)) AS [col]
FROM (SELECT 0 AS [col]
FROM [tempdb].[dbo].[TEMP_ID_21523] AS T3_1
INNER JOIN
(SELECT CASE
WHEN ([T4_1].[wm_week_day_nbr] = CAST ((3) AS SMALLINT)) THEN CAST ((1) AS INT)
ELSE CAST ((0) AS INT)
END AS [col],
CASE
WHEN ([T4_1].[wm_week_day_nbr] = CAST ((7) AS SMALLINT)) THEN CAST ((1) AS INT)
ELSE CAST ((0) AS INT)
END AS [col1],
[T4_1].[calendar_date] AS [calendar_date],
[T4_1].[fiscal_month_nbr] AS [fiscal_month_nbr]
FROM [db_ARdev1].[AR_CORE_DIM_TABLES].[calendar_dim] AS T4_1) AS T3_2
ON ([T3_2].[calendar_date] = [T3_1].[col])
GROUP BY [T3_2].[calendar_date], [T3_2].[fiscal_month_nbr], [T3_2].[col], [T3_2].[col1]) AS T2_1
GROUP BY [T2_1].[col]) AS T1_1</source_statement>
<destination>Control</destination>
<destination_table>[QTable_3ff26b5253004eec9d9ca50492bab1e2]</destination_table>
</dsql_operation>
<dsql_operation operation_type="ON">
<location permanent="false" distribution="AllDistributions" />
<sql_operations>
<sql_operation type="statement">DROP TABLE [tempdb].[dbo].[TEMP_ID_21523]</sql_operation>
</sql_operations>
</dsql_operation>
<dsql_operation operation_type="RETURN">
<location distribution="Control" />
<select>SELECT [T1_1].[col1] AS [col],
[T1_1].[col] AS [col1]
FROM (SELECT CONVERT (INT, [T2_1].[col], 0) AS [col],
isnull(CONVERT (DATETIME, N'2016-10-03 13:04:34.203', 0), CONVERT (DATETIME, N'2016-10-03 13:04:34.203', 0)) AS [col1]
FROM (SELECT ISNULL([T3_1].[col], CONVERT (BIGINT, 0, 0)) AS [col]
FROM (SELECT SUM([T4_1].[col]) AS [col]
FROM [tempdb].[QTables].[QTable_3ff26b5253004eec9d9ca50492bab1e2] AS T4_1) AS T3_1) AS T2_1) AS T1_1</select>
</dsql_operation>
<dsql_operation operation_type="ON">
<location permanent="false" distribution="Control" />
<sql_operations>
<sql_operation type="statement">DROP TABLE [tempdb].[QTables].[QTable_3ff26b5253004eec9d9ca50492bab1e2]</sql_operation>
</sql_operations>
</dsql_operation>
</dsql_operations>
</dsql_query>
在 DWU 1000,您将获得 32 个最大并发查询和 40 个并发槽,因此您的一些查询将不得不排队。
您做出了哪些索引和分发选择?这个 table 很小,所以它听起来更适合聚集索引而不是聚集列存储(默认值)。还要确保您已经创建了统计信息。
您从哪里调用 sqlcmd,例如 Azure VM,所以它 "closer" 到 DW,或者从您的笔记本电脑,在这种情况下您可能正在等待网络往返。
查看并发 DMV:sys.dm_pdw_exec_requests
查看等待 DMV:sys.dm_pdw_waits
这个 recent answer 看起来也很有用。
我已经对您的示例 EXPLAIN
计划进行了注释。在 SSMS 中打开行号或在诸如 Sublime 文本之类的内容中查看以获得最佳效果:
- 第 3 行是正在分析的查询。
- 第 4 行将计划中的操作或步骤总数列为 8。每个操作都保存在 XML. 中的 dsql_operation 元素中
- 第 5 行开始操作 1,
RND_ID
,或 RandomIdOperation。此操作只是为查询计划中使用的临时对象创建一个唯一名称。标识符是 TEMP_ID_21523. - 第 8 行开始操作 2,
ON
,或 OnOperation。这对数据库或对象执行操作。此特定步骤在第 9 行指定的所有节点上创建一个临时 table [TEMP_ID_21523]。在所有节点上创建临时 table 的 DDL 在第 11 行。此临时 table 只有一列,称为 'col' 数据类型 DATE。 - 第 14 行是操作 3,称为
SHUFFLE_MOVE
或 ShuffleMoveOperation 的数据移动服务 (DMS) 操作。 SHUFFLE_MOVE 重新分发已分发的 table。 - 第 16 行给出了 SHUFFLE_MOVE 中使用的语句。它将数据从 table [AR_CORE_DIM_TABLES].[calendar_dim] 的计算列移动到临时 table [TEMP_ID_21523],我们知道它存在于所有节点。
- 第 22 行开始下一个操作 4,另一个
ON
,或 OnOperation。此操作在控制节点上创建另一个 temp table,具有一个 BIGINT 列。此 table 的 DDL 在第 25 行提供。 - 第 28 行开始操作 5,一个
PARTITION_MOVE
,或 PartitionMoveOperation。此 DMS 操作将数据从分布式 table 移动到控制节点上的单个 table。该操作用于控制节点上的聚合操作。此特定步骤将数据从所有节点上存在的 temp table [TEMP_ID_21523] 移动到控制节点上的目标 temp table [QTable_3ff2...]。 - 第 31 到 49 行列出了用于执行此操作的 SQL。
- 第 53 行开始操作 6,另一个
ON
,或 OnOperation。此步骤删除存在于所有节点上的临时 table [TEMP_ID_21523]。 - 第 59 行开始第 7 个操作,共 8 个操作,
RETURN
或 ReturnOperation。该操作发生在控制节点上,将查询结果从控制节点发送给提交查询的用户。返回的 SQL 显示在第 61-67 行中。 - 第 69 行开始最后一个操作 8 of 8,另一个
ON
,或 OnOperation。此特定步骤会删除控制节点上存在的温度 table [QTable_3ff2...]。
对于您的查询,PARTITION_MOVE
或 SHUFFLE_MOVE
步骤最有可能导致性能问题,提高性能需要删除或改进它们。
为了更进一步,我需要了解 table [AR_CORE_DIM_TABLES].[calendar_dim] 和视图 [AR_WM_VM].[ 的 DDL。 CALENDAR_DAY GROUP] 这样我就可以计算出分布以及是否使用了任何计算列。
此注释基于 APS 帮助文件部分中有关 EXPLAIN
计划和 Understanding Query Plans
的类似注释,其中一些文本是从中复制的。我已经根据你的计划进行了调整。