Jakiego typu danych najlepiej użyć do przechowywania szerokości i długości geograficznej w bazie danych MySQL?


431

Biorąc pod uwagę, że będę wykonywać obliczenia dla par lat / long, jaki typ danych najlepiej nadaje się do użycia z bazą danych MySQL?


1
Uważam ten link za bardzo przydatny: howto-use-mysql-spatial-ext.blogspot.com/2007/11/... Może być nieco starszy, ale zawiera pełne wyjaśnienie, w tym przykłady.
madc

Imho większość ludzi tutaj nie rozumie, co się dzieje. Gdy tylko kod aplikacji dotknie liczby, pod warunkiem, że użyje się podwójnej liczby (co większość robi), liczba zmienia się w co najwyżej podwójną precyzję . Przechowywanie go nawet z milionem miejsc po przecinku nic nie da. Przechowywanie go z ograniczoną liczbą miejsc po przecinku (np. 6) niszczy część tej precyzji i dodaje nagromadzony błąd za każdym razem, gdy jest ponownie zapisywany w bazie danych . Podwójny przenosi około 16 znaczących liczb, potencjalnie wszystkie miejsca po przecinku. Złomowanie 10 z nich powoduje nagromadzenie błędu w czasie. Jest „zmiennoprzecinkowy” z jakiegoś powodu. Cd.
Stormwind,

Cont: 6 miejsc po przecinku może być poprawnych podczas przechowywania postaci uzyskanej ze źródła zewnętrznego, niezmienionej i po raz pierwszy - jako materiału źródłowego. Ale jeśli wykonujesz na nim obliczenia choćby raz i przechowujesz go ponownie, głupotą jest usunięcie części jego precyzji poprzez wymuszenie określonego formatu dziesiętnego. Wykonywanie obliczeń wyłącznie wewnątrz serwera może być inne (serwer może wewnętrznie używać czegoś innego niż podwaja się), a użycie gorszych reprezentacji liczbowych niż dwukrotność w obliczeniach aplikacji c równomiernie określa potrzebę precyzji przechowywania.
Stormwind,

Cont: JEŻELI serwer przechowuje numer z większą precyzją, pomimo deklarowanego „9.6” (co nie wiem, czy to robi), to nic z tych wszystkich rzeczy nie ma znaczenia, a format jest wyłącznie kwestią wygody - ma niewiele do zrobić z problemami z precyzją. Ale nie zdziwiłbym się, gdyby serwer faktycznie zaokrąglał dowolną liczbę z dokładnością do 6 miejsc po przecinku w tym formacie.
Stormwind,

Cont: Wreszcie: w przypadku lat, lon's, szósty dziesiętny jest kwestią przyciągania do ok. Siatka 11-centymetrowa. Za każdym razem, gdy czyta się (dotyka), oblicza i zapisuje ponownie, z 6 miejscami po przecinku, pojawi się nowe przyciąganie (= skumulowany błąd). Jeśli wszystkie błędy pójdą w tym samym kierunku, wystąpi duży błąd. Jeśli wykonasz na nim tymczasowe multiplikacje (np. Przeskaluj w górę, a następnie odejmij i przeskaluj w dół), może wzrosnąć jeszcze bardziej. Nie marnuj precyzji bez dobrego uzasadnienia!
Stormwind,

Odpowiedzi:


161

Używaj rozszerzeń przestrzennych MySQL z GIS.


25
Czy masz jakieś inne linki do przykładów lub inne informacje na temat tego, jak najlepiej zacząć z nimi korzystać?
Codebeef

6
MYSQL Spatial jest dobrą opcją, ale nadal ma znaczące ograniczenia i zastrzeżenia (od 6). Proszę zobaczyć moją odpowiedź poniżej ...
James Schek

1
@James Schek ma rację. Ponadto MySQL wykonuje wszystkie obliczenia przy użyciu geometrii euklidesowej, więc nie reprezentuje rzeczywistego przypadku użycia dla lat / lng.
mkuech

Do twojej wiadomości; MySQL obsługuje indeks przestrzenny tylko z tabelami * .myisam, tj. Silnikiem ISAM. Link: dev.mysql.com/doc/refman/5.0/en/creating-spatial-indexes.html
PodTech.io

Spójrz na ten artykuł na końcu Aktualizacja: mysqlserverteam.com/mysql-5-7-and-gis-an-example
Jaspal Singh

