8 दशमलव स्थानों के साथ अक्षांश / देशांतर के लिए MySQL डेटा प्रकार का क्या उपयोग किया जाना चाहिए?


257

मैं मानचित्र डेटा के साथ काम कर रहा हूं, और Latitude/Longitude8 दशमलव स्थानों तक फैला हुआ हूं । उदाहरण के लिए:

Latitude 40.71727401
Longitude -74.00898606

मैंने Google दस्तावेज़ में देखा जो उपयोग करता है:

lat FLOAT( 10, 6 ) NOT NULL,  
lng FLOAT( 10, 6 ) NOT NULL

हालाँकि, उनके दशमलव स्थान केवल 6 पर जाते हैं।
क्या मुझे FLOAT(10, 8)इस डेटा को संग्रहीत करने पर विचार करने के लिए उपयोग करना चाहिए या कोई अन्य विधि है, इसलिए यह सटीक है। इसका उपयोग मानचित्र गणनाओं के साथ किया जाएगा। धन्यवाद!


4
क्या आपको वास्तव में 1.1 मिमी तक पृथ्वी की सतह पर मूल्यों को संग्रहीत करने की आवश्यकता है ? यदि ऐसा है, तो आप पहली बार में लैट्लिंग में मान क्यों जमा कर रहे हैं?
ओवलेंग


2
गूगल डॉक्टर गलत है! floatप्रकार का उपयोग न करें - जिसमें केवल 7 अंक सटीक हैं। आपको कम से कम 9 की आवश्यकता है। आपको 10 की आवश्यकता नहीं है - कुछ अजीब कारण के लिए डॉक्स एक अंक के रूप में माइनस साइन की गणना करते हैं। या तो: double(9,6)या decimal(9,6)
एरियल

5
आपको वास्तव में कितनी सटीकता की आवश्यकता है? 6 दशमलव स्थानों आप दो लोग एक दूसरे को चूमने भेद करने के लिए पर्याप्त सटीक देता है। 8 अपनी उंगलियों को अलग बता सकते हैं। FLOATदो आइटम 1.7 एम (5.6 फीट) को अलग करता है। उन सभी को "मानचित्र" अनुप्रयोगों के लिए बहुत अधिकता है!
रिक जेम्स

जवाबों:


594

DECIMAL सटीक अंकगणित के लिए MySQL डेटा-प्रकार है। FLOAT के विपरीत इसकी सटीक संख्या के किसी भी आकार के लिए तय की जाती है, इसलिए FLOAT के बजाय इसका उपयोग करके आप अपनी गणना करते समय सटीक त्रुटियों से बच सकते हैं। यदि आप केवल गणना के बिना संख्याओं को संग्रहीत और पुनः प्राप्त कर रहे थे तो व्यवहार में FLOAT सुरक्षित होगा, हालांकि DECIMAL का उपयोग करने में कोई नुकसान नहीं है। गणना के साथ FLOAT अभी भी ज्यादातर ठीक है, लेकिन 8d.p के लिए पूरी तरह से निश्चित है। परिशुद्धता आपको DECIMAL का उपयोग करना चाहिए।

अक्षांश -90 से +90 (डिग्री) तक है, इसलिए DECIMAL (10, 8) उसके लिए ठीक है, लेकिन अनुदैर्ध्य -180 से +180 (डिग्री) तक है, इसलिए आपको DECIMAL (11, 8) की आवश्यकता है। पहली संख्या संग्रहीत अंकों की कुल संख्या है, और दूसरी दशमलव बिंदु के बाद की संख्या है।

संक्षेप में: lat DECIMAL(10, 8) NOT NULL, lng DECIMAL(11, 8) NOT NULL

यह बताता है कि MySQL फ्लोटिंग-पॉइंट डेटा-प्रकारों के साथ कैसे काम करता है।

