是否可以强制优化器消除此分区视图中的不相关表?

swa*_*eck 22 sql-server partitioning sql-server-2014

我正在为大表测试不同的体系结构,我看到的一个建议是使用分区视图,将大表分解为一系列较小的“分区”表。

1 , 2 , 3 , 4

在测试这种方法时,我发现了一些对我来说没有多大意义的东西。当我过滤事实视图上的“分区列”时,优化器只查找相关表。此外,如果我过滤维度表上的那一列,优化器会消除不必要的表。

但是,如果我过滤维度的其他方面,优化器会在每个基表的 PK/CI 上寻找。

以下是相关查询:

select 
    od.[Year], 
    AvgValue = avg(ObservationValue)
from dbo.v_Observation o 
join dbo.ObservationDates od
    on o.ObservationDateKey = od.DateKey
where o.ObservationDateKey >= 20000101
    and o.ObservationDateKey <= 20051231
group by od.[Year];

select 
    od.[Year], 
    AvgValue = avg(ObservationValue)
from dbo.v_Observation o 
join dbo.ObservationDates od
    on o.ObservationDateKey = od.DateKey
where od.DateKey >= 20000101
    and od.DateKey <= 20051231
group by od.[Year];

select 
    od.[Year], 
    AvgValue = avg(ObservationValue)
from dbo.v_Observation o 
join dbo.ObservationDates od
    on o.ObservationDateKey = od.DateKey
where od.[Year] >= 2000 and od.[Year] < 2006
group by od.[Year];
Run Code Online (Sandbox Code Playgroud)

键上的事实过滤器

按键上的暗淡过滤器

方面的暗淡过滤器

这是SQL Sentry Plan Explorer 会话的链接

我正在对更大的表进行实际分区,以查看是否可以以类似的方式进行分区消除。

我确实对过滤维度某个方面的(简单)查询进行了分区消除。

同时,这是数据库的仅统计数据副本:

https://gist.github.com/swasheck/9a22bf8a580995d3b2aa

“旧的”基数估计器获得了更便宜的计划,但这是因为对每个(不必要的)索引搜索的基数估计值较低。

我想知道是否有办法让优化器在按维度的另一个方面进行过滤时使用键列,以便它可以消除对不相关表的搜索。

SQL Server 版本:

Microsoft SQL Server 2014 - 12.0.2000.8 (X64) 
    Feb 20 2014 20:04:26 
    Copyright (c) Microsoft Corporation
    Developer Edition (64-bit) on Windows NT 6.3 <X64> (Build 9600: ) (Hypervisor)
Run Code Online (Sandbox Code Playgroud)

Pau*_*ite 10

启用跟踪标志 4199。

我还必须发出:

UPDATE STATISTICS dbo.ObservationDates 
WITH ROWCOUNT = 73049;
Run Code Online (Sandbox Code Playgroud)

得到如下所示的计划。上传时缺少此表的统计信息。73,049 的数字来自 Plan Explorer 附件中的表基数信息。我使用了带有两个逻辑处理器的 SQL Server 2014 SP1 CU4(内部版本 12.0.4436),最大内存设置为 2048 MB,除了 4199 之外没有任何跟踪标志。

然后你应该得到一个具有动态分区消除功能的执行计划:

select 
    od.[Year], 
    AvgValue = avg(ObservationValue)
from dbo.v_Observation o 
join dbo.ObservationDates od
    on o.ObservationDateKey = od.DateKey
where 
    od.[Year] >= 2000 and od.[Year] < 2006
group by 
    od.[Year]
option (querytraceon 4199);
Run Code Online (Sandbox Code Playgroud)

计划片段:

计划片段

这可能看起来更糟,但过滤器都是启动过滤器。一个示例谓词是:

过滤器属性

每次循环迭代,都会测试启动谓词,并且只有当它返回 true 时才会执行它下面的聚集索引查找。因此,动态分区消除。

这也许不是高效的静电消除,特别是如果该计划是平行的。

您可能需要尝试像MAXDOP 1FAST 1FORCESEEK在视图上这样的提示来获得相同的计划。带有分区视图(如分区表)的优化器成本计算选择可能很棘手。

关键是您需要一个具有启动过滤器功能的计划,以使用分区视图进行动态分区消除。


带有嵌入USE PLAN提示的查询:(通过 gist.github.com):


Geo*_*son 6

我的观察一直是您必须在查询中明确指定分区列的值(或值范围),以便在分区视图中获得“表消除”。这是基于在从 SQL Server 2000 到 SQL Server 2014 的生产中使用分区视图的经验。

SQL Server 没有循环连接运算符的概念,其中引擎可以根据循环外侧的行的值动态地将查找直接指向循环内侧的正确表。然而,正如保罗的回答所解释的那样,有可能有一个带有启动过滤器的计划,以便在恒定时间内动态跳过循环内侧的不相关表(而不是通过实际执行查找来进行对数)。

但是请注意,对于分区表,支持这种类型的查找(到特定分区)。

如果您固定使用分区视图,另一种选择是将您的查询拆分为多个查询,例如:

-- Gather than the min/max values for the partition column
DECLARE @minDateKey INT,
        @maxDateKey INT
SELECT @minDateKey = MIN(DateKey),
        @maxDateKey = MAX(DateKey)
FROM dbo.ObservationDates od
WHERE od.[Year] >= 2000 and od.[Year] < 2006

-- Since I have a stats-only copy of the database, simulate having run the query above
-- (You can comment this out since you have the actual data.)
SELECT @minDateKey = 20000101, @maxDateKey = 20051231

-- Adjust the query to use the min/max values of the partition column
-- rather than filtering on a different column in the dimension table
select 
    od.[Year], 
    AvgValue = avg(ObservationValue)
from dbo.v_Observation o 
join dbo.ObservationDates od
    on o.ObservationDateKey = od.DateKey
WHERE od.DateKey >= @minDateKey AND od.DateKey <= @maxDateKey
group by od.[Year]
-- Must use OPTION RECOMPILE; otherwise the plan will touch all tables because it
-- must do so in order to be valid for all values of the parameters!
OPTION (RECOMPILE)
Run Code Online (Sandbox Code Playgroud)

这产生了以下计划。现在有一个额外的查询命中维度表,但对(可能更大)事实表的查询进行了优化。

在此处输入图片说明