SQL Always Getting Index Scan - sql-server

I have a query in TSQL like this
SELECT TOP 10 [e].[id], [e].[Title]
FROM [Table] AS [e]
WHERE (([e].[Confirmed] = 1) AND ([e].[Deleted] = 0)) AND ([e].
[Status] <> 3)
ORDER BY [e].[CreatedOn] DESC
whatever index i made i always get and index instead of seek
included, conditional index no matter what i do i always get an index scan
the last thing i tried was
CREATE NONCLUSTERED INDEX [UIXF-x] ON [dbo].[Table]
(
[CreatedOn] DESC
)
INCLUDE ( [id],
[Title] )
WHERE ([Confirmed]=(1) AND [Deleted]=(0) AND [Status] !=(3))
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF,
DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS =
ON) ON [PRIMARY]
GO
How can i get an index seek? i have tried everything . why i can't get an index seek?

Index is a tree and index scan is tree traversal (selecting first/last nodes) - exactly what you want.
Index seek - search in a tree using given predicate (search condition). In your query you have no predicate, that's why it's impossible to get index seek.
You can view a predicate in properties of node of query plan (of course, if it exists)
WHERE (([e].[Confirmed] = 1) AND ([e].[Deleted] = 0)) AND ([e].
[Status] <> 3) is not a predicate for your index

Related

Key Lookup Operator SQL Server

I have problem with this same query on different instances of SQL Server on-premise (dev and prod). This same configuration of indexes/partitions on both.
I do not know why this from dev server works much faster than this on prod. I did notice here that dev execution plan has a Key lookup operator related to nested loop. Just can't trigger prod server to take into account key lookup also. How I can force this same on prod?
DEV :
PROD :
Query:
WITH CTE AS
(
SELECT
B.CELL_VALUE_NET, B.CELL_VALUE_NET_NEGATIVE,
ROW_NUMBER() OVER (PARTITION BY B.CHASSI_ID, B.LOG_ID, B.CELL_NO ORDER BY B.CHASSI_ID, B.LOG_ID, B.CELL_NO, B.READING_DATE) ROW_ID,
B.CELL_VALUE - LAG(B.CELL_VALUE, 1) OVER (PARTITION BY B.CHASSI_ID ORDER BY B.CHASSI_ID, B.LOG_ID, B.CELL_NO, B.READING_DATE) CELL_VALUE_NET_NEW,
b.log_id, b.reading_date, b.cell_no
FROM
REL.TEMP_CHASSI_LAST_LOAD A
JOIN
REL.MACHINE_READING_CELL B WITH (NOLOCK) ON A.CHASSI_ID = B.CHASSI_ID
AND B.ROW_CREATION_DATE BETWEEN A.MIN_ROW_CREATION_DATE AND A.MAX_ROW_CREATION_DATE
WHERE
1 = 1
AND A.CHASSI_ID IN ('A30F012437', 'A30F012546', 'A30F012545', 'A30F012558', 'A30F012657', 'A30F082351', 'A30F082332', 'A30F082325', 'A30F082290')
)
SELECT
*
-- CELL_VALUE_NET = IIF(CELL_VALUE_NET_NEW < 0,0,CELL_VALUE_NET_NEW),
--CELL_VALUE_NET_NEGATIVE = IIF(CELL_VALUE_NET_NEW < 0, CELL_VALUE_NET_NEW,NULL)
FROM
CTE
WHERE
1 = 1
AND ROW_ID > 1
Data in partitions:
All indexes are this same on both environments :
-- additional for later processes update index
CREATE NONCLUSTERED INDEX [REL.MACHINE_READING_CELL_NCI_CHASSI_ID_CELL_VALUE_CELL_VALUE_NET]
ON [REL].[MACHINE_READING_CELL] ([CHASSI_ID] ASC, [LOG_ID] ASC, [CELL_NO] ASC, [READING_DATE] ASC)
INCLUDE ([CELL_VALUE], [CELL_VALUE_NET])
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF,
SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF,
ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
GO
-- partitioned indexes :
ALTER TABLE [REL].[MACHINE_READING_CELL]
ADD CONSTRAINT [REL.MACHINE_READING_CELL_PK]
PRIMARY KEY CLUSTERED ([ROW_CREATION_DATE] ASC, [CHASSI_ID] ASC, [READING_DATE] ASC, [LOG_TYPE] ASC, [LOG_ID] ASC, [CELL_NO] ASC)
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF,
SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF,
ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
GO
-- foreign keys:
ALTER TABLE [REL].[MACHINE_READING_CELL] WITH CHECK
ADD CONSTRAINT [REL.LOG_REL.MACHINE_READING_CELL_FK1]
FOREIGN KEY([LOG_ID]) REFERENCES [REL].[LOG] ([LOG_ID])
GO
ALTER TABLE [REL].[MACHINE_READING_CELL] CHECK CONSTRAINT [REL.LOG_REL.MACHINE_READING_CELL_FK1]
GO
-- [REL].[TEMP_CHASSI_LAST_LOAD]
CREATE CLUSTERED INDEX [IDX_MR_CELL]
ON [REL].[TEMP_CHASSI_LAST_LOAD] ([CHASSI_ID] ASC, [MIN_ROW_CREATION_DATE] ASC, [MAX_ROW_CREATION_DATE] ASC)
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF,
SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF,
ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
GO
Query plans :
PROD : https://www.brentozar.com/pastetheplan/?id=Hyo3bf6ac
DEV : https://www.brentozar.com/pastetheplan/?id=H1qUMG6a9

SQL Paging (Offset, Fetch) query is very slow