अद्यतन: MySQL स्थानिक डेटा प्रकारों का समर्थन करता है और Pointएक एकल-मूल्य प्रकार है जिसका उपयोग किया जा सकता है। उदाहरण:

CREATE TABLE `buildings` (
  `coordinate` POINT NOT NULL,
  /* Even from v5.7.5 you can define an index for it */
  SPATIAL INDEX `SPATIAL` (`coordinate`)
) ENGINE=InnoDB;

/* then for insertion you can */
INSERT INTO `buildings` 
(`coordinate`) 
VALUES
(POINT(40.71727401 -74.00898606));

11
शायद मेरे जवाब ने सटीक शब्द का दुरुपयोग किया, क्योंकि DECIMAL अभी भी उतना ही सटीक है जितना कि आप इसे दे रहे हैं। मेरे मुद्दा यह है कि यह था है कि सही। बेशक कुछ गणना त्रुटि का विस्तार करती है। अगर मेरे पास एक DECMIAL x है तो पाप (x ^ 100) बंद होने जा रहा है। लेकिन अगर (DECIMAL (10, 8) या FLOAT (10, 8) का उपयोग करके) मैं 0.3 / 3 की गणना करता हूं, तो DECIMAL 0.100000000000 (सही) देता है, और फ्लोट 0.100000003974 (8dp को सही, लेकिन गुणा करने पर गलत होगा) देता है। मैं समझता हूं कि मुख्य अंतर यह है कि संख्याओं को कैसे संग्रहीत किया जाता है। DECIMAL दशमलव अंकों को संग्रहीत करता है, जहाँ FLOAT द्विआधारी सन्निकटन को संग्रहीत करता है।
गंडालिटर

1
परिशुद्धता के संदेह से, मैं DOUBLE जा रहा हूं।
रटाटा टाटा

1
8 दशमलव स्थान 1.1 मिमी (इंच के 1/16 से कम) सटीक है। आपको कभी अक्षांश और देशांतर की आवश्यकता क्यों होगी?
vartec

1
लगता है कि फेसबुक 12 डिसमिल तक और 13 लैंग के लिए इस्तेमाल करता है। vartec ने लिखा है कि 8 दशमलव 1.1 मिमी के बराबर है; 7 और 6 के बारे में क्या? (मैं गणित में अच्छा नहीं हूं)। मैं अभी के लिए डबल का उपयोग कर रहा हूं, लेकिन यह जांचना चाहूंगा कि क्या मैं प्रकार बदलकर दूरी की गणना में लाभ प्राप्त कर सकता हूं। धन्यवाद।
एलेन ज़ेलिंक

4
इस प्रश्न के उत्तर ( gis.stackexchange.com/questions/8650/… ) अक्षांश और देशांतर के दशमलव स्थानों की विभिन्न संख्याओं के साथ मिलने वाली शुद्धता के बारे में जानकारी देते हैं।
गंडाल्टर

16

इसके अतिरिक्त, आप देखेंगे कि floatमान गोल हैं।

// उदाहरण: दिए गए मान 41.0473112,29.0077011

फ्लोट (11,7) | दशमलव (11,7)
---------------------------
41.0473099 | 41.0473112
29.0077019 | 29.0077011


1
आप doubleडेटा प्रकार का उपयोग कर सकते हैं , जिसमें आवश्यक सटीकता है।
एरियल

1
मुझे एक उपयोगी मानचित्र दिखाएं जो उन दो बिंदुओं को अलग कर सके। मेरा दावा है कि दोनों प्रतिनिधित्व "अनावश्यक रूप से सटीक" हैं।
रिक जेम्स

14

प्रवास के लिए लारवल में प्रयुक्त दशमलव स्तंभ प्रकार

$table->decimal('latitude', 10, 8);
$table->decimal('longitude', 11, 8);

अधिक जानकारी के लिए उपलब्ध कॉलम प्रकार देखें


7

