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
sumber
Jawaban:
Jika Anda berencana melakukan komputasi spasial, EF 5.0 memungkinkan Ekspresi LINQ seperti:
Lalu ada alasan yang sangat bagus untuk menggunakan Geografi.
Penjelasan spasial dalam Kerangka Entitas .
Diperbarui dengan Membuat Database Spasial Berkinerja Tinggi
Seperti yang saya catat di Noel Abrahams Answer :
Jadi membandingkan jenis penyimpanan:
Hasil:
Jenis data geografi membutuhkan 30% lebih banyak ruang.
Selain itu, tipe data geografi tidak terbatas hanya untuk menyimpan Titik, Anda juga dapat menyimpan LineString, CircularString, CompoundCurve, Polygon, CurvePolygon, GeometryCollection, MultiPoint, MultiLineString, dan MultiPolygon, dan lainnya . Setiap upaya untuk menyimpan bahkan tipe Geografi yang paling sederhana (sebagai Lintang / Bujur) di luar Titik (misalnya LINESTRING (1 1, 2 2) contoh) akan menimbulkan baris tambahan untuk setiap titik, kolom untuk urutan urutan setiap titik dan kolom lain untuk pengelompokan garis. SQL Server juga memiliki metode untuk tipe data Geografi yang mencakup penghitungan Area, Batas, Panjang, Jarak, dan lainnya .
Tampaknya tidak bijaksana untuk menyimpan Garis Lintang dan Bujur sebagai Desimal di Server Sql.
Perbarui 2
Jika Anda berencana melakukan penghitungan seperti jarak, luas, dll., Sulit untuk menghitungnya dengan benar di permukaan bumi. Setiap tipe Geografi yang disimpan di SQL Server juga disimpan dengan ID Referensi Spasial . Id ini bisa dari berbagai bidang (bumi adalah 4326). Ini berarti bahwa kalkulasi di SQL Server akan benar-benar menghitung dengan benar di atas permukaan bumi (bukan sebagai burung gagak yang bisa menembus permukaan bumi).
sumber
geography
dan Anda memberikan beberapa yang bagus. Pada akhirnya, saya memutuskan untuk hanya menggunakandecimal
bidang dalam kasus ini (lihat pembaruan bertele-tele saya), tetapi ada baiknya mengetahui bahwa saya dapat menggunakangeography
jika saya perlu melakukan sesuatu yang lebih menarik daripada sekadar memetakan koordinat.Hal lain yang perlu dipertimbangkan adalah ruang penyimpanan yang digunakan oleh masing-masing metode. Jenis geografi disimpan sebagai a
VARBINARY(MAX)
. Coba jalankan skrip ini:Hasil:
Jenis data geografi memakan ruang hampir dua kali lebih banyak.
sumber
sumber