Jie*_*ong 4 sql-server execution-plan linked-server sql-server-2014
为什么在通过链接服务器更新时使用 ISNULL() 使用远程扫描来检索所有行并在本地进行过滤,而不是通过远程查询进行过滤?
UPDATE LINKEDSERVER1.database1.dbo.table1 WITH(ROWLOCK)
SET number = ISNULL(number,0)
WHERE accounts = '123'
UPDATE LINKEDSERVER1.database1.dbo.table1 WITH(ROWLOCK)
SET number = number
WHERE accounts = '123'
Run Code Online (Sandbox Code Playgroud)
该表确实有一个针对帐户列的非聚集唯一索引,但 ISNULL() 未用于帐户列并且该索引应该仍然可用。我在这里错过了什么吗?
我在这里错过了什么吗?
并不真地。您会发现分布式查询处理有很多这样的棘手限制。
因此,如果您想要远程执行,使用链接服务器的经验法则是始终使用直通查询。
exec (
'
UPDATE database1.dbo.table1 WITH(ROWLOCK)
SET number = ISNULL(number,0)
WHERE accounts = ''123''
'
) at LINKEDSERVER1
Run Code Online (Sandbox Code Playgroud)
这只是一个猜测,很可能只是没有允许ISNULL(number,0)
推送到远程服务器的转换。
我不是 100% 确定除了执行计划的差异足以让它愚蠢地切换到远程扫描而不是远程查询(可能是因为 SET 运算符的事件顺序以及对正在设置的值使用函数,统计或 sargable 相关?)。
如果您改为这样编写查询,执行计划会显示什么?
UPDATE LINKEDSERVER1.database1.dbo.table1 WITH(ROWLOCK)
SET number = 0
WHERE accounts = '123'
AND number IS NULL
Run Code Online (Sandbox Code Playgroud)
我发现在执行远程查询操作时的另一个技巧是首先将需要更新的记录的聚集索引列拉到本地临时表中,然后通过该本地临时表加入远程表作为该UPDATE
过滤下来的记录,而不是和确保远程查询时。
例子:
SELECT ClusteredIndexColumn
INTO #TempTable1
FROM LINKEDSERVER1.database1.dbo.table1 -- if you have a local copy of table1 here that'd be even better
WHERE accounts = '123'
AND number IS NULL
UPDATE T1
SET number = 0
FROM LINKEDSERVER1.database1.dbo.table1 AS T1 WITH(ROWLOCK)
INNER JOIN #TempTable1 AS TT1
ON T1.ClusteredIndexColumn = TT1.ClusteredIndexColumn
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
197 次 |
最近记录: |