Mengingat bahwa saya akan melakukan perhitungan pada pasangan lat / long, tipe data apa yang paling cocok untuk digunakan dengan database MySQL?
Mengingat bahwa saya akan melakukan perhitungan pada pasangan lat / long, tipe data apa yang paling cocok untuk digunakan dengan database MySQL?
Jawaban:
Gunakan ekstensi spasial MySQL dengan GIS.
Google menyediakan solusi PHP / MySQL awal hingga akhir untuk contoh aplikasi "Pencari Lokasi" dengan Google Maps. Dalam contoh ini, mereka menyimpan nilai lat / lng sebagai "Float" dengan panjang "10,6"
FLOAT(10,6)
menyisakan 4 digit untuk bagian integer dari koordinat. Dan tidak, tandanya tidak masuk hitungan - yang berasal dari atribut yang ditandatangani.
Double
untuk Laravel
Pada dasarnya itu tergantung pada presisi yang Anda butuhkan untuk lokasi Anda. Menggunakan DOUBLE Anda akan memiliki ketelitian 3,5nm. DECIMAL (8,6) / (9,6) turun hingga 16cm. FLOAT adalah 1,7m ...
Tabel yang sangat menarik ini memiliki daftar yang lebih lengkap: 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
Semoga ini membantu.
Ekstensi Spasial MySQL adalah pilihan terbaik karena Anda memiliki daftar lengkap operator spasial dan indeks yang Anda inginkan. Indeks spasial akan memungkinkan Anda untuk melakukan perhitungan berbasis jarak dengan sangat cepat. Harap diingat bahwa pada 6.0, Ekstensi Spasial masih belum lengkap. Saya tidak meletakkan MySQL Spatial, hanya memberi tahu Anda tentang jebakan sebelum Anda terlalu jauh dalam hal ini.
Jika Anda hanya berurusan dengan poin dan hanya fungsi JARAK, ini baik-baik saja. Jika Anda perlu melakukan perhitungan apa pun dengan Polygons, Lines, atau Buffered-Points, operator spasial tidak memberikan hasil yang tepat kecuali Anda menggunakan operator "relate". Lihat peringatan di atas 21.5.6 . Hubungan seperti berisi, di dalam, atau berpotongan menggunakan MBR, bukan bentuk geometri yang tepat (yaitu Ellipse diperlakukan seperti Rectangle).
Juga, jarak dalam MySQL Spatial berada dalam satuan yang sama dengan geometri pertama Anda. Ini berarti jika Anda menggunakan Derajat Desimal, maka pengukuran jarak Anda dalam Derajat Desimal. Ini akan membuatnya sangat sulit untuk mendapatkan hasil yang tepat saat Anda mendapatkan furthur dari garis katulistiwa.
Ketika saya melakukan ini untuk database navigasi yang dibangun dari ARINC424 saya melakukan cukup banyak pengujian dan melihat kembali kode, saya menggunakan DECIMAL (18,12) (Sebenarnya sebuah NUMERIC (18,12) karena itu firebird).
Mengapung dan ganda tidak seakurat dan dapat menyebabkan kesalahan pembulatan yang mungkin merupakan hal yang sangat buruk. Saya tidak ingat apakah saya menemukan data nyata yang memiliki masalah - tetapi saya cukup yakin bahwa ketidakmampuan untuk menyimpan secara akurat dalam float atau double dapat menyebabkan masalah.
Intinya adalah bahwa ketika menggunakan derajat atau radian kita tahu rentang nilai - dan bagian fraksional membutuhkan angka paling banyak.
The MySQL Spatial Ekstensi adalah alternatif yang baik karena mereka mengikuti The OpenGIS Geometri Model . Saya tidak menggunakannya karena saya perlu menjaga portable database saya.
a*b
yang tidak sama b*a
(untuk beberapa nilai). Ada banyak contoh agak seperti: 2+2 = 3.9999
. Standar membersihkan banyak kekacauan, dan 'cepat' diadopsi oleh hampir setiap perangkat keras dan perangkat lunak. Jadi, diskusi ini telah berlaku, tidak hanya sejak 2008, tetapi untuk sepertiga abad.
Tergantung pada presisi yang Anda butuhkan.
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
Dari: http://mysql.rjweb.org/doc.php/latlng
Untuk meringkas:
DOUBLE
.DECIMAL(8,6)/(9,6)
.Pada MySQL 5.7 , pertimbangkan untuk menggunakan Jenis Data Spasial (SDT), khusus POINT
untuk menyimpan satu koordinat. Sebelum 5.7, SDT tidak mendukung indeks (dengan pengecualian 5.6 ketika tipe tabel adalah MyISAM).
catatan:
POINT
kelas, urutan argumen untuk menyimpan koordinat harus POINT(latitude, longitude)
.ST_Distance
) dan menentukan apakah satu titik terkandung dalam area lain ( ST_Contains
).CREATE TABLE geom (g GEOMETRY NOT NULL, SPATIAL INDEX(g)) ENGINE=MyISAM;
dan peringatan tentang batasan SDT, seperti yang disebutkan James , mungkin jawaban Anda akan lebih ringkas dan tepat dalam membantu orang lain juga. ..
Berdasarkan artikel wiki ini http://en.wikipedia.org/wiki/Decimal_degrees#Accuracy tipe data yang sesuai di MySQL adalah Desimal (9,6) untuk menyimpan garis bujur dan lintang di bidang yang berbeda.
Gunakan DECIMAL(8,6)
untuk garis lintang (90 hingga -90 derajat) dan DECIMAL(9,6)
untuk garis bujur (180 hingga -180 derajat). 6 tempat desimal baik untuk sebagian besar aplikasi. Keduanya harus "ditandatangani" untuk memungkinkan nilai negatif.
DECIMAL
jenis ini dimaksudkan untuk perhitungan keuangan di mana tidak ada floor/ceil
yang diterima. Polos FLOAT
secara signifikan mengungguli DECIMAL
.
Tidak perlu melangkah jauh, menurut Google Maps, yang terbaik adalah FLOAT (10,6) untuk lat dan lng.
lat FLOAT( 10, 6 ) NOT NULL,
lng FLOAT( 10, 6 ) NOT NULL
FLOAT
sintaks sudah tidak digunakan lagi mysql 8.0.17
. Mysql sekarang merekomendasikan untuk hanya menggunakan FLOAT
tanpa parameter presisi dev.mysql.com/doc/refman/8.0/en/numeric-type-overview.html dan dev.mysql.com/doc/refman/5.5/en/floating-point- types.html
Kami menyimpan lintang / bujur X 1.000.000 dalam basis data oracle kami sebagai ANGKA untuk menghindari kesalahan pembulatan dengan ganda.
Mengingat bahwa lintang / bujur ke tempat desimal ke-6 adalah akurasi 10 cm yang kami butuhkan. Banyak basis data lain juga menyimpan lat / panjang ke tempat desimal ke-6.
Dalam perspektif yang sama sekali berbeda dan lebih sederhana:
VARCHAR
), Misalnya: " -0000.0000001, -0000.000000000000001 " (35 panjang dan jika angka memiliki lebih dari 7 angka desimal maka dibulatkan);google.maps.geometry.poly.containsLocation(latLng, bermudaTrianglePolygon))
Dengan cara ini Anda tidak perlu khawatir tentang pengindeksan angka dan semua masalah lain yang terkait dengan tipe data yang dapat mengacaukan koordinat Anda.
tergantung pada aplikasi Anda, saya sarankan menggunakan FLOAT (9,6)
kunci spasial akan memberi Anda lebih banyak fitur, tetapi dengan tolok ukur produksi float jauh lebih cepat daripada kunci spasial. (0,01 VS 0,001 dalam AVG)
MySQL menggunakan ganda untuk semua pelampung ... Jadi, gunakan tipe ganda. Menggunakan float akan menyebabkan nilai bulat yang tidak terduga di sebagian besar situasi
DOUBLE
. MySQL memungkinkan Anda menyimpan data sebagai 4-byte FLOAT
atau 8-byte DOUBLE
. Jadi, ada kemungkinan akan kehilangan presisi saat menyimpan ekspresi ke dalam FLOAT
kolom.
Meskipun tidak optimal untuk semua operasi, jika Anda membuat petak peta atau bekerja dengan banyak marker (titik) dengan hanya satu proyeksi (mis. Mercator, seperti Google Maps dan banyak kerangka peta slippy lainnya harapkan), saya telah menemukan apa Saya menyebut "Sistem Koordinat Luas" untuk menjadi sangat, sangat berguna. Pada dasarnya, Anda menyimpan koordinat x dan y piksel di beberapa cara-diperbesar - Saya menggunakan tingkat zoom 23. Ini memiliki beberapa manfaat:
Saya membicarakan semua ini dalam posting blog baru-baru ini: http://blog.webfoot.com/2013/03/12/optimizing-map-tile-generation/
Saya sangat terkejut dengan beberapa jawaban / komentar.
Mengapa ada orang yang mau secara sukarela "mengurangi" ketepatan, dan kemudian melakukan perhitungan pada angka yang lebih buruk? Kedengarannya sangat bodoh.
Jika sumber memiliki 64-bit presisi, tentu akan bodoh untuk secara sukarela memperbaiki skala untuk contoh. 6 desimal, dan batasi presisi hingga maksimum 9 digit signifikan (yang terjadi dengan format desimal 9.6 yang umum diusulkan).
Secara alami, seseorang menyimpan data dengan presisi yang dimiliki bahan sumber. Satu-satunya alasan untuk menurunkan presisi adalah ruang penyimpanan yang terbatas.
Desimal 9,6-format menyebabkan fenomena snap-to-grid. Itu harus menjadi langkah terakhir, jika hal itu benar-benar terjadi.
Saya tidak akan mengundang akumulasi kesalahan ke sarang saya.
TL; DR
Gunakan FLOAT (8,5) jika Anda tidak bekerja di NASA / militer dan tidak membuat sistem navi pesawat.
Untuk menjawab pertanyaan Anda sepenuhnya, Anda perlu mempertimbangkan beberapa hal:
Format
Jadi, bagian pertama dari jawabannya adalah - Anda dapat menyimpan koordinat dalam format yang digunakan aplikasi Anda untuk menghindari konversi konstan bolak-balik dan membuat pertanyaan SQL yang lebih sederhana.
Kemungkinan besar Anda menggunakan Google Maps atau OSM untuk menampilkan data Anda, dan GMaps menggunakan format "derajat desimal 2". Jadi akan lebih mudah untuk menyimpan koordinat dalam format yang sama.
Presisi
Kemudian, Anda ingin menentukan presisi yang Anda butuhkan. Tentu saja Anda dapat menyimpan koordinat seperti "-32.608697550570334,21.278081997935146", tetapi apakah Anda pernah peduli tentang milimeter saat navigasi ke titik? Jika Anda tidak bekerja di NASA dan tidak melakukan lintasan satelit atau roket atau pesawat, Anda harus baik-baik saja dengan akurasi beberapa meter.
Format yang umum digunakan adalah 5 digit setelah titik yang memberi Anda akurasi 50cm.
Contoh : ada jarak 1cm antara X, 21.278081 8 dan X, 21.278081 9 . Jadi 7 digit setelah titik memberi Anda presisi 1 / 2cm dan 5 digit setelah titik akan memberikan Anda presisi 1/2 meter (karena jarak minimal antara titik yang berbeda adalah 1m, jadi kesalahan pembulatan tidak boleh lebih dari setengahnya). Untuk sebagian besar keperluan sipil, itu sudah cukup.
format derajat desimal menit (40 ° 26.767 ′ N 79 ° 58.933 ′ W) memberi Anda presisi yang sama persis dengan 5 digit setelah titik
Penyimpanan hemat ruang
Jika Anda memilih format desimal, maka koordinat Anda adalah pasangan (-32.60875, 21.27812). Jelas, 2 x (1 bit untuk tanda, 2 digit untuk derajat dan 5 digit untuk eksponen) sudah cukup.
Jadi di sini saya ingin mendukung Alix Axel dari komentar yang mengatakan bahwa saran Google untuk menyimpannya di FLOAT (10,6) benar-benar ekstra, karena Anda tidak perlu 4 digit untuk bagian utama (karena tanda dipisahkan dan garis lintang terbatas hingga 90 dan bujur dibatasi hingga 180). Anda dapat dengan mudah menggunakan FLOAT (8,5) untuk presisi 1 / 2m atau FLOAT (9,6) untuk presisi 50 / 2cm. Atau Anda bahkan dapat menyimpan lat dan panjang dalam tipe yang terpisah, karena FLOAT (7,5) sudah cukup untuk lat. Lihat referensi tipe float MySQL . Setiap dari mereka akan seperti FLOAT normal dan sama dengan 4 byte.
Biasanya ruang tidak menjadi masalah saat ini, tetapi jika Anda ingin benar-benar mengoptimalkan penyimpanan untuk beberapa alasan (Penafian: jangan melakukan pra-optimasi), Anda dapat memampatkan lat (tidak lebih dari 91.000 nilai + tanda) + panjang (tidak lebih dari 181 000 nilai + tanda) hingga 21 bit yang secara signifikan kurang dari 2xFLOAT (8 byte == 64 bit)
Fungsi spasial di PostGIS jauh lebih fungsional (yaitu tidak dibatasi pada operasi BBOX) daripada fungsi spasial MySQL. Lihat ini: tautan teks
Garis lintang berkisar dari -90 hingga +90 (derajat), jadi DECIMAL (10, 8) boleh digunakan untuk itu
garis bujur berkisar antara -180 hingga +180 (derajat) sehingga Anda memerlukan DECIMAL (11, 8).
Catatan: Angka pertama adalah jumlah total digit yang disimpan, dan yang kedua adalah angka setelah titik desimal.
Pendeknya: lat DECIMAL(10, 8) NOT NULL, lng DECIMAL(11, 8) NOT NULL
Saya sarankan Anda menggunakan Float datatype untuk SQL Server.
Perhitungan Lat Long membutuhkan ketelitian, jadi gunakan beberapa jenis tipe desimal dan buat ketelitiannya setidaknya 2 lebih tinggi dari angka yang akan Anda simpan untuk melakukan perhitungan matematika. Saya tidak tahu tentang tipe data sql saya tetapi dalam SQL server orang sering menggunakan float atau real bukan desimal dan mendapat masalah karena ini adalah angka yang diperkirakan bukan yang asli. Jadi pastikan tipe data yang Anda gunakan adalah tipe desimal sejati dan bukan tipe desimal mengambang dan Anda harus baik-baik saja.
A FLOAT
harus memberi Anda semua presisi yang Anda butuhkan, dan lebih baik untuk fungsi perbandingan daripada menyimpan masing-masing koordinat sebagai string atau sejenisnya.
Jika versi MySQL Anda lebih awal dari 5.0.3, Anda mungkin harus memperhatikan kesalahan perbandingan floating point tertentu .
Sebelum MySQL 5.0.3, kolom DECIMAL menyimpan nilai dengan presisi yang tepat karena mereka direpresentasikan sebagai string, tetapi perhitungan pada nilai DECIMAL dilakukan dengan menggunakan operasi floating-point. Pada 5.0.3, MySQL melakukan operasi DECIMAL dengan ketepatan 64 angka desimal, yang seharusnya bisa menyelesaikan masalah ketidakakuratan paling umum ketika sampai pada kolom DECIMAL
DECIMAL
ada (sebelum 5.0.3) kesalahan tertentu karena penggunaan implementasi mengambang.