Обновление:
См. Эту статью в моем блоге для эффективной стратегии индексации вашего запроса с использованием вычисляемых столбцов:
Основная идея заключается в том, что мы просто вычисляем округленные length
и startDate
для вас диапазонов, а затем ищем их, используя условия равенства (которые подходят для B-Tree
индексов)
В MySQL
и SQL Server 2008
вы можете использовать SPATIAL
индексы (R-Tree
).
Они особенно хороши для таких условий, как «выбрать все записи с заданной точкой в пределах диапазона записи», что как раз для вас.
Вы сохраняете start_date
и end_date
как начало и конец LineString
(преобразовывая их в UNIX
метки времени другого числового значения), индексируете их с индексом SPATIAL
и ищите все таких LineString
s, минимальная ограничивающая рамка которых (MBR
) содержит значение даты, о котором идет речь, с использованием MBRContains
.
Смотрите эту запись в моем блоге о том, как это сделать, в MySQL
:
и краткий обзор производительности для SQL Server
:
Такое же решение может быть применено для поиска данного IP
по сетевым диапазонам, хранящимся в базе данных.
Эта задача, наряду с вашим запросом, является другим часто используемым примером такого условия.
Обычные B-Tree
индексы не годятся, если диапазоны могут перекрываться.
Если они не могут (и вы это знаете), вы можете использовать блестящее решение, предложенное @AlexKuznetsov
Также обратите внимание, что производительность этого запроса полностью зависит от вашего распределения данных.
Если у вас много записей в B
и мало записей в A
, вы можете просто создать индекс для B.dates
и позволить TS/CIS
для A
перейти.
Этот запрос всегда будет читать все строки из A
и будет использовать Index Seek
в B.dates
во вложенном цикле.
Если ваши данные распространяются другим способом, i. е. у вас есть много строк в A
, но мало в B
, и диапазоны, как правило, короткие, тогда вы можете немного изменить дизайн таблиц:
A
start_date interval_length
, создайте составной индекс для A (interval_length, start_date)
и используйте этот запрос:
SELECT *
FROM (
SELECT DISTINCT interval_length
FROM a
) ai
CROSS JOIN
b
JOIN a
ON a.interval_length = ai.interval_length
AND a.start_date BETWEEN b.date - ai.interval_length AND b.date