I am still new to database administration and I'm trying to optimise a search query.
I had a query which looked like this and took 5-15 seconds to execute in some cases, and also was causing 100% CPU usage:
DECLARE @point geography;
SET @point = geography::STPointFromText('POINT(3.3109015 6.648294)', 4326);
SELECT TOP (1)
[Result].[PointId] AS [PointId],
[Result].[PointName] AS [PointName],
[Result].[LegendTypeId] AS [LegendTypeId],
[Result].[GeoPoint] AS [GeoPoint]
FROM (
SELECT
[Extent1].[GeoPoint].STDistance(@point) AS distance,
[Extent1].[PointId] AS [PointId],
[Extent1].[PointName] AS [PointName],
[Extent1].[LegendTypeId] AS [LegendTypeId],
[Extent1].[GeoPoint] AS [GeoPoint]
FROM [dbo].[GeographyPoint] AS [Extent1]
WHERE 18 = [Extent1].[LegendTypeId]
) AS [Result]
ORDER By [Result].distance ASC
This table has one clustered index on the PK, and one spatial Index on the geography
type column.
So when I executed the above query, it was performing a scan operation.
So I created a non-clustered index on the LegendTypeId
column:
CREATE NONCLUSTERED INDEX [GeographyPoint_LegendType_NonClustered] ON [dbo].[GeographyPoint]
(
[LegendTypeId] ASC
)
INCLUDE ( [PointId],
[PointName],
[GeoPoint])
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
and changed the query to:
DECLARE @point geography;
SET @point = geography::STPointFromText('POINT({0} {1})', 4326);
SELECT TOP (1)
[GeoPoint].STDistance(@point) AS distance,
[PointId],
[PointName],
[LegendTypeId],
[GeoPoint]
FROM [GeographyPoint]
WHERE 18 = [LegendTypeId]
ORDER By distance ASC
And now SQL Server performs a seek instead of the scan:
which in my view has increased the efficiency of the query, but when I deploy this to production, I still get the same results (high CPU usage, and average of 10 seconds to execute the query).
Note: No data is inserted, updated or removed from this table – only search/read.
Is it something I am doing wrong?
How can I fix this?
EDIT
Index Seak details
EDIT 2:
I changed the query, to use the method: 'Nearest Neighbor' from link: https://msdn.microsoft.com/en-us/library/ff929109.aspx, and now this is the result, This Query is also taking 3-5 seconds for the search - similar to the Second Query, (but not tested on Production)
Spatial Index settings:
CREATE SPATIAL INDEX [SPATIAL_Point] ON [dbo].[GeographyPoint]
(
[GeoPoint]
)USING GEOGRAPHY_GRID
WITH (GRIDS =(LEVEL_1 = MEDIUM,LEVEL_2 = MEDIUM,LEVEL_3 = MEDIUM,LEVEL_4 = MEDIUM),
CELLS_PER_OBJECT = 16, 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
EDIT 3
I followed instructions by @MickyT, dropped the Index on [LegendTypeId]
,and executed the following query:
DECLARE @point geography;
SET @point = geography::STPointFromText('POINT(3.3109 6.6482)', 4326);
SELECT TOP (1)
[PointId],
[PointName],
[LegendTypeId],
[GeoPoint]
FROM [GeographyPoint] WITH(INDEX(SPATIAL_Point))
WHERE
[GeoPoint].STDistance(@point) IS NOT NULL AND
18 = [LegendTypeId]
ORDER By [GeoPoint].STDistance(@point) ASC
OPTION(MAXDOP 1)
Statistics for this query are
And then I executed this Query again:
DECLARE @point geography;
SET @point = geography::STPointFromText('POINT(3.3109 6.6482)', 4326);
SELECT TOP (1)
[GeoPoint].STDistance(@point) AS distance,
[PointId],
[PointName],
[LegendTypeId],
[GeoPoint]
FROM [GeographyPoint] --WITH(INDEX(SPATIAL_Point))
WHERE 18 = [LegendTypeId]
ORDER By distance ASC
Statistics for this query are
ORDER BY Distance
clause.