繁体   English   中英

在这种情况下如何避免 SQL Server 上的表扫描

[英]How to avoid table scan on SQL Server in this situation

有两个表, CostsLogs 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM