phe*_*ehr 6 trigger performance sql-server cursors sql-server-2014
我有一个 3rd 方应用程序,它使用一个游标来更新我的 SQL Server 2014 表中的行。我无法修改此代码,因此设计了一种方案,将光标指向具有INSTEAD OF UPDATE触发器的视图,我可以在其中拦截并完全控制更新。我很清楚游标是邪恶的,但我不得不使用它们,因为我无法修改源程序。
当UPDATE ... WHERE CURRENT OF语句执行,它执行聚集索引扫描,而不是寻求以定位光标当前所指向的记录。我无法确定优化器在可能进行搜索时为什么要进行扫描。我相信它是导致问题的光标 + 视图 + 而不是更新触发器的组合,因为如果我从我的测试中删除这 3 个变量中的任何一个,索引查找就会被正确使用。
请注意,表中有多少行并不重要;优化器总是根据执行计划使用扫描。我什至删除了触发器中的所有逻辑以进一步简化测试。
下面是一些简单的代码来重现这个问题:
CREATE TABLE [dbo].[Person](
[Id] [int] IDENTITY(1,1) NOT NULL,
[Name] [varchar](40) NULL,
CONSTRAINT [PK_Person_Id] PRIMARY KEY CLUSTERED ( [Id] ASC )
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF,
ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY])
ON [PRIMARY]
GO
CREATE VIEW [dbo].[vPerson]
AS SELECT Id, Name FROM dbo.Person
GO
CREATE TRIGGER [dbo].[InsteadOfUpdate_vPerson] ON [dbo].[vPerson]
INSTEAD OF UPDATE
AS
BEGIN
SET NOCOUNT ON
END
GO
INSERT INTO Person VALUES('John Doe');
GO
--This will use a seek
UPDATE dbo.vPerson
SET Name = 'Jane Doe'
WHERE Id = 1
GO
--This will not use a seek
DECLARE c CURSOR FOR
SELECT * FROM dbo.vPerson
WHERE Id = 1
FOR UPDATE
OPEN c
FETCH NEXT FROM c
UPDATE dbo.vPerson
SET Name = 'Jane Doe'
WHERE CURRENT OF c
CLOSE c
DEALLOCATE c
GO
Run Code Online (Sandbox Code Playgroud)
任何有关尝试的帮助或建议将不胜感激。
这看起来像是一个疏忽。
当使用执行更新WHERE CURRENT OF
并且目标视图(模式绑定与否)具有 T-SQL 而不是更新触发器时,优化器无法生成应用样式索引循环连接,无论行数或任何其他考虑因素:
这显示了一个表中几乎有 20,000 行的示例(从 AdventureWorks 的 Person 表中复制,碰巧)。
连接谓词“卡住”在嵌套循环连接运算符本身上,而不是被推入内侧以产生搜索:
由于您无法更改代码,您应该通过正常的 Microsoft 支持渠道将此报告为错误。您也可以在 Connect 上报告错误,但通过该路线获得快速响应或修复的机会要低得多。
只是为了兴趣,您所追求的计划可以使用 API 游标定位更新(内部最类似的操作):
DECLARE
@cur integer,
@scrollopt integer = 2 | 8192 | 32768 | 131072, -- DYNAMIC | AUTO_FETCH | CHECK_ACCEPTED_TYPES | DYNAMIC_ACCEPTABLE
@ccopt integer = 2 | 32768 | 131072, -- SCROLL_LOCKS | CHECK_ACCEPTED_OPTS | SCROLL_LOCKS_ACCEPTABLE
@rowcount integer = 1;
-- Open the cursor
EXECUTE sys.sp_cursoropen
@cur OUTPUT,
N'
SELECT * FROM dbo.vPerson WHERE Id = 1;
',
@scrollopt OUTPUT,
@ccopt OUTPUT,
@rowcount OUTPUT;
-- Request a positioned update
EXECUTE sys.sp_cursor
@cur,
1, -- UPDATE
1, -- row number in buffer
'dbo.vPerson', -- table (unambiguous in this case)
'Name=''Banana'''; -- new value
-- Close
EXECUTE sys.sp_cursorclose -1;
Run Code Online (Sandbox Code Playgroud)
执行计划是:
注意 Person 上的索引查找(谓词不是“卡住”):
这不是您的解决方法,因为您无法更改源查询。没有办法暗示或计划指导您解决问题;优化器根本无法生成您在特定情况下期望的搜索计划。尝试例如FORCESEEK
提示只会导致错误消息,指出优化器无法生成执行计划。
归档时间: |
|
查看次数: |
1063 次 |
最近记录: |