1

我已阅读 SQL 数据仓库中的 Azure 并发和工作负载管理 https://azure.microsoft.com/en-us/documentation/articles/sql-data-warehouse-develop-concurrency/ 并了解对数量的限制可以根据规模使用的并发查询,但我无法理解并因此在这里提出的问题是,在测试文档状态时,我无法得到 Azure 声称的结果是真的。并发运行查询所花费的时间几乎与串行运行它们一样长。

示例 这是一个测试示例(只是一个测试) 我有 5 个存储过程,当它们单独运行时,它们每个大约需要 1 秒才能完成。因此,当我连续运行所有 5 个存储过程时,它们大约需要 5 秒,这是可以预料的,但是当我同时运行所有 5 个存储过程时,我希望它们在 1 秒多一点的时间内完成,但它们大约需要 4.5-4.7 秒才能完成。

一些 Azure 专家可以解释可能发生的情况吗?

我认为这可能是资源争用,但 sys.dm_pdw_resource_waits 在 5 个存储过程运行时显示没有阻塞。

当我运行 sys.dm_pdw_exec_requests 时,我看到所有 5 个 exec sproc 查询都在几毫秒内提交。Start_time 和 End_compile_time 也是如此。所有 5 个 sproc 的 end_time 再次在几毫秒内,但 Total_elapsed_time 接近 5000 毫秒,而不是预期的 1000 毫秒。如果我自己运行任何 sproc,则持续时间约为 1000 毫秒。就好像并发将同时启动所有 5 个存储过程,但在内部它们排队并按顺序运行。我最初是在一个有 8 个插槽的 DW200 上测试的,这对于我的 5 个存储过程来说应该足够了。为了安全起见,我扩展到 DW1000,它允许我最多 32 个并发查询(我使用的是 smallrc),但这对这个问题没有帮助。

这是我测试的方法(使用 DW1000)

  1. 我将 1000 条记录加载到 5 个单独的阶段表(stage1、stage2 等)中

    CREATE TABLE dbo.Stage1
    (
         ShortId bigint NOT NULL
        ,TestName varchar(50) NOT NULL
        ,TestValue varchar(50) NOT NULL
        ,CreateDate DateTime NOT NULL 
    )
    WITH
    (
        DISTRIBUTION = HASH (ShortId)
    )
    
  2. 我创建了 5 个事实表(fact1、fact2 等)。每个表具有与 stage 相同的 4 列,并在第一列上使用散列分布。我没有包含列存储索引(请记住,这只是一个测试)

    CREATE TABLE dbo.Fact1
    (
         ShortId bigint NOT NULL
        ,TestName varchar(50) NOT NULL
        ,TestValue varchar(50) NOT NULL
        ,CreateDate DateTime NOT NULL 
    )
    WITH
    (
        DISTRIBUTION = HASH (ShortId)
    )
    
  3. 我创建了 5 个存储过程,将数据从阶段插入到事实中。

    CREATE PROCEDURE dbo.TestLoad1
    AS
    BEGIN
        INSERT INTO dbo.Fact1   --this is dbo.Fact2 in sproc 2 etc...
        SELECT 
           stg.ShortId
          ,stg.PropertyName
          ,stg.PropertyValue 
          ,stg.AcquistionTime
        FROM dbo.Stage1 stg
            WHERE stg.ShortId NOT IN (SELECT ShortId from dbo.Fact1) --Fact2 etc..
    END
    
  4. 在 C# 中,我创建了一个快速测试方法,它创建 5 个连接、命令并使用 BeginExecuteReader/EndExecuteReader 来执行存储过程。(这只是一个测试,所以请原谅样式/代码)

    SqlConnection cnn1 = new SqlConnection("Data Source=<server>;Initial Catalog=<database>;Persist Security Info = True;User ID =<username>;Password = <password>;Pooling = False;MultipleActiveResultSets = False;Connect Timeout = 30;Encrypt = True;TrustServerCertificate = False");
    SqlConnection cnn2 = new SqlConnection("Data Source=<server>;Initial Catalog=<database>;Persist Security Info = True;User ID =<username>;Password = <password>;Pooling = False;MultipleActiveResultSets = False;Connect Timeout = 30;Encrypt = True;TrustServerCertificate = False");
    SqlConnection cnn3 = new SqlConnection("Data Source=<server>;Initial Catalog=<database>;Persist Security Info = True;User ID =<username>;Password = <password>;Pooling = False;MultipleActiveResultSets = False;Connect Timeout = 30;Encrypt = True;TrustServerCertificate = False");
    SqlConnection cnn4 = new SqlConnection("Data Source=<server>;Initial Catalog=<database>;Persist Security Info = True;User ID =<username>;Password = <password>;Pooling = False;MultipleActiveResultSets = False;Connect Timeout = 30;Encrypt = True;TrustServerCertificate = False");
    SqlConnection cnn5 = new SqlConnection("Data Source=<server>;Initial Catalog=<database>;Persist Security Info = True;User ID =<username>;Password = <password>;Pooling = False;MultipleActiveResultSets = False;Connect Timeout = 30;Encrypt = True;TrustServerCertificate = False");
    
    SqlCommand cmd1;
    SqlCommand cmd2;
    SqlCommand cmd3;
    SqlCommand cmd4;
    SqlCommand cmd5;
    IAsyncResult result1;
    IAsyncResult result2;
    IAsyncResult result3;
    IAsyncResult result4;
    IAsyncResult result5;
    SqlDataReader reader1;
    SqlDataReader reader2;
    SqlDataReader reader3;
    SqlDataReader reader4;
    SqlDataReader reader5;
    
    cnn1.Open();
    cnn2.Open();
    cnn3.Open();
    cnn4.Open();
    cnn5.Open();
    
    cmd1 = new SqlCommand("dbo.TestLoad1", cnn1);
    cmd2 = new SqlCommand("dbo.TestLoad2", cnn2);
    cmd3 = new SqlCommand("dbo.TestLoad3", cnn3);
    cmd4 = new SqlCommand("dbo.TestLoad4", cnn4);
    cmd5 = new SqlCommand("dbo.TestLoad5", cnn5);
    
    cmd1.CommandType = CommandType.StoredProcedure;
    cmd2.CommandType = CommandType.StoredProcedure;
    cmd3.CommandType = CommandType.StoredProcedure;
    cmd4.CommandType = CommandType.StoredProcedure;
    cmd5.CommandType = CommandType.StoredProcedure;
    
    result1 = cmd1.BeginExecuteReader(CommandBehavior.SingleRow);
    result2 = cmd2.BeginExecuteReader(CommandBehavior.SingleRow);
    result3 = cmd3.BeginExecuteReader(CommandBehavior.SingleRow);
    result4 = cmd4.BeginExecuteReader(CommandBehavior.SingleRow);
    result5 = cmd5.BeginExecuteReader(CommandBehavior.SingleRow);
    
    reader1 = cmd1.EndExecuteReader(result1);  //this is where the code waits for 5 seconds
    reader2 = cmd2.EndExecuteReader(result2);
    reader3 = cmd3.EndExecuteReader(result3);
    reader4 = cmd4.EndExecuteReader(result4);
    reader5 = cmd5.EndExecuteReader(result5);
    
    reader1.Close();
    reader2.Close();
    reader3.Close();
    reader4.Close();
    reader5.Close();
    