149

Google zapewnia początek ukończenia rozwiązania PHP / MySQL dla przykładowej aplikacji „Store Locator” z Google Maps. W tym przykładzie przechowują wartości lat / lng jako „Float” o długości „10,6”

http://code.google.com/apis/maps/articles/phpsqlsearch.html


11
Google wyraźnie nie rozumie, jak działa specyfikacja FLOAT: FLOAT(10,6)pozostawia 4 cyfry dla całkowitej liczby współrzędnych. I nie, znak się nie liczy - pochodzi od (nie) podpisanego atrybutu.
Alix Axel

2
Ale jeśli chcesz przechowywać jako integralne wartości części z [0, 180], powinno to być więcej niż wystarczające, prawda?
Hrvoje Golcic

37
@AlixAxel Myślę, że Google wie, co robi. Ponieważ stwierdza, że: " . Przy obecnych możliwościach powiększenia Map Google, powinny trzeba tylko 6 cyfr precyzji po przecinku, który pozwoli pola przechowywania 6 cyfr po przecinku, plus do 4 cyfr przed przecinku, np - 123,456789 stopni. ”. Jeśli zaznaczysz opcję niepodpisaną, wzór będzie wynosił 1234,567890 . Więc żadnych problemów.
1,44mb

16
@AlixAxel Odlicza liczby w sekwencji; nie używa rzeczywistej współrzędnej ...
Andrew Ellis

8
Używanie typu danych Doubledla Laravela
FooBar,

133

Zasadniczo zależy to od precyzji potrzebnej do lokalizacji. Używając DOUBLE uzyskasz precyzję 3,5 nm. DECIMAL (8,6) / (9,6) spada do 16 cm. FLOAT ma 1,7 m ...

Ta bardzo interesująca tabela ma bardziej kompletną listę: http://mysql.rjweb.org/doc.php/latlng :

Datatype               Bytes            Resolution

Deg*100 (SMALLINT)     4      1570 m    1.0 mi  Cities
DECIMAL(4,2)/(5,2)     5      1570 m    1.0 mi  Cities
SMALLINT scaled        4       682 m    0.4 mi  Cities
Deg*10000 (MEDIUMINT)  6        16 m     52 ft  Houses/Businesses
DECIMAL(6,4)/(7,4)     7        16 m     52 ft  Houses/Businesses
MEDIUMINT scaled       6       2.7 m    8.8 ft
FLOAT                  8       1.7 m    5.6 ft
DECIMAL(8,6)/(9,6)     9        16cm    1/2 ft  Friends in a mall
Deg*10000000 (INT)     8        16mm    5/8 in  Marbles
DOUBLE                16       3.5nm     ...    Fleas on a dog

Mam nadzieję że to pomoże.


2
Muszę napisać konstruktywny, szczegółowy komentarz koncentrujący się na treści postów, więc powiem, że obserwując tabelę dokładności podaną na stronie Ricka Jamesa, byłem lekko rozbawiony opisem rozdzielczości „pchły na psa” i czułem, że jest to godne pochwały. Technicznie rzecz biorąc, było to pomocne przedstawienie, które pomogło mi w podjęciu decyzji, jakiego rodzaju danych użyć do przechowywania współrzędnych do pomiaru odległości między dwoma adresami, którym, @ Simon, chciałbym podziękować za udostępnienie.
Sam_Butler

FWIW, użycie tego linku w „SMALLINT scaled” jest strasznie nieefektywne. Odpowiedź Oguzhana to świetny sposób na przechowywanie długich / krótkich znaków z 7 cyframi po przecinku, w 4-bajtowym znaku int. Wielka precyzja (~ 1 cm) w małym rozmiarze (4B).
ToolmakerSteve

74

Rozszerzenia przestrzenne MySQL są najlepszą opcją, ponieważ masz do dyspozycji pełną listę operatorów przestrzennych i indeksów. Indeks przestrzenny pozwoli bardzo szybko wykonać obliczenia oparte na odległości. Należy pamiętać, że od wersji 6.0 rozszerzenie przestrzenne jest nadal niekompletne. Nie odkładam MySQL Spatial, tylko informuję o pułapkach, zanim dojdziesz do tego zbyt daleko.

