SQL Server 2005 Derived Tables, Common Table Expressions and Indexed Views Query Processing Part III
So in Part II of this article I had created a View so that I could then create an index on this view to see if that was going to give me the expected results. I did create the view, but not the index. So you probably already know. These columns are non-deterministic and as a result the create index statement fails.
CREATE
UNIQUE CLUSTERED INDEX [IDX1] ON [dbo].[vDateSelection]
(
[ID]
ASC
)
WITH (STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, IGNORE_DUP_KEY = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = OFF) ON [PRIMARY]
GO
Msg 1963, Level 16, State 1, Line 1
Cannot create index on view "TESTDATABASE.dbo.vDateSelection". The view contains a convert that is imprecise or non-deterministic.
So that ends the questions...for now about indexed views and the effect of the results.
So here comes the results of how this works with no changes to the actual syntax of the query. I will introduce them one a time and then we will take a deep dive into why this behavior works sometimes and not all. And if this is correct behavior, is there the possibility that something that is executed today could fail in the future.
So looking at the scripts from my previous post there are some obvious elements missing form the schema. How about a primary key on each of the tables...and lets make these clustered unique as well.
CREATE
TABLE [dbo].[testTable1](
[ID] [int]
IDENTITY(1,1) NOT NULL,
[LookupTypeID] [int]
NOT NULL,
[LookupValue] [varchar]
(50) NOT NULL,
CONSTRAINT [PK_testTable1] PRIMARY KEY CLUSTERED
(
[ID]
ASC
)
WITH (PAD_INDEX = OFF, IGNORE_DUP_KEY = OFF) ON [PRIMARY]
)
ON [PRIMARY]
GO
CREATE
TABLE [dbo].[testTable2](
[ID] [int]
NOT NULL,
[LookupType] [varchar]
(50) NOT NULL,
CONSTRAINT [PK_testTable2] PRIMARY KEY CLUSTERED
(
[ID]
ASC
)
WITH (PAD_INDEX = OFF, IGNORE_DUP_KEY = OFF) ON [PRIMARY]
)
ON [PRIMARY]
GO
We can then also add the foreign key constraint for the ID. As you can see I have modified testTable1 by adding an Identity columns for my primary key.
ALTER
TABLE dbo.testTable1 WITH NOCHECK ADD CONSTRAINT
FK_testTable1_testTable2
FOREIGN KEY
(
LookupTypeID
) REFERENCES dbo.testTable2
(
ID
) ON UPDATE NO ACTION
ON DELETE NO ACTION
NOT FOR REPLICATION
GO
ALTER
TABLE dbo.testTable1
NOCHECK CONSTRAINT FK_testTable1_testTable2
GO
With these changes we are close, Well I thought...but I am still getting the same error.
'Simple Query WITH FILTER'
SELECT
a
.[LookupValue]
,DATEPART(MONTH,CONVERT(SMALLDATETIME,a.[LookupValue])) AS MonthPart
,DATEPART(YEAR,CONVERT(SMALLDATETIME,a.[LookupValue])) AS YearPart
FROM
[dbo]
.[testTable1] a INNER JOIN
[dbo]
.[testTable2] b ON
a
.[LookupTypeID] = b.[ID] AND b.[LookupType] = 'Date'
WHERE
DATEPART(MONTH,CONVERT(SMALLDATETIME,a.[LookupValue])) = 1 AND
DATEPART(YEAR,CONVERT(SMALLDATETIME,a.[LookupValue])) = 2007;
GO
'DERIVED TABLE WITH FILTER'
SELECT
ID,MonthPart,YearPart FROM
(
SELECT
a
.[ID] AS ID
,DATEPART(MONTH,CONVERT(SMALLDATETIME,a.[LookupValue])) AS MonthPart
,DATEPART(YEAR,CONVERT(SMALLDATETIME,a.[LookupValue])) AS YearPart
FROM
[dbo]
.[testTable1] a INNER JOIN
[dbo]
.[testTable2] b ON
a
.[LookupTypeID] = b.[ID]
AND b.[LookupType] = 'Date'
) AS DateSelection
WHERE
DateSelection
.MonthPart = 1 AND
DateSelection
.YearPart = 2007
GO
'COMMON TABLE EXPRESSION WITH FILTER'
GO
WITH
DateSelection (ID,MonthPart,YearPart)
AS
(
SELECT
a
.[ID] AS ID
,DATEPART(MONTH,CONVERT(SMALLDATETIME,a.[LookupValue])) AS MonthPart
,DATEPART(YEAR,CONVERT(SMALLDATETIME,a.[LookupValue])) AS YearPart
FROM
[dbo]
.[testTable1] a INNER JOIN
[dbo]
.[testTable2] b ON
a
.[LookupTypeID] = b.[ID]
AND b.[LookupType] = 'Date'
)
SELECT
ID
,MonthPart,YearPart
FROM
DateSelection
WHERE
DateSelection
.MonthPart = 1 AND
DateSelection
.YearPart = 2007
GO
'VIEW WITH FILTER'
SELECT
ID
,MonthPart,YearPart
FROM
vDateSelection DateSelection
WHERE
DateSelection
.MonthPart = 1 AND
DateSelection
.YearPart = 2007
GO
The results were the same.
So lets go the full distance now and add the index to the LookupTypeID Field to complete the cycle.
--Add Non Clustered Index.
CREATE
NONCLUSTERED INDEX [IDX_testTable1_01] ON [dbo].[testTable1]
(
[LookupTypeID]
ASC
)
WITH (STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, IGNORE_DUP_KEY = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = OFF) ON [PRIMARY]
GO
And BAM. Still the same results. What could be going on here...In the article I will try to understand this myself as well as get some commentary from some insiders...
Stay Tuned.
Comments
Anonymous
January 01, 2007
This was an interesting break down Patrick. I enjoyed following along with you as you worked through this problem.Anonymous
March 04, 2009
This is an interesting article. I am building a derived query as such in the form below with added joins at each level to try and build a view, Why; sql 2005 refused my use of temp tables in view and now wondering if I should have gone the route of CTE? select g.* , from table3, (select f.* from Table1, (select E.* from table2,( select....) G join table4 H on H.ID=G.ID where G.ID > 5Anonymous
March 04, 2009
This is an interesting article. I am building a derived query as such in the form below with added joins at each level to try and build a view, Why; sql 2005 refused my use of temp tables in view and now wondering if I should have gone the route of CTE? select g.* , from table3, (select f.* from Table1, (select E.* from table2,( select....) G join table4 H on H.ID=G.ID where G.ID > 5