Reputation: 203
I have a database with just one table Logs
that contains columns:
Id
(PK Clustered, int, not null),ServiceName
(nvarchar(255), not null) and some other columns like TaskVariant
(nvarchar(1024)),Source
(nvarchar(1024)).I have created an index INDEX_SERVICENAME
(Non-Unique, Non-Clustered) on the ServiceName
column and that includes all columns except Id, ServiceName
.
Problem:
I want to select all columns from table filtering by ServiceName
and by TaskVariant
or by Source
with paging. My original query is for selecting last 100 items filtering by Source
is:
SELECT TOP (100)
[Filter1].[Id] AS [Id],
[Filter1].[Date] AS [Date],
[Filter1].[Data] AS [Data],
[Filter1].[ServiceName] AS [ServiceName],
[Filter1].[LogLevel] AS [LogLevel],
[Filter1].[StackTrace] AS [StackTrace],
[Filter1].[TaskVariant] AS [TaskVariant],
[Filter1].[Source] AS [Source],
[Filter1].[Message] AS [Message]
FROM ( SELECT [Extent1].[Id] AS [Id], [Extent1].[Date] AS [Date], [Extent1].[Data] AS [Data], [Extent1].[ServiceName] AS [ServiceName], [Extent1].[LogLevel] AS [LogLevel], [Extent1].[StackTrace] AS [StackTrace], [Extent1].[TaskVariant] AS [TaskVariant], [Extent1].[Source] AS [Source], [Extent1].[Message] AS [Message], row_number() OVER (ORDER BY [Extent1].[Id] DESC) AS [row_number]
FROM [dbo].[Logs] AS [Extent1]
WHERE (@serviceName = [Extent1].[ServiceName]) AND (@source = [Extent1].[Source])
) AS [Filter1]
WHERE [Filter1].[row_number] > 0
ORDER BY [Filter1].[Id] DESC
This query works very fast ~ 00:00:00 time.
But when I tried to filter by TaskVariant
query takes ~ 00:02:18 minutes (next query).
SELECT TOP (100)
[Filter1].[Id] AS [Id],
[Filter1].[Date] AS [Date],
[Filter1].[Data] AS [Data],
[Filter1].[ServiceName] AS [ServiceName],
[Filter1].[LogLevel] AS [LogLevel],
[Filter1].[StackTrace] AS [StackTrace],
[Filter1].[TaskVariant] AS [TaskVariant],
[Filter1].[Source] AS [Source],
[Filter1].[Message] AS [Message]
FROM ( SELECT [Extent1].[Id] AS [Id], [Extent1].[Date] AS [Date], [Extent1].[Data] AS [Data], [Extent1].[ServiceName] AS [ServiceName], [Extent1].[LogLevel] AS [LogLevel], [Extent1].[StackTrace] AS [StackTrace], [Extent1].[TaskVariant] AS [TaskVariant], [Extent1].[Source] AS [Source], [Extent1].[Message] AS [Message], row_number() OVER (ORDER BY [Extent1].[Id] DESC) AS [row_number]
FROM [dbo].[Logs] AS [Extent1]
WHERE (@serviceName = [Extent1].[ServiceName]) AND (@taskVariant = [Extent1].[TaskVariant])
) AS [Filter1]
WHERE [Filter1].[row_number] > 0
ORDER BY [Filter1].[Id] DESC
Question: why does the second query execute so much slower and how to solve this issue?
Thank you very much for your suggestions.
Execution Plans1
Upvotes: 2
Views: 3059
Reputation: 77657
The difference in execution time you are seeing is primarily due to the fact that the first has an index and second doesn't. As for why it's such a large difference, it's likely the fact that since there's an index, it means that the values are sorted.
Since the values are sorted, you can use very efficient string search algorithms that can make the number of operations when filtering orders of magnitude smaller.
In addition, there's a lot of other characteristics that can affect this. It's possible that the entire index is in memory, while the table data is not, so the filtering in the first query could be done all on memory and never touch the disk, where as the other may not.
Upvotes: 0
Reputation: 10610
The index works like a hierarchy/tree, with levels corresponding to the columns in it.
So if your index is on ServiceName, TaskVariant
, you can quickly filter to specific ServiceName
s because that is the top level in the tree.
But if you try to filter by TaskVariant
, you now have to read through the entire index: you can't just jump to a specific TaskVariant
because the same TaskVariant
will be under different ServiceName
s.
If you want to filter on TaskVariant, you need another index that starts with TaskVariant
. NB: don't just create full indices on every column: every index takes up additional space and requires more work on UPDATE
s and INSERT
s
Upvotes: 2