Loại dữ liệu lý tưởng để sử dụng khi lưu trữ vĩ độ / kinh độ trong cơ sở dữ liệu MySQL là gì?


430

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?


1
Tôi thấy liên kết này rất hữu ích: howto-use-mysql-spatial-ext.blogspot.com/2007/11/. Nó có thể cũ hơn một chút, nhưng nó chứa một lời giải thích đầy đủ bao gồm các ví dụ.
madc

Imho hầu hết mọi người ở đây không hiểu chuyện gì xảy ra. Ngay khi mã ứng dụng chạm vào một số, với điều kiện một người sử dụng gấp đôi (hầu hết làm như vậy), số đó biến thành tối đa gấp đôi độ chính xác . Lưu trữ nó sau đó với thậm chí một triệu số thập phân sẽ không làm được điều gì tốt. Lưu trữ nó với một số thập phân giới hạn (ví dụ 6) phá hủy một phần của độ chính xác đó và thêm một lỗi tích lũy mỗi khi nó được ghi lại vào cơ sở dữ liệu . Một đôi mang 16 số đáng kể, có khả năng tất cả các số thập phân. Loại bỏ 10 trong số chúng tạo ra một lỗi tích lũy theo thời gian. Đó là "điểm nổi" vì lý do. Tiếp
Bão tố

Tiếp: 6 số thập phân có thể ổn khi lưu trữ một số liệu có được từ nguồn bên ngoài, không thay đổi và lần đầu tiên - làm tài liệu nguồn. Nhưng nếu thực hiện phép tính trên nó dù chỉ một lần và lưu trữ lại, thì thật là ngu ngốc khi loại bỏ một phần độ chính xác của nó bằng cách thực thi một định dạng thập phân cụ thể. Việc thực hiện phép tính chỉ bên trong máy chủ có thể khác nhau (máy chủ có thể hoặc không thể sử dụng thứ gì khác ngoài nhân đôi) và sử dụng các biểu diễn số tệ hơn gấp đôi trong tính toán của ứng dụng, giải quyết nhu cầu lưu trữ chính xác như nhau.
Bão tố

Tiếp: NẾU máy chủ lưu trữ số với độ chính xác cao hơn , mặc dù đã tuyên bố "9.6" (mà tôi không biết nếu có), thì không có vấn đề gì cả, và định dạng hoàn toàn là vấn đề tiện lợi - có rất ít làm với các vấn đề chính xác. Nhưng tôi sẽ không ngạc nhiên nếu máy chủ thực sự làm tròn bất kỳ số nào thành 6 chính xác thập phân với định dạng đó.
Bão tố

Tiếp: Cuối cùng: Đối lat, lon, những chữ số thập phân thứ 6 là một vấn đề chụp vào một ca. Lưới 11 cm. Mỗi lần đọc (chạm), tính toán và lưu trữ lại, với 6 số thập phân, sẽ có một ảnh chụp mới (= lỗi tích lũy). Nếu tất cả các lỗi xảy ra theo cùng một hướng, sẽ có một lỗi lớn . Nếu thực hiện phép nhân tạm thời trên nó (ví dụ: tăng tỷ lệ, sau đó trừ và thu nhỏ lại), nó có thể phát triển lớn hơn nữa. Đừng phế liệu chính xác mà không có một rason tốt!
Bão tố

Câu trả lời:


160

Sử dụng các phần mở rộng không gian của MySQL với GIS.


24
Bạn có bất kỳ liên kết nào khác đến các ví dụ hoặc bất kỳ thông tin nào khác về cách tốt nhất để bắt đầu với chúng không?
Codebeef

6
MYSQL Spatial là một lựa chọn tốt, nhưng vẫn có giới hạn và cảnh báo đáng kể (tính đến 6). Xin vui lòng xem câu trả lời của tôi dưới đây ...
James Schek

1
@James Schek nói đúng. Thêm vào đó, MySQL thực hiện tất cả các tính toán của nó bằng hình học euclid, do đó, nó không đại diện cho trường hợp sử dụng trong thế giới thực cho lat / lng.
mkuech

