492

Bearing in mind that I'll be performing calculations on lat / long pairs, what datatype is best suited for use with a MySQL database?

Cœur
  • 37,241
  • 25
  • 195
  • 267
Codebeef
  • 43,508
  • 23
  • 86
  • 119
  • 1
    I found this link very useful: http://howto-use-mysql-spatial-ext.blogspot.com/2007/11/using-circular-area-selection.html It may be a little bit older, but it contains a complete explanation including examples. – madc Jul 15 '11 at 17:03
  • Imho most people here do not understand what happens. As soon as the app code *touches* a number, provided one uses doubles (which most do), the number *turns into at most double precision*. Storing it then with even a million decimals won't do any good. Storing it with a **limited** number of decimals (eg. 6) *destroys* part of that precision and adds an accumulated error *each time it is re-written into the database*. A double carries ca 16 significant numbers, potentially all decimals. Scrapping off 10 of them creates an accumulated error over time. It is "floating point" for reason. Cont. – Stormwind Jan 25 '17 at 03:04
  • Cont: 6 decimals may be ok when storing a figure as acquired from an external source, unaltered and for the first time - as source material. But if performing a calculation on it even once, and storing it again, it is *dumb* to remove part of it's precision by enforcing a specific decimal format. Performing the calculation solely inside the server may be different (the server may or may not be using something else than doubles internally), and using worse numeric representations than double in the app calculation ofc decreses the need for storage precision equally. – Stormwind Jan 25 '17 at 03:11
  • Cont: IF the server stores the number with a *higher* precision, **despite** the claimed "9.6" (which i do not know if it does), then nothing of all this matters, and the format is purely a matter of convenience - has little to do with precision issues. But i would not be surprised if the server actually rounds any number into 6 decimal precision with that format. – Stormwind Jan 25 '17 at 03:26
  • 1
    Cont: Finally: For lat,lon's, the 6th decimal is a matter of *snapping* into a ca. 11-centimeter grid. Each time one reads (touches), calculates and stores again, with 6 decimals, there will be a new snapping (= accumulated error). If all errors happen to go in the same direction, there will be a *big* error. If performing temporary multiplications on it (eg. scale up, then subtract and scale down), it may grow even bigger. Do not scrap precision without a good rason! – Stormwind Jan 25 '17 at 03:35
  • @Stormwind - No, repeatedly fetching and storing (without any arithmetic) does not 'accumulate' errors _each_ time (maybe once). This claim applies to all numeric datatypes. – Rick James May 06 '18 at 03:22
  • (In MySQL, at least), `DECIMAL(9.6)` is stored _exactly_. Normal reading and writing involves _no_ corruption of the value. – Rick James May 06 '18 at 03:24
  • @Rick James Indeed, but the Q says "Bearing in mind that I'll be performing calculations on lat / long pairs"... Here: Say the db stores as integers. Grab 1 (a good source value) from it. Calc/scale up 51 %, write 1.51 to the db (say it stores it with 1000 decimals - doesn't matter). Re-grab the value, now you get 2. Add PI/2 (1.5707963267948966) and write 3.5707963267948966. Fetch, now you get 4. But a more exact value at t his stage would be 3.0807963267948963. Etc. Same with 6 decimals, it only happens at the 6th. IF the db works wthis way, the accuracy will be lost over time. – Stormwind May 07 '18 at 12:20
  • @Stormwind - The "calculation" is likely to be one for "distance". Even with the Haversine formula, the precision is good enough for finding the 'nearest 10 starbucks'. – Rick James May 07 '18 at 14:04
  • @Stormwind - another calculation experiment... Take a long list of dollars & cents, round each to the nearest dollar, add. Now compare with the exact sum. You might be surprised at how close the sum of the rounded values is to the exact value. The maximum error is N/2 dollars. But the distribution of the result is a bell curve, with a standard deviation of (IIRC) sqrt(N/12). – Rick James May 07 '18 at 14:09
  • @Stormwind - You are right about how float calculations _can_ build up. My claim is that they don't in normal lat/lng usage. – Rick James May 07 '18 at 14:11
  • True, it all depends on usage. There is a pretty nice analogy though: Take a 32-bit game physics engine (7 significants) and do small movement close to (0,0,0) - everything goes fine, movement is smooth. Now try to do the *identical* movement at (100000,0,0) - no go. The object will never leave it's place, not in a million iterations, or it will take big, ugly jumps. IF the calculation does repeated small adjustments on big values, the result may "hang". Big numeric values may take you to hell :-). Hence one option is to move the numeric space closer to zero. – Stormwind May 08 '18 at 16:14
  • @Codebeef I noticed that you've rollback **ajreal** edit. Yet, I feel it's better to have consistent pluralization, so I've partially re-applied the modification. If you prefer to have both plurals (_latitudes / longitudes_), I'll let you update it. – Cœur Dec 03 '18 at 04:58
  • @ToolmakerSteve - I don't think we disagree on anything? I was reacting on repeatedly writing to a database with limited precision (6 decimals!) as a part of a calculation. A (rather exaggerated) example would be to start counting days at new year - each day add 1 and keep in headmemory. But each friday round to closest 10 [= write to db with limited precision], write, fetch at saturday and continue adding ones to the fetched. At end of year, you'd have an accumulated 540 days :-). As 7, 17, 27 etc would round up to 10, 20, 30 etc. I fully agree with you to keep raw data at highest precision. – Stormwind Apr 08 '19 at 18:06
  • @ToolmakerSteve - Admitted I'm paranoid. For me, "possible" is almost the same as "inevitable". Example: Buffer overruns were never intended, but yet we've seen them for 40 years, because they were possible. But note: The original Q says "perform calculations on" which is a very round statement. We don't know what it means. For me, *potentially* multiple db r/w's. And If it snaps to west (in the 11 cm grid) at 60% of the writes and to east 40 %... (no matter how precise the CPU was) and you do it a 1000 times... Why invite that? Np, your claims are valid too - it depends! :-) – Stormwind Apr 09 '19 at 12:00
  • @Stormwind - Ahhh, I just reread what you said more carefully. I see your point now, and agree: if someone reads/writes geo data in a way that always rounds to 6 digits, they will soon run into significant accumulated errors. I'm so used to just specifying "float" that I forgot about the option to specify # digits. Its good to warn people **not to specify # digits, just choose float (~26 bits of precision) or double (lots of precision, costs 2x memory)**, unless they understand the consequences of limiting digits. (I've deleted all my earlier comments, because they will only confuse people.) – ToolmakerSteve Apr 09 '19 at 14:35