Jeśli masz do czynienia wyłącznie z punktami i tylko z funkcją ODLEGŁOŚCI, to jest w porządku. Jeśli konieczne jest wykonanie jakichkolwiek obliczeń za pomocą wielokątów, linii lub punktów buforowanych, operatory przestrzenne nie zapewniają dokładnych wyników, chyba że użyje się operatora „powiązania”. Zobacz ostrzeżenie na górze 21.5.6 . Relacje, takie jak zawiera, wewnątrz lub przecina, wykorzystują MBR, a nie dokładny kształt geometrii (tzn. Elipsa jest traktowana jak prostokąt).

Ponadto odległości w MySQL Spatial są w tych samych jednostkach, co Twoja pierwsza geometria. Oznacza to, że jeśli używasz stopni dziesiętnych, wówczas twoje pomiary odległości są w stopniach dziesiętnych. Utrudni to uzyskanie dokładnych wyników, gdy zdobędziesz jeszcze więcej od równika.


26
Przekształcanie: Rozszerzenia przestrzenne MySQL nie nadają się do obliczania wielkich odległości między punktami na powierzchni Ziemi reprezentowanymi przez szerokość / długość. Ich funkcje odległości itp. Są przydatne tylko na współrzędnych kartezjańskich, płaskich i współrzędnych.
O. Jones

71

Kiedy zrobiłem to dla bazy danych nawigacji zbudowanej z ARINC424, przeprowadziłem sporo testów i patrząc wstecz na kod, użyłem DECIMAL (18,12) (Właściwie NUMERYCZNY (18,12), ponieważ był firebird).

Liczba zmiennoprzecinkowa i liczba podwójna nie są tak precyzyjne i mogą powodować błędy zaokrąglania, co może być bardzo złe. Nie pamiętam, czy znalazłem jakieś rzeczywiste dane, które miałyby problemy - ale jestem całkiem pewien, że niemożność dokładnego przechowywania w liczbach zmiennoprzecinkowych lub podwójnych może powodować problemy

Chodzi o to, że używając stopni lub radianów znamy zakres wartości - a część ułamkowa potrzebuje jak najwięcej cyfr.

W MySQL Spatial Rozszerzenia są dobrą alternatywą, ponieważ idą OpenGIS geometrii modelu . Nie korzystałem z nich, ponieważ musiałem mieć przenośną bazę danych.


3
Dziękuję, to było pomocne. Dziwnie jest czytać wszystkie te pytania i odpowiedzi z 2008 roku, zdając sobie sprawę, że było to już 8 lat temu.
aexl

1
@TheSexiestManinJamaica - Przed IEEE 754-1985 sprzęt zmiennoprzecinkowy był chaotyczny. Było nawet na maszynie, gdzie a*bnie było równe b*a(dla niektórych wartości). Było wiele przykładów nieco jak: 2+2 = 3.9999. Standard wyczyścił wiele bałaganu i został „szybko” przyjęty przez praktycznie każdy sprzęt i oprogramowanie. Tak więc ta dyskusja jest aktualna nie tylko od 2008 roku, ale przez jedną trzecią wieku.
Rick James

42

Zależy od wymaganej precyzji.

Datatype           Bytes       resolution
------------------ -----  --------------------------------
Deg*100 (SMALLINT)     4  1570 m    1.0 mi  Cities
DECIMAL(4,2)/(5,2)     5  1570 m    1.0 mi  Cities
SMALLINT scaled        4   682 m    0.4 mi  Cities
Deg*10000 (MEDIUMINT)  6    16 m     52 ft  Houses/Businesses
DECIMAL(6,4)/(7,4)     7    16 m     52 ft  Houses/Businesses
MEDIUMINT scaled       6   2.7 m    8.8 ft
FLOAT                  8   1.7 m    5.6 ft
DECIMAL(8,6)/(9,6)     9    16cm    1/2 ft  Friends in a mall
Deg*10000000 (INT)     8    16mm    5/8 in  Marbles
DOUBLE                16   3.5nm     ...    Fleas on a dog

Od: http://mysql.rjweb.org/doc.php/latlng

Podsumować:

  • Najbardziej precyzyjna dostępna opcja to DOUBLE.
  • Najczęściej stosowanym typem jest DECIMAL(8,6)/(9,6).

Począwszy od MySQL 5.7 , rozważ użycie typów danych przestrzennych (SDT), szczególnie POINTdo przechowywania pojedynczej współrzędnej. Przed wersją 5.7 SDT nie obsługuje indeksów (z wyjątkiem 5.6, gdy typem tabeli jest MyISAM).