आप हस्ताक्षरित पूर्णांक के रूप में अपना डेटा-प्रकार सेट कर सकते हैं। जब आप SQL में कोऑर्डिनेट करते हैं तो आप lat * 10000000 और long * 10000000 के रूप में सेट कर सकते हैं। और जब आप दूरी / त्रिज्या के साथ चयन करते हैं तो आप स्टोरेज निर्देशांक को 10000000 में विभाजित करेंगे। मैं इसे 300K पंक्तियों के साथ टेस्ट कर रहा था, क्वेरी रिस्पांस टाइम अच्छा है। (2 x 2.67GHz CPU, 2 GB RAM, MySQL 5.5.49)


कौन सा तेज है? ऐसा करना या फ्लोट या दशमलव का उपयोग करना?
दिनदिनीज

1
@ डिनिडिनिज़ - गति का अंतर बहुत छोटा है। फ़ेचिंग पंक्तियाँ किसी भी डेटाबेस कार्रवाई के समय को अभिभूत करती हैं।
रिक जेम्स

10000000 क्यों? यदि दशमलव मान के बाद इसमें 6 से अधिक अंक हों तो क्या होगा? या यह हमेशा 6 दशमलव अंक लौटाएगा।
महबूब मोरशेड

@MahbubMorshed - आपका मतलब 7 अंक है - इसमें 7 शून्य अंक दिखाए गए हैं। लेकिन हां, यह तकनीक हमेशा 7 अंकों का संग्रह कर रही है, अब और नहीं। (यदि 4-बाइट पूर्णांक का उपयोग करते हैं, तो 7 अंक से अधिक गुणक नहीं बढ़ा सकता है क्योंकि देशांतर मान 180 के रूप में बड़ा हो सकता है, और हस्ताक्षरित पूर्णांक से अधिक बहने से बचना चाहिए।) यह एकल-सटीक फ़्लोट में संग्रहीत करने की तुलना में 2 अंकों अधिक सटीक है। जिसमें केवल देशांतर मानों पर लगभग 5 अंक-से-सही-दशमलव-बिंदु है। ); (१७९.९९९९६ १७९.९९९९८ से दूर सुरक्षित रूप से है १७९.९९९९८ और १७९.९९९९७ एक ही नाव मूल्य के रूप में संग्रहीत कर सकते हैं)।
ToolmakerSteve

यह सबसे अच्छा व्यापार-बंद है जो मैंने कहीं भी देखा है। यहां मैं उपयोग करने के लिए और यह पुष्टि करने के लिए कोड दिखाता हूं कि यह दशमलव बिंदु के बाद 7 अंक प्रदान करता है, 4-बाइट पर हस्ताक्षर किए इंट में, लंबे / अव्यक्त मान के लिए (इसलिए सीमा -180 .. + 180 के भीतर)। छोटे आकार में महान परिशुद्धता (~ 1 सेमी) (4 बी)।
टूलमेकरसैट

6

फ्लोट का उपयोग न करें ... यह आपके निर्देशांक को गोल करेगा, जिसके परिणामस्वरूप कुछ अजीब घटनाएं होंगी।

दशमलव का उपयोग करें


4

MySQL के पास अब स्थानिक डेटा प्रकारों के लिए समर्थन है क्योंकि यह प्रश्न पूछा गया था। इसलिए वर्तमान स्वीकृत उत्तर गलत नहीं है, लेकिन यदि आप अतिरिक्त कार्यक्षमता की तलाश कर रहे हैं जैसे किसी दिए गए बहुभुज के भीतर सभी बिंदुओं को ढूंढना तो POINT डेटा प्रकार का उपयोग करें।

भू-स्थानिक डेटा प्रकारों और स्थानिक विश्लेषण कार्यों पर मैसकल डॉक्स को चेकआउट करें


4

मेरा मानना ​​है कि MySQL में Lat / Lng को स्टोर करने का सबसे अच्छा तरीका एक SPAT अनुक्रमणिका के साथ POINT कॉलम (2D डेटाटाइप) है।

