我有一个有分区的表。在该表上,我们正在创建一个使用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个分区。
答案 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/
的一些非常好的文章