Tenendo presente che eseguirò calcoli su coppie lat / long, quale tipo di dati è più adatto per l'uso con un database MySQL?
Tenendo presente che eseguirò calcoli su coppie lat / long, quale tipo di dati è più adatto per l'uso con un database MySQL?
Risposte:
Usa le estensioni spaziali di MySQL con GIS.
Google fornisce un inizio per completare la soluzione PHP / MySQL per un'applicazione "Store Locator" di esempio con Google Maps. In questo esempio, memorizzano i valori lat / lng come "Float" con una lunghezza di "10,6"
FLOAT(10,6)
lascia 4 cifre per la parte intera della coordinata. E no, il segno non conta - viene dall'attributo (non) firmato.
Double
di dati per Laravel
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. GALLEGGIANTE è 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 sia di aiuto.
Le estensioni spaziali di MySQL sono l'opzione migliore perché hai l'elenco completo di operatori e indici spaziali a tua disposizione. 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 l'operatore "correlazione". Vedere 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 NUMERIC (18,12) perché era firebird).
Galleggianti e doppi non sono così precisi e possono causare errori di arrotondamento che possono essere una cosa molto negativa. Non riesco a ricordare se ho trovato dati reali che avevano 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 del maggior numero di cifre.
Le estensioni spaziali MySQL sono una buona alternativa perché seguono il modello geometria OpenGIS . Non li ho usati perché dovevo mantenere il mio database portatile.
a*b
non era uguale b*a
(per alcuni valori). Ci sono stati molti esempi un po 'come: 2+2 = 3.9999
. Lo standard ha ripulito un sacco di confusione ed è stato "rapidamente" adottato praticamente da ogni componente hardware e software. Quindi, questa discussione è stata valida, non solo dal 2008, ma per un terzo di secolo.
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
Riassumere:
DOUBLE
.DECIMAL(8,6)/(9,6)
.A partire da MySQL 5.7 , considera l'utilizzo di Tipi di dati spaziali (SDT), in particolare POINT
per la memorizzazione di una singola coordinata. Prima di 5.7, SDT non supporta gli indici (ad eccezione di 5.6 quando il tipo di tabella è MyISAM).
Nota:
POINT
classe, l'ordine degli argomenti per la memorizzazione delle coordinate deve essere POINT(latitude, longitude)
.ST_Distance
) e la determinazione se un punto è contenuto in un'altra area ( ST_Contains
).CREATE TABLE geom (g GEOMETRY NOT NULL, SPATIAL INDEX(g)) ENGINE=MyISAM;
e l'avvertimento sulle limitazioni SDT, come ha detto James , forse la tua risposta sarà più concisa e precisa nell'aiutare anche altre persone. ..
Sulla base di questo articolo wiki http://en.wikipedia.org/wiki/Decimal_degrees#Accuracy il tipo di dati appropriato in MySQL è Decimale (9,6) per memorizzare la longitudine e la latitudine in campi separati.
Utilizzare DECIMAL(8,6)
per latitudine (da 90 a -90 gradi) e DECIMAL(9,6)
per longitudine (da 180 a -180 gradi). 6 decimali vanno bene per la maggior parte delle applicazioni. Entrambi dovrebbero essere "firmati" per consentire valori negativi.
DECIMAL
tipo è inteso per calcoli finanziari in cui non floor/ceil
è accettato. Plain FLOAT
supera significativamente le prestazioni DECIMAL
.
Non c'è bisogno di andare lontano, secondo Google Maps, il migliore è FLOAT (10,6) per lat e lng.
lat FLOAT( 10, 6 ) NOT NULL,
lng FLOAT( 10, 6 ) NOT NULL
FLOAT
sintassi sia obsoleta a partire da mysql 8.0.17
. Mysql ora consiglia di utilizzare FLOAT
senza parametri di precisione dev.mysql.com/doc/refman/8.0/en/numeric-type-overview.html e dev.mysql.com/doc/refman/5.5/en/floating-point- types.html
Memorizziamo 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 memorizzano anche lat / long al sesto decimale.
In una prospettiva completamente diversa e più semplice:
VARCHAR
), ad esempio: " -0000.0000001, -0000.000000000000001 " (lunghezza 35 e se un numero ha più di 7 cifre decimali, viene arrotondato);google.maps.geometry.poly.containsLocation(latLng, bermudaTrianglePolygon))
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 dell'applicazione, suggerisco di utilizzare 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
DOUBLE
. MySQL ti consente di archiviare i dati come 4 byte FLOAT
o 8 byte DOUBLE
. Pertanto, è probabile che si verifichi una perdita di precisione durante la memorizzazione di un'espressione in una FLOAT
colonna.
Sebbene non sia ottimale per tutte le operazioni, se stai realizzando riquadri di mappe o lavorando con un gran numero di marcatori (punti) con una sola proiezione (ad esempio Mercator, come Google Maps e molti altri framework di mappe scivolose si aspettano), 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:
Ne ho parlato in un recente post sul blog: http://blog.webfoot.com/2013/03/12/optimizing-map-tile-generation/
Sono molto sorpreso da alcune risposte / commenti.
Perché mai qualcuno dovrebbe essere disposto a "pre-diminuire" volontariamente la precisione, e in seguito eseguire calcoli sui numeri peggiori? Alla fine sembra stupido.
Se la sorgente ha una precisione a 64 bit, certamente sarebbe stupido fissare volontariamente la scala ad es. 6 decimali e limita la precisione a un massimo di 9 cifre significative (cosa che accade con il formato decimale 9.6 comunemente proposto).
Naturalmente, si memorizzano i dati con la precisione del materiale di origine. L'unico motivo per ridurre la precisione sarebbe lo spazio di archiviazione limitato.
Il formato decimale 9.6 genera un fenomeno snap-to-grid. Questo dovrebbe essere l'ultimo passo, se mai dovesse succedere.
Non inviterei errori accumulati nel mio nido.
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
Quindi la prima parte della risposta sarebbe: è possibile memorizzare le coordinate nel formato utilizzato dall'applicazione per evitare conversioni costanti avanti e indietro e rendere più semplici le query SQL.
Molto probabilmente usi Google Maps o OSM per visualizzare i tuoi dati e GMaps utilizza il formato "gradi decimali 2". 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 è di 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.
gradi formato minuti decimali (40 ° 26.767 ′ N 79 ° 58.933 ′ O) offre 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 la parte principale (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 riferimento ai tipi di float MySQL . 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) + long (no più di 181000 valori + segno) a 21 bit che è significativamente inferiore a 2xFLOAT (8 byte == 64 bit)
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: link del testo
Le latitudini vanno da -90 a +90 (gradi), quindi DECIMAL (10, 8) va bene per quello
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
Ti suggerisco di utilizzare il tipo di dati Float per SQL Server.
I calcoli Lat Long richiedono precisione, quindi usa un tipo di decimale e aumenta la precisione di almeno 2 in più rispetto al numero che memorizzerai per eseguire 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 rispetto alla memorizzazione di ciascuna coordinata come stringa o simili.
Se la tua versione di MySQL è precedente alla 5.0.3, potresti dover tenere conto di alcuni errori di confronto in virgola mobile .
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 operazioni DECIMAL con una precisione di 64 cifre decimali, che dovrebbe risolvere i problemi di imprecisione più comuni quando si tratta di colonne DECIMAL
DECIMAL
(prima della 5.0.3) c'erano alcuni errori dovuti all'uso dell'implementazione mobile.