[英]How to avoid table scan on SQL Server in this situation
有两个表, Costs
和Logs
。 Costs
表的数据可以是百万行, Logs
表的数据可以是几十亿行。
我需要在每次运行 100 条记录内更新生产环境中服务任务中Costs
表中的CostBy
列。
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 = ''
但是,该语句引入了一个巨大的性能问题, Costs
表中的表扫描Costs
高。
我的问题是如何避免Costs
表中的表扫描或如何优化更新语句?
提前致谢。
您可能想尝试以下操作。
首先,在 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 (DATA_COMPRESSION = PAGE)
,它可以以 CPU 为代价显着改善 IO 时间。 这取决于哪个是你的瓶颈。
此外,根据数据的性质,更新统计信息可能会改善您的查询。 如果 CostBy = '' 的行数与其中的其他值不成比例,您可能会受益于该字段的完整统计信息。 如果您只需要在此特定查询中使用它们,请考虑使用NORECOMPUTE
,这一次。
CREATE STATISTICS st_Costs_CostBy
ON Costs (CostBy)
WITH FULLSCAN, NORECOMPUTE;
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.