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


22

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

1234

在测试这种方法时,我发现有些东西对我来说并没有太大意义。当我在事实视图的“分区列”上进行过滤时,优化程序仅在相关表上进行搜索。此外,如果我在维度表的该列上进行过滤,则优化程序会消除不必要的表。

但是,如果我在维度的其他方面进行过滤,则优化器将在每个基本表的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];

关键事实过滤器

按键上的暗淡滤镜

方面的暗淡滤镜

这是指向 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)

仅供参考..最后一个统计数据流已损坏CREATE STATISTICS [_WA_Sys_00000008_2FCF1A8A] ON [dbo].[Observation_2010]([StationStateCode]) WITH STATS_STREAM = 0x01000000010000000000000000000000D4531EDB00000000D5080000000000009508000000000000AF030000AF000000020000000000000008D000340000000007000000E65DE0007DA5000076F9780000000000867704000000000000000000ABAAAA3C0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
Kin Shah

似乎仅统计数据库的脚本被截断了。我尝试单击“查看完整文件”并下载zip,但是无论哪种方式我都没有该ObservationDates表的统计信息。即使4199,我也没有得到与Paul相同的计划,这就是为什么。
杰夫·帕特森

@GeoffPatterson它对我有用。您是否单击了原始文件的链接?gist.githubusercontent.com/swasheck/9a22bf8a580995d3b2aa/raw/… 但是,正如Kin所指出的,最后的统计数据流已损坏:/
swasheck

我确实单击了原始文件的链接。该脚本可以正常工作(Kin指出的问题除外),但不包含任何用于创建统计信息的逻辑ObservationDates。我最终UPDATE STATISTICS ObservationDates WITH ROWCOUNT = 10000手动运行以得到Paul演示的计划。
Geoff Patterson

奇。创建一个新的数据库并运行该脚本,我有stats对象(好吧,它们是索引),ObservationDates所以我不确定那是怎么回事。此外,我也无法获得生成的计划报酬。我将尝试更新以查看。
swasheck '16

Answers:


10

启用跟踪标志4199。

我还必须发出:

UPDATE STATISTICS dbo.ObservationDates 
WITH ROWCOUNT = 73049;

得到如下所示的计划。上传中缺少此表的统计信息。73,049数字来自计划资源管理器附件中的表基数信息。我将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);

计划片段:

计划片段

这看起来可能更糟,但是“筛选器”都是启动筛选器。谓词示例为:

筛选器属性

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

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

您可能需要尝试类似的提示MAXDOP 1FAST 1FORCESEEK在视图上获取相同的计划。具有分区视图(如分区表)的优化器成本选择可能很棘手。

关键是您需要一个具有启动筛选器的计划,以使用分区视图来消除动态分区。


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


1
很好的信息,谢谢保罗!在写完答案后,我一直想知道为什么SQL Server没有办法进行这种消除。原来有,我之前没看过!
杰夫·帕特森

6

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

SQL Server没有循环联接运算符的概念,在该联接运算符中,引擎可以根据循环外侧的行的值将搜索直接直接对准循环内侧的适当表。但是,正如Paul的回答所解释的那样,可能有一个带有启动过滤器的计划,以便在恒定时间内动态跳过循环内侧的不相关的表(与实际执行查找的对数相反)。

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

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

-- 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)

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

在此处输入图片说明


如果将第一个查询合并到第二个查询而不求助于变量,是否会达到相同的效果?
Andriy M

@AndriyM如果我正确地理解了您,答案是否定的,如果您尝试将两个查询合并,则将无法获得相同的效果,并且查询计划将触摸分区视图中的所有表。如果要执行第一个查询,然后粘贴值2000010120051231不是变量(或通过应用程序中的两个独立查询执行类似的操作),则可以,无需使用变量即可达到相同的效果。
Geoff Patterson'1
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.