FYI; Mysql chỉ hỗ trợ chỉ mục không gian với các bảng * .myisam, tức là công cụ ISAM. Liên kết: dev.mysql.com/doc/refman/5.0/en/creating-spatial-indexes.html
PodTech.io

Hãy xem bài viết này ở phần cuối Cập nhật: mysqlserverteam.com/mysql-5-7-and-gis-an-example
Jaspal Singh

149

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


11
Google rõ ràng không hiểu cách thức đặc tả FLOAT hoạt động: 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).
Alix Axel

2
Nhưng nếu bạn cần lưu trữ dưới dạng các giá trị phần tách rời từ [0, 180] thì sẽ đủ hơn, phải không?
Hrvoje Golcic

37
@AlixAxel Tôi nghĩ Google biết họ đang làm gì. Bởi vì nó khẳng định rằng: " . Với khả năng zoom hiện tại của Google Maps, bạn chỉ nên cần 6 chữ số chính xác sau khi thập phân đó sẽ cho phép các lĩnh vực lưu trữ 6 chữ số sau chữ số thập phân, cộng với 4 chữ số trước chữ số thập phân, ví dụ: - 123,456789 độ. ". Nếu không dấu được kiểm tra, mẫu sẽ là 1234,567890 . Vì vậy, không có vấn đề.
1,44mb

16
@AlixAxel Ông đang đếm các số trong chuỗi; không sử dụng tọa độ thực tế ...
Andrew Ellis

8
Sử dụng kiểu dữ liệu Doublecho Laravel
FooBar

133

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.


2
Tôi cần phải viết một bài bình luận mang tính xây dựng, tập trung vào nội dung của các bài đăng, vì vậy tôi sẽ nói rằng trong khi quan sát bảng chính xác như được cung cấp từ trang web của Rick James, tôi đã rất thích thú với mô tả độ phân giải "bọ chét trên một con chó" và cảm thấy nó xứng đáng với danh tiếng. Về mặt kỹ thuật, đây là một mô tả hữu ích hỗ trợ tôi trong việc quyết định sử dụng kiểu dữ liệu nào khi lưu trữ tọa độ để đo khoảng cách giữa hai địa chỉ, mà @Simon, tôi muốn cảm ơn bạn đã chia sẻ.
Sam_Butler

FWIW, việc sử dụng "SMALLINT thu nhỏ" của liên kết đó là không hiệu quả khủng khiếp. Câu trả lời của Oguzhan là cách tuyệt vời để lưu trữ long / lat với 7 chữ số sau dấu thập phân, trong một int có ký hiệu 4 byte. Độ chính xác tuyệt vời (~ 1cm) trong một kích thước nhỏ (4B).
ToolmakerSteve

74

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.


26
Nghỉ ngơi: Phần mở rộng không gian của MySQL không phù hợp để tính khoảng cách vòng tròn lớn giữa các điểm trên bề mặt trái đất được biểu thị bằng lat / long. Các hàm khoảng cách của chúng, v.v., chỉ hữu ích trên các tọa độ cartesian, phẳng, tọa độ.
O. Jones

71

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.


3
Cảm ơn bạn, điều này rất hữu ích. Cảm thấy kỳ lạ khi đọc tất cả những câu hỏi và câu trả lời từ năm 2008 nhận ra rằng nó đã 8 năm trước.
aexl

1
@TheSexiestManinJamaica - Trước IEEE 754-1985, phần cứng dấu phẩy động máy tính đã hỗn loạn. Thậm chí còn có trên máy a*bkhô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ỷ.
Rick James

42

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:

  • Tùy chọn có sẵn chính xác nhất là DOUBLE.
  • Loại nhìn thấy phổ biến nhất được sử dụng là 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ú:

  • Khi sử dụng POINTlớp, thứ tự của các đối số để lưu trữ tọa độ phải là POINT(latitude, longitude).
  • Có một cú pháp đặc biệt để tạo một chỉ mục không gian .
  • Lợi ích lớn nhất của việc sử dụng SDT là bạn có quyền truy cập vào Hàm phân tích không gian , ví dụ: tính khoảng cách giữa hai điểm ( ST_Distance) và xác định xem một điểm có nằm trong khu vực khác không ( ST_Contains).