Uwaga:

  • Podczas korzystania z POINTklasy kolejność argumentów do przechowywania współrzędnych musi być następująca POINT(latitude, longitude).
  • Istnieje specjalna składnia do tworzenia indeksu przestrzennego .
  • Największą zaletą korzystania z SDT jest to, że masz dostęp do funkcji analiz przestrzennych , np. Obliczania odległości między dwoma punktami ( ST_Distance) i określania, czy jeden punkt jest zawarty w innym obszarze ( ST_Contains).

2
Kopiujesz wklejoną część poprzedniej odpowiedzi i „podsumowujesz” czymś, co facet, który stworzył tę tabelę, nie zalecił : «Jak podzielić? Cóż, MySQL jest bardzo wybredny. Więc FLOAT / DOUBLE nie ma. DECIMAL został wydany. Więc utknęliśmy z jakąś kludge. Zasadniczo musimy przekonwertować Lat / Lng na pewien rozmiar INT i użyć PARTITION BY RANGE. » ORAZ «FLOAT ma 24 znaczące bity; DOUBLE ma 53. (Nie działają z PARTYCJONOWANIEM, ale są uwzględnione dla kompletności. Często ludzie używają DOUBLE, nie zdając sobie sprawy z tego, ile to jest przesada i ile zajmuje miejsca.) »Po prostu zostaw część SDT, którą napisałeś.
Armfoot

1
@Armfoot Jeśli spojrzysz na czas zmian, jest to inna odpowiedź, która została skopiowana ode mnie. Nie ma to znaczenia: widzę, że Stack Overflow jest bardziej „notatką na przyszłość”.
Gajus

1
Nie, nie skopiował od ciebie, po prostu wkleił tabelę tak jak ty z linku, do którego odwoływał się w 2014 roku (twój post pochodzi z 2015 roku). Przy okazji, myślę, że źle napisałeś „Specjalny”, kiedy łączyłeś Typy danych przestrzennych . Ta część, którą napisałeś, jest w rzeczywistości przydatna dla osób, które chcą zacząć z nich korzystać, jeśli dodasz więcej przykładów takich jak CREATE TABLE geom (g GEOMETRY NOT NULL, SPATIAL INDEX(g)) ENGINE=MyISAM;ostrzeżenie o ograniczeniach SDT, jak wspomniał James , być może twoja odpowiedź będzie bardziej zwięzła i precyzyjna w pomaganiu również innym ludziom. ..
Armfoot

@Gajus - Jestem zaszczycony, że dwóch z was znalazło mój dokument! (Nie, nie wiem, jak duża jest pchła, ale czułem, że zwróci to uwagę kogoś.)
Rick James

Podczas korzystania z klasy POINT kolejność argumentów służących do przechowywania współrzędnych musi być POINT (długość / X, szerokość / Y).
AndreyP


19

Użyj DECIMAL(8,6)dla szerokości geograficznej (90 do -90 stopni) i DECIMAL(9,6)długości geograficznej (180 do -180 stopni). W przypadku większości aplikacji wystarczy 6 miejsc po przecinku. Oba powinny być „podpisane”, aby uwzględnić wartości ujemne.


DECIMALtyp jest przeznaczony do obliczeń finansowych, w przypadku których nie floor/ceilsą akceptowane. Zwykły FLOATznacznie przewyższa DECIMAL.
Kondybas

1
@Kondybas - Ponieważ głównym kosztem w bazie danych jest pobieranie wierszy, różnica wydajności między liczbą zmiennoprzecinkową a dziesiętną nie powinna stanowić problemu.
Rick James

14

Według Google Maps nie trzeba daleko się posuwać, najlepiej FLOAT (10,6) dla lat i lng.


skąd masz te informacje, nie mogę ich znaleźć? na wypadek, gdyby coś się zmieniło.
webfacer

1
@webfacer, znajduje się w sekcji „Tworzenie tabeli w MySQL” tutaj: developers.google.com/maps/documentation/javascript/… np. lat FLOAT( 10, 6 ) NOT NULL, lng FLOAT( 10, 6 ) NOT NULL
turrican_34

1
@webfacer, Wygląda na to, że ta FLOATskładnia jest przestarzała od dnia mysql 8.0.17. Mysql zaleca teraz używanie FLOATbez żadnych parametrów dokładności dev.mysql.com/doc/refman/8.0/en/numeric-type-overview.html i dev.mysql.com/doc/refman/5.5/en/floating-point- types.html
turrican_34

