Mysql
 sql >> Datenbank >  >> RDS >> Mysql

Räumlicher Index wird nicht verwendet

Leider ST_Distance() < threshold ist kein Sargable Suchkriterium. Um diese Abfrage zu erfüllen, muss MySQL den Wert der Funktion für jede Zeile in der Tabelle berechnen und ihn dann mit dem Schwellenwert vergleichen. Es muss also einen vollständigen Tabellen-Scan (oder vielleicht einen vollständigen Index-Scan) durchführen.

Um einen Index auszunutzen, um diese Abfrage zu beschleunigen, benötigen Sie ein Bounding-Box-Kriterium. Die Abfrage ist viel aufwendiger, aber auch viel schneller. Angenommen, Ihre x/y-Punkte in Ihrer Geometrie stellen Breiten-/Längengrade in Grad dar, könnte diese Abfrage wie folgt aussehen:

   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) 

Wie funktioniert das? Zum einen enthält der MbrContains( gebunden, Artikel) Funktion ist sargable . Zum anderen ergibt das große hässliche Concat-Element eine diagonale Linie von der südwestlichen zur nordöstlichen Ecke des Begrenzungsrechtecks. Mit Ihrem Datenpunkt und einem Umkreis von zehn Meilen sieht es so aus.

LINESTRING(37.8785 -94.2564,38.1684 -93.8884)

Wenn Sie GeomFromText() verwenden Rendern dieser diagonalen Linie im ersten Argument von MbrContains() es dient als Begrenzungsrechteck. MbrContains() kann dann den raffinierten Quadtree-Geometrieindex ausnutzen.

Drittens ST_Distance() , in MySQL, verarbeitet keine Breiten- und Längengradberechnungen für Großkreise. (PostgreSQL hat eine umfassendere GIS-Erweiterung .) MySQL ist so dumm wie ein Pfannkuchen im Flachland. Es geht davon aus, dass Ihre Punkte in Ihren geometrischen Objekten in planarer Geometrie dargestellt werden. Also ST_Distance() < 10.0 mit lng/lat Punkten macht etwas seltsam.

Es gibt einen Fehler in den Ergebnissen, die diese Abfrage generiert; Es gibt alle Punkte im Begrenzungsrahmen zurück, nicht nur innerhalb des angegebenen Radius. Das ist mit einer separaten Entfernungsberechnung lösbar. Ich habe das alles in einigen Einzelheiten hier .

Hinweis :Für Breiten- und Längengrad in GPS-Auflösung, 32-Bit FLOAT Daten haben eine ausreichende Genauigkeit. DOUBLE verwendet die Geo-Erweiterung von MySQL. Wenn Sie in Grad arbeiten, liegen mehr als fünf Nachkommastellen außerhalb der Genauigkeit von GPS. DECIMAL() ist kein idealer Datentyp für Lat/Lng-Koordinaten.