Lưu ý rằng tôi sẽ thực hiện các phép tính trên các cặp lat / long, kiểu dữ liệu nào phù hợp nhất để sử dụng với cơ sở dữ liệu MySQL?
Lưu ý rằng tôi sẽ thực hiện các phép tính trên các cặp lat / long, kiểu dữ liệu nào phù hợp nhất để sử dụng với cơ sở dữ liệu MySQL?
Câu trả lời:
Sử dụng các phần mở rộng không gian của MySQL với GIS.
Google cung cấp một sự khởi đầu để kết thúc giải pháp PHP / MySQL cho một ứng dụng "Cửa hàng định vị" ví dụ với Google Maps. Trong ví dụ này, họ lưu trữ các giá trị lat / lng là "Float" với độ dài "10,6"
http://code.google.com.vn/apis/maps/articles/phpsqlsearch.html
FLOAT(10,6)
để lại 4 chữ số cho phần nguyên của tọa độ. Và không, dấu hiệu không được tính - xuất phát từ thuộc tính đã ký (chưa).
Double
cho Laravel
Về cơ bản, nó phụ thuộc vào độ chính xác bạn cần cho vị trí của bạn. Sử dụng NHÂN ĐÔI bạn sẽ có độ chính xác 3,5nm. DECIMAL (8,6) / (9,6) giảm xuống 16cm. FLOAT là 1,7m ...
Bảng rất thú vị này có một danh sách đầy đủ hơn: 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
Hi vọng điêu nay co ich.
Tiện ích mở rộng không gian của MySQL là tùy chọn tốt nhất vì bạn có danh sách đầy đủ các toán tử và chỉ số không gian theo ý của bạn. Một chỉ số không gian sẽ cho phép bạn thực hiện các phép tính dựa trên khoảng cách rất nhanh. Xin lưu ý rằng kể từ 6.0, phần mở rộng không gian vẫn chưa hoàn thành. Tôi không đặt MySQL Spatial xuống, chỉ cho bạn biết về những cạm bẫy trước khi bạn đi quá xa về vấn đề này.
Nếu bạn đang xử lý nghiêm các điểm và chỉ có chức năng DISTANCE, thì điều này là ổn. Nếu bạn cần thực hiện bất kỳ phép tính nào với Đa giác, Đường hoặc Điểm đệm, toán tử không gian không cung cấp kết quả chính xác trừ khi bạn sử dụng toán tử "liên quan". Xem cảnh báo ở đầu ngày 21.5.6 . Các mối quan hệ như chứa, bên trong hoặc giao nhau đang sử dụng MBR, không phải là hình dạng hình học chính xác (tức là một hình elip được xử lý như hình chữ nhật).
Ngoài ra, khoảng cách trong MySQL Spatial là cùng đơn vị với hình học đầu tiên của bạn. Điều này có nghĩa là nếu bạn đang sử dụng Độ thập phân, thì các phép đo khoảng cách của bạn là Độ thập phân. Điều này sẽ làm cho rất khó để có được kết quả chính xác khi bạn nhận được furthur từ đường xích đạo.
Khi tôi làm điều này cho một cơ sở dữ liệu điều hướng được xây dựng từ ARINC424, tôi đã thực hiện một số lượng thử nghiệm hợp lý và nhìn lại mã, tôi đã sử dụng một DECIMAL (18,12) (Trên thực tế là SỐ MỘT (18,12) vì đó là firebird).
Phao và đôi không chính xác và có thể dẫn đến lỗi làm tròn có thể là một điều rất xấu. Tôi không thể nhớ nếu tôi tìm thấy bất kỳ dữ liệu thực sự nào có vấn đề - nhưng tôi khá chắc chắn rằng việc không thể lưu trữ chính xác trong một float hoặc double có thể gây ra vấn đề
Vấn đề là khi sử dụng độ hoặc radian, chúng ta biết phạm vi của các giá trị - và phần phân số cần nhiều chữ số nhất.
Phần mở rộng không gian MySQL là một lựa chọn tốt vì chúng tuân theo Mô hình hình học OpenGIS . Tôi đã không sử dụng chúng vì tôi cần giữ cơ sở dữ liệu của mình.
a*b
không bằng nhau b*a
(đối với một số giá trị). Có rất nhiều ví dụ giống như : 2+2 = 3.9999
. Tiêu chuẩn đã dọn sạch rất nhiều mớ hỗn độn và được 'nhanh chóng' chấp nhận bởi hầu hết mọi phần cứng và phần mềm. Vì vậy, cuộc thảo luận này đã có giá trị, không chỉ từ năm 2008, mà trong một phần ba thế kỷ.
Phụ thuộc vào độ chính xác mà bạn yêu cầu.
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
Từ: http://mysql.rjweb.org/doc.php/latlng
Để tóm tắt:
DOUBLE
.DECIMAL(8,6)/(9,6)
.Kể từ MySQL 5.7 , hãy cân nhắc sử dụng các kiểu dữ liệu không gian (SDT), đặc biệt POINT
để lưu trữ một tọa độ. Trước 5.7, SDT không hỗ trợ các chỉ mục (ngoại trừ 5.6 khi loại bảng là MyISAM).
Ghi chú:
POINT
lớp, thứ tự của các đối số để lưu trữ tọa độ phải là POINT(latitude, longitude)
.ST_Distance
) và xác định xem một điểm có nằm trong khu vực khác không ( ST_Contains
).CREATE TABLE geom (g GEOMETRY NOT NULL, SPATIAL INDEX(g)) ENGINE=MyISAM;
và cảnh báo về các hạn chế SDT, như James đã đề cập , có lẽ câu trả lời của bạn sẽ ngắn gọn và chính xác hơn trong việc giúp đỡ người khác. ..
Dựa trên bài viết wiki này http://en.wikipedia.org/wiki/Decimal_degrees#Accuracy loại dữ liệu phù hợp trong MySQL là Decimal (9,6) để lưu trữ kinh độ và vĩ độ trong các trường riêng biệt.
Sử dụng DECIMAL(8,6)
cho vĩ độ (90 đến -90 độ) và DECIMAL(9,6)
cho kinh độ (180 đến -180 độ). 6 vị trí thập phân là tốt cho hầu hết các ứng dụng. Cả hai nên được "ký" để cho phép các giá trị âm.
DECIMAL
loại được dành cho tính toán tài chính, nơi không floor/ceil
được chấp nhận. Đồng bằng FLOAT
vượt trội đáng kể DECIMAL
.
Không cần phải đi xa, theo Google Maps, tốt nhất là FLOAT (10,6) cho lat và lng.
lat FLOAT( 10, 6 ) NOT NULL,
lng FLOAT( 10, 6 ) NOT NULL
FLOAT
cú pháp đó không được dùng nữa mysql 8.0.17
. Mysql hiện khuyên bạn chỉ nên sử dụng FLOAT
mà không có bất kỳ tham số chính xác nào dev.mysql.com/doc/refman/8.0/en/numeric-type-overview.html và dev.mysql.com/doc/refman/5.5/en/floating-point- loại.html
Chúng tôi lưu trữ vĩ độ / kinh độ X 1.000.000 trong cơ sở dữ liệu tiên tri của chúng tôi dưới dạng SỐ để tránh các lỗi làm tròn với số lần nhân đôi.
Cho rằng vĩ độ / kinh độ đến vị trí thập phân thứ 6 có độ chính xác 10 cm là tất cả những gì chúng ta cần. Nhiều cơ sở dữ liệu khác cũng lưu trữ lat / long đến vị trí thập phân thứ 6.
Trong một quan điểm hoàn toàn khác và đơn giản hơn:
VARCHAR
), vd: " -0000.0000001, -0000.000000000000001 " (35 độ dài và nếu một số có nhiều hơn 7 chữ số thập phân thì nó sẽ được làm tròn);google.maps.geometry.poly.containsLocation(latLng, bermudaTrianglePolygon))
Bằng cách này, bạn không cần phải lo lắng về việc lập chỉ mục số và tất cả các vấn đề khác liên quan đến các loại dữ liệu có thể làm hỏng tọa độ của bạn.
tùy thuộc vào ứng dụng của bạn, tôi đề nghị sử dụng FLOAT (9,6)
Các phím không gian sẽ cung cấp cho bạn nhiều tính năng hơn, nhưng theo tiêu chuẩn sản xuất, các phao nổi nhanh hơn nhiều so với các phím không gian. (0,01 VS 0,001 trong AVG)
MySQL sử dụng gấp đôi cho tất cả số float ... Vì vậy, sử dụng kiểu double. Sử dụng float sẽ dẫn đến các giá trị làm tròn không thể đoán trước trong hầu hết các tình huống
DOUBLE
. MySQL cho phép bạn lưu trữ dữ liệu dưới dạng 4 byte FLOAT
hoặc 8 byte DOUBLE
. Vì vậy, có khả năng mất độ chính xác khi lưu trữ một biểu thức vào một FLOAT
cột.
Mặc dù nó không tối ưu cho tất cả các hoạt động, nhưng nếu bạn đang tạo các ô bản đồ hoặc làm việc với số lượng lớn các điểm đánh dấu (dấu chấm) chỉ với một phép chiếu (ví dụ: Mercator, như Google Maps và nhiều khung bản đồ slippy khác), tôi đã tìm thấy những gì Tôi gọi "Hệ thống tọa độ rộng lớn" là thực sự, thực sự tiện dụng. Về cơ bản, bạn lưu trữ tọa độ pixel x và y ở một số cách phóng to - Tôi sử dụng mức thu phóng 23. Điều này có một số lợi ích:
Tôi đã nói về tất cả những điều này trong một bài đăng trên blog gần đây: http://blog.webfoot.com/2013/03/12/optimizing-map-tile-generation/
Tôi rất ngạc nhiên bởi một số câu trả lời / ý kiến.
Tại sao mọi người lại sẵn sàng tự nguyện "giảm trước" độ chính xác, và sau đó thực hiện các phép tính trên những con số tồi tệ hơn? Nghe có vẻ ngu ngốc.
Nếu nguồn có độ chính xác 64 bit, chắc chắn sẽ rất ngu ngốc khi tự nguyện sửa thang đo thành ví dụ. 6 số thập phân và giới hạn độ chính xác ở mức tối đa là 9 lần đào đáng kể (xảy ra với định dạng thập phân 9.6 thường được đề xuất).
Đương nhiên, người ta lưu trữ dữ liệu với độ chính xác mà nguyên liệu gốc có. Lý do duy nhất để giảm độ chính xác sẽ là không gian lưu trữ hạn chế.
Định dạng thập phân 9,6 gây ra hiện tượng snap-to-lưới. Đó phải là bước cuối cùng, nếu nó hoàn toàn xảy ra.
Tôi sẽ không mời các lỗi tích lũy đến tổ của tôi.
TL; DR
Sử dụng FLOAT (8,5) nếu bạn không làm việc trong NASA / quân đội và không chế tạo hệ thống điều hướng máy bay.
Để trả lời câu hỏi của bạn đầy đủ, bạn cần xem xét một số điều:
định dạng
Vì vậy, phần đầu tiên của câu trả lời sẽ là - bạn có thể lưu trữ tọa độ theo định dạng mà ứng dụng của bạn sử dụng để tránh chuyển đổi liên tục qua lại và thực hiện các truy vấn SQL đơn giản hơn.
Rất có thể bạn sử dụng Google Maps hoặc OSM để hiển thị dữ liệu của mình và GMaps đang sử dụng định dạng "thập phân 2". Vì vậy, sẽ dễ dàng hơn để lưu trữ tọa độ trong cùng định dạng.
Độ chính xác
Sau đó, bạn muốn xác định độ chính xác bạn cần. Tất nhiên bạn có thể lưu trữ tọa độ như "-32.608697550570334,21.278081997935146", nhưng bạn đã bao giờ quan tâm đến milimet trong khi điều hướng đến điểm chưa? Nếu bạn không làm việc ở NASA và không làm vệ tinh hoặc tên lửa hoặc quỹ đạo máy bay, bạn sẽ ổn với độ chính xác vài mét.
Định dạng thường được sử dụng là 5 chữ số sau các dấu chấm cung cấp cho bạn độ chính xác 50 cm.
Ví dụ : có khoảng cách 1cm giữa X, 21,278081 8 và X, 21,278081 9 . Vì vậy, 7 chữ số sau dấu chấm cho bạn độ chính xác 1 / 2cm và 5 chữ số sau dấu chấm sẽ cho bạn độ chính xác 1/2 mét (vì khoảng cách tối thiểu giữa các điểm khác biệt là 1m, do đó sai số làm tròn không thể lớn hơn một nửa). Đối với hầu hết các mục đích dân sự, nó là đủ.
định dạng phút thập phân (40 ° 26.767 ′ N 79 ° 58.933 W) cung cấp cho bạn độ chính xác chính xác như 5 chữ số sau khi chấm
Lưu trữ không gian hiệu quả
Nếu bạn đã chọn định dạng thập phân, thì tọa độ của bạn là một cặp (-32.60875, 21.27812). Rõ ràng, 2 x (1 bit cho dấu, 2 chữ số cho độ và 5 chữ số cho số mũ) là đủ.
Vì vậy, ở đây tôi muốn hỗ trợ Alix Axel từ các bình luận nói rằng đề xuất của Google để lưu trữ nó trong FLOAT (10,6) là thực sự bổ sung, vì bạn không cần 4 chữ số cho phần chính (vì dấu hiệu bị tách ra và vĩ độ bị hạn chế đến 90 và kinh độ được giới hạn ở 180). Bạn có thể dễ dàng sử dụng FLOAT (8,5) cho độ chính xác 1 / 2m hoặc FLOAT (9,6) cho độ chính xác 50 / 2cm. Hoặc thậm chí bạn có thể lưu trữ lat và long trong các loại riêng biệt, vì FLOAT (7,5) là đủ cho lat. Xem tài liệu tham khảo kiểu float của MySQL . Bất kỳ ai trong số họ sẽ giống như FLOAT bình thường và bằng 4 byte.
Ngày nay, không gian thường không phải là vấn đề, nhưng nếu bạn muốn thực sự tối ưu hóa lưu trữ vì một số lý do (Tuyên bố miễn trừ trách nhiệm: không thực hiện tối ưu hóa trước), bạn có thể nén lat (không quá 91 000 giá trị + dấu hiệu) + dài (không hơn 181 000 giá trị + dấu) đến 21 bit nhỏ hơn đáng kể so với 2xFLOAT (8 byte == 64 bit)
Các chức năng không gian trong PostGIS có nhiều chức năng hơn (nghĩa là không bị hạn chế đối với các hoạt động BBOX) so với các chức năng trong các chức năng không gian của MySQL. Kiểm tra xem nó: liên kết văn bản
Vĩ độ nằm trong khoảng từ -90 đến +90 (độ), do đó, DECIMAL (10, 8) là ổn đối với điều đó
kinh độ nằm trong khoảng từ -180 đến +180 (độ), do đó bạn cần phải có QUYẾT ĐỊNH (11, 8).
Lưu ý: Số đầu tiên là tổng số chữ số được lưu trữ và số thứ hai là số sau dấu thập phân.
Nói ngắn gọn: lat DECIMAL(10, 8) NOT NULL, lng DECIMAL(11, 8) NOT NULL
Tôi đề nghị bạn sử dụng kiểu dữ liệu Float cho SQL Server.
Tính toán Lat Long yêu cầu độ chính xác, vì vậy hãy sử dụng một số loại thập phân và làm cho độ chính xác cao hơn ít nhất 2 so với số bạn sẽ lưu trữ để thực hiện các phép tính toán. Tôi không biết về các kiểu dữ liệu sql của tôi nhưng trong máy chủ SQL, mọi người thường sử dụng float hoặc real thay vì thập phân và gặp rắc rối vì đây là những con số ước tính không phải là số thực. Vì vậy, chỉ cần đảm bảo loại dữ liệu bạn sử dụng là loại thập phân thực chứ không phải loại thập phân nổi và bạn sẽ ổn.
A FLOAT
sẽ cung cấp cho bạn tất cả độ chính xác mà bạn cần và tốt hơn cho các hàm so sánh hơn là lưu trữ mỗi tọa độ dưới dạng một chuỗi hoặc tương tự.
Nếu phiên bản MySQL của bạn sớm hơn 5.0.3, bạn có thể cần lưu ý một số lỗi so sánh dấu phẩy động nhất định .
Trước MySQL 5.0.3, các cột DECIMAL lưu trữ các giá trị với độ chính xác chính xác vì chúng được biểu diễn dưới dạng chuỗi, nhưng các phép tính trên các giá trị DECIMAL được thực hiện bằng các phép toán dấu phẩy động. Kể từ 5.0.3, MySQL thực hiện các hoạt động DECIMAL với độ chính xác 64 chữ số thập phân, điều này sẽ giải quyết hầu hết các vấn đề không chính xác phổ biến khi nói đến các cột DECIMAL
DECIMAL
đã có (trước 5.0.3) một số lỗi nhất định do sử dụng triển khai nổi.