【问题标题】:Performance Strategy for growing data增长数据的性能策略
【发布时间】:2016-02-25 22:30:36
【问题描述】:

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

我在 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])

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

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

在以下两种方法中,哪一种适合这种逐渐增长的场景?或者有什么策略可以让一种方法在数据增长的情况下比另一种更有效?

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

参考文献

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

测试查询

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

计划 2

【问题讨论】:

  • 嘿@Lijo,你能创建 LWManifestReceiptExecutions 表的表和索引吗
  • 你想从 LWManifestReceiptExecutions 中选择 DISTINCT TOP 5000 OrderID 无序还是你可以通过 orderid 接受它?

标签: sql-server performance


【解决方案1】:

正如上面评论的那样,您没有指定表 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 中处理数十亿数据。

我可以看到您正在根据查询成本比较查询,您得出的结论是 更高百分比的查询意味着这更昂贵,

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

现在来回答您的问题, 您已经表达了两个查询以获得结果,但两者并不相同,

IN PLAN 1 查询 1

  • 由 JOIN 表示

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

IN PLAN 2 查询 2

  • 用IN表示

    QO 与查询一做同样的事情,但有额外的不同排序(排序和流聚合) 其背后的原因是您将此查询表示为 IN 并且表 #OrdersForRC 可以包含重复的行 只是为了消除它是必要的。

IN PLAN 2 查询 1

  • 由 JOIN 表示

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

IN PLAN 2 查询 2

  • 由 IN 表示

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

如果您只需将临时表标记为 NOT NULL 和 Unique 那么您更有可能在 JOIN 中获得相同的执行计划。

CREATE TABLE #OrdersForRC 
(OrderID INT not null Unique)

执行计划

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2010-12-30
    • 2018-11-10
    • 1970-01-01
    • 1970-01-01
    • 2012-08-10
    • 1970-01-01
    • 2011-02-04
    • 1970-01-01
    相关资源
    最近更新 更多