2
Bạn sao chép phần đã dán của câu trả lời trước đó và "tóm tắt" với nội dung mà anh chàng đã tạo bảng đó không khuyến nghị : «Làm thế nào để THAM GIA? Chà, MySQL rất kén chọn. Vì vậy, FLOAT / NHÂN ĐÔI đã ra. Quyết định là ra. Vì vậy, chúng tôi bị mắc kẹt với một số bùn. Về cơ bản, chúng ta cần chuyển đổi Lat / Lng sang một số kích thước của INT và sử dụng PHẦN THAM GIA B RNG RANGE. » VÀ «FLOAT có 24 bit đáng kể; NHÂN ĐÔI có 53. (Chúng không hoạt động với THAM GIA nhưng được bao gồm để hoàn thiện. Thông thường mọi người sử dụng NHÂN ĐÔI mà không nhận ra mức độ quá mức của nó và mất bao nhiêu dung lượng.) »Chỉ cần để lại phần SDT bạn đã viết.
Armfoot

1
@Armfoot Nếu bạn nhìn vào thời gian chỉnh sửa, đó là câu trả lời khác được sao chép từ tôi. Không thành vấn đề: Tôi đang thấy Stack Overflow nhiều hơn về "ghi chú cho tương lai của tôi".
Gajus

1
Không có anh ấy đã không sao chép từ bạn, anh ấy chỉ dán bảng như bạn đã làm từ liên kết anh ấy tham chiếu vào năm 2014 (bài viết của bạn là từ năm 2015). Btw, tôi nghĩ bạn đã viết sai chính tả "Đặc biệt" khi bạn liên kết các kiểu dữ liệu không gian . Phần này bạn đã viết thực sự hữu ích cho những người muốn bắt đầu sử dụng chúng, nếu bạn thêm một số ví dụ như 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. ..
Armfoot

@Gajus - Tôi rất vinh dự khi hai bạn tìm thấy tài liệu của tôi! (Không, tôi không biết con bọ chét to như thế nào, nhưng tôi cảm thấy nó sẽ thu hút sự chú ý của ai đó.)
Rick James

Khi sử dụng lớp POINT, thứ tự của các đối số để lưu trữ tọa độ phải là POINT (kinh độ / X, vĩ độ / Y).
AndreyP


19

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.


DECIMALloạ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 FLOATvượt trội đáng kể DECIMAL.
Kondybas

1
@Kondybas - Vì chi phí chính trong cơ sở dữ liệu là tìm nạp các hàng, nên chênh lệch hiệu suất giữa float và thập phân không phải là vấn đề đáng lo ngại.
Rick James

14

Không cần phải đi xa, theo Google Maps, tốt nhất là FLOAT (10,6) cho lat và lng.


bạn lấy thông tin này ở đâu tôi có thể tìm thấy nó? chỉ trong trường hợp có gì đó thay đổi.
webfacer

1
@webfacer, Đó là trong "Tạo một bảng trong MySQL" phần ở đây: developers.google.com/maps/documentation/javascript/... ví dụ lat FLOAT( 10, 6 ) NOT NULL, lng FLOAT( 10, 6 ) NOT NULL
turrican_34

1
@webfacer, có vẻ như FLOATcú 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 FLOATmà 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.htmldev.mysql.com/doc/refman/5.5/en/floating-point- loại.html
turrican_34

7

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.


2
Nhân với một số lượng lớn (như một triệu) là tuyệt vời nếu bạn có nhiều dữ liệu vì các hoạt động số nguyên (ví dụ: truy xuất được lập chỉ mục) nhanh hơn nhiều so với số float.
Vịt Kaitlin Sherwood

@KaitlinDuckSherwood - bit là bit - Tôi không biết bất kỳ lý do nào mà float 32 bit sẽ chậm hơn khi truy xuất (được lập chỉ mục hoặc nói cách khác) so với số nguyên 32 bit. Ngay cả toán học trôi nổi ngày nay cũng đủ nhanh để trở thành một vấn đề. Tuy nhiên, tôi đồng ý với nhận xét để sử dụng hệ số nhân ngụ ý với một số nguyên: nó tối đa hóa độ chính xác mà bạn nhận được từ 32 bit. Một chút bằng chứng trong tương lai khi công nghệ cải thiện.
ToolmakerSteve

