SQL सर्वर 2008 भूगोल डेटा प्रकार का उपयोग क्यों करें?


105

मैं एक ग्राहक डेटाबेस को पुनः डिज़ाइन कर रहा हूं और सूचना के नए टुकड़ों में से एक जिसे मैं मानक पते फ़ील्ड (स्ट्रीट, सिटी, आदि) के साथ संग्रहीत करना चाहता हूं, वह पते का भौगोलिक स्थान है। मेरे पास केवल एक ही उपयोग मामला है कि उपयोगकर्ताओं को Google मानचित्र पर निर्देशांक को मैप करने की अनुमति दी जाए जब पता अन्यथा नहीं मिल सकता है, जो अक्सर तब होता है जब क्षेत्र नया विकसित होता है, या एक दूरस्थ / ग्रामीण स्थान पर होता है।

मेरा पहला झुकाव अक्षांश और देशांतर को दशमलव मानों के रूप में संग्रहीत करना था, लेकिन फिर मुझे याद आया कि SQL Server 2008 R2 में geographyडेटा प्रकार है। मेरे पास उपयोग करने का बिल्कुल कोई अनुभव नहीं है geography, और अपने शुरुआती शोध से, यह मेरे परिदृश्य के लिए अधिक महत्वपूर्ण है।

उदाहरण के लिए, अक्षांश और देशांतर के साथ काम करने के लिए, decimal(7,4)मैं यह कर सकता हूं:

insert into Geotest(Latitude, Longitude) values (47.6475, -122.1393)
select Latitude, Longitude from Geotest

लेकिन इसके साथ geography, मैं यह करूंगा:

insert into Geotest(Geolocation) values (geography::Point(47.6475, -122.1393, 4326))
select Geolocation.Lat, Geolocation.Long from Geotest

हालांकि ऐसा नहीं है कि और अधिक जटिल है, क्यों ऐड जटिलता अगर मैं करने के लिए नहीं है?

इससे पहले कि मैं उपयोग करने के विचार को छोड़ दूं geography, क्या ऐसा कुछ है जिस पर मुझे विचार करना चाहिए? क्या स्थानिक सूचकांक बनाम अक्षांश और देशांतर क्षेत्रों का उपयोग करके किसी स्थान की खोज करना तेज़ होगा? क्या इसका उपयोग करने के फायदे हैं geographyजो मुझे ज्ञात नहीं हैं? या, फ्लिप साइड पर, क्या ऐसे कैविएट हैं, जिनके बारे में मुझे पता होना चाहिए कि मुझे उपयोग करने से कौन हतोत्साहित करेगा geography?


अपडेट करें

@ एरिक फिलिप्स ने निकटता वाली खोजों को करने की क्षमता लाई geography, जो बहुत ही शांत है।

दूसरी ओर, एक त्वरित परीक्षण यह दिखा रहा है कि selectअक्षांश (देशांतर) प्राप्त करने के लिए एक सरल का उपयोग करते समय काफी धीमा है geography। , और मुझे एसओ पर एक और एसओ प्रश्न के स्वीकृत उत्तर पर एक टिप्पणी है geography:

@SaphuA आपका स्वागत है। एक सुन्नत के रूप में एक अशक्त GEOGRAPHY डेटाटाइप कॉलम पर एक स्थानिक सूचकांक का उपयोग करने के लिए बहुत ही उपयोगी है। कुछ गंभीर प्रदर्शन के मुद्दे हैं, इसलिए यह सुनिश्चित करें कि GEOGRAPHY कॉलम नॉन-नॉलेबल है भले ही आपको अपने स्कीमा को फिर से तैयार करना पड़े। - टॉमस जून 18 को 11:18 बजे

सभी सभी में, निकटता की खोज बनाम प्रदर्शन और जटिलता में व्यापार बंद होने की संभावना को तौलते हुए, मैंने geographyइस मामले में उपयोग को त्यागने का फैसला किया है ।


मेरे द्वारा चलाए गए परीक्षण का विवरण:

मैंने दो टेबल बनाई, एक का उपयोग कर geographyऔर दूसरे का उपयोग decimal(9,6)अक्षांश और देशांतर के लिए:

