0

有两个表,CostsLogs。表中的数据Costs可以是数百万行,Logs表中的数据可以是数十亿行。

我需要在每次运行 100 条记录内更新生产环境中服务任务的表中的CostBy列。Costs

CREATE TABLE Cost
(
    C_PK uniqueidentifier primary key not null,
    C_CostBy varchar(3) not null
)

CREATE TABLE Logs
(
    L_PK uniqueidentifier primary key not null,
    L_ParentTable varchar(255) not null,  -- Table Cost and other table's name
    L_ParentID uniqueidentifier not null, -- Cost's pk and other table's pk
    L_Event varchar(3) not null, -- Part are 'ADD' and other event types
    L_User varchar(3) not null 
 )

CREATE NONCLUSTERED INDEX [L_ParentID] 
    ON [dbo].[Costs] ([L_ParentID] ASC)

这是原始更新声明:

UPDATE TOP(100) Costs
SET CostBy = ISNULL(L_User, '~UK')
FROM Costs
LEFT JOIN Logs ON L_ParentID = C_PK AND L_Event = 'ADD'
WHERE CostBy = ''

但是,该语句引入了一个海量的性能问题,table scan in table 的成本很高Costs

我的问题是如何避免表中的表扫描Costs或如何优化更新语句?

提前致谢。

4

1 回答 1

0

您可能想尝试以下方法。

首先,在 Logs 上创建索引,包括所有相关列:

CREATE INDEX ix ON Logs 
(
  L_Parent_ID -- join condition, variable
)
INCLUDE 
(
  L_User -- no filter condition, but you use it your update
)
WHERE 
(
  L_Event = 'ADD' -- join condition, constant
)

如果这是一个唯一索引,即。对于给定的父 ID,只有一行存在 ADD 事件,请确保将其设为唯一索引,因为它可以显着提高性能。

其次,这是一个命中注定的情况,您可以尝试使用 CostBy 索引,因为您只是在寻找要更新的空 CostBy 值。该索引需要根据您的查询进行更新,因为它正在更新它,因此它可能会减慢您的查询速度而不是加快它的速度。这取决于许多因素。

如果您有企业许可证,请同时使用 with WITH (DATA_COMPRESSION = PAGE),它可以显着提高 IO 时间,但会以 CPU 为代价。这取决于哪个是您的瓶颈。

此外,根据数据的性质,更新统计数据可能会改善您的查询。如果 CostBy = '' 的行数与其中的其他值不成比例,您可能会从该字段的完整统计信息中受益。考虑NORECOMPUTE一下您是否只需要它们来执行此特定查询,这一次。

CREATE STATISTICS st_Costs_CostBy
ON Costs (CostBy)  
WITH FULLSCAN, NORECOMPUTE;  
于 2020-03-27T10:48:51.767 回答