6

Trong một quan điểm hoàn toàn khác và đơn giản hơn:

  • nếu bạn đang dựa vào Google để hiển thị bản đồ, điểm đánh dấu, đa giác của mình, bất cứ điều gì, thì hãy để Google tính toán!
  • bạn lưu tài nguyên trên máy chủ của mình và bạn chỉ cần lưu trữ vĩ độ và kinh độ với nhau dưới dạng một chuỗi ( 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);
  • nếu Google trả về hơn 7 chữ số thập phân cho mỗi số, bạn vẫn có thể nhận được dữ liệu đó được lưu trữ trong chuỗi của mình, chỉ trong trường hợp bạn muốn phát hiện một số lần chạy trốn hoặc vi khuẩn trong tương lai ;
  • bạn có thể sử dụng ma trận khoảng cách hoặc thư viện hình học của họ để tính khoảng cách hoặc phát hiện các điểm trong một số khu vực nhất định với các cuộc gọi đơn giản như sau:google.maps.geometry.poly.containsLocation(latLng, bermudaTrianglePolygon))
  • có rất nhiều API "phía máy chủ" mà bạn có thể sử dụng (trong Python , Ruby on Rails , PHP , CodeIgniter , Laravel , Yii , Zend Framework , v.v.) sử dụng API Google Maps.

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.


Không tốt. OP cho biết anh ấy sẽ thực hiện các phép tính trên các cặp lat / lng - câu trả lời của bạn loại trừ điều đó
Yarin

4
@Yarin Đây là một câu hỏi phổ biến trong đó một vài (hoặc rất nhiều) người chỉ cần một câu trả lời về cách lưu trữ tọa độ theo nhu cầu của riêng họ (rất nhiều trong số họ có thể chỉ sử dụng bản đồ của Google). Downvote của bạn cho thấy câu trả lời này có thể không giúp được họ ... Bằng cách lưu trữ tọa độ trong một chuỗi, họ sẽ biết chính xác các giá trị ban đầu được cung cấp cho họ (ví dụ: bởi Google) sẽ giúp họ sau này nếu họ quyết định phát triển ứng dụng riêng và thực hiện các tính toán trên chúng. Vào thời điểm đó, họ vẫn sẽ có dữ liệu thô ban đầu chỉ vì họ không làm hỏng nó với các chuyển đổi.
Armfoot

4

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)


1
Bạn có thể vui lòng cung cấp kết quả kiểm tra của bạn với các chi tiết ở đây?
NameNotFoundException

4

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


1
MySQL thực hiện các hoạt động trongDOUBLE . MySQL cho phép bạn lưu trữ dữ liệu dưới dạng 4 byte FLOAThoặ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 FLOATcột.
Rick James

4

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:

  • Bạn thực hiện chuyển đổi pixel lat / lng sang mercator đắt tiền một lần thay vì mỗi lần bạn xử lý điểm
  • Lấy tọa độ ô vuông từ một bản ghi cho một mức thu phóng sẽ mất một lần thay đổi.
  • Lấy tọa độ pixel từ một bản ghi sẽ có một ca phải và một bit VÀ.
  • Các ca làm việc rất nhẹ đến mức thực tế khi thực hiện chúng bằng SQL, điều đó có nghĩa là bạn có thể thực hiện DISTINCT để chỉ trả về một bản ghi cho mỗi vị trí pixel, điều này sẽ cắt giảm các bản ghi số được trả về bởi phụ trợ, nghĩa là ít xử lý hơn mặt trước

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/


4

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ế.

  • Lưu trữ số liệu nguồn với độ chính xác ban đầu
  • Lưu trữ số liệu được tính từ nguồn trong độ chính xác mà phép tính xảy ra (ví dụ: nếu mã ứng dụng sử dụng gấp đôi, lưu trữ kết quả dưới dạng nhân đôi)

Đị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.


2
Bởi vì hầu hết các công cụ và ứng dụng GPS chỉ chính xác đến 6 chữ số thập phân. Lưu trữ dữ liệu với độ chính xác cao hơn nhiều so với những công cụ có thể đo gis.stackexchange.com/questions/8650/ mẹo
Yarin

