Saya mendesain ulang basis data pelanggan dan salah satu bagian informasi baru yang ingin saya simpan bersama dengan bidang alamat standar (Jalan, Kota, dll.) Adalah lokasi geografis dari alamat tersebut. Satu-satunya kasus penggunaan yang ada dalam pikiran saya adalah mengizinkan pengguna untuk memetakan koordinat di peta Google ketika alamatnya tidak dapat ditemukan, yang sering terjadi ketika area tersebut baru dikembangkan, atau berada di lokasi terpencil / pedesaan.
Kecenderungan pertama saya adalah menyimpan lintang dan bujur sebagai nilai desimal, tetapi kemudian saya ingat bahwa SQL Server 2008 R2 memiliki geography
tipe data. Saya sama sekali tidak memiliki pengalaman menggunakan geography
, dan dari penelitian awal saya, tampaknya skenario saya berlebihan.
Misalnya, untuk bekerja dengan garis lintang dan bujur yang disimpan sebagai decimal(7,4)
, saya dapat melakukan ini:
insert into Geotest(Latitude, Longitude) values (47.6475, -122.1393)
select Latitude, Longitude from Geotest
tetapi dengan geography
, saya akan melakukan ini:
insert into Geotest(Geolocation) values (geography::Point(47.6475, -122.1393, 4326))
select Geolocation.Lat, Geolocation.Long from Geotest
Meskipun tidak yang jauh lebih rumit, mengapa kompleksitas add jika saya tidak perlu?
Sebelum saya meninggalkan ide untuk menggunakan geography
, apakah ada yang harus saya pertimbangkan? Apakah akan lebih cepat jika mencari lokasi menggunakan indeks spasial vs. mengindeks bidang Lintang dan Bujur? Apakah ada keuntungan menggunakan geography
yang tidak saya sadari? Atau, di sisi lain, apakah ada peringatan yang harus saya ketahui yang akan membuat saya enggan menggunakannya geography
?
Memperbarui
@Erik Philips mengemukakan kemampuan untuk melakukan pencarian kedekatan geography
, yang sangat keren.
Di sisi lain, uji cepat menunjukkan bahwa cara sederhana select
untuk mendapatkan lintang dan bujur jauh lebih lambat saat menggunakan geography
(detail di bawah). , dan komentar pada jawaban yang diterima untuk pertanyaan SO lainnya geography
membuat saya curiga:
@SaphuA Sama-sama. Sebagai catatan, berhati-hatilah saat menggunakan indeks spasial pada kolom tipe data GEOGRAFI yang tidak dapat diisi. Ada beberapa masalah kinerja yang serius, jadi buatlah kolom GEOGRAFI tersebut tidak dapat dinolkan meskipun Anda harus merombak skema Anda. - Tomas 18 Juni pukul 11:18
Secara keseluruhan, dengan mempertimbangkan kemungkinan melakukan pencarian kedekatan vs. kompromi dalam kinerja dan kompleksitas, saya telah memutuskan untuk mengabaikan penggunaan geography
dalam kasus ini.
Rincian tes yang saya jalankan:
Saya membuat dua tabel, satu menggunakan geography
dan menggunakan lainnya decimal(9,6)
untuk garis lintang dan bujur:
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)
)
dan menyisipkan satu baris menggunakan nilai garis lintang dan garis bujur yang sama ke dalam setiap tabel:
insert into GeographyTest(Location) values (geography::Point(47.6475, -122.1393, 4326))
insert into LatLongTest(Latitude, Longitude) values (47.6475, -122.1393)
Akhirnya, menjalankan kode berikut menunjukkan bahwa, di komputer saya, memilih lintang dan bujur kira-kira 5 kali lebih lambat saat menggunakan 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
Hasil:
GeographyDuration LatLongDuration
----------------- ---------------
5146 1020
5143 1016
5169 1030
AvgGeographyDuration AvgLatLongDuration
-------------------- ------------------
5152 1022
Yang lebih mengejutkan adalah meskipun tidak ada baris yang dipilih, misalnya memilih mana RowId = 2
, yang tidak ada, geography
masih lebih lambat:
GeographyDuration LatLongDuration
----------------- ---------------
1607 948
1610 946
1607 947
AvgGeographyDuration AvgLatLongDuration
-------------------- ------------------
1608 947