Qual è il tipo di dati ideale da utilizzare quando si memorizzano latitudine / longitudine in un database MySQL?

StackOverflow https://stackoverflow.com/questions/159255

Domanda

Tenendo presente che eseguirò calcoli su coppie lat / long, quale tipo di dati è più adatto per l'uso con un database MySQL?

È stato utile?

Soluzione

Usa le estensioni spaziali di MySQL con GIS.

/ p>

Altri suggerimenti

Google fornisce un inizio per completare la soluzione PHP / MySQL per un esempio "Store Locator" applicazione con Google Maps. In questo esempio, memorizzano i valori lat / lng come " Float " con una lunghezza di "10,6"

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

Fondamentalmente dipende dalla precisione di cui hai bisogno per le tue posizioni. Usando DOUBLE avrai una precisione di 3,5 nm. DECIMAL (8,6) / (9,6) scende a 16 cm. FLOAT è 1,7 m ...

Questa tabella molto interessante ha un elenco più completo: 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

Spero che questo aiuti.

Le estensioni spaziali di MySQL sono l'opzione migliore perché hai a disposizione l'elenco completo degli operatori e degli indici spaziali. Un indice spaziale ti consentirà di eseguire calcoli basati sulla distanza molto rapidamente. Tieni presente che a partire dalla 6.0, l'estensione spaziale è ancora incompleta. Non sto abbattendo MySQL Spatial, solo per farti conoscere le insidie ??prima di andare troppo avanti su questo.

Se hai a che fare con i punti e solo con la funzione DISTANZA, va bene. Se è necessario eseguire calcoli con poligoni, linee o punti bufferizzati, gli operatori spaziali non forniscono risultati esatti a meno che non si utilizzi la "relazione" operatore. Vedi l'avvertenza nella parte superiore di 21.5.6 . Le relazioni come contiene, all'interno o intersecano utilizzano l'MBR, non la forma geometrica esatta (ovvero un'ellisse viene trattata come un rettangolo).

Inoltre, le distanze in MySQL Spatial sono nelle stesse unità della tua prima geometria. Ciò significa che se si utilizzano i gradi decimali, le misurazioni della distanza sono in gradi decimali. Ciò renderà molto difficile ottenere risultati esatti quando si ottiene furthur dall'equatore.

Quando l'ho fatto per un database di navigazione creato da ARINC424 ho fatto un bel po 'di test e guardando indietro al codice, ho usato un DECIMAL (18,12) (in realtà un NUMERICO (18,12) perché era firebird ).

I float e i doppi non sono così precisi e possono causare errori di arrotondamento che possono essere una cosa molto negativa. Non ricordo se ho trovato dati reali che presentavano problemi, ma sono abbastanza certo che l'incapacità di archiviare accuratamente in un float o in un doppio potrebbe causare problemi

Il punto è che quando si usano gradi o radianti conosciamo l'intervallo dei valori e la parte frazionata ha bisogno della maggior parte delle cifre.

Le MySQL Spatial Extensions sono una buona alternativa perché seguono The OpenGIS Geometry Model . Non li ho usati perché dovevo mantenere il mio database portatile.

Dipende dalla precisione richiesta.

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

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

Per riassumere:

  • L'opzione disponibile più precisa è DOUBLE .
  • Il tipo visto più comunemente usato è DECIMAL (8,6) / (9,6) .

A partire da MySQL 5.7 , considera l'utilizzo di Tipi di dati territoriali (SDT), in particolare POINT per memorizzare una singola coordinata. Prima di 5.7, SDT non supporta gli indici (ad eccezione di 5.6 quando il tipo di tabella è MyISAM).

Nota:

  • Quando si utilizza la classe POINT , l'ordine degli argomenti per la memorizzazione delle coordinate deve essere POINT (latitudine, longitudine) .
  • Esiste una sintassi speciale per creare un indice spaziale .
  • Il più grande vantaggio dell'uso di SDT è che hai accesso alle Funzioni di analisi spaziale , ad es calcolo della distanza tra due punti ( ST_Distance ) e determinare se un punto è contenuto in un'altra area ( ST_Contains ).

Basato su questo articolo wiki http://en.wikipedia.org/wiki/Decimal_degrees#Accuracy il tipo di dati appropriato in MySQL è Decimale (9,6) per la memorizzazione della longitudine e della latitudine in campi separati.

Usa DECIMAL (8,6) per la latitudine (da 90 a -90 gradi) e DECIMAL (9,6) per la longitudine (da 180 a -180 gradi). 6 decimali vanno bene per la maggior parte delle applicazioni. Entrambi dovrebbero essere "firmati" per consentire valori negativi.

