Я изменяю структуру базы данных клиентов, и одна из новых частей информации, которую я хотел бы хранить вместе со стандартными адресными полями (улица, город и т. Д.), - это географическое местоположение адреса. Единственный вариант использования, который я имею в виду, - это разрешить пользователям отображать координаты на картах 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
(подробности ниже). и комментарий к принятому ответу на другой вопрос SO по 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