SQL分区消除

发布于 2024-12-05 17:47:06 字数 2853 浏览 0 评论 0原文

我当前正在测试分区配置,使用实际执行计划来识别 RunTimePartitionSummary/PartitionsAccessed 信息。

当针对分区列使用文字运行查询时,分区消除工作正常(使用 = 和 <=)。但是,如果查询连接到查找表,则分区列 <= 到查找表中的列,并使用另一个条件限制查找表(以便仅返回一行,就像它是文字一样) 不会发生消除。

仅当连接条件为 <= 而不是 = 时,才会发生这种情况,即使结果相同。反转逻辑并在之间使用也不起作用,使用交叉应用函数也不起作用。

编辑:(重现步骤)

好的,开始吧!

--Create sample function
CREATE PARTITION FUNCTION pf_Test(date) AS RANGE RIGHT FOR VALUES ('20110101','20110102','20110103','20110104','20110105') 
--Create sample scheme
CREATE PARTITION SCHEME ps_Test AS PARTITION pf_Test ALL TO ([PRIMARY])
--Create sample table
CREATE TABLE t_Test
    (
        RowID int identity(1,1)
        ,StartDate date NOT NULL
        ,EndDate date NULL
        ,Data varchar(50) NULL
    )
ON ps_Test(StartDate)
--Insert some sample data
INSERT INTO t_Test(StartDate,EndDate,Data)
VALUES
    ('20110101','20110102','A')
    ,('20110103','20110104','A')
    ,('20110105',NULL,'A')
    ,('20110101',NULL,'B')
    ,('20110102','20110104','C')
    ,('20110105',NULL,'C')
    ,('20110104',NULL,'D')

--Check partition allocation
SELECT *,$PARTITION.pf_Test(StartDate) AS PartitionNumber FROM t_Test

--Run simple test (inlcude actual execution plan)
SELECT 
    *
    ,$PARTITION.pf_Test(StartDate)
FROM t_Test
WHERE StartDate <= '20110103' AND ISNULL(EndDate,getdate()) >= '20110103'
--<PartitionRange Start="1" End="4" />

--Run test with join to a lookup (with CTE for simplicity, but doesnt work with table either)
WITH testCTE AS
    (
        SELECT convert(date,'20110101') AS CalendarDate,'A' AS SomethingInteresting
        UNION ALL
        SELECT convert(date,'20110102') AS CalendarDate,'B' AS SomethingInteresting
        UNION ALL
        SELECT convert(date,'20110103') AS CalendarDate,'C' AS SomethingInteresting
        UNION ALL
        SELECT convert(date,'20110104') AS CalendarDate,'D' AS SomethingInteresting
        UNION ALL
        SELECT convert(date,'20110105') AS CalendarDate,'E' AS SomethingInteresting
        UNION ALL
        SELECT convert(date,'20110106') AS CalendarDate,'F' AS SomethingInteresting
        UNION ALL
        SELECT convert(date,'20110107') AS CalendarDate,'G' AS SomethingInteresting
        UNION ALL
        SELECT convert(date,'20110108') AS CalendarDate,'H' AS SomethingInteresting
        UNION ALL
        SELECT convert(date,'20110109') AS CalendarDate,'I' AS SomethingInteresting
    )

SELECT
    C.CalendarDate
    ,T.*
    ,$PARTITION.pf_Test(StartDate)
FROM t_Test T
    INNER JOIN testCTE C
        ON T.StartDate <= C.CalendarDate AND ISNULL(T.EndDate,getdate()) >= C.CalendarDate
WHERE C.SomethingInteresting = 'C'    --<PartitionRange Start="1" End="6" />

--So all 6 partitions are scanned despite only 2,3,4 being required, as per the simple select. 

--编辑以使结果范围相同以确保公平测试

I am currently testing a partitioning configuration, using actual execution plan to identify RunTimePartitionSummary/PartitionsAccessed info.

