26

I'm using MSSQL Server 2008 R2 and I'm trying to optimize my Views when I stumbled upon Indexed Views. Unfortunately most of my Views use a Left Outer Joins which is not supported with Indexed Views. After a bunch of research, I'm left confused the best way to go about this. The way I see it, I have the following options:

1) Convert the left joins to inner joins using the trick to simulate a left join with "OR (IsNull(a) AND IsNull(b))"

I found this solution in a couple places, but there was mention of a performance loss.

2) Convert the left joins to inner joins and replace the nullable column's nulls with empty guids (00000000-0000-0000-0000-000000000000) and add a single row in the right table with a matching guid.

This appears the most obvious performance-wise, but it seems a waste of space for every row that would otherwise be NULL.

3) Break my view up into two views. The first view being the majority of my logic that is Indexable. And the second view deriving from the first view and adding the left joins.

The idea here being, there might be a performance gain via the base view being indexed. And that even querying the derived view would gain at least some of the performance benefit.

4) Don't index my views

Would leaving the view the way it is be more performant than any of the above options?

5) The idea I didn't think of

I scripted my basic scenario as follows:

   CREATE TABLE [dbo].[tbl_Thumbnails](
        [ThumbnailId] [uniqueidentifier] NOT NULL,
        [Data] [image] NULL,
        [Width] [smallint] NOT NULL,
        [Height] [smallint] NOT NULL
     CONSTRAINT [PK_tbl_Thumbnails] PRIMARY KEY CLUSTERED 
    (
        [ThumbnailId] ASC
    )WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
    ) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]

    GO

    CREATE TABLE [dbo].[tbl_Tags](
        [TagId] [uniqueidentifier] NOT NULL,
        [ThumbnailId] [uniqueidentifier] NULL
     CONSTRAINT [PK_tbl_Tags] PRIMARY KEY CLUSTERED 
    (
        [TagId] 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 VIEW [dbo].[v_Tags] WITH SCHEMABINDING AS
    SELECT     dbo.tbl_Tags.TagId, dbo.tbl_Tags.ThumbnailId
    FROM         dbo.tbl_Tags LEFT OUTER JOIN
                          dbo.tbl_Thumbnails
    ON     dbo.tbl_Tags.ThumbnailId = dbo.tbl_Thumbnails.ThumbnailId

    GO

    INSERT INTO tbl_Tags VALUES ('16b23bb8-bf17-4784-b80a-220da1163584', NULL)
    INSERT INTO tbl_Tags VALUES ('e8b50f03-65a9-4d1e-b3b4-268f01645c4e', 'a45e357b-ca9c-449a-aa27-834614eb3f6e')
    INSERT INTO tbl_Thumbnails VALUES ('a45e357b-ca9c-449a-aa27-834614eb3f6e', NULL, 150, 150)

Now, doing the following query yields "Cannot create index on view "Test.dbo.v_Tags" because it uses a LEFT, RIGHT, or FULL OUTER join, and no OUTER joins are allowed in indexed views. Consider using an INNER join instead.":

CREATE UNIQUE CLUSTERED INDEX [TagId] ON [dbo].[v_Tags] 
(
[TagId] ASC
)
GO 

This is expected behavior, but what course of action would you recommend to gets the best performance from my scenario? The take home point here is best performance.

Levitikon
  • 7,749
  • 9
  • 56
  • 74
  • 1
    What did you end up doing with this? I am facing a similar issue trying to index some views. – user1948635 Jan 31 '14 at 13:44
  • Facing similar situation, the denormalized table (with triggers or some other way of keeping it up to date) could be an option in the list as well. – Alex M Oct 01 '14 at 11:34
  • I answered a very similar question about materializing indexes on left joins. While there isn't a direct way to do it... here is option #5 http://stackoverflow.com/a/31171129/1902664 – cocogorilla Apr 20 '16 at 23:01

1 Answers1

6

Why are you indexing your views? You mentioned "waste of space" in your solution 2, but did you know that when you index your view, you persist it on the DB?

In other words, you make a copy of the data the view would return on the DB and every time the data is updated on the source tables, some internal mechanism of SQL Server has to update it on this new data structure created because now SQL server reads from the view, not the tables anymore.

If you use Profiler + DTA or even DMVS you can come up with the correct indexes to be created on your tables that any view would benefit from

Diego
  • 34,802
  • 21
  • 91
  • 134
  • 1
    What if the view presents almost constant data (rarely changed in underlying tables) and is also used in many places? Indexed view helps a lot for performance in this case – Marcel Toth Sep 10 '12 at 14:02
  • 7
    You also have to index your view if you want to create a full text index on it. – Paw Baltzersen Aug 06 '14 at 08:03