sql >> Databasteknik >  >> RDS >> Mysql

Spatial Index används inte

Tyvärr ST_Distance() < threshold är inte sargable sökkriterium. För att tillfredsställa denna fråga måste MySQL beräkna funktionens värde för varje rad i tabellen och sedan jämföra det med tröskeln. Så den måste göra en fullständig tabellskanning (eller kanske en fullständig indexskanning).

För att utnyttja ett index för att snabba upp den här frågan behöver du ett begränsningsrutekriterium. Frågan är mycket mer utarbetad men också mycket snabbare. Om du antar att dina x/y-punkter i din geometri representerar latitud/longitud i grader, kan den frågan se ut så här:

   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) 

Hur fungerar detta? För en sak, MbrContains( bundet, objekt) funktion är sargable . För en annan sak ger det stora fula konkatföremålet en diagonal linje från sydväst till nordöstra hörnet av den avgränsande rektangeln. Med din datapunkt och tio mils radie ser det ut så här.

LINESTRING(37.8785 -94.2564,38.1684 -93.8884)

När du använder GeomFromText() rendering av den diagonala linjen i det första argumentet till MbrContains() den fungerar som en avgränsande rektangel. MbrContains() kan sedan utnyttja det snygga quadtree-geometriindexet.

För det tredje, ST_Distance() , i MySQL, hanterar inte storcirkel latitud och longitud beräkningar. (PostgreSQL har ett mer omfattande GIS-tillägg .) MySQL:s är dumt som en flapjack i flatland. Det förutsätter att dina punkter i dina geometriska objekt är representerade i plan geometri. Så ST_Distance() < 10.0 med lng/lat-punkter gör något konstigt.

Det finns en brist i resultaten som den här frågan genererar; den returnerar alla punkter i begränsningsrutan, inte bara inom den angivna radien. Det går att lösa med en separat avståndsberäkning. Jag har skrivit upp allt detta i någon detalj här .

Obs :För GPS-upplösning latitud och longitud, 32-bitars FLOAT data har tillräcklig precision. DOUBLE är vad MySQL:s geo-tillägg använder. När du arbetar i grader är mer än fem platser efter decimalkomma bortom GPS-precisionen. DECIMAL() är inte en idealisk datatyp för lat/lng-koordinater.




  1. Snabbskript som returnerar alla egenskaper från SERVERPROPERTY() i SQL Server 2017/2019

  2. Slå samman två MySQL-tabeller i olika databaser på samma server med Laravel Eloquent

  3. Kan jag gå med över datakällor i SSRS?

  4. SQL Saknar höger parentes på order by-sats