CREATE TABLE [dbo].[GeographyTest]
(
    [RowId] [int] IDENTITY(1,1) NOT NULL,
    [Location] [geography] NOT NULL,
    CONSTRAINT [PK_GeographyTest] PRIMARY KEY CLUSTERED ( [RowId] ASC )
) 

CREATE TABLE [dbo].[LatLongTest]
(
    [RowId] [int] IDENTITY(1,1) NOT NULL,
    [Latitude] [decimal](9, 6) NULL,
    [Longitude] [decimal](9, 6) NULL,
    CONSTRAINT [PK_LatLongTest] PRIMARY KEY CLUSTERED ([RowId] ASC)
) 

और प्रत्येक तालिका में समान अक्षांश और देशांतर मानों का उपयोग करके एक एकल पंक्ति सम्मिलित की गई:

insert into GeographyTest(Location) values (geography::Point(47.6475, -122.1393, 4326))
insert into LatLongTest(Latitude, Longitude) values (47.6475, -122.1393)

अंत में, निम्नलिखित कोड चलाने से पता चलता है कि, मेरी मशीन पर, अक्षांश और देशांतर का चयन करते समय लगभग 5 बार धीमी गति से उपयोग किया जाता है geography

declare @lat float, @long float,
        @d datetime2, @repCount int, @trialCount int, 
        @geographyDuration int, @latlongDuration int,
        @trials int = 3, @reps int = 100000

create table #results 
(
    GeographyDuration int,
    LatLongDuration int
)

set @trialCount = 0

while @trialCount < @trials
begin

    set @repCount = 0
    set @d = sysdatetime()

    while @repCount < @reps
    begin
        select @lat = Location.Lat,  @long = Location.Long from GeographyTest where RowId = 1
        set @repCount = @repCount + 1
    end

    set @geographyDuration = datediff(ms, @d, sysdatetime())

    set @repCount = 0
    set @d = sysdatetime()

    while @repCount < @reps
    begin
        select @lat = Latitude,  @long = Longitude from LatLongTest where RowId = 1
        set @repCount = @repCount + 1
    end

    set @latlongDuration = datediff(ms, @d, sysdatetime())

    insert into #results values(@geographyDuration, @latlongDuration)

    set @trialCount = @trialCount + 1

end

select * 
from #results

select avg(GeographyDuration) as AvgGeographyDuration, avg(LatLongDuration) as AvgLatLongDuration
from #results

drop table #results

परिणाम:

GeographyDuration LatLongDuration
----------------- ---------------
5146              1020
5143              1016
5169              1030

AvgGeographyDuration AvgLatLongDuration
-------------------- ------------------
5152                 1022

इससे भी अधिक आश्चर्य की बात यह है कि जब कोई पंक्तियों का चयन नहीं किया जाता है, उदाहरण के लिए RowId = 2, जहां चयन करना है , जो मौजूद नहीं है, geographyतब भी धीमी थी:

GeographyDuration LatLongDuration
----------------- ---------------
1607              948
1610              946
1607              947

AvgGeographyDuration AvgLatLongDuration
-------------------- ------------------
1608                 947

4
मैं दोनों को करने की सोच रहा हूं, लाट और लोन को अपने कॉलम में सहेजें, और भूगोल की वस्तु के लिए एक और कॉलम है, इसलिए अगर मुझे केवल लाट / लोन की आवश्यकता है तो मैं उन्हें कॉलम से लेता हूं, और अगर मुझे निकटता खोज की आवश्यकता है 'भूगोल का उपयोग करेंगे। क्या यह बुद्धिमान है? क्या कोई डाउनसाइड्स (इसके अलावा और जगह लेता है ...)?
युवल ए।

@YuvalA। यह निश्चित रूप से उचित लगता है, और एक अच्छा समझौता हो सकता है। मेरे सिर के ऊपर से केवल एक ही चिंता है कि क्या तालिका में भूगोल कॉलम होने से तालिका के खिलाफ प्रश्नों पर कोई प्रभाव पड़ता है - मुझे इसके साथ कोई अनुभव नहीं है, इसलिए आपको सत्यापित करने के लिए परीक्षण करने की आवश्यकता होगी।
जेफ ओगाटा