CREATE TABLE `cities` (
  `zip` varchar(8) NOT NULL,
  `country` varchar (2) GENERATED ALWAYS AS (SUBSTRING(`zip`, 1, 2)) STORED,
  `city` varchar(30) NOT NULL,
  `centre` point NOT NULL,
  PRIMARY KEY (`zip`),
  KEY `country` (`country`),
  KEY `city` (`city`),
  SPATIAL KEY `centre` (`centre`)
) ENGINE=InnoDB;


INSERT INTO `cities` (`zip`, `city`, `centre`) VALUES
('CZ-10000', 'Prague', POINT(50.0755381, 14.4378005));

0

पटरियों पर माइगेट माणिक का उपयोग करना

class CreateNeighborhoods < ActiveRecord::Migration[5.0]
  def change
    create_table :neighborhoods do |t|
      t.string :name
      t.decimal :latitude, precision: 15, scale: 13
      t.decimal :longitude, precision: 15, scale: 13
      t.references :country, foreign_key: true
      t.references :state, foreign_key: true
      t.references :city, foreign_key: true

      t.timestamps
    end
  end
end

-99..99 तक यह सीमा नहीं होगी? यह प्रशांत क्षेत्र से बाहर है!
रिक जेम्स

यह एक उदाहरण है जिसे पूर्ण सत्य के रूप में नहीं लिया जाना चाहिए। आप एक और DECIMAL दशमलव सटीक (20, 18) और इतने पर उपयोग कर सकते हैं ... यदि आपको भौगोलिक और स्थानिक डेटा को बचाने की आवश्यकता है तो आप इस उद्देश्य के लिए पोस्टगिस डेटाबेस का उपयोग कर सकते हैं। MySQL स्थानिक एक्सटेंशन एक अच्छा विकल्प है क्योंकि वे OpenGIS ज्यामिति मॉडल का पालन करते हैं। मैंने उनका उपयोग नहीं किया क्योंकि मुझे अपने डेटाबेस को पोर्टेबल रखने की आवश्यकता थी। postgis.net
gilcierweb

(20,18)यह भी +/- 99 पर सबसे ऊपर है।
रिक जेम्स

यह एक उदाहरण है जिसे पूर्ण सत्य के रूप में नहीं लिया जाना चाहिए। आप एक और DECIMAL दशमलव सटीक (20, 18) और इतने पर उपयोग कर सकते हैं ... यदि आपको भौगोलिक और स्थानिक डेटा को बचाने की आवश्यकता है तो आप इस उद्देश्य के लिए पोस्टगिस डेटाबेस का उपयोग कर सकते हैं। MySQL स्थानिक एक्सटेंशन एक अच्छा विकल्प है क्योंकि वे OpenGIS ज्यामिति मॉडल का पालन करते हैं। मैंने उनका उपयोग नहीं किया क्योंकि मुझे अपने डेटाबेस को पोर्टेबल रखने की आवश्यकता थी। postgis.net
gilcierweb

यार यह सिर्फ एक उदाहरण है, आप अपनी इच्छित सटीकता का उपयोग कर सकते हैं, अगर दशमलव आपको भौगोलिक और स्थानिक डेटा के लिए बनाए गए डेटाबेस का उपयोग करने में मदद नहीं कर रहा है
gilcierweb

-1

Oğuzhan KURNU answer के उत्तर का सटीक उपयोग करने / साबित करने के लिए कोड ।

सारांश:
एक छोटे आकार (4 बी) में महान सटीकता (~ 1 सेमी)।

प्रेसिजन (बहुत के करीब) 7 दशमलव अंकों के मूल्यों के लिए सीमा पर [-180, 180] है।
ऐसा इसलिए है दशमलव के अधिकार के लिए 7 अंक (~ 1 सेमी) , 9 अंक की कुल (या 10 अंक, प्रारंभिक "1" "180" की गिनती अगर) + -180 के पास के लिए।
इसे 4-बाइट फ्लोट के साथ विपरीत करें , जिसमें कुल ~ 7 अंक हैं, इसलिए दशमलव के दाईं ओर + = 180 (~ 1m) के लिए ~ 5 अंक ।

