提高Lat / Long地理位置的性能

时间:2017-05-30 17:09:02

标签: sql-server

我有两个表,Bins和Locations,第一个有300万个记录,第二个有3000万个。我正在尝试将Bin for Location与以下代码匹配

Create Table #tbl_locations (LocationID int not null, Lat float not null, Lon float not null) 
Create Table #tbl_bins (BinID int not null, MinLat float not null, MaxLat float not null, MinLon float not null, MaxLon float not null) 

CREATE NONCLUSTERED INDEX [IX_tbl_locations] ON [#tbl_locations] ([Lat] ASC, [Lon] ASC) 
ON [PRIMARY]
CREATE NONCLUSTERED INDEX [IX_tbl_bins1] ON [#tbl_bins] ([MinLat] ASC, [MaxLat] ASC) 
ON [PRIMARY]
CREATE NONCLUSTERED INDEX [IX_tbl_bins2_ABC] ON [#tbl_bins] ([MinLon] ASC, [MaxLon] ASC) 
ON [PRIMARY]

Select L.LocationID, C.BinID
From   #tbl_bins C 
Inner Join #tbl_locations L 
ON (L.Lat Between C.MinLat And C.MaxLat) 
AND (L.Lon Between C.MinLon And C.MaxLon)

不幸的是性能非常差,我已经尝试索引不同的字段,但这没有用。一切仍然需要超过10分钟才能运行。

任何想法如何让这个表现更好?也许更好的匹配算法? SQL Server 2012 SP3。 BinID和LocationID已经在它们上创建了PRIMARY KEY CLUSTERED。 当我检查执行计划时,我看到JOIN是由NESTED LOOP执行的。

STATISTICS IO的输出是

Table '#tbl_locations_________________________________________________________________________________________________________000000000283'. 
Scan count 2631070, logical reads 25575057, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table '#tbl_bins________________________________________________________________________________________________________000000000284'. 
Scan count 17, logical reads 14741, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

非常感谢!

编辑 - 如果不是临时表,我使用真实的,这将是导出的模式

/****** Object:  Table [dbo].[tbl_Bins]    Script Date: 5/30/2017 3:49:05 PM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[tbl_Bins](
    [BinID] [int] NOT NULL,
    [MinLat] [float] NOT NULL,
    [MaxLat] [float] NOT NULL,
    [MinLon] [float] NOT NULL,
    [MaxLon] [float] NOT NULL,
 CONSTRAINT [PK_tbl_Bins] PRIMARY KEY CLUSTERED 
(
    [BinID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]

GO
/****** Object:  Table [dbo].[tbl_Locations]    Script Date: 5/30/2017 3:49:05 PM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[tbl_Locations](
    [ExposureID] [int] NOT NULL,
    [Accgrpid] [int] NOT NULL,
    [LocID] [int] NOT NULL,
    [Lat] [float] NOT NULL,
    [Lon] [float] NOT NULL,
 CONSTRAINT [PK_tbl_locations] PRIMARY KEY CLUSTERED 
(
    [ExposureID] ASC,
    [Accgrpid] ASC,
    [LocID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]

GO
/****** Object:  Index [IX_tbl_bins1]    Script Date: 5/30/2017 3:49:05 PM ******/
CREATE NONCLUSTERED INDEX [IX_tbl_bins1] ON [dbo].[tbl_Bins]
(
    [MinLat] ASC,
    [MaxLat] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
GO
/****** Object:  Index [IX_tbl_bins2_ABC]    Script Date: 5/30/2017 3:49:05 PM ******/
CREATE NONCLUSTERED INDEX [IX_tbl_bins2_ABC] ON [dbo].[tbl_Bins]
(
    [MinLon] ASC,
    [MaxLon] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
GO
/****** Object:  Index [IX_tbl_locations]    Script Date: 5/30/2017 3:49:05 PM ******/
CREATE NONCLUSTERED INDEX [IX_tbl_locations] ON [dbo].[tbl_Locations]
(
    [Lat] ASC,
    [Lon] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
GO

2 个答案:

答案 0 :(得分:0)

我找到了改善这种情况的方法。

SELECT     L.LocationID, C.BinID
FROM       #tbl_bins C 
INNER JOIN #tbl_locations L 
ON         (L.Lat Between C.MinLat And C.MaxLat) 
AND        (L.Lon Between C.MinLon And C.MaxLon)
WHERE FLOOR(C.MinLat * 1000 ) <= FLOOR(L.Lat*1000) 
AND   FLOOR(C.MinLon * 1000 ) <= FLOOR(L.Lon*1000) 
AND CEILING(C.MaxLat * 1000 ) >= CEILING(L.Lat*1000) 
AND CEILING(C.MaxLon * 1000 ) >= CEILING(L.Lon*1000) 

这可以通过减少要加入的Bins数量来帮助查询。

答案 1 :(得分:0)

创建覆盖索引:

@if (session()->has('name'))
    {{ session('name') }}
@endif

拥有这样的索引意味着不需要访问该表以便检索CREATE INDEX IX_tbl_lat_long_locations ON [#tbl_locations] (Lat, Lon, LocationID)

如果可以,请将其设为LocationID索引。