Non c'è bisogno di andare lontano, secondo Google Maps, il migliore è FLOAT (10,6) per lat e lng.

Archiviamo latitudine / longitudine X 1.000.000 nel nostro database Oracle come NUMERI per evitare errori di arrotondamento con i doppi.

Dato che latitudine / longitudine al 6 ° decimale era una precisione di 10 cm che era tutto ciò di cui avevamo bisogno. Molti altri database archiviano anche lat / long al sesto decimale.

In una prospettiva completamente diversa e più semplice:

In questo modo non devi preoccuparti di indicizzare i numeri e tutti gli altri problemi associati ai tipi di dati che potrebbero rovinare le tue coordinate.

a seconda della tua applicazione, suggerisco di usare FLOAT (9,6)

le chiavi spaziali ti daranno più funzionalità, ma nei benchmark di produzione i float sono molto più veloci delle chiavi spaziali. (0,01 VS 0,001 in AVG)

MySQL usa il doppio per tutti i float ... Quindi usa il tipo double. L'uso di float porterà a valori arrotondati imprevedibili nella maggior parte delle situazioni

Anche se non è ottimale per tutte le operazioni, se stai realizzando riquadri di mappe o lavorando con un gran numero di marker (punti) con una sola proiezione (ad esempio Mercator, come Google Maps e molti altri framework di mappe slippy attesi), I ho trovato quello che chiamo "Vast Coordinate System" per essere davvero molto utile. Fondamentalmente, memorizzi le coordinate dei pixel xey in un modo ingrandito - Uso il livello di zoom 23. Questo ha diversi vantaggi:

  • Effettui la costosa trasformazione da lat / lng a mercator pixel una volta anziché ogni volta che gestisci il punto
  • Ottenere le coordinate del riquadro da un record dato un livello di zoom richiede uno spostamento a destra.
  • Ottenere le coordinate pixel da un record richiede uno spostamento a destra e un AND bit a bit.
  • I turni sono così leggeri che è pratico eseguirli in SQL, il che significa che puoi fare un DISTINCT per restituire solo un record per posizione dei pixel, che ridurrà i record numerici restituiti dal backend, il che significa meno elaborazione sul front-end.

Ne ho parlato in un recente post sul blog:     http://blog.webfoot.com/2013/03/ 12 / ottimizzando-map-tile generazione /

Sono molto sorpreso da alcune risposte / commenti.

Perché mai qualcuno dovrebbe essere disposto a "pre-diminuire" volontariamente? la precisione e poi eseguire calcoli sui numeri peggiori? Alla fine sembra stupido.

Se la sorgente ha una precisione a 64 bit, sarebbe certamente stupido fissare volontariamente la scala su es. 6 decimali e limita la precisione a un massimo di 9 cifre significative (che si verifica con il formato decimale 9.6 comunemente proposto).

Naturalmente, si archiviano i dati con la precisione del materiale sorgente. L'unico motivo per ridurre la precisione sarebbe lo spazio di archiviazione limitato.

  • Memorizza i dati sorgente con precisione originale
  • Memorizza i dati calcolati dalla sorgente con precisione nel calcolo (ad es. se il codice di applicazione utilizza i doppi, archivia i risultati come doppi)

Il formato decimale 9.6 provoca un fenomeno snap-to-grid. Questo dovrebbe essere l'ultimo passo, se mai dovesse succedere.

Non inviterei errori accumulati nel mio nido.

Le funzioni spaziali in PostGIS sono molto più funzionali (cioè non vincolate alle operazioni BBOX) rispetto a quelle nelle funzioni spaziali MySQL. Dai un'occhiata: testo del link

TL; DR

Usa FLOAT (8,5) se non lavori nella NASA / militare e non stai realizzando sistemi di navi per aeromobili.


Per rispondere pienamente alla tua domanda, dovresti considerare diverse cose:

Formato

  • gradi minuti secondi : 40 & # 176; 26 & # 8242; 46 & # 8243; N 79 & # 176; 58 & # 8242; 56 & # 8243; W
  • gradi decimali : 40 & # 176; 26,767 & # 8242; N 79 & # 176; 58,933 & # 8242; W
  • gradi decimali 1 : 40.446 & # 176; N 79.982 & # 176; W
  • gradi decimali 2 : -32.60875, 21.27812
  • Qualche altro formato fatto in casa? Nessuno ti proibisce di creare il tuo sistema di coordinate centrato sulla tua casa e di memorizzarlo come direzione e distanza da casa tua. Questo potrebbe avere senso per alcuni problemi specifici su cui stai lavorando.

