Наше приложение имеет ряд относительно простых геопространственных запросов, запущенных на SQL Server, большинство из которых в конечном итоге выглядят примерно так:
declare @stateCode nvarchar(2) = 'FL'
declare @point geography = geography::STGeomFromText('POINT(-83.89371700 30.45409700)', 4326)
declare @version nvarchar(max) = 'V1'
declare @maxDistance decimal = 10000
SELECT TOP (1)
fs.[Score] AS [Score],
fs.[ResponseTime] AS [ResponseTime],
fs.[CensusBlock] AS [CensusBlock]
FROM [dbo].[EFByPerilFireScores] AS fs with (index(IX_EFByPerilFireScores_Spatial))
WHERE fs.[StateCode] = @stateCode AND
fs.[Version] = @version AND
fs.[GeoLocation].STDistance(@point) IS NOT NULL AND
fs.[GeoLocation].STDistance(@point) < @maxDistance
ORDER BY fs.[GeoLocation].STDistance(@point) ASC
(В реальном приложении это Entity Framework, ноон генерирует эквивалентный SQL, и странное поведение, которое мы наблюдаем, происходит как с EF, так и с более простым SQL, описанным выше.)
В подавляющем большинстве случаев эти запросы возвращаются в течение ста миллисекунд или около того - слишком медленно, чтобывремя от SSMS.Но очень редко они занимают гораздо больше времени, например, 30-90 секунд.И странная вещь, когда это происходит, и я вставляю сгенерированный SQL в SSMS и запускаю точно такой же SQL 10-20 раз вручную (те же параметры и все остальное), большую часть времени он возвращает за секунду,но иногда это занимает гораздо больше времени.Таким образом, нельзя винить индекс, работающий по-разному с разными данными.
Выполнение запроса более 1000 раз, хронирование его каждый раз, в результате время (в мс) выглядит примерно так:
24
22
25
21
29
23
23
24
22
26
23
24
29
418
23
22
22
23
25
21
22
21
24
26
22
22
24
23
23
25
23
24
57
43
50
34
29
26
24
35
34
46
51
27
14071
21
21
23
22
22
22
22
23
19
22
21
20
19
Это в последней версии SQL 2017 (RTM-CU13), установленной на моем локальном компьютере разработчика, и на БД не запущены никакие другие процессы.
Я знаю, что геопространственные индексы SQL ServerПричудливые, и иногда в прошлом нам приходилось прибегать к таким вещам, как подсказки индекса, чтобы заставить их использовать SQL Server, но это ведет себя так же, даже с подсказками индекса.И я не думаю, что видел это раньше.
Таблица для запроса выше выглядит так:
CREATE TABLE [dbo].[EFByPerilFireScores](
[Id] [int] IDENTITY(1,1) NOT NULL,
[StateCode] [nvarchar](2) NOT NULL,
[Version] [nvarchar](10) NOT NULL,
[CensusBlock] [nvarchar](15) NOT NULL,
[Latitude] [decimal](10, 7) NOT NULL,
[Longitude] [decimal](10, 7) NOT NULL,
[IsModeledResponseTime] [bit] NOT NULL,
[ResponseTime] [decimal](18, 4) NOT NULL,
[IsModeledFire] [bit] NOT NULL,
[Score] [decimal](18, 4) NOT NULL,
[GeoLocation] [geography] NOT NULL,
CONSTRAINT [PK_dbo.EFByPerilFireScores] 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] TEXTIMAGE_ON [PRIMARY]
GO
ALTER TABLE [dbo].[EFByPerilFireScores] WITH NOCHECK ADD CONSTRAINT [FK_dbo.EFByPerilFireScores_dbo.EFStates_StateCode] FOREIGN KEY([StateCode])
REFERENCES [dbo].[EFStates] ([Code])
GO
ALTER TABLE [dbo].[EFByPerilFireScores] CHECK CONSTRAINT [FK_dbo.EFByPerilFireScores_dbo.EFStates_StateCode]
GO
CREATE SPATIAL INDEX [IX_EFByPerilFireScores_Spatial] ON [dbo].[EFByPerilFireScores]
(
[GeoLocation]
)USING GEOGRAPHY_AUTO_GRID
WITH (
CELLS_PER_OBJECT = 12, PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, FILLFACTOR = 80) ON [PRIMARY]
GO
ALTER TABLE [dbo].[EFByPerilFireScores] ADD CONSTRAINT [PK_dbo.EFByPerilFireScores] PRIMARY KEY CLUSTERED
(
[Id] 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) ON [PRIMARY]
GO
CREATE UNIQUE NONCLUSTERED INDEX [UX_EFByPerilFireScore_StateCode_Version_Latitude_Longitude] ON [dbo].[EFByPerilFireScores]
(
[StateCode] ASC,
[Version] ASC,
[Latitude] ASC,
[Longitude] 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]
GO
Есть предложения?