7

Przechowujemy szerokość / długość geograficzną X 1 000 000 w naszej bazie danych Oracle jako LICZBY, aby uniknąć błędów zaokrąglania z podwójnymi.

Biorąc pod uwagę, że szerokość / długość geograficzna do 6. miejsca po przecinku wynosiła 10 cm dokładności, to było wszystko, czego potrzebowaliśmy. Wiele innych baz danych również przechowuje długość / szerokość do 6 miejsc po przecinku.


2
Mnożenie przez dużą liczbę (np. Milion) jest świetne, jeśli masz dużo danych, ponieważ operacje na liczbach całkowitych (np. Indeksowanie) są znacznie szybsze niż zmiennoprzecinkowe.
Kaitlin Duck Sherwood

@KaitlinDuckSherwood - bity to bity - nie znam żadnego powodu, dla którego 32-bitowa liczba zmiennoprzecinkowa byłaby wolniejsza do pobierania (indeksowana lub inna) niż 32-bitowa liczba całkowita. Nawet pływająca matematyka w dzisiejszych czasach jest wystarczająco szybka, aby nie stanowić problemu. Niemniej zgadzam się z komentarzem, aby użyć domniemanego mnożnika z liczbą całkowitą: maksymalizuje on precyzję uzyskaną z 32 bitów. Trochę zabezpieczenia na przyszłość w miarę poprawy technologii.
ToolmakerSteve,

6

W zupełnie innej i prostszej perspektywie:

  • jeśli polegasz na Google w wyświetlaniu swoich map, znaczników, wielokątów, cokolwiek, to pozwól, aby obliczenia zostały wykonane przez Google!
  • oszczędzasz zasoby na serwerze i po prostu przechowujesz szerokość i długość geograficzną razem jako jeden ciąg ( VARCHAR), np .: „ -0000.0000001, -0000.000000000000001 ” (długość 35, a jeśli liczba ma więcej niż 7 cyfr dziesiętnych, wówczas zostanie zaokrąglona);
  • jeśli Google zwróci więcej niż 7 cyfr dziesiętnych na liczbę, możesz mimo to uzyskać te dane zapisane w ciągu, na wypadek gdybyś chciał w przyszłości wykryć niektóre ucieczki lub mikroby ;
  • możesz użyć ich macierzy odległości lub biblioteki geometrii do obliczania odległości lub wykrywania punktów w niektórych obszarach za pomocą wywołań tak prostych:google.maps.geometry.poly.containsLocation(latLng, bermudaTrianglePolygon))
  • istnieje wiele interfejsów API „po stronie serwera”, z których można korzystać (w Pythonie , Ruby on Rails , PHP , CodeIgniter , Laravel , Yii , Zend Framework itp.), które używają interfejsu API Google Maps.

W ten sposób nie musisz się martwić indeksowaniem liczb i wszystkimi innymi problemami związanymi z typami danych, które mogą popsuć twoje współrzędne.


Nie dobrze. OP powiedział, że wykona obliczenia dla par lat / lng - twoje odpowiedzi wykluczają, że
Yarin

4
@Yarin To popularne pytanie, w którym kilka (lub wiele) osób potrzebuje odpowiedzi na pytanie, jak przechowywać współrzędne zgodnie z własnymi potrzebami (wiele z nich może po prostu korzystać z map Google). Twoja opinia sugeruje, że ta odpowiedź może im nie pomóc ... Przechowując współrzędne w ciągu, będą dokładnie znać oryginalne wartości, które zostały im przekazane (np. Przez Google), co pomoże im później, jeśli zdecydują się ewoluować własna aplikacja i wykonaj na nich obliczenia. W tym czasie będą nadal mieć oryginalne nieprzetworzone dane tylko dlatego, że nie popsuły ich konwersjami.
Armfoot

4

w zależności od zastosowania sugeruję użycie FLOAT (9,6)

klucze przestrzenne dadzą ci więcej funkcji, ale w testach wydajności pływaki są znacznie szybsze niż klucze przestrzenne. (0,01 VS 0,001 w systemie AVG)


1
Czy możesz podać szczegóły swojego testu tutaj?
NameNotFoundException

4

