Tôi đang thiết kế lại cơ sở dữ liệu khách hàng và một trong những phần thông tin mới mà tôi muốn lưu trữ cùng với các trường địa chỉ chuẩn (Đường phố, Thành phố, v.v.) là vị trí địa lý của địa chỉ. Trường hợp sử dụng duy nhất mà tôi nghĩ đến là cho phép người dùng lập bản đồ tọa độ trên bản đồ Google khi không thể tìm thấy địa chỉ, điều này thường xảy ra khi khu vực này mới phát triển hoặc ở vùng sâu vùng xa / nông thôn.
Xu hướng đầu tiên của tôi là lưu trữ vĩ độ và kinh độ dưới dạng giá trị thập phân, nhưng sau đó tôi nhớ rằng SQL Server 2008 R2 có một geography
kiểu dữ liệu. Tôi hoàn toàn không có kinh nghiệm sử dụng geography
, và từ nghiên cứu ban đầu của tôi, nó có vẻ là quá mức cần thiết cho kịch bản của tôi.
Ví dụ: để làm việc với vĩ độ và kinh độ được lưu trữ dưới dạng decimal(7,4)
, tôi có thể thực hiện điều này:
insert into Geotest(Latitude, Longitude) values (47.6475, -122.1393)
select Latitude, Longitude from Geotest
nhưng với geography
, tôi sẽ làm điều này:
insert into Geotest(Geolocation) values (geography::Point(47.6475, -122.1393, 4326))
select Geolocation.Lat, Geolocation.Long from Geotest
Mặc dù nó không phải là phức tạp hơn nhiều, tại sao add phức tạp nếu tôi không phải?
Trước khi tôi từ bỏ ý định sử dụng geography
, có điều gì tôi nên cân nhắc không? Sẽ nhanh hơn khi tìm kiếm vị trí bằng chỉ mục không gian so với lập chỉ mục các trường Kinh độ và Vĩ độ? Có những lợi ích khi sử dụng geography
mà tôi không biết? Hoặc, ngược lại, có những cảnh báo mà tôi nên biết có thể làm tôi nản lòng khi sử dụng geography
?
Cập nhật
@Erik Philips mang đến khả năng thực hiện các tìm kiếm ở vùng lân cận geography
, điều này rất tuyệt vời.
Mặt khác, một thử nghiệm nhanh cho thấy việc đơn giản select
để lấy vĩ độ và kinh độ chậm hơn đáng kể khi sử dụng geography
(chi tiết bên dưới). , và một nhận xét về câu trả lời được chấp nhận cho một câu hỏi SO khác geography
đã giúp tôi thoải mái:
@SaphuA Không có chi. Như một chú thích phụ, hãy RẤT cẩn thận khi sử dụng chỉ mục không gian trên cột kiểu dữ liệu GEOGRAPHY có thể bỏ qua. Có một số vấn đề nghiêm trọng về hiệu suất, vì vậy hãy đặt cột GEOGRAPHY đó không thể null ngay cả khi bạn phải sửa sang lại giản đồ của mình. - Tomas ngày 18 tháng 6 lúc 11:18
Nói chung, cân nhắc giữa khả năng thực hiện các tìm kiếm vùng lân cận so với sự đánh đổi về hiệu suất và độ phức tạp, tôi đã quyết định từ bỏ việc sử dụng geography
trong trường hợp này.
Chi tiết về bài kiểm tra tôi đã chạy:
Tôi đã tạo hai bảng, một bảng sử dụng geography
và một bảng khác sử dụng decimal(9,6)
cho vĩ độ và kinh độ:
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)
)
và chèn một hàng duy nhất sử dụng cùng các giá trị kinh độ và vĩ độ vào mỗi bảng:
insert into GeographyTest(Location) values (geography::Point(47.6475, -122.1393, 4326))
insert into LatLongTest(Latitude, Longitude) values (47.6475, -122.1393)
Cuối cùng, chạy đoạn mã sau cho thấy rằng, trên máy của tôi, việc chọn vĩ độ và kinh độ chậm hơn khoảng 5 lần khi sử dụng 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
Các kết quả:
GeographyDuration LatLongDuration
----------------- ---------------
5146 1020
5143 1016
5169 1030
AvgGeographyDuration AvgLatLongDuration
-------------------- ------------------
5152 1022
Điều đáng ngạc nhiên hơn là ngay cả khi không có hàng nào được chọn, chẳng hạn như chọn nơi RowId = 2
không tồn tại, geography
vẫn chậm hơn:
GeographyDuration LatLongDuration
----------------- ---------------
1607 948
1610 946
1607 947
AvgGeographyDuration AvgLatLongDuration
-------------------- ------------------
1608 947