Indexed view doesn't appear to be using index on queries

Indexed view doesn't appear to be using index on queries

Post by Brandon Lill » Tue, 05 Nov 2002 23:21:35



I created an indexed view, which is several aggregates grouped by a
resource, date, resourcetype, and datetype.  My clustered index contains the
same fields in the same order, and when I query the view, the columns are
also in the same order as the index.

I saved the query plan for the query in the view and compared it against the
actual view, and they are the same....  Why isn't the view using my
clustered index?  I am using SQL 2000 Enterprise.

Well, while typing this I THINK I found my answer...  According to BOL, even
though a view has a clustered index on it, SQL expands the view when the
query is processed... Using WITH (NOEXPAND) seems to force the query
optimizer to use the clustered index on the view.  ANd it runs MUCH faster
this way in my tests.  I knew I created that damn index for a reason.  What
is the point of creating an indexed view, if SQL will ignore it unless you
FORCE it to use it????  Seems silly to me, perhaps somebody can shed some
light on this.

Also, isn't there a trick to get indexed views to work in editions other
than Enterprise?

Brandon
--
"In the beginning the universe was created. This has made a lot of people
very angry, and has been widely regarded as a bad move." - Douglas Noel
Adams (1952-2001)
[Please remove "nospam_" from email address to reply.]

 
 
 

Indexed view doesn't appear to be using index on queries

Post by Andrew J. Kell » Wed, 06 Nov 2002 00:17:14


Brandon,

When you use Indexed views there is certain criteria that must be met to not
only create the view but utilize it properly as well.  There are 5 or 6 SET
commands that need to be set properly by the client connection that is
accessing the view.  Even if the view is created properly the client still
needs to meet these conditions as well.  BOL has this criteria.   Check to
ensure the session is using all these settings.

--
Andrew J. Kelly   SQL MVP
Targitinteractive, Inc.

Check out the PASS Community Summit - Seattle, the largest and only user
event entirely dedicated to SQL Server, November 19-22.
http://www.sqlpass.org/events/seattle/index.cfm


Quote:> I created an indexed view, which is several aggregates grouped by a
> resource, date, resourcetype, and datetype.  My clustered index contains
the
> same fields in the same order, and when I query the view, the columns are
> also in the same order as the index.

> I saved the query plan for the query in the view and compared it against
the
> actual view, and they are the same....  Why isn't the view using my
> clustered index?  I am using SQL 2000 Enterprise.

> Well, while typing this I THINK I found my answer...  According to BOL,
even
> though a view has a clustered index on it, SQL expands the view when the
> query is processed... Using WITH (NOEXPAND) seems to force the query
> optimizer to use the clustered index on the view.  ANd it runs MUCH faster
> this way in my tests.  I knew I created that damn index for a reason.
What
> is the point of creating an indexed view, if SQL will ignore it unless you
> FORCE it to use it????  Seems silly to me, perhaps somebody can shed some
> light on this.

> Also, isn't there a trick to get indexed views to work in editions other
> than Enterprise?

> Brandon
> --
> "In the beginning the universe was created. This has made a lot of people
> very angry, and has been widely regarded as a bad move." - Douglas Noel
> Adams (1952-2001)
> [Please remove "nospam_" from email address to reply.]


 
 
 

Indexed view doesn't appear to be using index on queries

Post by Brandon Lill » Wed, 06 Nov 2002 01:13:48


Yeah, I know about the criteria, which leads me to a couple questions:

SQL BOL:
  - The ANSI_NULLS option must have been set to ON for the execution of all
CREATE TABLE statements that create tables referenced by the view.

How do I know if ANSI_NULLS was on for the creation of all the referenced
tables?  The property "ExecIsAnsiNullsOn" is only valid for stored
procedures, triggers, and views.

I am fairly certain that this is done, because I do all my table
modifications through query analyzer and my connection properties always are
set:
    concat_null_yields_null
    ansi_nulls
    ansi_null_dflt_on
    ansi_padding
    ansi_warnings
    quoted_identifier
The database property IsNumericRoundAbortEnabled (NUMERIC_ROUNDABORT) is
disabled
View does use GROUP BY, but index only references grouped columns
Index does not include any text, ntext, or image columns

So, assuming that all this is correct, can you explain why I am having to
force the query optimizer to use the clustered index?  Below is my view, and
the query I am using to retrieve values from it

Brandon
--
"In the beginning the universe was created. This has made a lot of people
very angry, and has been widely regarded as a bad move." - Douglas Noel
Adams (1952-2001)
[Please remove "nospam_" from email address to reply.]