MySQL używa double dla wszystkich pływaków ... Więc użyj double. Użycie liczby zmiennoprzecinkowej doprowadzi do nieprzewidywalnych zaokrąglonych wartości w większości sytuacji


1
MySQL wykonuje operacje wDOUBLE . MySQL pozwala przechowywać dane jako 4-bajtowe FLOATlub 8-bajtowe DOUBLE. Tak więc istnieje prawdopodobieństwo utraty precyzji podczas przechowywania wyrażenia w FLOATkolumnie.
Rick James

4

Chociaż nie jest to optymalne dla wszystkich operacji, jeśli tworzysz kafelki mapy lub pracujesz z dużą liczbą znaczników (kropek) za pomocą tylko jednej projekcji (np. Mercator, jak Google Maps i wiele innych śliskich ram map), znalazłem to, co Nazywam „Ogromny Układ Współrzędnych”, aby był naprawdę bardzo przydatny. Zasadniczo przechowujesz współrzędne pikselowe xiy przy pewnym zbliżeniu - używam poziomu powiększenia 23. Ma to kilka zalet:

  • Kosztowną transformację pikseli na linii mercator wykonujesz jeden raz, a nie za każdym razem, gdy sobie poradzisz
  • Uzyskanie współrzędnej kafelka z rekordu przy danym poziomie powiększenia wymaga jednego przesunięcia w prawo.
  • Uzyskanie współrzędnej piksela z rekordu wymaga jednego przesunięcia w prawo i jednego bitowego AND.
  • Przesunięcia są tak lekkie, że praktyczne jest wykonywanie ich w SQL, co oznacza, że ​​możesz wykonać DISTINCT, aby zwrócić tylko jeden rekord na lokalizację piksela, co zmniejszy liczbę rekordów zwracanych przez backend, co oznacza mniej przetwarzania na przód.

O tym wszystkim mówiłem w niedawnym wpisie na blogu: http://blog.webfoot.com/2013/03/12/optimizing-map-tile-generation/


4

Jestem bardzo zaskoczony niektórymi odpowiedziami / komentarzami.

Dlaczego, u licha, ktoś miałby dobrowolnie „wstępnie zmniejszyć” precyzję, a następnie wykonać obliczenia na gorszych liczbach? Brzmi ostatecznie głupio.

Jeśli źródło ma 64-bitową precyzję, na pewno głupio byłoby dobrowolnie naprawić skalę np. 6 miejsc po przecinku i ogranicz precyzję do maksymalnie 9 cyfr znaczących (co dzieje się w przypadku powszechnie proponowanego formatu dziesiętnego 9,6).

Oczywiście dane są przechowywane z precyzją, jaką ma materiał źródłowy. Jedynym powodem zmniejszenia precyzji byłoby ograniczone miejsce do przechowywania.

  • Przechowuj dane źródłowe z oryginalną dokładnością
  • Przechowuj liczby obliczone ze źródła z dokładnością do obliczeń (np. Jeśli kod aplikacji używa podwójnych, zapisz wyniki jako podwójne)

Dziesiętny format 9,6 powoduje zjawisko przyciągania do siatki. To powinien być ostatni krok, jeśli w ogóle się wydarzy.

Nie zapraszam do mojego gniazda skumulowanych błędów.


2
Ponieważ większość narzędzi i aplikacji GPS ma dokładność do 6 miejsc po przecinku. Bezcelowe jest przechowywanie danych z większą precyzją niż narzędzia, które mogą mierzyć gis.stackexchange.com/questions/8650/…
Yarin

1
@Yarin Tak, rzeczywiście, ale mówisz o pomiarach i GPS, które nie są wymienione w pytaniu. Z pewnością istnieją dokładniejsze dane. Ale rozważmy GPS; powiedzmy, że źródłowy zestaw danych 64-bitowych liczb zmiennoprzecinkowych, który już zawiera niedokładność. 6 miejsc po przecinku oznacza przyciąganie szerokości geograficznej do najbliższych około 11 centymetrów. Dlatego teraz, przechowując tylko dane (z 6 miejscami po przecinku), otwieracie się na potencjalną niedokładność 22 cm (jeśli pierwotnie 11 cm też). Dobrowolnie, prawdopodobnie do wykonania 64-bitowych obliczeń, zanim możliwe będzie przechowywanie trzeciego czasu - teraz okno niedokładności 33 cm, + -16 cm. Brzmi głupio, imho.
Stormwind