Quindi la prima parte della risposta sarebbe: puoi memorizzare le coordinate nel formato usato dalla tua applicazione per evitare conversioni costanti avanti e indietro e fare query SQL più semplici.

Molto probabilmente usi Google Maps o OSM per visualizzare i tuoi dati e GMaps sta usando "gradi decimali 2" formato. Quindi sarà più facile memorizzare le coordinate nello stesso formato.

Precisione

Quindi, desideri definire la precisione di cui hai bisogno. Ovviamente puoi memorizzare coordinate come " -32.608697550570334,21.278081997935146 " ;, ma ti sei mai preoccupato dei millimetri durante la navigazione verso il punto? Se non stai lavorando nella NASA e non stai realizzando satelliti o missili o traiettorie di aerei, dovresti andare bene con diversi metri di precisione.

Il formato comunemente usato è composto da 5 cifre dopo i punti, per una precisione di 50 cm.

Esempio : c'è una distanza di 1 cm tra X, 21.278081 8 e X, 21.278081 9 . Quindi 7 cifre dopo punto offrono una precisione di 1/2 cm e 5 cifre dopo punto offrono una precisione di 1/2 metri (poiché la distanza minima tra punti distinti è 1m, quindi l'errore di arrotondamento non può essere superiore alla metà). Per la maggior parte degli scopi civili dovrebbe essere sufficiente.

formato dei minuti decimali in gradi (40 & # 176; 26.767 & # 8242; N 79 & # 176; 58.933 & # 8242; O) ti dà esattamente la stessa precisione di 5 cifre dopo il punto

Archiviazione efficiente in termini di spazio

Se hai selezionato il formato decimale, le tue coordinate sono una coppia (-32.60875, 21.27812). Ovviamente, saranno sufficienti 2 x (1 bit per segno, 2 cifre per gradi e 5 cifre per esponente).

Quindi qui vorrei supportare Alix Axel dai commenti dicendo che il suggerimento di Google di memorizzarlo in FLOAT (10,6) è davvero extra, perché non hai bisogno di 4 cifre per main parte (poiché il segno è separato e la latitudine è limitata a 90 e la longitudine è limitata a 180). Puoi facilmente usare FLOAT (8,5) per una precisione di 1/2 m o FLOAT (9,6) per una precisione di 50/2 cm. Oppure puoi anche memorizzare lat e long in tipi separati, perché FLOAT (7,5) è sufficiente per lat. Vedi i tipi di float MySQL reference . Ognuno di loro sarà come un normale FLOAT e comunque uguale a 4 byte.

Di solito lo spazio non è un problema al giorno d'oggi, ma se vuoi davvero ottimizzare l'archiviazione per qualche motivo (Dichiarazione di non responsabilità: non eseguire la pre-ottimizzazione), puoi comprimere lat (non più di 91000 valori + segno) + lungo (non più di 181000 valori + segno) a 21 bit che è significativamente inferiore di 2xFLOAT (8 byte == 64 bit)

  1. Le latitudini vanno da -90 a +90 (gradi), quindi DECIMAL (10, 8) va bene per questo

  2. le lunghezze vanno da -180 a +180 (gradi), quindi è necessario DECIMAL (11, 8).

Nota: il primo numero è il numero totale di cifre memorizzate e il secondo è il numero dopo il punto decimale.

In breve: lat DECIMAL (10, 8) NOT NULL, lng DECIMAL (11, 8) NOT NULL

I calcoli Lat Long richiedono precisione, quindi usa un tipo di tipo decimale e rendi la precisione almeno 2 superiore al numero che memorizzerai per eseguire i calcoli matematici. Non conosco i miei tipi di dati sql ma in SQL Server le persone usano spesso float o real invece di decimali e si mettono nei guai perché si tratta di numeri stimati non reali. Quindi assicurati solo che il tipo di dati che usi sia un tipo decimale vero e non un tipo decimale mobile e dovresti andare bene.

A FLOAT dovrebbe darti tutta la precisione di cui hai bisogno ed essere migliore per le funzioni di confronto piuttosto che memorizzare ogni coordinata come una stringa o simili.

Se la tua versione di MySQL è precedente alla 5.0.3, potresti dover prestare attenzione a errori di confronto in virgola mobile tuttavia.

  

Prima di MySQL 5.0.3, le colonne DECIMAL memorizzano i valori con precisione esatta perché sono rappresentate come stringhe, ma i calcoli sui valori DECIMAL vengono eseguiti utilizzando operazioni in virgola mobile. A partire dalla 5.0.3, MySQL esegue le operazioni DECIMAL con una precisione di 64 cifre decimali, che dovrebbe risolvere i problemi di imprecisione più comuni quando si tratta di colonne DECIMAL

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top