Mise à jour :
Consultez cet article sur mon blog pour une stratégie d'indexation efficace pour votre requête à l'aide de colonnes calculées :
L'idée principale est que nous calculons simplement la length
arrondie et startDate
pour vos plages, puis recherchez-les en utilisant des conditions d'égalité (qui sont bonnes pour B-Tree
index)
En MySQL
et dans SQL Server 2008
vous pouvez utiliser SPATIAL
index (R-Tree
).
Ils sont particulièrement adaptés aux conditions telles que "sélectionner tous les enregistrements avec un point donné à l'intérieur de la plage d'enregistrements", ce qui est votre cas.
Vous stockez la start_date
et end_date
comme début et fin d'un LineString
(en les convertissant en UNIX
horodatages d'une autre valeur numérique), indexez-les avec un SPATIAL
indexer et rechercher tous ces LineString
s dont la boîte englobante minimale (MBR
) contient la valeur de date en question, en utilisant MBRContains
.
Voir cette entrée dans mon blog sur la façon de faire cela dans MySQL
:
et un bref aperçu des performances de SQL Server
:
La même solution peut être appliquée pour rechercher un IP
donné par rapport aux plages de réseau stockées dans la base de données.
Cette tâche, ainsi que votre requête, est un autre exemple souvent utilisé d'une telle condition.
B-Tree
ordinaire les index ne sont pas bons si les plages peuvent se chevaucher.
S'ils ne le peuvent pas (et vous le savez), vous pouvez utiliser la solution géniale proposée par @AlexKuznetsov
Notez également que les performances de cette requête dépendent totalement de la distribution de vos données.
Si vous avez beaucoup d'enregistrements dans B
et quelques enregistrements en A
, vous pouvez simplement créer un index sur B.dates
et laissez le TS/CIS
sur A
allez.
Cette requête lira toujours toutes les lignes de A
et utilisera Index Seek
le B.dates
dans une boucle imbriquée.
Si vos données sont distribuées dans l'autre sens, i. e. vous avez beaucoup de lignes dans A
mais peu en B
, et que les plages sont généralement courtes, vous pourriez alors repenser un peu vos tableaux :
A
start_date interval_length
, créer un index composite sur A (interval_length, start_date)
et utilisez cette requête :
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