<-------- SQL Stuff -------->
CREATE VIEW dbo.ResourceTotals (Resource, [Date], ResourceType, DateType,
ChargeAmount, ChargeCount, PvtPayAmount, PvtPayCount, InsPayAmount,
InsPayCount, CrAdjAmount, CrAdjCount, DrAdjAmount, DrAdjCount, TranCount)
WITH SCHEMABINDING
AS SELECT CASE WHEN pass.x IN (1, 2) THEN PT_SProvKey ELSE PV_PrimProvKey
END AS Resource,
          CASE WHEN pass.x IN (1, 3) THEN PT_StartDate ELSE PT_EDate END AS
[Date],
          CAST(CASE WHEN pass.x IN (1, 2) THEN 'S' ELSE 'I' END AS char(1))
AS ResourceType,
          CAST(CASE WHEN pass.x IN (1, 3) THEN 'S' ELSE 'E' END AS char(1))
AS DateType,
          SUM(CASE ISNULL(PT_CrType, PT_DrType) WHEN 'c' THEN PT_Amount ELSE
0 END) AS ChargeAmount,
          SUM(CASE ISNULL(PT_CrType, PT_DrType) WHEN 'c' THEN 1 ELSE 0 END)
AS ChargeCount,
          SUM(CASE ISNULL(PT_CrType, PT_DrType) WHEN 'p' THEN PT_Amount ELSE
0 END) AS PvtPayAmount,
          SUM(CASE ISNULL(PT_CrType, PT_DrType) WHEN 'p' THEN 1 ELSE 0 END)
AS PvtPayCount,
          SUM(CASE ISNULL(PT_CrType, PT_DrType) WHEN 'i' THEN PT_Amount ELSE
0 END) AS InsPayAmount,
          SUM(CASE ISNULL(PT_CrType, PT_DrType) WHEN 'i' THEN 1 ELSE 0 END)
AS InsPayCount,
          SUM(CASE PT_CrType WHEN 'a' THEN PT_Amount ELSE 0 END) AS
CrAdjAmount,
          SUM(CASE PT_CrType WHEN 'a' THEN 1 ELSE 0 END) AS CrAdjCount,
          SUM(CASE PT_DrType WHEN 'a' THEN PT_Amount ELSE 0 END) AS
DrAdjAmount,
          SUM(CASE PT_DrType WHEN 'a' THEN 1 ELSE 0 END) AS DrAdjCount,
          COUNT_BIG(*) AS TranCount
   FROM dbo.TPatient_Visit
        JOIN dbo.TPatient_Transaction ON PT_VisitKey = PV_Key
                                     AND PT_PostedDate IS NOT NULL
        JOIN dbo.TPass AS pass ON pass.x BETWEEN 1 AND 4
   GROUP BY CASE WHEN pass.x IN (1, 2) THEN PT_SProvKey ELSE PV_PrimProvKey
END,
            CASE WHEN pass.x IN (1, 3) THEN PT_StartDate ELSE PT_EDate END,
            CAST(CASE WHEN pass.x IN (1, 2) THEN 'S' ELSE 'I' END AS
char(1)),
            CAST(CASE WHEN pass.x IN (1, 3) THEN 'S' ELSE 'E' END AS
char(1))
GO
CREATE UNIQUE CLUSTERED INDEX
IXUC__ResourceTotals__Resource_Date_ResourceType_DateType ON
dbo.ResourceTotals (Resource, [Date], ResourceType, DateType) ON [PRIMARY]
GO

-- This query refuses to use clustered index
-- Query runs in 6 seconds
SELECT *
FROM ResourceTotals
WHERE Resource = 11
  AND [Date] = '7/26/2002'
  AND ResourceType = 'i'
  AND DateType = 'S'

