Gre*_*icz 3 performance sql-server sql-server-2012 performance-tuning
我有一个相当简单的更新/查询,多年来一直让我感到非常悲伤。
最简单的形式是:
update VillageSemaphore
set TimeStamp = getdate()
where VillageID in (@X, @Y)
Run Code Online (Sandbox Code Playgroud)
但是,在某些存储过程中,查询还包括此“OR VillageID in (...)”子查询
update VillageSemaphore
set TimeStamp = getdate()
where VillageID in (@X, @Y)
OR VillageID in ( -- this subquery can return many rows, many different VillageIDs
select VSU.SupportingVillageID
from VillageSupportUnits VSU
where SupportedVillageID = @Z
and VSU.UnitCount <> 0
)
Run Code Online (Sandbox Code Playgroud)
请注意,此 OR 可以返回多个村庄 ID,而不仅仅是一个 @Z。这个版本的查询,有时会运行很长时间。没有索引重建,统计重建有帮助。当 Villages 表的内容被删除并重新填充时,它运行缓慢。在这种情况下,行数将只有几百行。我从来不知道这是为什么,而且总是忍受它。
但是,最近我正在查看查询计划:
与实际行数 (2) 相比,估计的行数 (4000) 似乎很大。
我创建了这个统计数据,但它没有帮助
CREATE STATISTICS [stat_x] ON [VillageSU]([UnitCount], [VillageID])
Run Code Online (Sandbox Code Playgroud)
所以我的问题:有什么建议为什么会这样,我可以做些什么来改善这一点?
作为参考,该表如下所示:
CREATE TABLE VillageSemaphore(
VillageID int NOT NULL,
TimeStamp datetime NOT NULL,
CONSTRAINT PK97 PRIMARY KEY CLUSTERED (VillageID)
)
Run Code Online (Sandbox Code Playgroud)
更新:按照 srutzky 的建议尝试此版本的查询
CREATE TABLE #VillagesToLock (VillageID INT NOT NULL);
insert into #VillagesToLock values (@X)
insert into #VillagesToLock values (@Y)
insert into #VillagesToLock select VSU.SupportingVillageID
from VillageSupportUnits VSU
where SupportedVillageID = @Z
and VSU.UnitCount <> 0
update VillageSemaphore set TimeStamp = getdate()
where VillageID in (select VillageID from #VillagesToLock)
Run Code Online (Sandbox Code Playgroud)
这是到目前为止的结果:http : //screencast.com/t/96KafTPoNGM - 查询计划看起来更好。
查询的成本也从 3% 下降到 1%,所以这看起来不错。3% 可能看起来不多,但这是一个 2500 行的存储过程!
问题:我无法将 #VillagesToLock.VillageID 设为 PK,因为它不是唯一的。我希望 #VillagesToLock 通常不超过 2-10 行。VillageSemaphore 可能有数千行。在这种情况下,是否值得在 #VillagesToLock 上放置索引?
感谢所有有时间帮助我的人!
虽然我不相信这是查询本身的问题(当它运行缓慢时你检查阻塞了吗?你检查运行时发生的等待类型),IN并且OR可能是一个有问题的模式来优化. 您是否考虑过将其分解为多个语句?
UPDATE dbo.VillageSemaphoreset
SET [TimeStamp] = GETDATE() -- TimeStamp is a terrible column name btw
WHERE VillageID = @X;
UPDATE dbo.VillageSemaphoreset
SET [TimeStamp] = GETDATE()
WHERE VillageID = @Y;
IF (whatever condition leads you to "sometimes add this OR")
BEGIN
UPDATE v
SET [TimeStamp] = GETDATE()
FROM dbo.VillageSemaphoreset AS v
WHERE VillageID = @Z
AND EXISTS
(
SELECT 1 FROM dbo.VillageSU AS vs
WHERE vs.VillageID = v.VillageID
);
END
Run Code Online (Sandbox Code Playgroud)
这可能会解决估计问题,但我同意 Max,UnitCount无论如何,带有前导列的统计数据对这些查询的估计没有帮助。
| 归档时间: |
|
| 查看次数: |
209 次 |
| 最近记录: |