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