1
आपने नए प्रश्न पूछने के बजाय अपने प्रश्न को नए प्रश्नों के साथ अद्यतन क्यों रखा?
चाड

@ आप क्या मतलब है यकीन नहीं है। मैंने एक बार प्रश्न का शरीर अद्यतन किया, और यह अधिक प्रश्न पूछने के लिए नहीं था।
जेफ ओगाटा

6
यह ध्यान देने योग्य है, अब, इस प्रश्न को खोजने वालों के लिए, कि SQL Server 2012 में स्थानिक अनुक्रमण के साथ महत्वपूर्ण प्रदर्शन बढ़ जाता है। नोट का यह भी तथ्य है कि जब तक आप स्थान की जानकारी संग्रहीत कर रहे हैं, आप अपने पहले से ही संग्रहीत पते को जियोडोड करने के लिए एक लुकअप सेवा का उपयोग करके बाद में स्थानिक जानकारी में जोड़ सकते हैं।
वोल्वॉक्स

जवाबों:


66

यदि आप कोई स्थानिक संगणना करने की योजना बनाते हैं, तो EF 5.0 LINQ एक्सप्रेशन जैसे:

private Facility GetNearestFacilityToJobsite(DbGeography jobsite)
{   
    var q1 = from f in context.Facilities            
             let distance = f.Geocode.Distance(jobsite)
             where distance < 500 * 1609.344     
             orderby distance 
             select f;   
    return q1.FirstOrDefault();
}

फिर भूगोल का उपयोग करने का एक बहुत अच्छा कारण है।

इकाई ढांचे के भीतर स्थानिक की व्याख्या

उच्च प्रदर्शन स्थानिक डेटाबेस बनाने के साथ अद्यतन किया गया

जैसा कि मैंने नोएल अब्राहम के उत्तर पर ध्यान दिया :

अंतरिक्ष पर एक नोट, प्रत्येक समन्वय को दोहरे-सटीक फ़्लोटिंग-पॉइंट संख्या के रूप में संग्रहीत किया जाता है जो 64 बिट्स (8 बाइट्स) लंबा होता है, और 8-बाइट बाइनरी मान दशमलव परिशुद्धता के 15 अंकों के बराबर होता है, इसलिए एक दशमलव (9 की तुलना में) , 6) जो केवल 5 बाइट्स है, वास्तव में उचित तुलना नहीं है। एक वास्तविक तुलना के लिए दशमलव को प्रत्येक LatLong (कुल 18 बाइट्स) के लिए न्यूनतम दशमलव (15,12) (9 बाइट्स) होना चाहिए।

इसलिए भंडारण प्रकारों की तुलना करना:

CREATE TABLE dbo.Geo
(    
geo geography
)
GO

CREATE TABLE dbo.LatLng
(    
    lat decimal(15, 12),   
    lng decimal(15, 12)
)
GO

INSERT dbo.Geo
SELECT geography::Point(12.3456789012345, 12.3456789012345, 4326) 
UNION ALL
SELECT geography::Point(87.6543210987654, 87.6543210987654, 4326) 

GO 10000

INSERT dbo.LatLng
SELECT  12.3456789012345, 12.3456789012345 
UNION
SELECT 87.6543210987654, 87.6543210987654

GO 10000

EXEC sp_spaceused 'dbo.Geo'

EXEC sp_spaceused 'dbo.LatLng'

परिणाम:

name    rows    data     
Geo     20000   728 KB   
LatLon  20000   560 KB

भूगोल डेटा-प्रकार 30% अधिक स्थान लेता है।