22 Answers22

189

Basically it depends on the precision you need for your locations. Using DOUBLE you'll have a 3.5nm precision. DECIMAL(8,6)/(9,6) goes down to 16cm. FLOAT is 1.7m...

This very interesting table has a more complete list: 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
starball
  • 20,030
  • 7
  • 43
  • 238
Simon
  • 3,580
  • 2
  • 23
  • 24
  • 7
    I need to write a constructive, detailed commentary focused on the contents of the posts, so I will say that while observing the accuracy table as provided from Rick James' website, I was mildly amused at the resolution description "fleas on a dog" and felt it worthy of kudos. Technically speaking, this was a helpful depiction that assisted me in deciding what datatype to use when storing coordinates for measuring the distance between two addresses, which, @Simon, I'd like to thank you for sharing. – Sam_Butler Jun 25 '17 at 22:30
  • 1
    FWIW, that link's use of "SMALLINT scaled" is horrendously inefficient. [Oguzhan's answer](https://stackoverflow.com/a/37127245/199364) is great way to store long/lat with **7** digits after decimal point, in a 4-byte signed int. Great precision (~1cm) in a small size (4B). – ToolmakerSteve Mar 31 '20 at 20:51
  • Is the Bytes column accurate? The [MySQL reference](https://dev.mysql.com/doc/refman/8.0/en/storage-requirements.html) says `DOUBLE` is 8 bytes. – JakeStrang Mar 07 '21 at 23:14
  • 2
    Going to answer my own question here, I'm guessing they've doubled the byte count for each type to account for latitude + longitude (ie. `2 doubles == 16 bytes`). – JakeStrang Mar 07 '21 at 23:19
173

Use MySQL's spatial extensions with GIS.

Kirk Strauser
  • 30,189
  • 5
  • 49
  • 65
  • 8
    MYSQL Spatial is a good option, but still has significant limits and caveats (as of 6). Please see my answer below... – James Schek Oct 02 '08 at 15:43
  • 1
    @James Schek is right. Plus, MySQL does all it's calculations using euclidean geometry, so it doesn't represent a real-world use case for lat/lng. – mkuech May 14 '13 at 14:53
  • FYI; Mysql support spatial index only with *.myisam tables, i.e. the ISAM engine. Link: http://dev.mysql.com/doc/refman/5.0/en/creating-spatial-indexes.html – PodTech.io Jan 15 '17 at 05:46
  • Have a look at this article in the end Update part: http://mysqlserverteam.com/mysql-5-7-and-gis-an-example/ – Jaspal Singh Jun 22 '17 at 15:15
  • 1
    How come this answer got so many vote with single line answer without example! – Sazzad Hissain Khan Mar 22 '20 at 19:15
160

Google provides a start to finish PHP/MySQL solution for an example "Store Locator" application with Google Maps. In this example, they store the lat/lng values as "Float" with a length of "10,6"

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

Ted Avery
  • 5,639
  • 3
  • 30
  • 29
  • 11
    Google clearly doesn't understand how the FLOAT specification works: `FLOAT(10,6)` leaves 4 digits for the integer part of the coordinate. And no, the sign doesn't count - that comes from the (un)signed attribute. – Alix Axel May 09 '13 at 09:54
  • 3
    But if you need to store as integral part values from [0, 180] should be more then enough, right? – Hrvoje Golcic Jan 15 '14 at 20:05
  • 43
    @AlixAxel I think Google knows what it is doing. Because it states that: "_With the current zoom capabilities of Google Maps, you should only need 6 digits of precision after the decimal. That will let the fields store 6 digits after the decimal, plus up to 4 digits before the decimal, e.g. **-123.456789** degrees._". If unsigned is checked the pattern will be **1234,567890**. So no problems. – tozlu Feb 19 '14 at 10:58
  • 18
    @AlixAxel He is counting off the the numbers in the sequence; not using an actual coordinate... – Andrew Ellis May 27 '14 at 21:57
  • 10
    Using datatype `Double` for Laravel – FooBar Nov 11 '14 at 12:07
  • 1
    According to [MySql](http://dev.mysql.com/doc/refman/5.7/en/floating-point-types.html): _"MySQL permits a nonstandard syntax: FLOAT(M,D) ... Here, (M,D) means than values can be stored with up to M digits in total, of which D digits may be after the decimal point. For example, a column defined as FLOAT(7,4) will look like -999.9999 when displayed."_ Using this example you would only need *FLOAT(9,6)* to store the coord -179.999999. – Ben Davison Jan 04 '17 at 17:40
  • 1
    Using `float` instead of `double` leads to inaccuries of around 1-2 meters. Just tested it myself, it blew up my entire application. Switching to double now. – phil294 Jan 28 '17 at 16:56
  • In MySQL, the 'sign' does not take a digit. So `(10,6)` is overkill on the integer side. (It happens not to matter, since 4 digits takes 2 bytes, and so does 3 digits.) – Rick James May 06 '18 at 03:28
  • 1
    @BenDavison - Since `FLOAT` has only about 7 'significant' digits, so `-179.999999` gets mangled exactly `-180.` `-179.99999` turns into about `-179.99998474` because there are only 24 bits of precision in IEEE-754's Float. – Rick James May 06 '18 at 03:35
76

When I did this for a navigation database built from ARINC424 I did a fair amount of testing and looking back at the code, I used a DECIMAL(18,12) (Actually a NUMERIC(18,12) because it was firebird).

Floats and doubles aren't as precise and may result in rounding errors which may be a very bad thing. I can't remember if I found any real data that had problems - but I'm fairly certain that the inability to store accurately in a float or a double could cause problems

The point is that when using degrees or radians we know the range of the values - and the fractional part needs the most digits.

The MySQL Spatial Extensions are a good alternative because they follow The OpenGIS Geometry Model. I didn't use them because I needed to keep my database portable.

Richard Harrison
  • 19,247
  • 4
  • 40
  • 67
  • 5
    Thank you, this was helpful. Feels weird reading all these questions and answers from 2008 realising it was already 8 years ago. – ᴍᴇʜᴏᴠ Nov 08 '16 at 22:03
  • 3
    @TheSexiestManinJamaica - Before IEEE 754-1985, computer floating-point hardware was chaotic. There was even on machine where `a*b` was not equal `b*a` (for some values). There were many examples somewhat like: `2+2 = 3.9999`. The standard cleaned up a lot of mess, and was 'rapidly' adopted by virtually every piece of hardware and software. So, this discussion has been valid, not just since 2008, but for a third of a century. – Rick James May 06 '18 at 03:42
76

MySQL's Spatial Extensions are the best option because you have the full list of spatial operators and indices at your disposal. A spatial index will allow you to perform distance-based calculations very quickly. Please keep in mind that as of 6.0, the Spatial Extension is still incomplete. I am not putting down MySQL Spatial, only letting you know of the pitfalls before you get too far along on this.

If you are dealing strictly with points and only the DISTANCE function, this is fine. If you need to do any calculations with Polygons, Lines, or Buffered-Points, the spatial operators do not provide exact results unless you use the "relate" operator. See the warning at the top of 21.5.6. Relationships such as contains, within, or intersects are using the MBR, not the exact geometry shape (i.e. an Ellipse is treated like a Rectangle).

Also, the distances in MySQL Spatial are in the same units as your first geometry. This means if you're using Decimal Degrees, then your distance measurements are in Decimal Degrees. This will make it very difficult to get exact results as you get furthur from the equator.

James Schek
  • 17,844
  • 7
  • 51
  • 64
  • 30
    Restating: MySQL Spatial Extensions aren't suitable for calculating great circle distances between points on the surface of the earth represented by lat/long. Their distance functions, etc, are only useful on cartesian, planar, coordinates. – O. Jones Feb 11 '12 at 00:17
  • 2
    The above highly rated note seems to be obsolete for a few years now. Since mysql 5.7 there is `ST_Distance_Sphere` to do exactly that. – Ecuador Dec 06 '21 at 22:51
47

Depends on the precision that you require.

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

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

To summarise:

  • The most precise available option is DOUBLE.
  • The most common seen type used is DECIMAL(8,6)/(9,6).

As of MySQL 5.7, consider using Spatial Data Types (SDT), specifically POINT for storing a single coordinate. Prior to 5.7, SDT does not support indexes (with exception of 5.6 when table type is MyISAM).

Note:

  • When using POINT class, the order of the arguments for storing coordinates must be POINT(latitude, longitude).
  • There is a special syntax for creating a spatial index.
  • The biggest benefit of using SDT is that you have access to Spatial Analyses Functions, e.g. calculating distance between two points (ST_Distance) and determining whether one point is contained within another area (ST_Contains).
Gajus
  • 69,002
  • 70
  • 275
  • 438
  • 4
    You copy pasted part of a previous answer and "summarise" with something the guy that created that table **did not recommend**: «How to PARTITION? Well, MySQL is very picky. So FLOAT/DOUBLE are out. DECIMAL is out. So, we are stuck with some kludge. Essentially, we need to convert Lat/Lng to some size of INT and use PARTITION BY RANGE.» AND «FLOAT has 24 significant bits; DOUBLE has 53. (They don't work with PARTITIONing but are included for completeness. **Often people use DOUBLE without realizing how much an overkill it is**, and how much space it takes.)» Just leave the SDT part you wrote. – Armfoot Nov 26 '15 at 11:51
  • 1
    @Armfoot If you look at the time of the edits, it is the other answer that copied from me. Not that it matters: I am seeing Stack Overflow more of a "notes for the future me". – Gajus Nov 26 '15 at 12:00
  • 2
    No he didn't copy from you, he just pasted the table like you did from the link he referenced on 2014 (your post is from 2015). Btw, I think you misspelled "Special" when you linked **Spatial** Data Types. This part you wrote is actually useful for people who want to start using them, if you add some more examples like `CREATE TABLE geom (g GEOMETRY NOT NULL, SPATIAL INDEX(g)) ENGINE=MyISAM;` and the warning about SDT limitations, as [James mentioned](http://stackoverflow.com/a/163084/1326147), perhaps your answer will be more concise and precise in helping other people as well... – Armfoot Nov 26 '15 at 12:07
  • @Gajus - I'm honored that two of you found my document! (No, I don't know how big a flea is, but I felt it would get someone's attention.) – Rick James May 06 '18 at 03:46
  • 1
    When using POINT class, the order of the arguments for storing coordinates must be POINT(longitude/X, latitude/Y). – AndreyP Mar 01 '19 at 16:42
  • @AndreyP - It appears that `POINT()` stores X and Y in `DOUBLE`. This is further substantiated by the size of a `POINT`. Down with fleas! – Rick James May 02 '19 at 22:01
37

Based on this wiki article http://en.wikipedia.org/wiki/Decimal_degrees#Accuracy the appropriate data type in MySQL is Decimal(9,6) for storing the longitude and latitude in separate fields.

saeed khalafinejad
  • 1,139
  • 9
  • 22
29

Use DECIMAL(8,6) for latitude (90 to -90 degrees) and DECIMAL(9,6) for longitude (180 to -180 degrees). 6 decimal places is fine for most applications. Both should be "signed" to allow for negative values.

Alexander Holsgrove
  • 1,795
  • 3
  • 25
  • 54
  • `DECIMAL` type is intended for financial calculations where no `floor/ceil` is accepted. Plain `FLOAT` significantly outperforms `DECIMAL`. – Kondybas Jul 28 '17 at 22:21
  • 4
    @Kondybas - Since the main cost in a database is fetching rows, the performance difference between float and decimal should not be a concern. – Rick James May 06 '18 at 03:49
22

No need to go far, according to Google Maps, the best is FLOAT(10,6) for lat and lng.

Mariano Peinador
  • 630
  • 9
  • 14
  • where did you get this information i can´t find it? just in case something changes. – webfacer Oct 20 '19 at 02:57
  • 4
    @webfacer, It's in the "Creating a table in MySQL" section here: https://developers.google.com/maps/documentation/javascript/mysql-to-maps e.g `lat FLOAT( 10, 6 ) NOT NULL,` `lng FLOAT( 10, 6 ) NOT NULL` – turrican_34 Oct 27 '19 at 12:55
  • 4
    @webfacer, It looks like that `FLOAT` syntax is deprecated as of `mysql 8.0.17`. Mysql now recommends to just use `FLOAT` without any precision parameters https://dev.mysql.com/doc/refman/8.0/en/numeric-type-overview.html and https://dev.mysql.com/doc/refman/5.5/en/floating-point-types.html – turrican_34 Oct 27 '19 at 13:29
  • And, MySQL has always ignored the numbers in parentheses that optionally adorn FLOAT and DOUBLE declarations. – O. Jones Nov 14 '21 at 00:04
  • @webfacer the link does not has that section any more... – burf May 18 '22 at 13:18
  • Confirmation that [M,D] extension options are deprecated as of 8.0.17: https://dev.mysql.com/doc/refman/8.0/en/mysql-nutshell.html#mysql-nutshell-deprecations – TonyG Mar 14 '23 at 17:39
8

We store latitude/longitude X 1,000,000 in our oracle database as NUMBERS to avoid round off errors with doubles.

Given that latitude/longitude to the 6th decimal place was 10 cm accuracy that was all we needed. Many other databases also store lat/long to the 6th decimal place.

  • 2
    Multiplying by some large number (like a million) is great if you have a lot of data because integer operations (e.g. indexed retrieval) are much much faster than floats. – Kaitlin Duck Sherwood Apr 22 '16 at 03:43
  • @KaitlinDuckSherwood - bits are bits - I'm not aware of any reason a 32-bit float would be slower for retrieval (indexed or otherwise) than a 32-bit integer. Even floating math these days is fast enough to be a non-issue. Nevertheless, I agree with the comment to use implied multiplier with an integer: it maximizes the precision you get out of 32 bits. A bit of future-proofing as technology improves. – ToolmakerSteve Apr 07 '19 at 15:32
7

TL;DR

Use FLOAT(8,5) if you're not working in NASA / military and not making aircrafts navi systems.


To answer your question fully, you'd need to consider several things:

Format

  • degrees minutes seconds: 40° 26′ 46″ N 79° 58′ 56″ W
  • degrees decimal minutes: 40° 26.767′ N 79° 58.933′ W
  • decimal degrees 1: 40.446° N 79.982° W
  • decimal degrees 2: -32.60875, 21.27812
  • Some other home-made format? Noone forbids you from making your own home-centric coordinates system and store it as heading and distance from your home. This could make sense for some specific problems you're working on.

So the first part of the answer would be - you can store the coordinates in the format your application uses to avoid constant conversions back and forth and make simpler SQL queries.

Most probably you use Google Maps or OSM to display your data, and GMaps are using "decimal degrees 2" format. So it will be easier to store coordinates in the same format.

Precision

Then, you'd like to define precision you need. Of course you can store coordinates like "-32.608697550570334,21.278081997935146", but have you ever cared about millimeters while navigation to the point? If you're not working in NASA and not doing satellites or rockets or planes trajectories, you should be fine with several meters accuracy.

Commonly used format is 5 digits after dots which gives you 50cm accuracy.

Example: there is 1cm distance between X,21.2780818 and X,21.2780819. So 7 digits after dot give you 1/2cm precision and 5 digits after dot will give you 1/2 meters precision (because minimal distance between distinct points is 1m, so rounding error cannot be more than half of it). For most civil purposes it should be enough.

degrees decimal minutes format (40° 26.767′ N 79° 58.933′ W) gives you exactly the same precision as 5 digits after dot

Space-efficient storage

If you've selected decimal format, then your coordinate is a pair (-32.60875, 21.27812). Obviously, 2 x (1 bit for sign, 2 digits for degrees and 5 digits for exponent) will be enough.

So here I'd like to support Alix Axel from comments saying that Google suggestion to store it in FLOAT(10,6) is really extra, because you don't need 4 digits for main part (since sign is separated and latitude is limited to 90 and longitude is limited to 180). You can easily use FLOAT(8,5) for 1/2m precision or FLOAT(9,6) for 50/2cm precision. Or you can even store lat and long in separated types, because FLOAT(7,5) is enough for lat. See MySQL float types reference. Any of them will be like normal FLOAT and equal to 4 bytes anyway.

Usually space is not an issue nowadays, but if you want to really optimize the storage for some reason (Disclaimer: don't do pre-optimization), you may compress lat(no more than 91 000 values + sign) + long(no more than 181 000 values + sign) to 21 bits which is significantly less than 2xFLOAT (8 bytes == 64 bits)

The Godfather
  • 4,235
  • 4
  • 39
  • 61
  • 2
    It's not just NASA that requires high precision. Civil engineers and builders need it too, or you get big puddles in parking lots and buildings where all the marbles roll into a corner. But surveyors don't rely on standard phone-grade GPS. For standard GPS, FLOAT (IEEE488 32-bit floating point format) has more than enough precision. – O. Jones Nov 14 '21 at 00:02
6

In a completely different and simpler perspective:

  • if you are relying on Google for showing your maps, markers, polygons, whatever, then let the calculations be done by Google!
  • you save resources on your server and you simply store the latitude and longitude together as a single string (VARCHAR), E.g.: "-0000.0000001,-0000.000000000000001" (35 length and if a number has more than 7 decimal digits then it gets rounded);
  • if Google returns more than 7 decimal digits per number, you can get that data stored in your string anyway, just in case you want to detect some flees or microbes in the future;
  • you can use their distance matrix or their geometry library for calculating distances or detecting points in certain areas with calls as simple as this: google.maps.geometry.poly.containsLocation(latLng, bermudaTrianglePolygon))
  • there are plenty of "server-side" APIs you can use (in Python, Ruby on Rails, PHP, CodeIgniter, Laravel, Yii, Zend Framework, etc.) that use Google Maps API.

This way you don't need to worry about indexing numbers and all the other problems associated with data types that may screw up your coordinates.

Community
  • 1
  • 1
Armfoot
  • 4,663
  • 5
  • 45
  • 60
  • 1
    No good. OP said he'd be performing calculations on the lat/lng pairs - your answers preclude that – Yarin May 15 '16 at 17:42
6
  1. Latitudes range from -90 to +90 (degrees), so DECIMAL(10, 8) is ok for that

  2. longitudes range from -180 to +180 (degrees) so you need DECIMAL(11, 8).

Note: The first number is the total number of digits stored, and the second is the number after the decimal point.

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

mahfuz
  • 2,728
  • 20
  • 18
5

While it isn't optimal for all operations, if you are making map tiles or working with large numbers of markers (dots) with only one projection (e.g. Mercator, like Google Maps and many other slippy maps frameworks expect), I have found what I call "Vast Coordinate System" to be really, really handy. Basically, you store x and y pixel coordinates at some way-zoomed-in -- I use zoom level 23. This has several benefits:

  • You do the expensive lat/lng to mercator pixel transformation once instead of every time you handle the point
  • Getting the tile coordinate from a record given a zoom level takes one right shift.
  • Getting the pixel coordinate from a record takes one right shift and one bitwise AND.
  • The shifts are so lightweight that it is practical to do them in SQL, which means you can do a DISTINCT to return only one record per pixel location, which will cut down on the number records returned by the backend, which means less processing on the front end.

I talked about all this in a recent blog post: http://blog.webfoot.com/2013/03/12/optimizing-map-tile-generation/

4

MySQL uses double for all floats ... So use type double. Using float will lead to unpredictable rounded values in most situations

mlinuxgada
  • 580
  • 3
  • 7
  • 1
    MySQL _performs operations in `DOUBLE`_. MySQL lets you _store_ data as either a 4-byte `FLOAT` or an 8-byte `DOUBLE`. So, there is likely to be a loss of precision when storing an expression into a `FLOAT` column. – Rick James May 06 '18 at 03:54
4

depending on you application, i suggest using FLOAT(9,6)

spatial keys will give you more features, but in by production benchmarks the floats are much faster than the spatial keys. (0,01 VS 0,001 in AVG)

Torben Brodt
  • 117
  • 4
4

The spatial functions in PostGIS are much more functional (i.e. not constrained to BBOX operations) than those in the MySQL spatial functions. Check it out: link text

Dylan
  • 109
  • 2
0

I suggest you use Float datatype for SQL Server.

Anderson
  • 89
  • 3
0

The ideal datatype for storing Lat Long values is decimal(9,6)

This is at approximately 10cm precision, whilst only using 5 bytes of storage.

e.g. CAST(123.456789 as decimal(9,6))

ukgav
  • 109
  • 1
  • 3
0

GeoLocationCoordinates returns a double data type representing the position's latitude and longitude in decimal degrees. You can try using double.

Edd Michira
  • 101
  • 1
  • 3
-2

Lat Long calculations require precision, so use some type of decimal type and make the precision at least 2 higher than the number you will store in order to perform math calculations. I don't know about the my sql datatypes but in SQL server people often use float or real instead of decimal and get into trouble because these are are estimated numbers not real ones. So just make sure the data type you use is a true decimal type and not a floating decimal type and you should be fine.

BCS
  • 75,627
  • 68
  • 187
  • 294
HLGEM
  • 94,695
  • 15
  • 113
  • 186
  • 1
    both float and decimal types have their place. as a rule of thumb, floats mean physical variables, and decimals are for countable entities (mostly money). i don't see why you'd prefer decimal for lat/long – Javier Oct 01 '08 at 19:26
  • 1
    I also think float is fine for lat/long. At least on SQL Server (4bytes, 7 digits). – Dragoljub Ćurčić May 21 '09 at 16:46
  • Float is not exact it is estimated, lake of exactness in a lat long is fatal! It could point you to a completely differnt spot on the globe. – HLGEM May 21 '09 at 17:26
  • 2
    The maximum error of float datatypes is low enough that this shouldn't be a problem. I mean, you have to be aware of error multiplication/accumulation with both implementations anyway. – Spidey Apr 16 '12 at 21:12
  • @HLGEM - Rounding to some number of _decimal_ places also lands you in a different spot on the globe. The question is whether that different spot is so close that it does not matter. – Rick James May 06 '18 at 03:59
-4

A FLOAT should give you all of the precision you need, and be better for comparison functions than storing each co-ordinate as a string or the like.

If your MySQL version is earlier than 5.0.3, you may need to take heed of certain floating point comparison errors however.

Prior to MySQL 5.0.3, DECIMAL columns store values with exact precision because they are represented as strings, but calculations on DECIMAL values are done using floating-point operations. As of 5.0.3, MySQL performs DECIMAL operations with a precision of 64 decimal digits, which should solve most common inaccuracy problems when it comes to DECIMAL columns

ConroyP
  • 40,958
  • 16
  • 80
  • 86
  • 2
    You need a real latitude/longitude coordinate datatype for easy math. Imagine the convenience of something like the equivalent of "select * from stores where distance(stores.location, mylocation) < 5 miles" – Kirk Strauser Oct 01 '08 at 19:23
  • 1
    Hadn't heard of the spatial extensions before, that does sound very convenient alright, having previously worked on an inherited app that does quite a bit of geo-related calculations, must check it out. – ConroyP Oct 01 '08 at 19:33
  • @ConroyP - No. That quote is pointing out that `DECIMAL` had (before 5.0.3) certain errors due to the use of floating implementation. – Rick James May 06 '18 at 04:01