Bir müşteri veri tabanını yeniden tasarlıyorum ve standart adres alanları (Cadde, Şehir vb.) İle birlikte saklamak istediğim yeni bilgilerden biri de adresin coğrafi konumu. Aklımdaki tek kullanım durumu, kullanıcıların adres başka türlü bulunamadığında Google haritalarındaki koordinatları haritalamasına izin vermektir, bu genellikle alan yeni geliştirildiğinde veya uzak / kırsal bir konumda olduğunda olur.
İlk eğilimim enlem ve boylamı ondalık değerler olarak saklamaktı, ancak daha sonra SQL Server 2008 R2'nin bir geography
veri türü olduğunu hatırladım . Kullanma konusunda kesinlikle hiç deneyimim yok geography
ve ilk araştırmamdan senaryom için fazla abartılı görünüyor.
Örneğin, depolanan enlem ve boylamla çalışmak için decimal(7,4)
şunu yapabilirim:
insert into Geotest(Latitude, Longitude) values (47.6475, -122.1393)
select Latitude, Longitude from Geotest
ama ile geography
bunu yapardım:
insert into Geotest(Geolocation) values (geography::Point(47.6475, -122.1393, 4326))
select Geolocation.Lat, Geolocation.Long from Geotest
O olmasa o ben yoksa çok daha neden eklenti karmaşıklığı karmaşık?
Kullanım fikrinden vazgeçmeden önce, düşünmem geography
gereken bir şey var mı? Enlem ve Boylam alanlarını endekslemeye kıyasla uzamsal dizin kullanarak bir konumu aramak daha mı hızlı olur? Farkında olmadığım kullanımın avantajları var geography
mı? Ya da kapak tarafında, beni kullanmaktan vazgeçirecek bilmem gereken uyarılar var geography
mı?
Güncelleme
@Erik Philips geography
, çok güzel olan yakınlık aramaları yapma yeteneğini gündeme getirdi .
Öte yandan, hızlı bir test, select
enlem ve boylamı elde etmenin basit , kullanılırken önemli ölçüde daha yavaş olduğunu gösteriyor geography
(ayrıntılar aşağıdadır). ve başka bir SO sorusunun kabul edilen yanıtıyla ilgili bir yorum geography
beni meraklandırdı:
@SaphuA Rica ederim. Bir yan not olarak, boş değer atanabilir bir GEOGRAPHY veri türü sütununda uzamsal bir dizin kullanmaya ÇOK dikkatli olun. Bazı ciddi performans sorunları var, bu nedenle şemanızı yeniden modellemeniz gerekse bile GEOGRAPHY sütununu null yapılamaz hale getirin. - Tomas 18 Haziran, 11:18
Sonuç olarak, yakınlık aramaları yapma olasılığı ile performans ve karmaşıklık arasındaki değiş tokuşu tartarak, geography
bu durumda kullanımından vazgeçmeye karar verdim .
Yaptığım testin detayları:
Biri enlem ve boylam için kullanan geography
ve diğeri kullanan iki tablo oluşturdum 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)
)
ve her tabloya aynı enlem ve boylam değerlerini kullanarak tek bir satır ekledi:
insert into GeographyTest(Location) values (geography::Point(47.6475, -122.1393, 4326))
insert into LatLongTest(Latitude, Longitude) values (47.6475, -122.1393)
Son olarak, aşağıdaki kodu çalıştırmak, makinemde enlem ve boylamı seçmenin, kullanırken yaklaşık 5 kat daha yavaş olduğunu gösteriyor 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
Sonuçlar:
GeographyDuration LatLongDuration
----------------- ---------------
5146 1020
5143 1016
5169 1030
AvgGeographyDuration AvgLatLongDuration
-------------------- ------------------
5152 1022
Daha şaşırtıcı olan ise, hiçbir satır seçilmediğinde bile, örneğin RowId = 2
var olmayan yeri seçmek gibi geography
, hala daha yavaştı:
GeographyDuration LatLongDuration
----------------- ---------------
1607 948
1610 946
1607 947
AvgGeographyDuration AvgLatLongDuration
-------------------- ------------------
1608 947