J'ai deux ensembles de mesures terrestres à partir de données satellites, chacun avec des champs temporels (mjd pour la date moyenne julienne) et des positions géographiques (GeoPoint, spatial) et je cherche des coïncidences entre les deux ensembles de sorte que leurs temps correspondent à un seuil de 3 heures (ou 0,125 jours) et leurs distances à moins de 200 km les uns des autres.
J'ai fait des index pour les champs mjd sur les tables et les tables spatiales.
Lorsque je viens de me joindre à la contrainte de temps, la base de données calcule 100 000 correspondances en 8 secondes et calcule les distances pour les 100 000 correspondances de cette période. La requête ressemble à ceci:
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) ) )
Et le plan exécuté est:
Une fois triées, 9 des distances étaient inférieures à 200 km, il y a donc des matchs. Le problème est que lorsque j'ajoute la contrainte de distance et l'exécute à la place,
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) ) )
ça part longtemps. De toute évidence, en 8 secondes, il a pu trouver 100 000 matchs dans le temps, dont 9 sous 200 km, l'optimiseur doit donc essayer quelque chose de sous-optimal. Le plan ressemble à ci-dessus avec un filtre sur les distances (je suppose).
Je peux forcer l'utilisation de l'index spatial avec ceci:
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) ) )
ce qui prend ensuite 3 minutes pour trouver 5 correspondances.
Comment puis-je dire à l'optimiseur de requête d'utiliser d'abord l'index MJD, puis l'index spatial ensuite (ou est-ce déjà ce qu'il fait) et existe-t-il un moyen de l'aider en lui indiquant le nombre de correspondances à attendre? S'il peut calculer 100 000 matchs avec des distances en 8 secondes qui ont 9 à moins de 200 km, l'ajout de l'indice spatial ne devrait-il pas le rendre plus rapide et non plus lent?
Merci pour tout autre conseil ou idée.
EDIT: Pour répondre à la question à quoi ressemble le plan sans les indices, ceci (et cela prend une éternité):
Il vaut peut-être aussi la peine de mentionner qu'il y a presque 1 million d'enregistrements dans une table et 8 millions dans l'autre
la source
Réponses:
Le problème est qu'il pourrait (et connaissant probablement les indices spatiaux) supposera que le filtre spatial sera beaucoup plus sélectif que le filtre temporel.
Mais si vous avez quelques millions d'enregistrements à moins de 200 km, cela pourrait être bien pire.
Vous lui demandez de trouver des enregistrements dans un rayon de 200 km, ce qui renvoie des données classées par ordre spatial. Trouver les enregistrements qui sont proches dans le temps signifie vérifier chacun d'eux.
Ou bien vous recherchez des enregistrements par heure et vous obtenez des résultats dans l'ordre chronologique. Ensuite, filtrer cette liste dans un rayon de 200 km consiste à vérifier chacune d'elles.
Si vous filtrez les données dans deux plages comme celle-ci, il devient difficile d'appliquer le deuxième filtre à l'aide d'un index. Il vaut peut-être mieux lui dire de ne pas utiliser l'index spatial si le filtre temporel est le plus serré.
Si les deux sont grands individuellement, et ce n'est qu'ensemble qu'ils sont serrés, alors vous avez un problème plus complexe, un problème que les gens ont essayé de résoudre depuis longtemps, et qui pourrait être bien résolu par des index couvrant la 3D (et au-delà) espace. Sauf que SQL Server n'en a pas.
Pardon.
Edit: plus d'infos ...
Il s'agit d'un problème similaire à la recherche de plages de temps couvrant un moment particulier. Lorsque vous recherchez les enregistrements qui commencent avant ce point, vous avez alors un désordre non ordonné des heures de fin - et vice-versa. Si vous recherchez dans l'annuaire des personnes dont le nom de famille commence par F, vous ne pouvez pas espérer trouver très facilement les personnes dont le prénom commence par R. Et un index sur le prénom n'aide pas non plus pour la même raison. Il est difficile de trouver des choses dans le prochain index lorsque votre premier index n'est pas une égalité.
Maintenant, si vous pouviez changer votre filtre de date en un filtre d'égalité (ou une série de filtres d'égalité), vous pourriez avoir une chance, sauf qu'un index spatial est un type spécial d'index et ne peut pas être utilisé comme deuxième niveau dans un indice composite.
Vous vous retrouvez donc dans une situation délicate, je le crains. :(
Modifier: Essayez:
Notez que je brise délibérément la sargabilité en divisant par 1000 avant de comparer à 200. Je veux que ce travail soit effectué dans la recherche de clé.
Attention, vous pourriez éviter d'avoir besoin des recherches (et des astuces) en INCLUANT GeoPoint et Time dans les deux index ix_MJD. Cela éliminera certainement une partie de la chaleur du plan de requête.
la source
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