इस दृष्टिकोण का उपयोग करने के तरीके:

const double Fixed7Mult = 10000000;

public static int DecimalDegreesToFixed7(double degrees)
{
    return RoundToInt(degrees * Fixed7Mult);
}

public static double Fixed7ToDecimalDegrees(int fixed7)
{
    return fixed7 / (double)Fixed7Mult;
}

सटीकता के परीक्षण:

/// <summary>
/// This test barely fails in 7th digit to right of decimal point (0.0000001 as delta).
/// Passes with 0.0000002 as delta.
/// </summary>
internal static void TEST2A_LatLongPrecision()
{
    //VERY_SLOW_TEST Test2A_ForRange(-180, 360, 0.0000001);
    //FAILS Test2A_ForRange(-180, 0.1, 0.0000001);

    Test2A_ForRange(-180, 0.1, 0.0000002);
    Test2A_ForRange(0, 0.1, 0.0000002);
    Test2A_ForRange(179.9, 0.1, 0.0000002);
}

/// <summary>
/// Test for the smallest difference.  A: 9.9999994E-08.
/// </summary>
internal static void TEST2B_LatLongPrecision()
{
    double minDelta = double.MaxValue;
    double vAtMinDelta = 0;
    //VERY_SLOW_TEST Test2B_ForRange(-180, 360, ref minDelta, ref vAtMinDelta);
    Test2B_ForRange(-180, 0.1, ref minDelta, ref vAtMinDelta);
    Test2B_ForRange(0, 0.1, ref minDelta, ref vAtMinDelta);
    Test2B_ForRange(179.9, 0.1, ref minDelta, ref vAtMinDelta);

    // Fails. Smallest delta is 9.9999994E-08; due to slight rounding error in 7th decimal digit.
    //if (minDelta < 0.0000001)
    //  throw new InvalidProgramException($"Fixed7 has less than 7 decimal digits near {vAtMinDelta}");

    // Passes.
    if (minDelta < 0.000000099)
        throw new InvalidProgramException($"Fixed7 has less than 7 decimal digits near {vAtMinDelta}");
}

परीक्षण द्वारा उपयोग किए जाने वाले सहायक तरीके:

private static void Test2A_ForRange(double minV, double range, double deltaV)
{
    double prevV = 0;
    int prevFixed7 = 0;
    bool firstTime = true;
    double maxV = minV + range;
    for (double v = minV; v <= maxV; v += deltaV) {
        int fixed7 = DecimalDegreesToFixed7(v);
        if (firstTime)
            firstTime = false;
        else {
            // Check for failure to distinguish two values that differ only in 7th decimal digit.
            // Fails.
            if (fixed7 == prevFixed7)
                throw new InvalidProgramException($"Fixed7 doesn't distinguish between {prevV} and {v}");
        }
        prevV = v;
        prevFixed7 = fixed7;
    }
}

private static void Test2B_ForRange(double minV, double range, ref double minDelta, ref double vAtMinDelta)
{
    int minFixed7 = DecimalDegreesToFixed7(minV);
    int maxFixed7 = DecimalDegreesToFixed7(minV + range);

    bool firstTime = true;
    double prevV = 0;   // Initial value is ignored.
    for (int fixed7 = minFixed7; fixed7 < maxFixed7; fixed7++) {
        double v = Fixed7ToDecimalDegrees(fixed7);
        if (firstTime)
            firstTime = false;
        else {
            double delta = Math.Abs(v - prevV);
            if (delta < minDelta) {
                minDelta = delta;
                vAtMinDelta = v;
            }
        }
        prevV = v;
    }
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.