Question

Why does using ISNULL() when updating through a linked server use Remote Scan to retrieve all rows and filter locally instead of filtering through Remote Query?

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'

The execution plan is as below: ExecutionPlan1

The table does have a nonclustered unique index for the accounts column, but ISNULL() is not used on the accounts column and the index should still be usable. Am I missing anything here?

Was it helpful?

Solution

Am I missing anything here?

Not really. You are discovering that distributed query processing has lots of tricky limitations like this.

So the rule of thumb for using Linked Servers is to always use passthrough queries if you want remote execution.

exec (
'
UPDATE database1.dbo.table1 WITH(ROWLOCK)
SET number = ISNULL(number,0)
WHERE accounts = ''123''
'
) at LINKEDSERVER1

OTHER TIPS

I'm not 100% sure other than the difference in execution plan is enough for it to dumbly switch to a Remote Scan instead of Remote Query (maybe because of the order of events with the SET operator and using a function on the value being set, statistics or sargable related?).

What if you wrote the query like this instead, what does the execution plan show?

UPDATE LINKEDSERVER1.database1.dbo.table1 WITH(ROWLOCK)
SET number = 0
WHERE accounts = '123'
    AND number IS NULL

Another trick I've found to work in enforcing a Remote Query operator is first pulling the clustered index columns of the records that are needed to be updated into a local Temp Table, then joining to the remote table by that local Temp Table as part of the UPDATE to filter down the records instead and ensure a Remote Query occurs.

Example:

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
Licensed under: CC-BY-SA with attribution
Not affiliated with dba.stackexchange
scroll top