@Rick James Prawdopodobnie zapisałbym go jako 64-bitowy, tj. 0.3333333333333333. Mówimy o geodanych, prawda? „1/3” rzadko pojawia się w naturze, gdzie rzeczy są normalnie mierzone, z rozsądną precyzją.
Stormwind

4

TL; DR

Użyj FLOAT (8,5), jeśli nie pracujesz w NASA / wojsku i nie tworzysz systemów nawigacyjnych samolotów.


Aby w pełni odpowiedzieć na twoje pytanie, musisz rozważyć kilka rzeczy:

Format

  • stopnie minuty sekundy : 40 ° 26 ′ 46 ″ N 79 ° 58 ′ 56 ″ W
  • stopnie dziesiętne minuty : 40 ° 26,767 ′ N 79 ° 58,933 ′ W
  • stopnie dziesiętne 1 : 40,466 ° N 79,982 ° W
  • stopnie dziesiętne 2 : -32,60875, 21,27812
  • Jakiś inny domowy format? Nikt nie zabrania ci tworzenia własnego układu współrzędnych domu i przechowywania go jako kierunku i odległości od domu. Może to mieć sens w przypadku niektórych konkretnych problemów, nad którymi pracujesz.

Tak więc pierwsza część odpowiedzi brzmi - możesz przechowywać współrzędne w formacie używanym przez twoją aplikację, aby uniknąć ciągłych konwersji tam iz powrotem i uprościć zapytania SQL.

Najprawdopodobniej używasz Map Google lub OSM do wyświetlania danych, a GMaps używają formatu „stopnie dziesiętne 2”. Dzięki temu łatwiej będzie przechowywać współrzędne w tym samym formacie.

Precyzja

Następnie chcesz zdefiniować potrzebną precyzję. Oczywiście możesz przechowywać współrzędne, takie jak „-32.608697550570334,21.278081997935146”, ale czy kiedykolwiek dbałeś o milimetry podczas nawigacji do punktu? Jeśli nie pracujesz w NASA i nie wykonujesz trajektorii satelitów, rakiet lub samolotów, powinieneś być w porządku z dokładnością do kilku metrów.

Powszechnie stosowanym formatem jest 5 cyfr po kropkach, co daje dokładność 50 cm.

Przykład : odległość 1 cm między X 21,278081 8 a X 21,278081 9 . Tak więc 7 cyfr po kropce daje dokładność 1/2 cm, a 5 cyfr po kropce daje precyzję 1/2 metra (ponieważ minimalna odległość między odrębnymi punktami wynosi 1 m, więc błąd zaokrąglenia nie może przekraczać połowy). W większości celów cywilnych powinno wystarczyć.

format minut po przecinku (40 ° 26,767 ′ N 79 ° 58,933 ′ W) daje dokładnie taką samą dokładność jak 5 cyfr po kropce

Energooszczędne miejsce do przechowywania

Jeśli wybrałeś format dziesiętny, twoją współrzędną jest para (-32.60875, 21.27812). Oczywiście wystarczą 2 x (1 bit na znak, 2 cyfry na stopnie i 5 cyfr na wykładnik).

Więc tutaj chciałbym wesprzeć Alix Axel z komentarzy mówiących, że sugestia Google, aby przechowywać go w FLOAT (10,6) jest naprawdę dodatkowa, ponieważ nie potrzebujesz 4 cyfr dla głównej części (ponieważ znak jest oddzielony, a szerokość geograficzna jest ograniczona do 90, a długość geograficzna jest ograniczona do 180). Możesz z łatwością użyć FLOAT (8,5) dla dokładności 1 / 2m lub FLOAT (9,6) dla dokładności 50 / 2cm. Lub możesz nawet przechowywać lat i long w osobnych typach, ponieważ FLOAT (7,5) wystarcza dla lat. Zobacz odwołanie do typów pływaków MySQL . Każdy z nich będzie podobny do normalnego FLOAT i będzie równy 4 bajtom.

Zwykle przestrzeń nie jest obecnie problemem, ale jeśli chcesz naprawdę zoptymalizować pamięć z jakiegoś powodu (Oświadczenie: nie rób wstępnej optymalizacji), możesz skompresować lat (nie więcej niż 91 000 wartości + znak) + długi (nie ponad 181 000 wartości + znak) do 21 bitów, czyli znacznie mniej niż 2xFLOAT (8 bajtów == 64 bitów)


