I have table structure as follows:
CREATE TABLE [dbo].[Test] (
[ID] [int] IDENTITY(1, 1) NOT NULL
, [ProductID] [int] NOT NULL
, [CountryID] [int] NOT NULL
, CONSTRAINT [PK_Test] PRIMARY KEY CLUSTERED ([ID] ASC) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
CREATE TABLE [dbo].[TestData] (
[ID] [int] IDENTITY(1, 1) NOT NULL
, [TestID] [int] NOT NULL
, [TimeSeries] [int] NOT NULL
, [Values] [float] NULL
, CONSTRAINT [PK_TestData] PRIMARY KEY CLUSTERED ([ID] ASC) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
ALTER TABLE [dbo].[TestData]
WITH CHECK ADD CONSTRAINT [FK_Test_TestData] FOREIGN KEY ([TestID]) REFERENCES [dbo].[Test]([ID])
GO
ALTER TABLE [dbo].[TestData] CHECK CONSTRAINT [FK_Test_TestData]
GO
Some test data:
INSERT INTO dbo.Test (ProductID, CountryID)
VALUES (1, 1), (1, 2), (1, 3), (1, 4)
, (2, 1);
INSERT INTO dbo.TestData (TestID, TimeSeries, [Values])
VALUES (1, 2013, 0.5), (1, 2014, 1.9)
, (2, 2013, 0.78), (2, 2014, 9.7)
, (3, 2012, 0.77), (3, 2013, 5.6), (3, 2014, 1.54)
, (4, 2011, 0.81), (4, 2014, 6.7);
And I've created Pivoted view out of it:
CREATE VIEW dbo.vw_PivotedTest
AS
SELECT ProductID, CountryID, [2011], [2012], [2013], [2014]
FROM (
SELECT T.ProductID, T.CountryID, TD.TimeSeries, TD.[Values]
FROM dbo.Test AS T
LEFT JOIN dbo.TestData AS TD
ON TD.TestID = T.ID
) AS S
PIVOT (
AVG([Values])
FOR TimeSeries IN ([2011], [2012], [2013], [2014])
) AS P;
And I'd query it like that:
SELECT ProductID, CountryID, [2011]
FROM dbo.vw_PivotedTest;
Now comes the question: is it possible for SQL Server to pick only rows from dbo.TestData, where TimeSeries value is only 2011 instead of scanning everything?
I gave a look at execution plan and it seems to be scanning whole table and doesn't filter these results out.
Best Answer
Not as it stands, you will have to add an index for it and that will never be able to scan only the 2011 column from the pivoted view - adding index onto that view is not possible and will give an error
Msg 10114, Level 16, State 1, Line 17 Cannot create index on view "a.dbo.vw_PivotedTest" because it uses the PIVOT operator. Consider not indexing this view.
.Then you need to create an index for the underlying data to get the Pivot operator to run faster. Let's look at if the Optimizer has something to say.
Your sample data is really small so run your query like this.
Which will optimize the query for a larger set, you can also add
GO 50
after the insert statement into the dbo.TestData table to run the insert statements 50 times and thereby adding more data and then you can skip the option part.You will then get the following index suggestion from the optimizer:
Which will help but will scan on the ProductID - which makes sense, you can also create that index like this
But you will end up with the same queryplan and more expensive inserts so there is little to gain.