私は顧客データベースを再設計しています。標準の住所フィールド(Street、Cityなど)とともに保存したい新しい情報の1つは、住所の地理的な場所です。私が考えている唯一の使用例は、住所が見つからない場合にユーザーがGoogleマップに座標をマッピングできるようにすることです。これは、エリアが新しく開発された場合や、遠隔地や農村部にある場合によく発生します。
私の最初の傾向は、緯度と経度を10進値として格納することでしたが、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どういたしまして。余談ですが、null許容のGEOGRAPHYデータ型列で空間インデックスを使用するときは十分注意してください。深刻なパフォーマンスの問題があるため、スキーマを再構築する必要がある場合でも、GEOGRAPHY列をnullにできないようにしてください。–トーマス6月18日11:18
全体として、近接検索を実行する可能性と、パフォーマンスと複雑さのトレードオフを比較検討してgeography
、この場合はの使用を省略することにしました。
私が実行したテストの詳細:
私は2つのテーブルを作成しました。1つは緯度と経度geography
を使用し、もう1つはを使用してい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