IN 子句 - 列表值和查询之间的性能差异

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 子句中使用子查询时如何避免性能下降?

Mik*_*son 9

您正在使用链接服务器访问Table1Table2

第一个查询按原样发送到另一台服务器并在那里执行,仅返回您想要的行。

第二个查询是在本地表TB_BRANCH 和远程表之间进行连接Table1。为此,它Table1Table2本地服务器获取所有行以及从本地服务器获取所有行,并在本地执行连接操作。

性能下降是因为将远程服务器的全部内容Table1Table2从远程服务器移动到本地服务器需要时间。

在 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_IDvarchar(10)你需要在脚本中的两个地方修改它,如果它是别的东西。

XML 参数必须是 avarchar(max)而不是 as,XML因为XML远程查询不支持该数据类型。也不支持表值参数,因此这里不是一个选项。

这个查询的查询计划不是很有趣。这将只是一个远程扫描。如果您想知道远程端的计划是什么样的,您必须在那里捕获计划。