When a query is run with a literal against the partitioning column the partition elimination works fine (using = and <=). However if the query is joined to a lookup table, with the partitioning column <= to a column in the lookup table and restricting the lookup table with another criteria (so that only one row is returned, the same as if it was a literal) elimination does not occur.

This only seems to happen if the join criteria is <= rather than =, even though the result is the same. Reversing the logic and using between does not work either, nor does using a cross applied function.

Edit: (Repro Steps)

OK here you go!

--Create sample function
CREATE PARTITION FUNCTION pf_Test(date) AS RANGE RIGHT FOR VALUES ('20110101','20110102','20110103','20110104','20110105') 
--Create sample scheme
CREATE PARTITION SCHEME ps_Test AS PARTITION pf_Test ALL TO ([PRIMARY])
--Create sample table
CREATE TABLE t_Test
    (
        RowID int identity(1,1)
        ,StartDate date NOT NULL
        ,EndDate date NULL
        ,Data varchar(50) NULL
    )
ON ps_Test(StartDate)
--Insert some sample data
INSERT INTO t_Test(StartDate,EndDate,Data)
VALUES
    ('20110101','20110102','A')
    ,('20110103','20110104','A')
    ,('20110105',NULL,'A')
    ,('20110101',NULL,'B')
    ,('20110102','20110104','C')
    ,('20110105',NULL,'C')
    ,('20110104',NULL,'D')

--Check partition allocation
SELECT *,$PARTITION.pf_Test(StartDate) AS PartitionNumber FROM t_Test

--Run simple test (inlcude actual execution plan)
SELECT 
    *
    ,$PARTITION.pf_Test(StartDate)
FROM t_Test
WHERE StartDate <= '20110103' AND ISNULL(EndDate,getdate()) >= '20110103'
--<PartitionRange Start="1" End="4" />

--Run test with join to a lookup (with CTE for simplicity, but doesnt work with table either)
WITH testCTE AS
    (
        SELECT convert(date,'20110101') AS CalendarDate,'A' AS SomethingInteresting
        UNION ALL
        SELECT convert(date,'20110102') AS CalendarDate,'B' AS SomethingInteresting
        UNION ALL
        SELECT convert(date,'20110103') AS CalendarDate,'C' AS SomethingInteresting
        UNION ALL
        SELECT convert(date,'20110104') AS CalendarDate,'D' AS SomethingInteresting
        UNION ALL
        SELECT convert(date,'20110105') AS CalendarDate,'E' AS SomethingInteresting
        UNION ALL
        SELECT convert(date,'20110106') AS CalendarDate,'F' AS SomethingInteresting
        UNION ALL
        SELECT convert(date,'20110107') AS CalendarDate,'G' AS SomethingInteresting
        UNION ALL
        SELECT convert(date,'20110108') AS CalendarDate,'H' AS SomethingInteresting
        UNION ALL
        SELECT convert(date,'20110109') AS CalendarDate,'I' AS SomethingInteresting
    )

SELECT
    C.CalendarDate
    ,T.*
    ,$PARTITION.pf_Test(StartDate)
FROM t_Test T
    INNER JOIN testCTE C
        ON T.StartDate <= C.CalendarDate AND ISNULL(T.EndDate,getdate()) >= C.CalendarDate
WHERE C.SomethingInteresting = 'C'    --<PartitionRange Start="1" End="6" />

--So all 6 partitions are scanned despite only 2,3,4 being required, as per the simple select. 

--edited to make resultant ranges identical to ensure fair test

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

孤独陪着我 2024-12-12 17:47:06

查询扫描所有分区是有意义的。

所有分区都涉及谓词 T.StartDate <= C.CalendarDate,因为查询规划器不可能知道 C.CalendarDate 可能采用哪些值。

It makes sense for the query to scan all the partitions.

All partitions are involved in the predicate T.StartDate <= C.CalendarDate, because the query planner can't possibly know which values C.CalendarDate might take.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文