增长数据的绩效战略

时间:2016-02-25 22:30:36

标签: sql-server performance

我知道性能调优是需要针对每个环境进行的。但我已尽最大努力使我的问题清楚,看看我是否遗漏了可能的改进。

我在SQL Server 2005中有一个表[TestExecutions]。截至今天,它有大约20万条记录。预计在几个月内将增长到500万。

CREATE TABLE [dbo].[TestExecutions]
(
    [TestExecutionID] [int] IDENTITY(1,1) NOT NULL,
    [OrderID] [int] NOT NULL,
    [LineItemID] [int] NOT NULL,
    [Manifest] [char](7) NOT NULL,
    [RowCompanyCD] [char](4) NOT NULL,
    [RowReferenceID] [int] NOT NULL,
    [RowReferenceValue] [char](3) NOT NULL,
    [ExecutedTime] [datetime] NOT NULL
) 

CREATE INDEX [IX_TestExecutions_OrderID] 
ON [dbo].[TestExecutions] ([OrderID]) 
INCLUDE ([LineItemID], [Manifest], [RowCompanyCD], [RowReferenceID])

我有两个查询用于相同的目的(Query2和Query 3)。对于#OrdersForRC中的100条记录,Query2工作得更好(39%对47%),而在#OrdersForRC中有10000条记录,根据执行计划,查询3工作得更好(53%对33%)。

在使用的最初几个月内,#OrdersForRC表将有近100条记录。它将在几个月内逐渐增加到2500条记录。

在以下两种方法中,哪种方法适用于这种逐步增长的方案?或者,即使数据增长,是否存在使一种方法比另一种更好的策略?

注意:在Plan2中,第一个查询使用Hash Match

参考

  1. query optimizer operator choice - nested loops vs hash match (or merge)
  2. Execution Plan Basics — Hash Match Confusion
  3. 测试查询

    CREATE TABLE #OrdersForRC 
    (
        OrderID INT
    )
    
    INSERT INTO #OrdersForRC
    --SELECT DISTINCT TOP 100 OrderID FROM [TestExecutions]
    SELECT DISTINCT TOP 5000 OrderID FROM LWManifestReceiptExecutions
    
    --QUERY 2:
    SELECT H.OrderID,H.LineItemID,H.Manifest,H.RowCompanyCD,H.RowReferenceID
    FROM dbo.[TestExecutions] (NOLOCK) H
    INNER JOIN #OrdersForRC R
        ON R.OrderID = H.OrderID
    
    --QUERY 3:
    SELECT H.OrderID,H.LineItemID,H.Manifest,H.RowCompanyCD,H.RowReferenceID
    FROM dbo.[TestExecutions] (NOLOCK) H
    WHERE OrderID IN (SELECT OrderID FROM #OrdersForRC)
    
    DROP TABLE #OrdersForRC
    

    计划1

    enter image description here

    计划2

    enter image description here

1 个答案:

答案 0 :(得分:1)

AS上面评论过你没有指定表LWManifestReceiptExecutions的表定义以及它中的行数和        您正在选择没有订单的前N行,您想要TOP N随机ID还是按特定顺序或顺序对您来说无关紧要?

如果订单很重要,那么您可以在Order By中创建所需的列索引  如果订单ID在[dbo]。[TestExecutions]表中是唯一的,那么您应该将其标记为唯一的drop并重新创建索引,如果UNIQUE

 Drop Index [IX_TestExecutions_OrderID]  ON [dbo].[TestExecutions]
  CREATE UNIQUE INDEX   [IX_TestExecutions_OrderID] 
ON [dbo].[TestExecutions]  ([OrderID])  
INCLUDE ([LineItemID], [Manifest], [RowCompanyCD], [RowReferenceID])

您曾问过数据是否会持续增长,并且会在几个月内达到数百万。 无需担心sql server可以使用正确的构建模式和索引轻松处理这些查询, 当这个数据模型开始受到伤害时,你可以看看 其他选项,但现在不是,我看到人们在sql server中处理数十亿的数据。

我可以看到你在查询成本的基础上比较查询,你得出结论 查询具有更高的百分比意味着这更昂贵,

情况并非如此总是查询成本基于查询计划中所有迭代器的聚合子树成本, 并且Iterator的总估计成本是I / O和CPU组件的简单总和。 成本值表示特定硬件配置的预期执行时间(以秒为单位) 但是使用现代硬件,这些成本可能无关紧要。

现在来看你的问题, 您已经表达了两个查询来获得结果,但两者都不相同,

  

IN PLAN 1查询1

  • 由JOIN
  • 表示

QO正在选择嵌套循环连接,这对于特定的场景是个不错的选择  关键字OrderID IN表#OrdersForRC的每一行寻求表dbo中的值。[TestExecutions]  直到所有行匹配

  

IN PLAN 2 Query 2

  • 由IN

    表示

    QO正在执行与查询一样的操作,但有更多不同的排序(排序和流聚合) 它背后的原因是你已经将此查询表达为IN,而表#OrdersForRC可以包含重复的行 只是为了消除这一点是必要的。

  

IN PLAN 2查询1

  • 由JOIN
  • 表示

现在#OrdersForRC中表中的行数为1000,QO选择了循环连接的散列连接 因为1000行的循环连接比散列连接和循环连接具有更多的成本,并且行是无序的 并且可以包含空值,因此HASH JOIN在这里是完美的策略。

  

IN PLAN 2 Query 2

  • 由IN
  • 表示

QO选择了Distinct Sort的原因与在Plan 2查询2中选择的原因相同,然后是Merge Join 因为行现在按两个表的ID列排序。

IF 你只是将临时表标记为NOT NULL和Unique然后它更有可能你会在JOIN中得到相同的执行计划。

CREATE TABLE #OrdersForRC 
(OrderID INT not null Unique)

执行计划

Performance Strategy for growing data