如何确保 SQL Server 查询优化器使用查询中的确切表

jab*_*abs 4 sql-server-2008 sql-server ssis

我有一个在 SQL Server 2008 中运行的查询:

select count(*)
from table1 join
table2 on table1.col1 = table2.col2
Run Code Online (Sandbox Code Playgroud)

在运行此脚本的数据仓库中,一个名为的表thin_table1专门填充table1(我们使用此薄表创建索引视图。阅读此答案了解更多详细信息)。

问题是优化器选择使用thin_table1而不是table1在执行期间。这在 SQL Server 2005 中不会发生。这个新的执行计划不适用于我们当前的操作。

如何在数据库或会话级(或在 SSIS 中)关闭此“传递”功能?我在数据加载期间运行了许多 SSIS 包和存储过程,所以我不想单独接触所有对象。

此时,即使知道该功能称为什么也有助于寻找答案。

编辑:
在 2005 年回过头来看看同样的计划。看起来它确实发生在那里,但它的戏剧性效果要小得多。我认为这是 2008 年的问题,但 2005 年出现了相同的功能。

EDIT2:
这里的 DBA 注意到该计划正在引用索引视图。我们通常在运行时删除索引视图,但在这个测试场景中,它们仍然被构建。看起来当索引视图处于活动状态时,它将在查询执行时使用该视图以及与其关联的任何表。

有没有办法绕过这种对索引视图的自动引用?

Pau*_*ite 8

只有两种可能的方式,对您的查询的执行计划可能无法读取table1直接。我将使用在AdventureWorks 示例数据库中创建的以下索引视图来说明:

CREATE VIEW dbo.IV
WITH SCHEMABINDING
AS
SELECT p.ProductID, cnt = COUNT_BIG(*)
FROM Production.Product AS p
JOIN Production.TransactionHistory AS th ON
    th.ProductID = p.ProductID
GROUP BY
    p.ProductID;
GO
CREATE UNIQUE CLUSTERED INDEX cuq
ON dbo.IV (ProductID);
Run Code Online (Sandbox Code Playgroud)

1.表1是索引视图

在这种情况下,优化器将做出基于估计成本的决定,是从索引视图中读取还是扩展视图并从它引用的基表中读取。例子:

SELECT
    ProductID,
    cnt
FROM dbo.IV;
Run Code Online (Sandbox Code Playgroud)

优化器选择直接从索引视图中读取:

直接索引视图

如果优化器选择扩展视图,我们可以使用NOEXPAND 表提示来防止这种情况发生。非企业 SKU需要此提示才能直接访问索引视图。

EXPAND VIEWS 查询提示力扩大视图,导致一个计划,从基本表中读取:

SELECT
    ProductID,
    cnt
FROM dbo.IV
OPTION (EXPAND VIEWS);
Run Code Online (Sandbox Code Playgroud)

扩大视野

2. 存在与查询匹配的索引视图

SQL Server 企业版包含一项功能,可以将查询与索引视图匹配,其中索引视图在查询中引用:

SELECT p.ProductID, cnt = COUNT_BIG(*)
FROM Production.Product AS p
JOIN Production.TransactionHistory AS th ON
    th.ProductID = p.ProductID
WHERE
    p.ProductID BETWEEN 1 AND 100
GROUP BY
    p.ProductID;
Run Code Online (Sandbox Code Playgroud)

尽管没有提到我们的索引视图,执行计划确实:

索引视图匹配

关于索引视图匹配

这种匹配只有在查询处理器保证重写将始终产生正确结果的情况才有可能。这些保证包括以下事实:对索引视图引用的表的任何更改也将反映在索引视图中。

任何INSERTUPDATEDELETEMERGE查询,影响ProductTransactionHistory表将添加到执行计划,使我们的索引视图进行相应的修改额外的操作。

查询优化器不会跟踪用户可能从基表创建的任何表 - 它们不会被维护以反映基表更改,并且在这些新表上创建的任何索引视图将仅反映对这些表的更改,不是原件。这里没有魔法——索引视图与其基表之间的关系非常明确。

薄表示例

举一个似乎与您的问题相匹配的示例,假设我们从Product基表中创建了一个“精简”的提取,其中仅包含ProductID列:

CREATE TABLE dbo.ThinProduct
(
    ProductID integer NOT NULL

    CONSTRAINT PK_ThinProduct
    PRIMARY KEY (ProductID)
);

INSERT dbo.ThinProduct
    (ProductID)
SELECT
    p.ProductID
FROM Production.Product AS p;
Run Code Online (Sandbox Code Playgroud)

现在我们删除原始索引视图并创建一个引用瘦表的新视图:

DROP VIEW dbo.IV;
GO
CREATE VIEW dbo.IVthin
WITH SCHEMABINDING
AS
SELECT p.ProductID, cnt = COUNT_BIG(*)
FROM dbo.ThinProduct AS p
JOIN Production.TransactionHistory AS th ON
    th.ProductID = p.ProductID
GROUP BY
    p.ProductID;
GO
CREATE UNIQUE CLUSTERED INDEX cuq
ON dbo.IVthin (ProductID);
Run Code Online (Sandbox Code Playgroud)

直接引用瘦 Product 表的新查询可以使用新的索引视图:

SELECT p.ProductID, cnt = COUNT_BIG(*)
FROM dbo.ThinProduct AS p
JOIN Production.TransactionHistory AS th ON
    th.ProductID = p.ProductID
WHERE
    p.ProductID BETWEEN 1 AND 100
GROUP BY
    p.ProductID;
Run Code Online (Sandbox Code Playgroud)

细索引视图

引用原始Product表的查询不能使用这个新的索引视图,因为不能保证IVthinProduct表的任何更改保持同步(它将反映对ThinProduct表的更改):

SELECT p.ProductID, cnt = COUNT_BIG(*)
FROM Production.Product AS p
JOIN Production.TransactionHistory AS th ON
    th.ProductID = p.ProductID
WHERE
    p.ProductID BETWEEN 1 AND 100
GROUP BY
    p.ProductID;
Run Code Online (Sandbox Code Playgroud)

执行计划显示基表访问 - 它不能使用索引视图:

基表访问计划

概括

索引视图匹配只能在引擎强制执行适当的保证时执行。问题中概述的场景不能像那里概述的那样发生。SSIS 包必须引用可扩展的索引视图或发出可与索引视图匹配的查询,table1以便查询引用解析为该命名对象以外的任何内容。

我很欣赏这个答案可能对你没有帮助,除非是一般意义上的,但是围绕这个问题的讨论已经持续了很长一段时间,没有出现明确的细节。通过包含实际的 SSIS 查询、表和索引视图定义以及实际执行计划,可以使回答者更容易具体解决该问题。