sql >> Databasteknik >  >> RDS >> Mysql

avståndsberäkningar i mysql-frågor

Alternativ 1:Gör beräkningen på databasen genom att byta till en databas som stöder GeoIP.

Alternativ 2:Gör beräkningen på databasen med en lagrad procedur så här:

CREATE FUNCTION calcDistance (latA double, lonA double, latB double, LonB double)
    RETURNS double DETERMINISTIC
BEGIN
    SET @RlatA = radians(latA);
    SET @RlonA = radians(lonA);
    SET @RlatB = radians(latB);
    SET @RlonB = radians(LonB);
    SET @deltaLat = @RlatA - @RlatB;
    SET @deltaLon = @RlonA - @RlonB;
    SET @d = SIN(@deltaLat/2) * SIN(@deltaLat/2) +
    COS(@RlatA) * COS(@RlatB) * SIN(@deltaLon/2)*SIN(@deltaLon/2);
    RETURN 2 * ASIN(SQRT(@d)) * 6371.01;
END//

Om du har ett index på latitud och longitud i din databas kan du minska antalet beräkningar som behöver beräknas genom att arbeta fram en initial begränsningsruta i PHP ($minLat, $maxLat, $minLong och $maxLong), och begränsa raderna till en delmängd av dina poster baserat på det (VAR latitud MELLAN $minLat OCH $maxLat OCH longitud MELLAN $minLong OCH $maxLong). Då behöver MySQL bara utföra avståndsberäkningen för den delmängden av rader.

Om du helt enkelt använder en lagrad procedur för att beräkna avståndet) måste SQL fortfarande titta igenom varje post i din databas och beräkna avståndet för varje post i din databas innan den kan bestämma om den ska returnera den raden eller kassera den .

Eftersom beräkningen är relativt långsam att utföra, skulle det vara bättre om du kunde minska mängden rader som behöver beräknas, och eliminera rader som klart kommer att falla utanför det erforderliga avståndet, så att vi bara kör den dyra beräkningen för ett mindre antal rader.

Om du tänker på att det du gör i princip är att rita en cirkel på en karta, centrerad på din första punkt och med en avståndsradie; sedan identifierar formeln helt enkelt vilka rader som faller inom den cirkeln... men den måste fortfarande kontrollera varje enskild rad.

Att använda en begränsningsram är som att rita en fyrkant på kartan först med vänster, höger, övre och nedre kanter på lämpligt avstånd från vår mittpunkt. Vår cirkel kommer sedan att ritas inom den rutan, med de nordligaste, östligaste, sydligaste och västaste punkterna på cirkeln som rör rutans kanter. Vissa rader kommer att falla utanför den rutan, så SQL bryr sig inte ens om att försöka beräkna avståndet för dessa rader. Den beräknar bara avståndet för de rader som faller inom begränsningsrutan för att se om de också faller inom cirkeln.

Inom din PHP (gissar att du kör PHP från variabelnamnet $), kan vi använda en mycket enkel beräkning som räknar ut den lägsta och högsta latitud och longitud baserat på vårt avstånd, och ställ sedan in dessa värden i WHERE-satsen i din SQL påstående. Detta är i själva verket vår låda, och allt som faller utanför den kasseras automatiskt utan att man faktiskt behöver beräkna dess avstånd.

Det finns en bra förklaring av detta (med PHP-kod) på Movable Type webbplats det borde vara viktig läsning för alla som planerar att göra något GeoPositioneringsarbete i PHP.

REDIGERA Värdet 6371.01 i den lagrade calcDistance proceduren är multiplikatorn för att ge dig ett returnerat resultat i kilometer. Använd lämpliga alternativa multiplikatorer om du vill resultera i miles, nautiska mil, meter, vad som helst



  1. Vad betyder INT(5) i mysql?

  2. AT TIME ZONE – en ny favoritfunktion i SQL Server 2016

  3. mysql välja int som valuta eller konvertera int till valutaformat?

  4. Vad är skillnaden mellan ROWNUM och ROW_NUMBER i en Oracle-databas?