इसके अतिरिक्त भूगोल डेटाटाइप केवल एक बिंदु को संग्रहीत करने तक सीमित नहीं है, आप लाइनस्ट्रीमिंग, सर्कुलरस्ट्रिंग, कंपाउंडकर्वे, पॉलीगॉन, कर्वप्रोलीगॉन, ज्योमेट्रीकोलेक्शन, मल्टीप्वाइंट, मल्टीलाइनरिंग, और मल्टीपोलियन और भी बहुत कुछ स्टोर कर सकते हैं । एक बिंदु से परे भूगोल प्रकार (लाट / दीर्घ) के रूप में भी सरलता से संग्रहीत करने का कोई भी प्रयास (उदाहरण के लिए LINESTRING (1 1, 2 2) उदाहरण) प्रत्येक बिंदु के लिए अतिरिक्त पंक्तियों को उकसाएगा, प्रत्येक बिंदु के आदेश के लिए अनुक्रमण के लिए एक स्तंभ और लाइनों के समूहीकरण के लिए एक और कॉलम। SQL सर्वर में भूगोल डेटा प्रकारों के लिए विधियां भी शामिल हैं , जिसमें गणना क्षेत्र, सीमा, लंबाई, दूरियां और बहुत कुछ शामिल हैं

यह Sql सर्वर में अक्षांश और देशांतर को दशमलव के रूप में संग्रहीत करने के लिए नासमझ लगता है।

अपडेट २

यदि आप दूरी, क्षेत्र आदि जैसी किसी भी गणना को करने की योजना बनाते हैं, तो पृथ्वी की सतह पर इन की सही गणना करना मुश्किल है। SQL सर्वर में संग्रहीत प्रत्येक भूगोल प्रकार भी एक स्थानिक संदर्भ आईडी के साथ संग्रहीत किया जाता है । ये आईडी विभिन्न क्षेत्रों की हो सकती है (पृथ्वी 4326 है)। इसका मतलब यह है कि SQL सर्वर में गणना वास्तव में पृथ्वी की सतह पर सही तरीके से गणना करेगी ( जैसे-कौवा-मक्खियों के रूप में जो पृथ्वी की सतह के माध्यम से हो सकती है)।

यहां छवि विवरण दर्ज करें


1
इस जानकारी में जोड़ने के लिए, भूगोल का उपयोग करने से चतुष्कोणीय खोजों की क्षमता का विस्तार होता है, जो अन्य लाट / लोंगो (आमतौर पर सिर्फ आयतों) के बीच एक लंबा / लंबा होता है, क्योंकि भूगोल डेटा प्रकार आपको लगभग किसी भी आकार और आकार के कई क्षेत्र बनाने की अनुमति देता है।
एरिक फिलिप्स

1
एक बार फिर धन्यवाद। मैंने उपयोग करने पर विचार करने के लिए कारण पूछा geographyऔर आपने कुछ अच्छे प्रदान किए। अंत में, मैंने decimalइस मामले में सिर्फ खेतों का उपयोग करने का फैसला किया (मेरे लंबे-लंबे अपडेट देखें), लेकिन यह जानना अच्छा है कि मैं उपयोग कर सकता geographyहूं अगर मुझे कभी भी निर्देशांक मैप करने की तुलना में कुछ भी कट्टरपंथी करने की आवश्यकता होती है।
जेफ ओगाटा

6

एक और बात पर विचार करने के लिए प्रत्येक विधि द्वारा लिया गया भंडारण स्थान है। भूगोल प्रकार को एक के रूप में संग्रहीत किया जाता है VARBINARY(MAX)। इस स्क्रिप्ट को चलाने का प्रयास करें:

CREATE TABLE dbo.Geo
(
    geo geography

)

GO

CREATE TABLE dbo.LatLon
(
    lat decimal(9, 6)
,   lon decimal(9, 6)

)

GO

INSERT dbo.Geo
SELECT geography::Point(36.204824, 138.252924, 4326) UNION ALL
SELECT geography::Point(51.5220066, -0.0717512, 4326) 

GO 10000

INSERT dbo.LatLon
SELECT  36.204824, 138.252924 UNION
SELECT 51.5220066, -0.0717512

GO 10000

EXEC sp_spaceused 'dbo.Geo'
EXEC sp_spaceused 'dbo.LatLon'

परिणाम:

name    rows    data     
Geo     20000   728 KB   
LatLon  20000   400 KB

भूगोल डेटा-प्रकार लगभग दो गुना अधिक स्थान लेता है।


