统计数据是否像Azure数据仓库中的哈希一样帮助连接字段?

统计数据是否像Azure数据仓库中的哈希一样帮助连接字段?,azure,azure-sqldw,parallel-data-warehouse,Azure,Azure Sqldw,Parallel Data Warehouse,在Azure Data Warehouse中,建议对您计划加入甚至可能聚合的字段上的分布式表使用哈希。还建议您创建计划使用的字段的统计信息 假设有两个表具有相同数量的记录和字段。一个表散列在一个非常独特的键上,另一个是循环,数据在60个数据库中随机平均分配 -- CustomerID is alphanumeric SELECT [ProductID] ,COUNT(DISTINCT [CustomerID]) AS [Unique Records] FROM [dbo].[FactT

在Azure Data Warehouse中,建议对您计划加入甚至可能聚合的字段上的分布式表使用哈希。还建议您创建计划使用的字段的统计信息

假设有两个表具有相同数量的记录和字段。一个表散列在一个非常独特的键上,另一个是循环,数据在60个数据库中随机平均分配

-- CustomerID is alphanumeric
SELECT
   [ProductID]
  ,COUNT(DISTINCT [CustomerID]) AS [Unique Records]
FROM [dbo].[FactTable]
GROUP BY
   [Product]
在哈希表上,如果对哈希键进行聚合,可以看到它在0.05秒内返回结果。在循环表中,使用相同的聚合,它是0.51秒

CREATE STATISTICS [ProductID] ON [dbo].[FactTable] ([ProductID]);
CREATE STATISTICS [CustomerID] ON [dbo].[FactTable] ([CustomerID]);
将统计信息应用于要聚合的字段时,哈希表仍会在0.05秒内返回。没有变化。对循环表执行相同操作时,结果将在0.05秒内返回到与哈希相同的值

注:2000 DWU在xlarge资源中运行查询(最大内存分配)

在检查散列键的分布时,我发现在60个数据库的一个分布中存储了1.4亿条记录。5000万条其他记录均匀分布在其他59个数据库中。默认值是使我的哈希键不是哈希的最佳候选项

我的问题是,虽然带有统计信息的循环表在我与另一个表进行哈希运算的同一个字段上表现出色,但当我对带有该键的联接使用循环时,相同的性能会保持不变吗?我还没有完全测试它,但正在寻找最好的方法


统计数据对连接有帮助吗?我读到的一些文章说他们有,但是在考虑分发密钥上的循环时,看看是否有其他人对这种方法有更可靠的答案。我真的没有任何一个好的候选者不会像我上面的例子中的1.4亿那样造成数据倾斜。

首先,在当前版本的Azure SQL data Warehouse中,您应该始终创建将在联接中使用的列的统计信息,
分组依据
等。忽略没有统计数据的计时,因为它们不相关

一个好的散列键的标准之一是它。如果你没有一个好的候选人,那么
ROUND_-ROBIN
是另一种选择。关于循环,需要记住的一点是,数据总是在移动,但有时也可以。这实际上取决于您的关键查询是什么。我的建议是对它们进行优化

对于您给出的示例,性能非常快,不值得花费太多时间。你有更现实的问题吗

Azure SQL数据仓库进行缓存,类似于SQL Server,如前所述

当您从门户提供仓库时,我使用AdventureWorksDW示例模拟了一个测试平台,发现哈希表在这些示例查询中的性能明显更好(尽管存在较大的偏差),但您的里程可能会有所不同(YMMV):

我的结果(表中有6亿行):


如果我看两个查询(,)的两个解释计划,我会看到一个更简单的哈希表计划,没有数据移动。“rr”计划包含一个
SHUFFLE\u MOVE
操作符,该操作符重新分配一个分布式表。

如果您希望答案更具体,如果您可以发布测试的所有查询的解释计划,则会有所帮助。将单词
EXPLAIN
放在查询前面,运行它,然后将XML复制到您的问题中。实际上没有,但包含SQL示例以供参考。这只是一个基本的按查询选择计数(不同)组。你能得到一个吗?我想看看统计数据是否会改变解释计划,或者性能差异是否仅仅与缓存有关。我会看看是否可以。我不相信这是缓存。在应用统计数据之前,我以相同的速度(0.51)多次运行查询。它立刻改变了。我真的没有注意到Azure DW中有任何缓存。我的问题是,即使在简单的查询中,它也挂在10亿行上。简单的查询在执行DATEPART时分组,并在高度唯一的行上分组,以避免在这些高度唯一的行上执行COUNT(DISTINCT)操作,这需要很长时间。这听起来与您描述的场景(性能为亚秒)完全不同?如果您可以提供DDL、一些示例数据和正在运行的实际查询以及解释计划,那么有人将能够帮助您。老实说,您刚才描述的场景听起来像是一个单独的问题,它基本上是同一个查询,但在一个具有更多记录的不同表上。唯一的区别是,还有一个基于一组数据的过滤器,该过滤器中有10亿条记录,其中我显示的示例查询基于另一个数据子集,该数据子集只有2亿条记录,我将其拆分到另一个表中。当我将其拆分后,查询能够在几秒钟内返回,而不是在几分钟内返回。但是的,这可能是另一个问题。为什么相同的查询不能在更大的数据上工作?:)就上下文而言,我的大部分麻烦来自countdistinct或预聚合数据以进行分组,从而获得与countdistinct相同的结果(以避免使用distinct子句)。在这两种情况下,它们都需要很长时间来处理更大的数据集。因此,我将表分开,对另一个循环进行哈希运算,以查看通过循环进行哈希运算是否有任何性能提升。对于类似的测试,必须使用字母数字(50)的CustomerID,并且拥有超过2000万个Unique,默认值为大于1亿的一个值。您使用的CustomerID类似于基于INT的数据类型。这将大大加快聚合速度。
-- 603,980,000 rows
CREATE TABLE dbo.FactTable_rr
WITH ( 
    DISTRIBUTION = ROUND_ROBIN, 
    CLUSTERED COLUMNSTORE INDEX
)
AS
SELECT a.ProductKey AS [ProductID], a.CustomerKey AS [CustomerID]
FROM [dbo].[FactInternetSales] a
    CROSS JOIN ( SELECT TOP 1000 1 FROM [dbo].[FactInternetSales] ) b(c)
    CROSS JOIN ( SELECT TOP 10 1 FROM [dbo].[FactInternetSales] ) c(c)