-- Query plan for previous query
  |--Stream Aggregate(DEFINE:([Expr1020]=Count(*), [Expr1010]=SUM(If
(isnull([TPatient_Transaction].[PT_CrType],
[TPatient_Transaction].[PT_DrType])='c') then
[TPatient_Transaction].[PT_Amount] else 0.00), [Expr1011]=SUM(If
(isnull([TPatient_Transaction].[
       |--Parallelism(Gather Streams)
            |--Filter(WHERE:((([Expr1006]=11 AND [Expr1007]='Jul 26 2002
12:00AM') AND [Expr1008]='i') AND [Expr1009]='S'))
                 |--Compute Scalar(DEFINE:([Expr1006]=If ([TPass].[x]=2 OR
[TPass].[x]=1) then [TPatient_Transaction].[PT_SProvKey] else
[TPatient_Visit].[PV_PrimprovKey], [Expr1007]=If ([TPass].[x]=3 OR
[TPass].[x]=1) then [TPatient_Transaction].[PT_Start
                      |--Nested Loops(Inner Join)
                           |--Hash Match(Inner Join,
HASH:([TPatient_Visit].[PV_Key])=([TPatient_Transaction].[PT_VisitKey]))
                           |    |--Parallelism(Repartition Streams,
PARTITION COLUMNS:([TPatient_Visit].[PV_Key]))
                           |    |    |--Index
Scan(OBJECT:([Development].[dbo].[TPatient_Visit].[AI_PV_PrimProvKey]))
                           |    |--Parallelism(Repartition Streams,
PARTITION COLUMNS:([TPatient_Transaction].[PT_VisitKey]))
                           |         |--Clustered Index
Scan(OBJECT:([Development].[dbo].[TPatient_Transaction].[PK__TPatient_Transa
ction]), WHERE:([TPatient_Transaction].[PT_PostedDate]<>NULL))
                           |--Table Spool
                                |--Clustered Index
Seek(OBJECT:([Development].[dbo].[TPass].[PK__TPass]), SEEK:([TPass].[x] >=
1 AND [TPass].[x] <= 4) ORDERED FORWARD)

-- I have to force SQL Server to not expand the view.  This query runs in
-- Query runs in .01 seconds
SELECT *
FROM ResourceTotals WITH (NOEXPAND)
WHERE Resource = 11
  AND [Date] = '7/26/2002'
  AND ResourceType = 'i'
  AND DateType = 'S'

-- Query plan for previous query
  |--Clustered Index
Seek(OBJECT:([Development].[dbo].[ResourceTotals].[IXUC__ResourceTotals__Res
ource_Date_ResourceType_DateType]), SEEK:([ResourceTotals].[Resource]=11 AND
[ResourceTotals].[Date]='Jul 26 2002 12:00AM' AND
[ResourceTotals].[ResourceType]=

 
 
 

Indexed view doesn't appear to be using index on queries

Post by Andrew J. Kell » Wed, 06 Nov 2002 04:12:55


>How do I know if ANSI_NULLS was on for the creation of all the referenced
>tables?  The property "ExecIsAnsiNullsOn" is only valid for stored
>procedures, triggers, and views.

Good question... Unfortunately I don't have an answer as of yet on that.

And your sure the session your using to select from the view has all the
proper settings?   This is exactly what happens when one or more of the
current session settings are not correct.    Other than that I don't have
any other suggestions short of dropping and recreating the base table and
view to ensure it was created properly. Probably a lot of work though.   I
am just getting into Indexed views myself so I haven't done too much with
them yet.  Hopefully Kimberly Tripp will see this as she has some very good
views on indexed views (pun intended<g>).

--
Andrew J. Kelly   SQL MVP
Targitinteractive, Inc.

Check out the PASS Community Summit - Seattle, the largest and only user
event entirely dedicated to SQL Server, November 19-22.
http://www.sqlpass.org/events/seattle/index.cfm

"Brandon Lilly" <blilly@nospam_medevolve.com> wrote in message

news:eao1b0BhCHA.1676@tkmsftngp08...
> Yeah, I know about the criteria, which leads me to a couple questions:

> SQL BOL:
>   - The ANSI_NULLS option must have been set to ON for the execution of
all
> CREATE TABLE statements that create tables referenced by the view.

> How do I know if ANSI_NULLS was on for the creation of all the referenced
> tables?  The property "ExecIsAnsiNullsOn" is only valid for stored
> procedures, triggers, and views.

> I am fairly certain that this is done, because I do all my table
> modifications through query analyzer and my connection properties always
are
> set:
>     concat_null_yields_null
>     ansi_nulls
>     ansi_null_dflt_on
>     ansi_padding
>     ansi_warnings
>     quoted_identifier
> The database property IsNumericRoundAbortEnabled (NUMERIC_ROUNDABORT) is
> disabled
> View does use GROUP BY, but index only references grouped columns
> Index does not include any text, ntext, or image columns

> So, assuming that all this is correct, can you explain why I am having to
> force the query optimizer to use the clustered index?  Below is my view,
and
> the query I am using to retrieve values from it

> Brandon
> --
> "In the beginning the universe was created. This has made a lot of people
> very angry, and has been widely regarded as a bad move." - Douglas Noel
> Adams (1952-2001)
> [Please remove "nospam_" from email address to reply.]

> <-------- SQL Stuff -------->
> CREATE VIEW dbo.ResourceTotals (Resource, [Date], ResourceType, DateType,
> ChargeAmount, ChargeCount, PvtPayAmount, PvtPayCount, InsPayAmount,
> InsPayCount, CrAdjAmount, CrAdjCount, DrAdjAmount, DrAdjCount, TranCount)
> WITH SCHEMABINDING
> AS SELECT CASE WHEN pass.x IN (1, 2) THEN PT_SProvKey ELSE PV_PrimProvKey
> END AS Resource,
>           CASE WHEN pass.x IN (1, 3) THEN PT_StartDate ELSE PT_EDate END
AS
> [Date],
>           CAST(CASE WHEN pass.x IN (1, 2) THEN 'S' ELSE 'I' END AS
char(1))
> AS ResourceType,
>           CAST(CASE WHEN pass.x IN (1, 3) THEN 'S' ELSE 'E' END AS
char(1))
> AS DateType,
>           SUM(CASE ISNULL(PT_CrType, PT_DrType) WHEN 'c' THEN PT_Amount
ELSE
> 0 END) AS ChargeAmount,
>           SUM(CASE ISNULL(PT_CrType, PT_DrType) WHEN 'c' THEN 1 ELSE 0
END)
> AS ChargeCount,
>           SUM(CASE ISNULL(PT_CrType, PT_DrType) WHEN 'p' THEN PT_Amount
ELSE
> 0 END) AS PvtPayAmount,
>           SUM(CASE ISNULL(PT_CrType, PT_DrType) WHEN 'p' THEN 1 ELSE 0
END)
> AS PvtPayCount,
>           SUM(CASE ISNULL(PT_CrType, PT_DrType) WHEN 'i' THEN PT_Amount
ELSE
> 0 END) AS InsPayAmount,
>           SUM(CASE ISNULL(PT_CrType, PT_DrType) WHEN 'i' THEN 1 ELSE 0
END)
> AS InsPayCount,
>           SUM(CASE PT_CrType WHEN 'a' THEN PT_Amount ELSE 0 END) AS
> CrAdjAmount,
>           SUM(CASE PT_CrType WHEN 'a' THEN 1 ELSE 0 END) AS CrAdjCount,
>           SUM(CASE PT_DrType WHEN 'a' THEN PT_Amount ELSE 0 END) AS
> DrAdjAmount,
>           SUM(CASE PT_DrType WHEN 'a' THEN 1 ELSE 0 END) AS DrAdjCount,
>           COUNT_BIG(*) AS TranCount
>    FROM dbo.TPatient_Visit
>         JOIN dbo.TPatient_Transaction ON PT_VisitKey = PV_Key
>                                      AND PT_PostedDate IS NOT NULL
>         JOIN dbo.TPass AS pass ON pass.x BETWEEN 1 AND 4
>    GROUP BY CASE WHEN pass.x IN (1, 2) THEN PT_SProvKey ELSE
PV_PrimProvKey
> END,
>             CASE WHEN pass.x IN (1, 3) THEN PT_StartDate ELSE PT_EDate
END,
>             CAST(CASE WHEN pass.x IN (1, 2) THEN 'S' ELSE 'I' END AS
> char(1)),
>             CAST(CASE WHEN pass.x IN (1, 3) THEN 'S' ELSE 'E' END AS
> char(1))
> GO
> CREATE UNIQUE CLUSTERED INDEX
> IXUC__ResourceTotals__Resource_Date_ResourceType_DateType ON
> dbo.ResourceTotals (Resource, [Date], ResourceType, DateType) ON [PRIMARY]
> GO

> -- This query refuses to use clustered index
> -- Query runs in 6 seconds
> SELECT *
> FROM ResourceTotals
> WHERE Resource = 11
>   AND [Date] = '7/26/2002'
>   AND ResourceType = 'i'
>   AND DateType = 'S'

> -- Query plan for previous query
>   |--Stream Aggregate(DEFINE:([Expr1020]=Count(*), [Expr1010]=SUM(If
> (isnull([TPatient_Transaction].[PT_CrType],
> [TPatient_Transaction].[PT_DrType])='c') then
> [TPatient_Transaction].[PT_Amount] else 0.00), [Expr1011]=SUM(If
> (isnull([TPatient_Transaction].[
>        |--Parallelism(Gather Streams)
>             |--Filter(WHERE:((([Expr1006]=11 AND [Expr1007]='Jul 26 2002
> 12:00AM') AND [Expr1008]='i') AND [Expr1009]='S'))
>                  |--Compute Scalar(DEFINE:([Expr1006]=If ([TPass].[x]=2 OR
> [TPass].[x]=1) then [TPatient_Transaction].[PT_SProvKey] else
> [TPatient_Visit].[PV_PrimprovKey], [Expr1007]=If ([TPass].[x]=3 OR
> [TPass].[x]=1) then [TPatient_Transaction].[PT_Start
>                       |--Nested Loops(Inner Join)
>                            |--Hash Match(Inner Join,
> HASH:([TPatient_Visit].[PV_Key])=([TPatient_Transaction].[PT_VisitKey]))
>                            |    |--Parallelism(Repartition Streams,
> PARTITION COLUMNS:([TPatient_Visit].[PV_Key]))
>                            |    |    |--Index
> Scan(OBJECT:([Development].[dbo].[TPatient_Visit].[AI_PV_PrimProvKey]))
>                            |    |--Parallelism(Repartition Streams,
> PARTITION COLUMNS:([TPatient_Transaction].[PT_VisitKey]))
>                            |         |--Clustered Index

Scan(OBJECT:([Development].[dbo].[TPatient_Transaction].[PK__TPatient_Transa

- Show quoted text -

> ction]), WHERE:([TPatient_Transaction].[PT_PostedDate]<>NULL))
>                            |--Table Spool
>                                 |--Clustered Index
> Seek(OBJECT:([Development].[dbo].[TPass].[PK__TPass]), SEEK:([TPass].[x]
>=
> 1 AND [TPass].[x] <= 4) ORDERED FORWARD)

> -- I have to force SQL Server to not expand the view.  This query runs in
> -- Query runs in .01 seconds
> SELECT *
> FROM ResourceTotals WITH (NOEXPAND)
> WHERE Resource = 11
>   AND [Date] = '7/26/2002'
>   AND ResourceType = 'i'
>   AND DateType = 'S'

> -- Query plan for previous query
>   |--Clustered Index

Seek(OBJECT:([Development].[dbo].[ResourceTotals].[IXUC__ResourceTotals__Res

- Show quoted text -

> ource_Date_ResourceType_DateType]), SEEK:([ResourceTotals].[Resource]=11
AND
> [ResourceTotals].[Date]='Jul 26 2002 12:00AM' AND
> [ResourceTotals].[ResourceType]=

 
 
 

Indexed view doesn't appear to be using index on queries

Post by Steve Kas » Wed, 06 Nov 2002 04:21:35


Brandon,

  To answer part of you question, the NOEXPAND hint can and must be used with
non-Enterprise versions of SQL Server 2000 to take advantage of indexed views.

Steve Kass
Drew University


> I created an indexed view, which is several aggregates grouped by a
> resource, date, resourcetype, and datetype.  My clustered index contains the
> same fields in the same order, and when I query the view, the columns are
> also in the same order as the index.

> I saved the query plan for the query in the view and compared it against the
> actual view, and they are the same....  Why isn't the view using my
> clustered index?  I am using SQL 2000 Enterprise.

> Well, while typing this I THINK I found my answer...  According to BOL, even
> though a view has a clustered index on it, SQL expands the view when the
> query is processed... Using WITH (NOEXPAND) seems to force the query
> optimizer to use the clustered index on the view.  ANd it runs MUCH faster
> this way in my tests.  I knew I created that damn index for a reason.  What
> is the point of creating an indexed view, if SQL will ignore it unless you
> FORCE it to use it????  Seems silly to me, perhaps somebody can shed some
> light on this.

> Also, isn't there a trick to get indexed views to work in editions other
> than Enterprise?

> Brandon
> --
> "In the beginning the universe was created. This has made a lot of people
> very angry, and has been widely regarded as a bad move." - Douglas Noel
> Adams (1952-2001)
> [Please remove "nospam_" from email address to reply.]

 
 
 

Indexed view doesn't appear to be using index on queries

Post by Brandon Lill » Thu, 07 Nov 2002 07:23:26



Quote:>   To answer part of you question, the NOEXPAND hint can and must be used
with
> non-Enterprise versions of SQL Server 2000 to take advantage of indexed

views.

This is actually EXCELLENT news, because I knew that I heard that there was
a way to get non-enterprise/Developer editions to use indexed views, but I
didn't know this was how it was accomplished.  I don't even see why
Microsoft bothered to intentionally disable the automatic use of indexed
views in anything other than enterprise edition.  But as long as there is a
way around it, woo hoo! ;)

Brandon
--
"In the beginning the universe was created. This has made a lot of people
very angry, and has been widely regarded as a bad move." - Douglas Noel
Adams (1952-2001)
[Please remove "nospam_" from email address to reply.]