Maj*_*j0r 7 performance sql-server sql-server-2012 enterprise-edition query-performance
我想就我遇到的问题提供一些意见。我们有一段代码在我们的存储过程中重复,每次都需要相当长的时间来处理,当合并时读取的数量会在数十万个项目上达到数亿。基本上我们有一个项目,并且项目可以有多达12台机器,每一个都有自己的状态。
这些是(简化的)表结构:
CREATE TABLE dbo.ItemMachineState
(
[itemID] [int],
[machineID] [int],
[stateID] [int]
)
CREATE TABLE dbo.Transition
(
[machineID] [int] NOT NULL,
[eventID] [int] NOT NULL,
[stateID] [int] NOT NULL,
[nextStateID] [int] NOT NULL
)
Run Code Online (Sandbox Code Playgroud)
发生的情况是,在处理过程中,我们创建了一个我们针对的 #temp 表,并且最终每个项目都有一个 eventID。然后将该临时表连接回 ItemState 和 Transition,如下所示:
UPDATE dbo.ItemState
SET stateID = tr.nextStateID
FROM #temp t
JOIN dbo.ItemMachineState ist ON ist.itemID = t.itemID
JOIN Transition tr ON tr.stateID = ist.stateID AND
tr.machineID = ist.machineID AND
tr.eventID = t.eventID
Run Code Online (Sandbox Code Playgroud)
因此,我们计算的 eventID 决定了给定项目的机器会发生什么,这取决于它们各自所处的状态。 问题是一个事件可以在一个运动中操纵零个或多个机器状态,如果该事件是相关的到状态和机器的特定组合。
以下是这些状态转换之一的示例:
ItemID 3468489 在 ItemMachineState 中首先看起来像这样...
itemID machineID stateID
----------- ----------- -----------
3468489 12 4
3468489 14 113
3468489 15 157
3468489 16 165
3468489 18 169
3468489 19 165
3468489 20 157
3468489 21 165
3468489 23 173
3468489 24 173
3468489 26 9
3468489 36 9
Run Code Online (Sandbox Code Playgroud)
我们做了一些工作,最终有一个#temp 表,它有一个 ItemID 和一个 EventID...
itemID eventID
----------- -----------
3468489 64
Run Code Online (Sandbox Code Playgroud)
然后我们将这两个表连接到 Transition,对于这个特定的 eventID,它看起来像这样:
machineID eventID stateID nextStateID
----------- ----------- ----------- -----------
13 64 73 79
13 64 74 79
13 64 75 79
13 64 76 79
13 64 77 79
13 64 78 79
13 64 187 79
13 64 188 79
13 64 189 79
13 64 190 79
13 64 191 79
36 64 9 79
36 64 194 79
36 64 196 79
36 64 208 79
36 64 210 79
36 64 213 79
36 64 218 79
46 64 73 79
47 64 73 79
70 64 73 79
70 64 75 79
70 64 76 79
70 64 77 79
70 64 78 79
Run Code Online (Sandbox Code Playgroud)
把它们放在一起:
SELECT t.itemID, t.eventID, ist.machineID, ist.stateID, tr.nextStateID
FROM #temp t
JOIN dbo.ItemMachineState ist ON ist.itemID = t.itemID
JOIN Transition tr ON tr.stateID = ist.stateID AND
tr.machineID = ist.machineID AND
tr.eventID = t.eventID
itemID eventID machineID stateID nextStateID
----------- ----------- ----------- ----------- -----------
3468489 64 36 9 79
Run Code Online (Sandbox Code Playgroud)
因此,在此特定示例中,此事件仅与此项目的一台机器相关。它的 stateID 在 machineID 36 上从 9 更新为 79,并且此 Item 的其他所有内容都保持不变。
我想就如何以不同的方式处理这个问题提出建议。我们不能离开表结构,但我们可以改变在转换/事件期间将 stateID 设置为 nextStateID 的方式。正如你在上面看到的,这是通过消除来工作的;我们需要当前状态和机器来确定下一个状态是什么,对于那台机器,对于那个事件。在某些情况下,这不会更新任何内容,有时它会一次性更新多台机器,我们喜欢这种能力。我不认为通过简单地更改索引或添加查询提示就能找到解决这个问题的最精简的解决方案,我们需要一种新方法来限制读取次数和处理时间,但为我们提供相同的功能。
我想避免将索引等引入讨论中,因为我必须使用真实的例子,这污染了我在这里要问的问题的本质,我更改了列和表的名称以简化我的问题。无论如何,给你:
查询计划 http://pastebin.com/xhPa4t8d,创建和索引脚本 http://pastebin.com/sp70QuEJ
请注意,在查询计划中,我们强制执行 INNER LOOP JOIN。如果只使用简单的 JOIN,则查询的处理时间会呈指数级增长。
使用 @wBob UNIQUE CLUSTERED 索引,之前:
使用OPTION (MERGE JOIN, HASH JOIN)
导致此执行计划和结果:
将很快更新其他信息
归档时间: |
|
查看次数: |
3216 次 |
最近记录: |