2
अंतरिक्ष पर एक नोट, प्रत्येक समन्वय को दोहरे-सटीक फ़्लोटिंग-पॉइंट संख्या के रूप में संग्रहीत किया जाता है जो 64 बिट्स (8 बाइट्स) लंबा होता है, और 8-बाइट बाइनरी मान दशमलव परिशुद्धता के 15 अंकों के बराबर होता है , इसलिए एक दशमलव (9 की तुलना में) , 6) जो केवल 5 बाइट्स है , वास्तव में उचित तुलना नहीं है। एक वास्तविक तुलना के लिए दशमलव को प्रत्येक LatLong (कुल 18 बाइट्स) के लिए न्यूनतम दशमलव (15,12) (9 बाइट्स) होना चाहिए।
एरिक फिलिप्स

9
@ ErikPhilips इस बात का कारण है कि दशमलव (15, 12) का उपयोग तब करें, जब आपको एक दशमलव (9, 6) की आवश्यकता हो? उपरोक्त तुलना एक व्यावहारिक है - एक अकादमिक अभ्यास नहीं।
नोएल अब्राहम

-1
    CREATE FUNCTION [dbo].[fn_GreatCircleDistance]
(@Latitude1 As Decimal(38, 19), @Longitude1 As Decimal(38, 19), 
            @Latitude2 As Decimal(38, 19), @Longitude2 As Decimal(38, 19), 
            @ValuesAsDecimalDegrees As bit = 1, 
            @ResultAsMiles As bit = 0)
RETURNS decimal(38,19)
AS
BEGIN
    -- Declare the return variable here
    DECLARE @ResultVar  decimal(38,19)

    -- Add the T-SQL statements to compute the return value here
/*
Credit for conversion algorithm to Chip Pearson
Web Page: www.cpearson.com/excel/latlong.aspx
Email: chip@cpearson.com
Phone: (816) 214-6957 USA Central Time (-6:00 UTC)
Between 9:00 AM and 7:00 PM

Ported to Transact SQL by Paul Burrows BCIS
*/
DECLARE  @C_RADIUS_EARTH_KM As Decimal(38, 19)
SET @C_RADIUS_EARTH_KM = 6370.97327862
DECLARE  @C_RADIUS_EARTH_MI As Decimal(38, 19)
SET @C_RADIUS_EARTH_MI = 3958.73926185
DECLARE  @C_PI As Decimal(38, 19)
SET @C_PI =  pi()

DECLARE @Lat1 As Decimal(38, 19)
DECLARE @Lat2 As Decimal(38, 19)
DECLARE @Long1 As Decimal(38, 19)
DECLARE @Long2 As Decimal(38, 19)
DECLARE @X As bigint
DECLARE @Delta As Decimal(38, 19)

If @ValuesAsDecimalDegrees = 1 
Begin
    set @X = 1
END
Else
Begin
    set @X = 24
End 

-- convert to decimal degrees
set @Lat1 = @Latitude1 * @X
set @Long1 = @Longitude1 * @X
set @Lat2 = @Latitude2 * @X
set @Long2 = @Longitude2 * @X

-- convert to radians: radians = (degrees/180) * PI
set @Lat1 = (@Lat1 / 180) * @C_PI
set @Lat2 = (@Lat2 / 180) * @C_PI
set @Long1 = (@Long1 / 180) * @C_PI
set @Long2 = (@Long2 / 180) * @C_PI

-- get the central spherical angle
set @Delta = ((2 * ASin(Sqrt((power(Sin((@Lat1 - @Lat2) / 2) ,2)) + 
    Cos(@Lat1) * Cos(@Lat2) * (power(Sin((@Long1 - @Long2) / 2) ,2))))))

If @ResultAsMiles = 1 
Begin
    set @ResultVar = @Delta * @C_RADIUS_EARTH_MI
End
Else
Begin
    set @ResultVar = @Delta * @C_RADIUS_EARTH_KM
End

    -- Return the result of the function
    RETURN @ResultVar

END

2
नए उत्तर हमेशा स्वागत योग्य हैं, लेकिन कृपया कुछ संदर्भ जोड़ें। संक्षेप में यह बताना कि उपरोक्त समस्या कैसे हल करती है, इसका उत्तर दूसरों के लिए अधिक उपयोगी है।
Leigh
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.