1
@Yarin Có thực sự, nhưng bạn nói về các phép đo và GPS, không được đề cập trong câu hỏi. Chắc chắn là có con số chính xác hơn. Nhưng hãy xem xét GPS; giả sử một tập hợp dữ liệu nguồn của các số float 64 bit, đã chứa một sự không chính xác. 6 số thập phân có nghĩa là chụp một vĩ độ đến khoảng 11 cm gần nhất. Do đó, bằng cách chỉ lưu trữ dữ liệu (với 6 số thập phân), bạn mở ra cho độ chính xác 22 cm tiềm năng (nếu ban đầu là 11 cm). Tự nguyện, có thể thực hiện phép tính 64 bit trên đó, trước khi có thể lưu trữ lần thứ 3 - bây giờ là cửa sổ không chính xác 33 cm, + -16 cm. Âm thanh câm, imho.
Bão tố

@Rick James Tôi có khả năng lưu trữ nó dưới dạng 64 bit. 0.3333333333333333. Chúng ta nói chuyện geodata, phải không? "1/3" hiếm khi xuất hiện trong tự nhiên, nơi mọi thứ thường được đo, với độ chính xác hợp lý.
Bão tố

4

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

  • độ phút giây : 40 ° 26 46 N 79 ° 58 56 W
  • độ thập phân phút : 40 ° 26,767 ′ N 79 ° 58,933 W
  • độ thập phân 1 : 40.446 ° N 79.982 ° W
  • độ thập phân 2 : -32.60875, 21.27812
  • Một số định dạng nhà làm khác? Không ai cấm bạn tạo hệ thống tọa độ trung tâm của riêng bạn và lưu trữ nó dưới dạng tiêu đề và khoảng cách từ nhà của bạn. Điều này có thể có ý nghĩa đối với một số vấn đề cụ thể mà bạn đang làm việc.

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)


3

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


1
  1. Vĩ độ nằm trong khoảng từ -90 đến +90 (độ), do đó, DECIMAL (10, 8) là ổn đối với điều đó

  2. 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



-2

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.


1
cả hai kiểu float và thập phân đều có vị trí của chúng. như một quy tắc tự nhiên, số float có nghĩa là các biến vật lý và số thập phân dành cho các thực thể có thể đếm được (chủ yếu là tiền). tôi không hiểu lý do tại sao bạn thích số thập phân cho lat / long
Javier

1
Tôi cũng nghĩ float là tốt cho lat / long. Ít nhất là trên SQL Server (4byte, 7 chữ số).
Dragoljub určić

Float không chính xác như nó được ước tính, hồ chính xác trong một thời gian dài là gây tử vong! Nó có thể chỉ cho bạn một điểm hoàn toàn khác biệt trên toàn cầu.
HLGEM

2
Lỗi tối đa của kiểu dữ liệu float là đủ thấp nên đây không phải là vấn đề. Ý tôi là, bạn phải nhận thức được việc nhân / tích lũy lỗi với cả hai cách thực hiện.
Spidey

@HLGEM - Làm tròn đến một số vị trí thập phân cũng đưa bạn đến một vị trí khác trên toàn cầu. Câu hỏi là liệu điểm khác biệt đó có gần đến mức không thành vấn đề.
Rick James

-3

A FLOATsẽ 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


2
Bạn cần một kiểu dữ liệu tọa độ vĩ độ / kinh độ thực để dễ dàng toán học. Hãy tưởng tượng sự tiện lợi của một cái gì đó giống như tương đương với "select * from cửa hàng, nơi khoảng cách (stores.location, Vị trí của tôi) <5 dặm"
Kirk Strauser

1
Trước đây chưa từng nghe nói về các tiện ích mở rộng không gian, nghe có vẻ rất thuận tiện, trước đây đã từng làm việc trên một ứng dụng được kế thừa có khá nhiều tính toán liên quan đến địa lý, phải kiểm tra nó.
ConroyP

@ConroyP - Không. Câu nói đó chỉ ra rằng DECIMALđã có (trước 5.0.3) một số lỗi nhất định do sử dụng triển khai nổi.
Rick James
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.