3

Funkcje przestrzenne w PostGIS są znacznie bardziej funkcjonalne (tj. Nie są ograniczone do operacji BBOX) niż funkcje przestrzenne MySQL. Sprawdź to: link do tekstu


1
  1. Szerokości geograficzne wynoszą od -90 do +90 (stopni), więc DECIMAL (10, 8) jest do tego odpowiedni

  2. długości geograficzne wynoszą od -180 do +180 (stopni), więc potrzebujesz DECIMAL (11, 8).

Uwaga: Pierwsza liczba to całkowita liczba zapisanych cyfr, a druga to liczba po przecinku.

W skrócie: lat DECIMAL(10, 8) NOT NULL, lng DECIMAL(11, 8) NOT NULL



-2

Długie obliczenia wymagają precyzji, więc używaj pewnego rodzaju typu dziesiętnego i zwiększ dokładność co najmniej 2 razy więcej niż liczba, którą zapiszesz, aby wykonać obliczenia matematyczne. Nie wiem o moich typach danych SQL, ale na serwerze SQL ludzie często używają liczb zmiennoprzecinkowych lub rzeczywistych zamiast dziesiętnych i wpadają w kłopoty, ponieważ są to szacunkowe liczby, a nie liczby rzeczywiste. Upewnij się więc, że używany typ danych jest prawdziwym typem dziesiętnym, a nie zmiennoprzecinkowym, i wszystko powinno być w porządku.


1
zarówno typy zmiennoprzecinkowe, jak i dziesiętne mają swoje miejsce. z reguły zmiennoprzecinkowe oznaczają zmienne fizyczne, a ułamki dziesiętne odnoszą się do jednostek policzalnych (głównie pieniędzy). nie rozumiem, dlaczego wolisz dziesiętne dla długości / długości
Javier

1
Myślę też, że float jest odpowiedni dla lat / long. Przynajmniej na SQL Server (4 bajty, 7 cyfr).
Dragoljub Ćurčić

Pływak nie jest dokładny, szacuje się, jezioro dokładności w ciągu ostatnich lat jest śmiertelne! Może wskazywać ci zupełnie inne miejsce na świecie.
HLGEM

2
Maksymalny błąd pływających typów danych jest na tyle niski, że nie powinno to stanowić problemu. To znaczy, musisz zdawać sobie sprawę z mnożenia / akumulacji błędów w obu implementacjach.
Spidey

@HLGEM - Zaokrąglenie do pewnej liczby miejsc po przecinku powoduje również wylądowanie w innym miejscu na świecie. Pytanie brzmi, czy to inne miejsce jest tak blisko, że nie ma to znaczenia.
Rick James

-3

A FLOATpowinno dać ci całą precyzję, jakiej potrzebujesz, i być lepsze dla funkcji porównawczych niż przechowywanie każdej współrzędnej jako łańcucha lub podobnego.

Jeśli Twoja wersja MySQL jest wcześniejsza niż 5.0.3, może być konieczne zwrócenie uwagi na niektóre błędy porównania zmiennoprzecinkowego .

W wersjach wcześniejszych niż MySQL 5.0.3 kolumny DECIMAL przechowują wartości z dokładną dokładnością, ponieważ są one reprezentowane jako ciągi, ale obliczenia wartości DECIMAL są wykonywane przy użyciu operacji zmiennoprzecinkowych. Od wersji 5.0.3 MySQL wykonuje operacje DECIMAL z dokładnością do 64 cyfr dziesiętnych, co powinno rozwiązać najczęstsze problemy z niedokładnością w przypadku kolumn DECIMAL


2
Potrzebujesz prostego typu współrzędnych szerokości i długości geograficznej, aby ułatwić matematykę. Wyobraź sobie wygodę czegoś w rodzaju „wybierz * ze sklepów, w których odległość (sklepy. Lokalizacja, lokalizacja) <5 mil”
Kirk Strauser

1
Nie słyszałem wcześniej o rozszerzeniach przestrzennych, co wydaje się bardzo wygodne, ponieważ wcześniej pracował nad odziedziczoną aplikacją, która wykonuje sporo obliczeń związanych z geo, musi to sprawdzić.
ConroyP

@ ConroyP - Nie. Ten cytat wskazuje, że DECIMALmiał (przed 5.0.3) pewne błędy z powodu zastosowania implementacji swobodnej.
Rick James
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.