use*_*379 3 performance sql-server optimization execution-plan
我改变了这个查询
SELECT ...
FROM linkedServer.DB.Schema.Table1 t1
LEFT JOIN linkedServer.DB.Schema.Table2 t2 ON t1.ORDER_ID = t2.ORDER_ID
WHERE t1.BRANCH_ID NOT IN (
'009991', '009992', '009993', '009994', '009995', '009996', '009999', '900001',
'900002', '900003', '900004', '900005', '900006', '900007', '900008', '999991',
'999992', '999993', '999994', '999995'
)
GROUP BY ...
Run Code Online (Sandbox Code Playgroud)
进入这个
SELECT ...
FROM linkedServer.DB.Schema.Table1 t1
LEFT JOIN linkedServer.DB.Schema.Table2 t2 ON t1.ORDER_ID = t2.ORDER_ID
WHERE t1.BRANCH_ID NOT IN (
SELECT b.BRANCH_ID
FROM TB_BRANCH b --25 rows in total
WHERE b.START_DT = '99999999' --the result of this sub-query is fewer than list above.
)
GROUP BY ...
Run Code Online (Sandbox Code Playgroud)
然后性能下降。
为什么执行计划会发生这种巨大的变化?在 IN 子句中使用子查询时如何避免性能下降?
您正在使用链接服务器访问Table1和Table2。
第一个查询按原样发送到另一台服务器并在那里执行,仅返回您想要的行。
第二个查询是在本地表TB_BRANCH 和远程表之间进行连接Table1。为此,它Table1从Table2本地服务器获取所有行以及从本地服务器获取所有行,并在本地执行连接操作。
性能下降是因为将远程服务器的全部内容Table1和Table2从远程服务器移动到本地服务器需要时间。
在 IN 子句中使用子查询时如何避免性能下降?
将TB_BRANCH(25 行)的内容移动到远程服务器以避免在不同服务器上的表之间进行连接。
将行从TB_BRANCH远程服务器移动到远程服务器的一种方法是使用sp_executesql值作为 XML 结构中的参数在远程服务器上执行查询。将 XML 解压缩到表变量并在主查询中使用表变量。
declare @X varchar(max);
set @X = (
select b.BRANCH_ID
from dbo.TB_BRANCH as b
where b.START_DT = '99999999'
for xml path('')
);
-- Create a SQL Statement
declare @SQL nvarchar(max);
set @SQL = '
declare @B table(BRANCH_ID varchar(10) primary key);
insert into @B(BRANCH_ID)
select B.X.value(''.'', ''varchar(10)'')
from (select cast(@X as xml)) as T(X)
cross apply T.X.nodes(''/BRANCH_ID/text()'') as B(X);
select *
from Schema.Table1 as t1
left outer join Schema.Table2 as t2
on t1.ORDER_ID = T2.ORDER_ID
where t1.BRANCH_ID not in (
select B.BRANCH_ID
from @B as B
);';
exec linkedServer.DB.Schema.sp_executesql @SQL, N'@X varchar(max)', @X
Run Code Online (Sandbox Code Playgroud)
我猜到的数据类型BRANCH_ID是varchar(10)你需要在脚本中的两个地方修改它,如果它是别的东西。
XML 参数必须是 avarchar(max)而不是 as,XML因为XML远程查询不支持该数据类型。也不支持表值参数,因此这里不是一个选项。
这个查询的查询计划不是很有趣。这将只是一个远程扫描。如果您想知道远程端的计划是什么样的,您必须在那里捕获计划。