За съжаление ST_Distance() < threshold
не е sargable
критерий за търсене. За да удовлетвори тази заявка, MySQL трябва да изчисли стойността на функцията за всеки ред в таблицата и след това да я сравни с прага. Така че трябва да направи пълно сканиране на таблица (или може би пълно сканиране на индекс).
За да използвате индекс за ускоряване на тази заявка, ще ви трябва критерий за ограничаваща кутия. Заявката е много по-сложна, но и много по-бърза. Ако приемем, че вашите x/y точки във вашата геометрия представляват географска ширина/дължина в градуси, тази заявка може да изглежда така:
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)
Как работи това? От една страна, MbrContains( подвързан,елемент) функция е sargable . От друга страна, големият грозен елемент concat дава диагонална линия от югозападния до североизточния ъгъл на ограничаващия правоъгълник. Използвайки вашата точка от данни и радиус от десет мили, изглежда така.
LINESTRING(37.8785 -94.2564,38.1684 -93.8884)
Когато използвате GeomFromText()
изобразяване на тази диагонална линия в първия аргумент на MbrContains()
той служи като ограничаващ правоъгълник. MbrContains()
след това може да използва изящния геометричен индекс на quadtree.
Трето, ST_Distance()
, в MySQL, не обработва големи изчисления на ширина и дължина на кръга. (PostgreSQL
има по-изчерпателно ГИС разширение
.) MySQL е тъп като плоча в равнината. Предполага се, че вашите точки във вашите геометрични обекти са представени в равнинна геометрия. Така че ST_Distance() < 10.0
с lng/lat точки прави нещо странно.
Има един недостатък в резултатите, генерирани от тази заявка; той връща всички точки в ограничителната кутия, а не само в посочения радиус. Това е разрешимо с отделно изчисляване на разстоянието. Написах всичко това в някои подробности тук .
Забележка :За географска ширина и дължина с GPS резолюция, 32-битов FLOAT
данните са с достатъчна точност. DOUBLE
е това, което използва георазширението на MySQL. Когато работите в градуси, повече от пет места след десетичната запетая са извън прецизността на GPS. DECIMAL()
не е идеален тип данни за координати lat/lng.