当 where 子句使用 OR 在连接中跨多个表进行过滤时,会发生表扫描而不是索引查找

Ric*_*ckJ 2 join sql-server index-tuning sql-server-2016

我们有一个应用程序生成的查询,该查询使用一个视图,该视图具有两个通过 LEFT OUTER 连接连接的表。当仅从一个表(任一表)中按字段过滤时,会发生索引查找并且速度相当快。当 where 子句使用 OR 包含两个表中字段的条件时,查询计划将切换到表扫描并且不使用任何索引。

被过滤的所有四个字段都在它们各自的表上建立索引。

快速查询计划,我从一张表中筛选 3 个字段:https : //www.brentozar.com/pastetheplan/?id=Hym_4PRSO

慢查询计划,我过滤四个字段......三个来自一个表,一个来自另一个表:https : //www.brentozar.com/pastetheplan/?id=r1dVNDRHO

理想情况下,我想了解为什么会发生这种情况以及如何推动查询引擎利用所有索引。

我考虑过联合,但不幸的是,这个遗留系统正在使用ntext无法联合的值。还要注意两个表之间的连接是一对一的,所以我真的希望优化器利用索引,但也许它不知道?

Rob*_*ley 5

在我看来,它正在执行扫描,因为如果 T1011 中的条件成立,它很可能需要来自 T553 的行。另一方面,如果 T553 上的任何条件成立,它将需要来自 T1011 的行。

因此索引必须能够处理在 T553 中查找行然后从 T1011 中拉入相关行,以及在 T1011 中查找行并从 T553 中拉入相关行。Query Optimizer 认为最好的方式是实现良好的连接并过滤结果。

为了使它更好,通过查询使用两种方式的联合。这应该有助于它决定以首选方式执行此操作,并且您可以根据需要优化 Union 的每一方。

就像是:

SELECT *, ROW_NUMBER....
FROM
(
SELECT *
FROM T1617
WHERE
  C1402001100 LIKE @P0
  OR C200000001 LIKE @P2
  OR C200000020 LIKE @P3
UNION
SELECT *
FROM T1617
WHERE C260100004 LIKE @P1
) t
Run Code Online (Sandbox Code Playgroud)

使用SELECT CAST(ntextCol as nvarchar(max)), ...的东西,它可以是联合在一起。

要记住的一件事是UNION操作员将删除重复项,不仅在两个数据集之间,而且在它们内部也是如此。不过,根据搜索中涉及的对象,这里有一些 PK。如果它确实适用于此处,那么答案将是在 的每一侧的视图中包含唯一的内容UNION,然后将其保留在外部查询中。