在调试此 C# 代码时,每条语句都小于 1ms,直到我到达行 reader1 = cmd1.EndExecuteReader(result1); 在这里它将等待 4-5 秒,然后继续前进,之后的每一行都很快(<1ms)。

在此延迟期间,如果我从 sys.dm_pdw_exec_requests 运行 select *,我会看到所有 5 个请求都已排队并正在运行。如果我继续重新运行查询持续时间不断增加,那么突然(大约 5 秒)所有 5 个查询都说它们已完成。

在解释我做错了什么或 Azure SQL DW 在内部做什么时,我们将不胜感激。

谢谢

4

1 回答 1

2

SQL 数据仓库允许单个查询通过单个查询来利用所有 CPU 或 IO。当查询能够充分利用资源时,添加另一个也竞争相同资源的查询将意味着两者的运行速度都会变慢。也就是说,如果您有一个使用 100% CPU 的查询并运行另一个同时使用 100% 的查询,则这两个查询将花费两倍的时间。这样做的好处是单个查询将尽可能快地运行,而竞争不同资源的两个查询也将尽可能快地运行。当您像上面那样运行测试时,所有查询都基本相同,预计串行或并行运行测试将花费相同的时间。

为了进一步调查您的结果,您可能会发现监控文章很有用。除了查看 sys.dm_pdw_exec_requests 之外,请尝试查看 sys.dm_pdw_request_steps(分布式 SQL 步骤的执行时间),我希望占 5 秒的大部分以及 sys.dm_pdw_sql_requests(分布式执行时间) )。

顺便说一句,您在上面提到您没有为测试添加列存储索引。在 SQL DW 中,默认表类型是 clustered columnstore。要删除此索引,请按如下方式更改您的 WITH 子句...

WITH(分布=哈希(ShortId),堆)

希望这可以帮助。

于 2016-09-24T16:02:05.593 回答