GO


CREATE STATISTICS st_dbo_FactTable_rr_ProductID ON dbo.FactTable_rr ( ProductID ) WITH FULLSCAN;
CREATE STATISTICS st_dbo_FactTable_rr_CustomerID ON dbo.FactTable_rr ( CustomerID ) WITH FULLSCAN;
GO


CREATE TABLE dbo.FactTable_hh
WITH ( 
    DISTRIBUTION = HASH( [ProductID] ),
    CLUSTERED COLUMNSTORE INDEX
)
AS
SELECT *
FROM FactTable_rr
GO

CREATE STATISTICS st_dbo_FactTable_hh_ProductID ON dbo.FactTable_hh ( ProductID ) WITH FULLSCAN;
CREATE STATISTICS st_dbo_FactTable_hh_CustomerID ON dbo.FactTable_hh ( CustomerID ) WITH FULLSCAN;
GO



-- Find data skew for a distributed table
DBCC PDW_SHOWSPACEUSED('dbo.FactTable_rr');
DBCC PDW_SHOWSPACEUSED('dbo.FactTable_hh');
GO


--EXPLAIN
SELECT
   [ProductID],
   COUNT(DISTINCT [CustomerID]) AS [Unique Records]
FROM [dbo].[FactTable_rr]
GROUP BY [ProductID]
OPTION ( LABEL = 'rr' );


--EXPLAIN
SELECT
   [ProductID],
   COUNT(DISTINCT [CustomerID]) AS [Unique Records]
FROM [dbo].[FactTable_hh]
GROUP BY [ProductID]
OPTION ( LABEL = 'hh' );


-- Summary
SELECT [label], COUNT(*) records, CAST( AVG(total_elapsed_time) / 1000. AS DECIMAL(10,2) ) total_elapsed_time_s
FROM sys.dm_pdw_exec_requests 
WHERE [label] IS NOT NULL
  AND command Like 'select%'
GROUP BY [label];