Я модифицирую базу данных клиентов, и одна из новых частей информации, которую я хотел бы сохранить вместе со стандартными полями адреса (улица, город и т. Д.), - это географическое расположение адреса. Единственный вариант использования, который я имею в виду, - это позволить пользователям отображать координаты на картах 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
?
Обновить
@Erik Philips открыл возможность выполнять поиск с близкого расстояния geography
, что очень круто.
С другой стороны, быстрый тест показывает, что простое select
получение широты и долготы значительно медленнее при использовании geography
(подробности ниже). , и комментарий к принятому ответу на другой вопрос SO geography
вызывает у меня подозрение:
@SaphuA Пожалуйста. В качестве примечания будьте ОЧЕНЬ осторожны при использовании пространственного индекса для столбца типа данных GEOGRAPHY, допускающего значение NULL. Существует серьезная проблема с производительностью, поэтому сделайте столбец GEOGRAPHY не допускающим значения NULL, даже если вам придется переделывать схему. - Tomas 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
источник
Ответы:
Если вы планируете выполнять какие-либо пространственные вычисления, EF 5.0 позволяет использовать такие выражения LINQ, как:
Тогда есть очень веская причина использовать географию.
Объяснение пространственного в Entity Framework .
Обновлено с помощью создания высокопроизводительных пространственных баз данных
Как я отметил в ответе Ноэля Абрахамса :
Итак, сравнивая типы хранилищ:
Результат:
Тип данных geography занимает на 30% больше места.
Кроме того, тип данных geography не ограничивается только хранением Point, вы также можете хранить LineString, CircularString, CompoundCurve, Polygon, CurvePolygon, GeometryCollection, MultiPoint, MultiLineString и MultiPolygon и другие . Любая попытка сохранить даже простейшие типы географии (как широта / долгота) за пределами точки (например, экземпляр LINESTRING (1 1, 2 2)) приведет к появлению дополнительных строк для каждой точки, столбца для упорядочивания порядка каждой точки. и еще один столбец для группировки строк. SQL Server также имеет методы для типов данных Geography, которые включают вычисление площади, границы, длины, расстояний и т . Д.
Кажется неразумным хранить широту и долготу как десятичные в Sql Server.
Обновление 2
Если вы планируете выполнять какие-либо вычисления, такие как расстояние, площадь и т. Д., Правильно рассчитать их по поверхности земли будет сложно. Каждый тип Geography, хранящийся в SQL Server, также хранится с идентификатором пространственной привязки . Эти id могут быть разных сфер (земля 4326). Это означает, что вычисления в SQL Server на самом деле будут правильно рассчитывать по поверхности земли ( а не по прямой, которые могли бы проходить через поверхность земли).
источник
geography
и вы привели несколько хороших. В конце концов, я решил просто использоватьdecimal
поля в этом случае (см. Мое длинное обновление), но хорошо знать, что я могу использовать,geography
если мне когда-либо понадобится что-то более интересное, чем просто отображение координат.Еще одна вещь, которую следует учитывать, - это пространство для хранения, занимаемое каждым методом. Тип географии хранится в виде файла
VARBINARY(MAX)
. Попробуйте запустить этот скрипт:Результат:
Тип данных geography занимает почти вдвое больше места.
источник
источник