SQL查询:分区计数因变量或硬编码参数而异

时间:2015-10-14 10:54:58

标签: sql-server-2008 query-optimization partition

我有一个有分区的表。在该表上,我们正在创建一个使用partition by的视图。当我们通过从变量传递日期上下文来查询视图时,它不会使用分区上下文进行查询。请帮我解决这个问题。

以下是查询表创建,数据填充和创建所需索引:

IF EXISTS(SELECT 1 FROM sys.indexes WHERE name='IX_TRAN_DATE' AND object_id = OBJECT_ID('TEST_TRANSACTION'))
BEGIN
PRINT 'Dropping Index IX_TRAN_DATE on TEST_TRANSACTION'

DROP INDEX IX_TRAN_DATE
    ON TEST_TRANSACTION;

END   
GO

IF EXISTS (SELECT 1 FROM DBO.SYSOBJECTS WHERE ID = OBJECT_ID(N'TEST_TRANSACTION') AND OBJECTPROPERTY(ID, N'ISUSERTABLE') = 1)
AND NOT EXISTS(SELECT * FROM sys.indexes WHERE name='IX_TRAN_DATE' AND object_id = OBJECT_ID('TEST_TRANSACTION'))
BEGIN
PRINT 'Creating Index IX_TRAN_DATE on TEST_TRANSACTION with primary'

CREATE CLUSTERED INDEX [IX_TRAN_DATE] ON [dbo].[TEST_TRANSACTION]
(
    [TRAN_DATE]
)WITH (SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF) ON [PRIMARY]

END   
GO

IF EXISTS(SELECT * FROM sys.indexes WHERE name='IX_TRAN_DATE' AND object_id = OBJECT_ID('TEST_TRANSACTION'))
BEGIN
PRINT 'Dropping Index IX_TRAN_DATE on TEST_TRANSACTION with primary'

DROP INDEX IX_TRAN_DATE
    ON TEST_TRANSACTION;

END   
GO

IF EXISTS (SELECT * FROM sys.partition_schemes WHERE type = 'PS' AND name = 'DATETIME_PS')
    BEGIN
        PRINT 'Dropping Partition Scheme DATETIME_PS'
        DROP PARTITION SCHEME DATETIME_PS
    END
GO

IF EXISTS (SELECT * FROM sys.partition_functions WHERE type = 'R' AND name = 'DATETIME_PF')
    BEGIN        
        PRINT 'Dropping Partition Function DATETIME_PF'
        DROP PARTITION FUNCTION DATETIME_PF
    END

GO

IF EXISTS (SELECT * FROM DBO.SYSOBJECTS WHERE ID = OBJECT_ID(N'TEST_TRANSACTION') AND OBJECTPROPERTY(ID, N'ISUSERTABLE') = 1)
BEGIN
    DROP TABLE TEST_TRANSACTION
END
GO

PRINT 'Creating Partition Function DATETIME_PF'
GO

CREATE PARTITION FUNCTION DATETIME_PF (datetime)
AS RANGE RIGHT FOR VALUES 
(
    '01/01/2000',
    '01/01/2001',
    '01/01/2002',
    '01/01/2003',
    '01/01/2004',
    '01/01/2005',
    '01/01/2006',
    '01/01/2007',
    '01/01/2008',
    '01/01/2009',
    '01/01/2010',
    '01/01/2011',
    '01/01/2012',
    '01/01/2013',
    '01/01/2014',
    '01/01/2015',
    '01/01/2016',
    '01/01/2017',
    '01/01/2018',
    '01/01/2019',
    '01/01/2020',
    '01/01/2021',
    '01/01/2022',
    '01/01/2023',
    '01/01/2024',
    '01/01/2025'
);

PRINT 'Creating Partition Scheme DATETIME_PS'
GO

CREATE PARTITION SCHEME DATETIME_PS
AS PARTITION DATETIME_PF
ALL TO ([PRIMARY]);

GO

CREATE TABLE [dbo].[TEST_TRANSACTION](
    [TEST_TRAN_ID] [bigint] IDENTITY(100000, 1) NOT NULL,
    [TRAN_DATE] [datetime] NOT NULL,
    [CREATED_DATE] [datetime] NOT NULL,
    [CREATED_BY] nvarchar(64) NULL
)
GO

DECLARE @dateVar date 
SET @dateVar = '01/01/2013'

