Bohužel ST_Distance() < threshold
není sargable
vyhledávací kritérium. K uspokojení tohoto dotazu musí MySQL vypočítat hodnotu funkce pro každý řádek v tabulce a poté ji porovnat s prahovou hodnotou. Musí tedy provést úplné prohledání tabulky (nebo možná úplné prohledání indexu).
Chcete-li využít index k urychlení tohoto dotazu, budete potřebovat kritérium ohraničovacího rámečku. Dotaz je mnohem propracovanější, ale také mnohem rychlejší. Za předpokladu, že vaše body x/y ve vaší geometrii představují zeměpisnou šířku/délku ve stupních, může tento dotaz vypadat takto:
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)
Jak to funguje? Za prvé, MbrContains( vázaná,položka) funkce je sargable . Za další věc, velký ošklivý prvek concat vytváří diagonální čáru od jihozápadního k severovýchodnímu rohu ohraničujícího obdélníku. Při použití vašeho datového bodu a okruhu deseti mil to vypadá takto.
LINESTRING(37.8785 -94.2564,38.1684 -93.8884)
Když použijete GeomFromText()
vykreslení této diagonální čáry v prvním argumentu na MbrContains()
slouží jako ohraničující obdélník. MbrContains()
pak může využít šikovný index geometrie quadtree.
Za třetí, ST_Distance()
, v MySQL nezpracovává velké výpočty zeměpisné šířky a délky kruhu. (PostgreSQL
má komplexnější rozšíření GIS
.) MySQL je hloupý jako flapjack v flatlandu. Předpokládá se, že vaše body ve vašich geometrických objektech jsou reprezentovány v rovinné geometrii. Takže ST_Distance() < 10.0
s body lng/lat dělá něco divného.
Ve výsledcích, které tento dotaz generuje, je jedna chyba; vrátí všechny body v ohraničovacím rámečku, nejen v zadaném poloměru. To je řešitelné samostatným výpočtem vzdálenosti. To vše jsem sepsal zde podrobně .
Poznámka :Pro zeměpisnou šířku a délku v rozlišení GPS, 32bitové FLOAT
data mají dostatečnou přesnost. DOUBLE
je to, co používá geo rozšíření MySQL. Když pracujete ve stupních, více než pět míst za desetinnou čárkou je mimo přesnost GPS. DECIMAL()
není ideální datový typ pro souřadnice zeměpisné šířky/délky.