Как оптимизировать запрос, чтобы он сначала выполнял поиск по одному индексу, а затем по другому

12

У меня есть два набора измерений Земли из спутниковых данных, каждый с полями времени (mjd для средней юлианской даты) и географическими положениями (GeoPoint, spacial), и я ищу совпадения между двумя наборами, чтобы их время совпадало с порогом 3 часа (или. 125 дней) и их расстояния в пределах 200 км друг от друга.

Я сделал индексы для полей mjd как для таблиц, так и для пространственных таблиц.

Когда я просто включаю ограничение по времени, база данных вычисляет 100 000 совпадений за 8 секунд и вычисляет расстояния для всех 100 000 совпадений за это время. Запрос выглядит так:

select top 100000 h.Time, m.Time, h.GeoPoint.STDistance(m.GeoPoint)/1000.0
from L2V5.dbo.header h join L2.dbo.MLS_Header m
on h.mjd between m.mjd-.125 and m.mjd+.125
option( table hint ( h, index(ix_MJD) ), table hint( m, index(ix_MJD) ) )

И выполненный план это:

Только ограничение MJD

При сортировке 9 расстояний были меньше 200 км, поэтому есть совпадения. Проблема в том, что когда я добавляю ограничение расстояния и запускаю его,

select top 10 h.Time, m.Time, h.GeoPoint.STDistance(m.GeoPoint)/1000.0
from L2V5.dbo.header h join L2.dbo.MLS_Header m
on h.mjd between m.mjd-.125 and m.mjd+.125
and h.GeoPoint.STDistance(m.GeoPoint)<200000
option( table hint ( h, index(ix_MJD) ), table hint( m, index(ix_MJD) ) )

это уходит в течение длительного времени. Очевидно, что за 8 секунд он может найти 100 000 временных матчей, 9 из которых были на расстоянии менее 200 км, поэтому оптимизатор должен попробовать что-то неоптимальное. План выглядит аналогично приведенному выше с фильтром по расстояниям (я предполагаю).

с пространственной константой, без пространственного фильтра

Я могу заставить использование пространственного индекса с этим:

select top 5 h.Time, m.Time, h.GeoPoint.STDistance(m.GeoPoint)/1000.0 
from L2V5.dbo.header h join L2.dbo.MLS_Header m 
on h.GeoPoint.STDistance(m.GeoPoint)<200000
and h.mjd between m.mjd-.125 and m.mjd+.125 
option( table hint ( h, index(ix_MJD), index(ix_GeoPoint) ), table hint( m, index(ix_MJD) ) )

оба ограничения с обоими индексами

что затем занимает 3 минуты, чтобы найти 5 совпадений.

Как мне сказать оптимизатору запросов использовать сначала поиск по индексу MJD, а затем - по пространственному индексу (или это то, что он уже делает), и есть ли способ помочь ему, сказав, сколько совпадений ожидать? Если он может вычислить 100 000 совпадений с расстояниями за 8 секунд, у которых 9 меньше 200 км, разве добавление пространственного индекса не сделает его быстрее, а не медленнее?

Спасибо за любые другие советы или идеи.

РЕДАКТИРОВАТЬ: Чтобы ответить на вопрос, как план выглядит без намеков, это (и это занимает вечность):

нет подсказок

Также стоит упомянуть, что в одной таблице почти 1 млн записей, а в другой - 8 млн.

user261963
источник
Как выглядит ваш план запроса, если вы удалите эти подсказки?
Зейн
@Zane, я отредактировал сообщение и добавил план запроса без подсказок. Это заменяет поиски сканированием, и выбор времени ужасен.
user261963

Ответы:

6

Проблема в том, что он может (и, зная пространственные индексы, вероятно, будет) предполагать, что пространственный фильтр будет намного более избирательным, чем временной фильтр.

Но если у вас есть несколько миллионов записей в пределах 200 км, то это может быть значительно хуже.

Вы просите его найти записи в пределах 200 км, которые возвращают данные, упорядоченные по некоторому пространственному порядку. Найти там записи, которые близки по времени, значит проверить каждую.

Или же вы находите записи по времени и получаете результаты по времени. Затем фильтрация этого списка по радиусу 200 км - это проверка каждого из них.

Если вы фильтруете данные в двух диапазонах, как это, становится трудно применить второй фильтр, используя индекс. Возможно, вам лучше запретить использовать пространственный индекс, если временной фильтр более узкий.

Если оба они велики по отдельности, и только вместе они тесно связаны, то у вас есть более сложная проблема, которую люди пытались решить в течение длительного времени, и которая могла бы быть хорошо решена с помощью индексов, охватывающих 3D (и далее) Космос. За исключением того, что у SQL Server их нет.

Сожалею.

Редактировать: подробнее ...

Эта проблема аналогична поиску диапазонов времени, охватывающих определенный момент времени. Когда вы ищете записи, которые начинаются до этого момента, у вас возникает неупорядоченный беспорядок времен окончания - и наоборот. Если вы ищете людей в телефонной книге, чьи фамилии начинаются с F, вы не можете надеяться найти людей, чьи имена начинаются с R, очень легко. И индекс по имени не помогает ни по той же причине. Найти вещи в следующем индексе сложно, когда ваш первый индекс не равен.

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

Так что, боюсь, ты остался в неловкой ситуации. :(

Редактировать: Попробуйте:

select top 100000 h.Time, m.Time, h.GeoPoint.STDistance(m.GeoPoint)/1000.0
from L2V5.dbo.header h join L2.dbo.MLS_Header m
on h.mjd between m.mjd-.125 and m.mjd+.125
where h.GeoPoint.STDistance(m.GeoPoint)/1000.0 < 200
option( table hint ( h, index(ix_MJD) ) );

Обратите внимание, что я намеренно нарушаю проходимость путем деления на 1000, прежде чем сравнивать с 200. Я хочу, чтобы эта работа была выполнена в поиске ключей.

Напоминаем, что вы могли бы избежать необходимости поиска (и подсказок), включив GeoPoint и Time в оба индекса ix_MJD. Это, безусловно, отнимает часть тепла в плане запросов.

Роб Фарли
источник
Я не знаю, меняет ли это что-нибудь, но временной фильтр намного более избирателен.
user261963
Ok. Так допустимо ли найти все совпадающие по времени строки, а затем проверить каждое местоположение без индекса?
Роб Фарли
... так что план выглядит как ваш первоначальный, но имеет дополнительный предикат или фильтр.
Роб Фарли
Предложил некоторые изменения с быстрым редактированием. Вам не нужно намекать о м, просто ч. Хотя, если вы можете поменять местами то, к которому вы добавляете 1/8, чтобы убедиться, что вы изменяете столбец из меньшей таблицы и используете эти значения для поиска в большей, это тоже поможет. Если h равно 8M, а m равно 1M, оставьте предикат BETWEEN и укажите только h. Если все наоборот, измените свой предикат и подсказку (но лучше, чем изменить подсказку, это добавить эти столбцы в индекс).
Роб Фарли
Кажется, в конце концов лучше всего использовать все подсказки за столом, пока я делаю h между m, а не наоборот. Запрос больше не использует индексы GeoPoint вообще, но он все равно не использовал их эффективно. Я включил столбец GeoPoint в индекс MJD, и это очень помогло. select top 10000 h.Time, m.Time, m.GeoPoint.STDistance(h.GeoPoint), h.mjd-m.mjd from L2V5.dbo.header h join L2.dbo.MLS_Header m on m.GeoPoint.STDistance(h.GeoPoint)<200000 and m.mjd between h.mjd-.125 and h.mjd+.125 order by h.mjd
user261963