While (YEAR(@dateVar) < 2017)
BEGIN

    INSERT INTO [TEST_TRANSACTION] ([TRAN_DATE], [CREATED_DATE], [CREATED_BY]) 
    VALUES (@dateVar, GETDATE(), 'admin')

    SET @dateVar = DATEADD(DAY, 15, @dateVar)

END
GO

CREATE CLUSTERED INDEX [IX_TRAN_DATE] ON [dbo].[TEST_TRANSACTION]
(
    [TRAN_DATE]
)WITH (SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF) ON [DATETIME_PS]([TRAN_DATE])

我在TEST_TRANSACTION表上创建以下视图:

IF EXISTS (SELECT * FROM sysobjects WHERE type = 'V' AND name = 'TICKET_SHIPPER_DISTRIBUTION')
    BEGIN
        PRINT 'Dropping View TICKET_SHIPPER_DISTRIBUTION'
        DROP View TICKET_SHIPPER_DISTRIBUTION
    END
GO

PRINT 'Creating View TICKET_SHIPPER_DISTRIBUTION'
GO

CREATE VIEW dbo.TICKET_SHIPPER_DISTRIBUTION
AS

SELECT
    bitr.[TRAN_DATE]
    ,ROW_NUMBER() OVER (
    PARTITION BY 
       bitr.[TRAN_DATE]
    ORDER BY
        bitr.TRAN_DATE,
        bitr.CREATED_DATE ASC
    ) AS ROW_NUM
FROM
    TEST_TRANSACTION bitr

现在,如果我们运行以下查询

- 查询1 - 将具有分区计数= 27

DBCC DROPCLEANBUFFERS
DBCC FREEPROCCACHE

DECLARE @startDate datetime
DECLARE @endDate datetime
SET @startDate='2015-07-10 00:00:00'
SET @endDate = '2015-08-01 00:00:00'
Select * from TICKET_SHIPPER_DISTRIBUTION where TRAN_DATE >= @startDate and TRAN_DATE <= @endDate

execution plan snapshot for query 1

- QUERY 2将具有分区计数= 1

DBCC DROPCLEANBUFFERS
DBCC FREEPROCCACHE
Select * from TICKET_SHIPPER_DISTRIBUTION WHERE TRAN_DATE > '2015-07-10 00:00:00' AND TRAN_DATE < '2015-08-01 00:00:00'

execution plan snapshot for query 2

请帮助我理解为什么查询1和2的执行存在差异,以及如何使查询1跟随分区并仅扫描1个分区。

3 个答案:

答案 0 :(得分:0)

我在一个干净的DB上运行它,它为每个查询返回1行计数。我正在使用SQL 2014 Developer Edition。

你的&lt; &GT;在上面的查询中是不同的,但它应该对结果没有区别。

答案 1 :(得分:0)

我已经弄明白了。实际上它与表或分区的分区无关。它实际上是关于我们如何传递日期参数。

参考http://www.sqlservercentral.com/Forums/Topic547887-149-1.aspx建议的3个选项,动态查询的选项2帮助了我。

我仍在努力使其在没有动态查询的单个存储过程中工作。任何建议都会非常感激。

答案 2 :(得分:0)

好的,我看到了这个问题。

表上有一个聚簇索引,但是当您从视图中执行select *时,它会将查询转换为Clustered Index Scan,这就是它命中每个分区的原因。

如果您按如下方式发出查询,您将获得Clustered Index Seek并且只有一个分区被命中,因为您指定了Clustered Index中的唯一字段。

SELECT  TRAN_DATE
FROM    TICKET_SHIPPER_DISTRIBUTION
WHERE   TRAN_DATE >= @startDate AND
        TRAN_DATE <= @endDate;

或没有视图

SELECT  bitr.TRAN_DATE
       ,ROW_NUMBER() OVER ( PARTITION BY bitr.TRAN_DATE ORDER BY bitr.TRAN_DATE, bitr.CREATED_DATE ASC ) AS ROW_NUM
FROM    TEST_TRANSACTION bitr
WHERE   TRAN_DATE > @startDate AND
        TRAN_DATE < @endDate;    

您只需要注意如何设计和使用集群/覆盖索引,您应该没问题,并且不需要动态SQL。

以下是有关索引设计和使用http://www.sqlskills.com/blogs/kimberly/category/indexes/

的一些非常好的文章