Актуализация:
Вижте тази статия в моя блог за ефективна стратегия за индексиране за вашата заявка с помощта на изчислени колони:
Основната идея е, че просто изчисляваме закръглена 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
във вложен цикъл.
Ако вашите данни се разпространяват обратно, т.е. д. имате много редове в 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