Question

This is my query:

exec sp_executesql N'set arithabort off;set statistics time on; set transaction isolation level read uncommitted;With cte as (Select peta_rn = ROW_NUMBER() OVER (ORDER BY  d.LastStatusChangedDateTime  desc )  
                                                , d.DocumentID,
                                                d.IsReEfiled, d.IGroupID, d.ITypeID, d.RecordingDateTime, d.CreatedByAccountID, d.JurisdictionID, 
                                                d.LastStatusChangedDateTime as LastStatusChangedDateTime
                                                ,  d.IDate, d.InstrumentID, d.DocumentStatusID
                                                , u.Username
                                                , it.Abbreviation AS ITypeAbbreviation
                                                , ig.Abbreviation AS IGroupAbbreviation,
                                                d.DocumentDate                                               
                                From Documents d                             
                                Inner Join ITypes it  on it.ITypeID = d.ITypeID
                                 Inner Join Users u on d.UserID = u.UserID Inner Join IGroupes ig on ig.IGroupID = d.IGroupID
                                Where 1=1  And  (  d.DocumentStatusID = 9  ) ) Select cte.DocumentID, 
                                cte.IsReEfiled, cte.IGroupID, cte.ITypeID, cte.RecordingDateTime, cte.CreatedByAccountID, cte.JurisdictionID, 
                        cte.LastStatusChangedDateTime as LastStatusChangedDateTime
                        ,  cte.IDate, cte.InstrumentID, cte.DocumentStatusID,cte.IGroupAbbreviation, cte.Username, j.JDAbbreviation, inf.DocumentName,
                       cte.ITypeAbbreviation, cte.DocumentDate, ds.Abbreviation as DocumentStatusAbbreviation,  ds.Name as DocumentStatusName,
                        ( SELECT CAST(CASE WHEN cte.DocumentID = (
                                SELECT TOP 1 doc.DocumentID
                                FROM  Documents doc
                                WHERE doc.JurisdictionID = cte.JurisdictionID
                                        AND doc.DocumentStatusID = cte.DocumentStatusID
                                ORDER BY LastStatusChangedDateTime) 
                            THEN 1
                            ELSE 0
                        END AS BIT)
                        ) AS CanChangeStatus ,

                        Upper((Select Top 1 Stuff( (Select ''='' + dbo.GetDocumentNameFromParamsWithPartyType(Business, FirstName, MiddleName, LastName, t.Abbreviation, NameTypeID, pt.Abbreviation, IsGrantor, IsGrantee)  From DocumentNames dn
                                Left Join Titles t
                                    on dn.TitleID = t.TitleID               
                                Left Join PartyTypes pt
                                    On pt.PartyTypeID = dn.PartyTypeID
                                        Where DocumentID = cte.DocumentID
                                            For XML PATH('''')),1,1,''''))) as FlatDocumentName, (SELECT COUNT(*) FROM CTE) AS TotalRecords

                        FROM cte Left Join DocumentStatuses ds On
                        cte.DocumentStatusID = ds.DocumentStatusID Left Join InstrumentFiles inf On cte.DocumentID = inf.DocumentID 
                    Left Join Jurisdictions j on j.JurisdictionID = cte.JurisdictionID Where 1=1 And 
                    peta_rn>@7 AND peta_rn<=@8 Order by peta_rn set statistics time off; ',N'@0 int,@1 int,@2 int,@3 int,@4 int,@5 int,@6 int,@7 int,@8 int',
                    @0=1,@1=5,@2=9,@3=1,@4=5,@5=9,@6=1,@7=97500,@8=97550

And this is my IGroupes table definition:

CREATE TABLE [dbo].[IGroupes](
    [IGroupID] [int] IDENTITY(1,1) NOT NULL,
    [Name] [varchar](64) NOT NULL,
    [JurisdictionID] [int] NOT NULL,
    [Abbreviation] [varchar](12) NOT NULL,
 CONSTRAINT [PK_IGroupes] PRIMARY KEY NONCLUSTERED 
(
    [IGroupID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, FILLFACTOR = 90) ON [PRIMARY]
) ON [PRIMARY]

GO

SET ANSI_PADDING OFF
GO

SET ANSI_PADDING ON

GO

/****** Object:  Index [IX_IGroupes_Abbreviation]    Script Date: 10/11/2013 4:21:46 AM ******/
CREATE NONCLUSTERED INDEX [IX_IGroupes_Abbreviation] ON [dbo].[IGroupes]
(
    [Abbreviation] ASC
)
INCLUDE (   [IGroupID],
    [Name],
    [JurisdictionID]) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, FILLFACTOR = 90) ON [PRIMARY]
GO

SET ANSI_PADDING ON

GO

/****** Object:  Index [IX_IGroupes_JurisdictionID]    Script Date: 10/11/2013 4:21:46 AM ******/
CREATE NONCLUSTERED INDEX [IX_IGroupes_JurisdictionID] ON [dbo].[IGroupes]
(
    [JurisdictionID] ASC
)
INCLUDE (   [IGroupID],
    [Name],
    [Abbreviation]) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, FILLFACTOR = 90) ON [PRIMARY]
GO

SET ANSI_PADDING ON

GO

/****** Object:  Index [IX_IGroupes_Name]    Script Date: 10/11/2013 4:21:46 AM ******/
CREATE NONCLUSTERED INDEX [IX_IGroupes_Name] ON [dbo].[IGroupes]
(
    [Name] ASC
)
INCLUDE (   [IGroupID],
    [JurisdictionID],
    [Abbreviation]) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, FILLFACTOR = 90) ON [PRIMARY]
GO

Yet please see it is using table scan. This operation is costing me too much. IGroupes table just has 7 rows and Documents table has approximately 98K records. Yet when I join on d.IGroupID = ig.IGroupID it shows actual number of rows above 600K! That is the problem. Please see the attached screenshot:

enter image description here

In case anybody is interested in the full query plan xml, here it is:

https://www.dropbox.com/s/kldx24x3j8vndpe/plan.xml

Any help is appreciated. Thanks!

Was it helpful?

Solution

None of the 3 indexes (other than the PK) you have on IGroupes are going to help this query because you are not using any of those fields in a where or join clause. Unless you need those indexes for other queries, I would delete them. They are just going to give the query optimizer more choices to test (and reject).

The index on the Primary Key PK_IGroupes should be clustered. That will allow it to do an index seek (or bookmark lookup). If it can't be clustered for some other reason, try creating an index on IGroupID and Abbreviation, in that order (or including the Abbreviation column in the existing PK index).

If it still doesn't pick up the right index, you can use a hint such as WITH(INDEX(0)) or WITH(INDEX('index-name')).

The 600k rows does come from the fact that it is doing a nested loop join on 98k rows multiplied by the 7 rows. If the index above doesn't work, you can try replacing the INNER JOIN iGroupes with INNER HASH JOIN IGroupes.

OTHER TIPS

Probably in this case table scan is more efficient than using any of the indexes you have on the IGroupes table. If you think table scan operation is bottleneck in this query (though with 3% cost I'm not sure it is) either you may try modifying PK_IGroupes to become clustered index or you may try index like

CREATE UNIQUE NONCLUSTERED INDEX [IX_IGroupes_IGroupID]
    ON [dbo].[IGroupes] ([IGroupID]) INCLUDE ([Abbreviation])
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top