【问题标题】:Azure SQL Data Warehouse - Slow LEFT JOIN with temporary tableAzure SQL 数据仓库 - 使用临时表进行慢速左连接
【发布时间】:2016-03-11 23:41:59
【问题描述】:

我在“Azure SQL 数据仓库”中运行了一个非常简单的查询(见下文),它需要 5 秒。如果我在“Azure SQL Server”中运行相同的查询,则需要 0 秒,这似乎更正常。 (这个查询基本上是一堆没有条件的 LEFT JOINS,如果你运行它,你会从执行计划中看到。)

这怎么可能需要 5 秒?

CREATE TABLE #output(
  val INT
 )

INSERT INTO #output VALUES (1)

SELECT 
 (SELECT val FROM #output),
 (SELECT val FROM #output),
 (SELECT val FROM #output),
 (SELECT val FROM #output),
 (SELECT val FROM #output),
 (SELECT val FROM #output),
 (SELECT val FROM #output),
 (SELECT val FROM #output)

【问题讨论】:

  • 对不起,我仍然对这里发生的事情感到困惑
  • 您是否尝试过 UPDATE STATISTICS #output 如果不同的 SQL 引擎执行不同,则表明它们使用不同的查询计划。更新临时表的统计信息可以显着改进所选计划。我知道 SQL Server 假设只有一条记录,但 Datawarehouse 版本可能没有
  • #output 中只插入了 1 条记录。正如我所提到的,“Azure SQL Server”不需要时间。 (我在循环中运行它以查看差异的大小,而在 SQLDW 中花费 45 分钟在 SQL Server 中花费了 4 秒。所以差异是巨大的)。
  • 我还使用 CREATE STATISTICS stats_col1 在#output (val) 上更新了统计信息,但没有区别

标签: sql-server performance join temp-tables azure-sqldw


【解决方案1】:

Azure SQL 数据仓库的主张是两位数 TB 的数据和数十亿行。这就是它的根本设计目的,因此您很可能会发现,对于某些较小的查询、某些查询模式和较小的数据库,它们将无法执行,就像您会发现将 30TB 加载到 SQL PaaS 数据库中无法执行一样任何一个。在这些情况下,您需要重新考虑您的查询以及您是否真的想在那里运行这些查询。例如,在这种情况下,一个简单的重写为 UNION 查询在我的 Azure SQL 数据仓库中带来了亚秒级的性能,例如

SELECT val FROM #output
UNION ALL
SELECT val FROM #output
UNION ALL
SELECT val FROM #output
UNION ALL
SELECT val FROM #output
UNION ALL
SELECT val FROM #output
UNION ALL
SELECT val FROM #output
UNION ALL
SELECT val FROM #output
UNION ALL
SELECT val FROM #output


SELECT *
FROM
    (
    SELECT 'a' s, val FROM #output
    UNION ALL
    SELECT 'b' s, val FROM #output
    UNION ALL
    SELECT 'c' s, val FROM #output
    UNION ALL
    SELECT 'd' s, val FROM #output
    UNION ALL
    SELECT 'e' s, val FROM #output
    UNION ALL
    SELECT 'f' s, val FROM #output
    UNION ALL
    SELECT 'g' s, val FROM #output
    UNION ALL
    SELECT 'h' s, val FROM #output
    ) x
PIVOT ( MAX(val) FOR s In ( [a], [b], [c], [d], [e], [f], [g], [h] ) ) pvt


-- Use CTAS to materialise the pivot view if required
CREATE TABLE #output2
WITH
(
    DISTRIBUTION = ROUND_ROBIN,
    LOCATION = USER_DB,
    HEAP
)
AS
SELECT *
FROM
    (
    SELECT 'a' s, val FROM #output
    UNION ALL
    SELECT 'b' s, val FROM #output
    UNION ALL
    SELECT 'c' s, val FROM #output
    UNION ALL
    SELECT 'd' s, val FROM #output
    UNION ALL
    SELECT 'e' s, val FROM #output
    UNION ALL
    SELECT 'f' s, val FROM #output
    UNION ALL
    SELECT 'g' s, val FROM #output
    UNION ALL
    SELECT 'h' s, val FROM #output
    ) x
PIVOT ( MAX(val) FOR s In ( [a], [b], [c], [d], [e], [f], [g], [h] ) ) pvt

如果您确实需要将行作为列,您可以随时使用PIVOT。我最近在创建大数字表时遇到了类似的问题。原始查询使用了一个循环,这通常是不好的做法,但它在 vanilla SQL Server 上运行几秒钟,并且是一次性操作。 Azure SQL Datawarehouse 的性能很糟糕,所以我只是在本地实例上运行查询,使用 bcp 复制数据并在几分钟内将其发送到仓库中。 (我还找到了一种更基于集合的方式来生成数字表:)

我们还在考虑使用产品的仓库版本中尚不可用的变更数据捕获 (CDC),因此我们研究了在 vanilla SQL Server 中托管暂存区域,在这些表上使用 CDC 并移交给通过 SSIS 和 CDC 功能的仓库。我们已经拒绝了,但你明白了;如果您有真正的查询需要执行,但不会考虑重写它们,甚至不会考虑在 VM 中使用传统版本的 SQL Server,然后通过 SSIS、Polybase 等传递到仓库

HTH

(这可能应该移至 dba.stackexchange.com)

PS 为了排除显而易见的问题,我假设您知道您可以简单地编写此查询,并且您只是以这种方式编写它以突出显示一个问题:

SELECT val, val, val, val, val, val, val
FROM #output

我对此进行了更多挖掘,发现如果您已连接到主数据库,那么此查询运行得又快又好。您不能使用USE 语句来更改 Azure SQL 数据仓库中的数据库上下文,但如果您是通过某些客户端(例如 SSIS、sqlcmd)连接的,那么这可能是一种解决方法。我仍然坚持我最初的断言,即某些低容量查询模式并不特别适合这个版本的产品。我还在查看EXPLAIN 关键字,它提供了一种查询计划,因此您可以了解幕后发生的事情,但这是另一个故事......

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-01-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-06-30
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多