Оптимизируйте запрос ближайшего соседа на 70-миллионном облаке точек на SQL Server 2008

16

У меня около 75 миллионов записей в базе данных SQL Server 2008 R2 Express. Каждый - это длинный лат, соответствующий некоторому значению. Таблица имеет столбец географии. Я пытаюсь найти ближайшего соседа для данной широты и долготы (точка). У меня уже есть запрос с пространственным индексом на месте. Но в зависимости от того, где запись находится в базе данных, например, в первом или последнем квартале, запрос может занять от 3 до 30 секунд, чтобы найти ближайшего соседа. Я чувствую, что это может быть оптимизировано, чтобы дать намного более быстрый результат, оптимизируя запрос или пространственный индекс. Прямо сейчас применен некоторый пространственный индекс с настройками по умолчанию. Вот как выглядит моя таблица и запрос.

CREATE TABLE lidar(
    [id] [bigint] IDENTITY(1,1) NOT NULL,
    [POINTID] [int] NOT NULL,
    [GRID_CODE] [numeric](17, 8) NULL,
    [geom] [geography] NULL,
 CONSTRAINT [PK_lidar_1] 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 SPATIAL INDEX [SPATIAL_lidar] ON [dbo].[lidar] ([geom]) USING  GEOGRAPHY_GRID 
WITH (
GRIDS =(LEVEL_1 = MEDIUM,LEVEL_2 = MEDIUM,LEVEL_3 = MEDIUM,LEVEL_4 = MEDIUM), 
CELLS_PER_OBJECT = 16, PAD_INDEX  = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF,  
ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]

Вот запрос, который я использую:

declare @ms_at geography = 'POINT (-95.66 30.04)';
select TOP(1) nearPoints.geom.STAsText()as latlon 
from
(
select r.geom
from lidar r With(Index(SPATIAL_lidar))
where r.geom.STIntersects(@ms_at.STBuffer(1000)) = 1
) nearPoints

Вот образец лат длинных в моей базе данных. дать представление о точности и плотности. Все 70 миллионов записей относятся к одному городу (данные Лидара).

POINT (-95.669434934023087 30.049513838913736)

Теперь этот запрос дает мне результаты, как я описал выше, но я хочу максимально повысить производительность. Я предполагаю, что путем настройки значений по умолчанию пространственного индекса я могу быть выше, чтобы лучше оптимизировать производительность. Есть какие-нибудь подсказки по этому поводу?

Я попытался изменить буфер от 10 до 1000, но с почти такими же результатами.

Также приветствуются любые другие предложения по улучшению производительности.

Вот система, которую я использую сейчас:

Windows 7 64bit Professional
Intel(R) Core(TM)2 Quad CPU    Q9650  @ 3.00GHz (4 CPUs), ~3.0GHz
Ram: 8 GB
NVIDIA GeForce 9500 GT
Shaunak
источник
1
Это лидарные данные? Если это так, рассмотрите возможность добавления lidarтега.
Кирк Куйкендалл
2
Я не говорю на SQL Server, но мне кажется, что ваш запрос должен найти все точки, находящиеся в 1000-метровом буфере целевой точки. Эти тесты точка-полигон будут намного медленнее, чем тесты на близость, которые являются основой для решений, предложенных в вашем предыдущем вопросе .
whuber
@whuber: я пробовал основанные на расстоянии запросы и время в минутах. путь к высокой. Может быть, я иду не так где-то. Что касается этих точек в многоугольнике, это занимает время в секундах. Даже изменение буфера от 10 до 10000 имеет мало времени.
Шаунак
1
@Shaunak Тогда что-то не так с запросами на основе расстояния, потому что теоретически они могут быть выполнены в среднем в микросекундах (или лучше) и в миллисекундах (в худшем случае) с использованием соответствующих индексов, таких как деревья KD . Возможно, вы захотите подумать об их улучшении, а не искать способы оптимизировать поиск в буфере.
whuber
Это данные сетки? Почему бы не использовать растр?
Мэтью Снейп

Ответы:

9

Попробуйте запустить хранимую процедуру sp_help_spatial_geography_index, чтобы получить подробную информацию об использовании вашего пространственного индекса. Вы должны быть в состоянии использовать что-то вроде:

declare @ms_at geography = 'POINT (-95.66 30.04)'
set @ms_at = @ms_at.STBuffer(1000).STAsText()
exec sp_help_spatial_geography_index 'lidar', 'SPATIAL_lidar', 0, @ms_at;

Опубликуйте результаты в своем вопросе, чтобы увидеть, если что-то выделяется. Значение каждого из пунктов можно найти здесь .

Если ваши координаты были спроецированы, вы также можете выполнить простой непространственный запрос для вычисленных полей X, Y и проверить X <MinX и X> MaxX и т. Д.

Проецирование ваших координат (в поле типа GEOMETRY) также позволяет вам ограничить пространственный индекс объемом данных, что может значительно повысить производительность. Замените экстенты мира экстентами ваших данных:

CREATE SPATIAL INDEX [SPATIAL_lidar] ON [dbo].[lidar] ([geom]) USING  GEOMETRY_GRID 
WITH (
GRIDS =(LEVEL_1 = MEDIUM,LEVEL_2 = MEDIUM,LEVEL_3 = MEDIUM,LEVEL_4 = MEDIUM), 
CELLS_PER_OBJECT = 16, PAD_INDEX  = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF,  
ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON,
BOUNDING_BOX =(-90, -180, 90, 180),) ON [PRIMARY]
geographika
источник
1
Согласно technet.microsoft.com/en-us/library/bb934196.aspx BOUNDING_BOX может использоваться только для GEOMETRY_GRID, но не для GEOGRAPHY_GRID
Келсо
1
Обновленный ответ. Тип GEOMETRY должен быть намного быстрее, так как BOUNDING_BOX может быть установлен.
География
1

Рассмотрим упрощение буфера с помощью BufferwithTolerance . Если точки плотно упакованы, система должна определить, находится ли точка по обе стороны от границы. Чем проще эта линия, тем меньше работы приходится выполнять машине.

Мэтью Снейп
источник