Mysql
 sql >> Base de données >  >> RDS >> Mysql

L'index spatial n'est pas utilisé

Malheureusement ST_Distance() < threshold n'est pas un sargable critère de recherche. Pour satisfaire cette requête, MySQL doit calculer la valeur de la fonction pour chaque ligne de la table, puis la comparer au seuil. Il doit donc effectuer une analyse complète de la table (ou peut-être une analyse complète de l'index).

Pour exploiter un index pour accélérer cette requête, vous allez avoir besoin d'un critère de boîte englobante. La requête est beaucoup plus élaborée mais aussi beaucoup plus rapide. En supposant que vos points x/y dans votre géométrie représentent la latitude/longitude en degrés, cette requête pourrait ressembler à ceci :

   set @latpoint = 38.0234332;
   set @lngpoint = -94.0724223;
   set @r = 10.0;    /* ten mile radius */
   set @units=69.0;    /* 69 statute miles per degree */
   SELECT AsText(geo) 
     FROM markers
      WHERE MbrContains(GeomFromText( 
       CONCAT('LINESTRING(', @latpoint-(@r/@units),' ',
                             @lngpoint-(@r /(@units* COS(RADIANS(@latpoint)))), 
                          ',', 
                             @latpoint+(@r/@units) ,' ', 
                             @lngpoint+(@r /(@units * COS(RADIANS(@latpoint)))),
                           ')')),
                    geo) 

Comment cela marche-t-il? D'une part, le MbrContains( lié, objet) la fonction est sargable . D'autre part, le gros élément concat laid donne une ligne diagonale du sud-ouest au coin nord-est du rectangle englobant. En utilisant votre point de données et un rayon de dix milles, cela ressemble à ceci.

LINESTRING(37.8785 -94.2564,38.1684 -93.8884)

Lorsque vous utilisez le GeomFromText() rendu de cette ligne diagonale dans le premier argument de MbrContains() il sert de rectangle de délimitation. MbrContains() peut alors exploiter l'index de géométrie astucieux quadtree.

Troisièmement, ST_Distance() , dans MySQL, ne gère pas les calculs de latitude et de longitude du grand cercle. (PostgreSQL a une extension SIG plus complète .) MySQL est aussi stupide qu'un flapjack en plaine. Il suppose que vos points dans vos objets géométriques sont représentés dans une géométrie plane. Donc ST_Distance() < 10.0 avec les points lng/lat fait quelque chose d'étrange.

Il y a un défaut dans les résultats générés par cette requête ; il renvoie tous les points dans la boîte englobante, pas seulement dans le rayon spécifié. Cela peut être résolu avec un calcul de distance séparé. J'ai écrit tout cela en détail ici .

Remarque  :Pour la latitude et la longitude en résolution GPS, FLOAT 32 bits les données ont une précision suffisante. DOUBLE est ce que l'extension géographique de MySQL utilise. Lorsque vous travaillez en degrés, plus de cinq décimales après la virgule dépassent la précision du GPS. DECIMAL() n'est pas un type de données idéal pour les coordonnées lat/lng.