I don't understand what is happening here. I am querying a single table as seen by my query below. I am only fetching the first 20 records yet the query is takes 24 seconds to complete.
Is there any way to speed up this paging query?
;WITH TempResult AS(
SELECT distinct
D.GLCompany
,D.GLAcct
,D.GLProdNum
,D.GLCostCenter
,D.FCSCompany
,D.FCSAcct
,D.FCSCostCenter
,D.JournalDetailId
,D.[EffDt]
,D.[JournalLineAmt]
,D.[JournalLineDesc]
,D.[ManagedByCd]
,D.[LegalOwnerId]
,D.[JournalLineNum]
,D.[RoundedFlagBit]
,D.[CLPreValErrCd]
,D.[GLPreValErrCd]
,D.[SuspenseErrCd]
,D.GLProfitCenter
,D.GLTradingPartner
,D.GLInternalOrder
,D.GLSubAcct
,D.GLAcctActivity
,D.GLDataSrc
,D.GLId
,D.GLProdGrp
,D.HeaderId
from MyDetail D
)
SELECT * FROM TempResult
ORDER BY TempResult.HeaderId
OFFSET 0 ROWS
FETCH NEXT 20 ROWS ONLY
OPTION(RECOMPILE)
There is a non clustered index on headerid as seen below
CREATE NONCLUSTERED INDEX [FCSAcctJournalDetail_idx] ON [dbo].[MyDetail]
(
[FCSAcct] ASC,
[FCSCompany] ASC,
[JournalEntryEffDt] ASC,
[DataDt] ASC,
[HeaderId] ASC,
[JournalDetailId] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
GO
Add an index on HeaderId:
CREATE NONCLUSTERED INDEX [FCSAcctJournalDetail_HeaderId_idx] ON [dbo].[MyDetail]
(
[HeaderId] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
GO
As David Browne wrote in his comment - the index you currently have is irrelevant to this query.
If the HeaderId was the first column in the index it would be relevant, but since it's not the first (and not even close to being the first), it's simply irrelevant in the context of this query.

Select query with covered Index resorting to index scan

I have a table with about 31 columns in it and about 10 million rows
Given the following query
Select top (1000)
[CallType],
[AttributedCallType],
[Extension],
[CallDurationBacking],
[AnswerTimeBacking],
[AccountCode],
[AuthorisationCode],
[RequestedRoute],
[SelectedRoute],
[SelectedTrunk],
[ConditionCode],
[CalibratedTime],
[StoredDialledNumber],
[AttributedSiteNumber],
[AttributedExtension],
[Cost],
[AttributedCountry],
[PlanName],
[ClassificationName]
from CallRecords
where ClientId = 15 and
Reported = 0 and
ResultCodeId > 1
order by id
And the following covering index
CREATE NONCLUSTERED INDEX [_dta_index_CallRecords_5_565577053__K2_K37_K31_1_3_4_5_6_7_8_9_10_11_12_13_14_15_16_17_18_19_25_26_28_32_33_34_35_36_38_39] ON [dbo].[CallRecords]
(
[ClientId] ASC,
[Reported] ASC,
[ResultCodeId] ASC
)
INCLUDE ( [Id],
[CallType],
[AttributedCallType],
[Extension],
[CallDurationBacking],
[AnswerTimeBacking],
[AccountCode],
[AuthorisationCode],
[RequestedRoute],
[SelectedRoute],
[SelectedTrunk],
[ConditionCode],
[CalibratedTime],
[StoredDialledNumber],
[AttributedSiteNumber],
[AttributedExtension],
[Cost],
[AttributedCountry],
[PlanName],
[ClassificationName]) 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]
Why would the execution plan be using a clustered index scan?
I would have thought SQL server would have chosen a seek
How could i force if to use an index seek / key lookup?
You probably get such result because of Ordering by ID.
Try deleting order by id. Among other things, you get non-relational results when ordering. Entrust ordering to your client application.
You can force select to use index using HINTS like:
from CallRecords WITH (INDEX(_dta_index_CallRecords_5_565577053__K2_K37_K31_1_3_4_5.....))

Why is there a table scan even though I have index on IGroupes table?

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:
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!
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.
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])

SQL Server 2008: Collation ignored in unique index?

I've created a compound unique index on my table:
CREATE TABLE [dbo].[SearchIndexWord](
[ID] [int] IDENTITY(1,1) NOT NULL,
[CatalogID] [int] NOT NULL,
[Word] [nvarchar](100) NOT NULL,
CONSTRAINT [PK_SearchIndexWord] 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]
CREATE UNIQUE NONCLUSTERED INDEX [IX_SearchIndexWord] ON [dbo].[SearchIndexWord]
(
[Word] ASC,
[CatalogID] ASC
)
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
ON [PRIMARY]
The collation for the entire database is set to SQL_Latin1_General_CP1_CI_AS. When I run the following T-SQL, it prints 'Does not equal':
IF 'm3/h' = 'm³/h'
PRINT 'Equals'
ELSE
PRINT 'Does not equal'
Then, if I try the following insert statement:
INSERT INTO [SearchIndexWord] (Word, CatalogID) VALUES ('m3/h', 1), ('m³/h', 1)
I get the following error message:
Msg 2601, Level 14, State 1, Line 1
Cannot insert duplicate key row in object 'dbo.SearchIndexWord' with unique index 'IX_SearchIndexWord'.
Why is this? I couldn't find it in the docs, but I assume the condition of two keys being duplicate is examined using the configured collation.
I've checked the table, column and index collation by the way, and they're all equal to the database collation.
Try this:
IF CAST('m3/h' AS NVARCHAR(100)) = CAST('m³/h' AS NVARCHAR(100))
PRINT 'Equals'
ELSE
PRINT 'Does not equal'
For me, this returns 'Equals' which explains why you're getting the duplicate key row error.
I suspect the values in the code IF 'm3/h' = 'm³/h' are created as VARCHAR.

Resources