我在处理数据库中的一个非常大的表时遇到了一些麻烦。在谈论这个问题之前,让我们谈谈我想要实现的目标。
我有两个源表:
SALES_MAN (ID_SMAN, SM_LATITUDE, SM_LONGITUDE)
来源2:CLIENT (ID_CLIENT, CLATITUDE, CLONGITUDE)
目标:DISTANCE (ID_SMAN, ID_CLIENT, SM_LATITUDE, SM_LONGITUDE, CLATITUDE, CLONGITUDE, DISTANCE)
我们的想法是使用目标表中的SALES_MAN
为每个客户端找到最接近ROW_NUMBER
的前N个。
我目前正在做的是计算每个客户和每个销售人员之间的距离:
INSERT INTO DISTANCE ([ID_SMAN], [ID_CLIENT], [DISTANCE],
[SM_LATITUDE], [SM_LONGITUDE], [CLATITUDE], [CLONGITUDE])
SELECT
[ID_SMAN], [ID_CLIENT],
geography::STGeomFromText('POINT('+IND_LATITUDE+' '+IND_LONGITUDE+')',4326).STDistance(geography::STGeomFromText('POINT('+DLR.[DLR_N_GPS_LATTITUDE]+' '+DLR.[DLR_N_GPS_LONGITUDE]+')',4326))/1000 as distance,
[SM_LATITUDE], [SM_LONGITUDE], [CLATITUDE], [CLONGITUDE]
FROM
[dbo].[SALES_MAN], [dbo].[CLIENT]
DISTANCE
表包含大约1毫秒的行。
为每位客户提供最近的5位销售人员的第二步是运行此查询:
SELECT *
FROM
(SELECT
*,
ROW_NUMBER() OVER(PARTITION BY ID_CLIENT ORDER BY DISTANCE) rang
FROM DISTANCE) TAB
WHERE rang < 6
最后一个查询真的很消耗。因此,为了避免使用SORT运算符,我尝试在DISTANCE和ID_CLIENT中创建一个已排序的非聚簇索引,但它不起作用。我还尝试在两个索引中包含所有需要的列。
但是当我在DISTANCE
上创建聚簇索引并在ID_CLIENT
中保留非聚簇排序索引时,事情变得更好了。
那么非聚集排序索引在这种情况下不起作用?
但是当我使用聚集索引时,我在加载数据时遇到了其他问题,我在开始加载过程之前有点被删除了。
那你觉得怎么样?我们如何处理这种表,以便能够在没有性能问题的情况下选择,插入或更新数据?
非常感谢
答案 0 :(得分:1)
评论太长了,但请考虑以下几点。
项目1)考虑在每个源表中添加Geography
字段。这将消除冗余的GEOGRAPHY::Point()
函数调用
Update YourTable Set GeoPoint = GEOGRAPHY::Point([Lat], [Lng], 4326)
那么距离的计算就是
,InMeters = C.GeoPoint.STDistance(S.GeoPoint)
,InMiles = C.GeoPoint.STDistance(S.GeoPoint) / 1609.344
第2项:不要生成每种可能的组合,而应考虑向JOIN
添加条件。请记住,Lat或Lng中的每个“1”大约是69英里,因此您可以缩小搜索范围。例如
From CLIENT C
Join SALES_MAN S
on S.Lat between C.Lat-1 and C.Lat+1
and S.Lng between C.Lng-1 and C.Lng+1
此+/- 1
可以是任何合理的价值......(即0.5
或甚至2.0
)
答案 1 :(得分:0)
ROW_NUMBER是一个窗口函数,需要与ORDER BY列相关的整行,因此最好在ROW_NUMBER之前过滤您的结果,
您需要更改以下代码:
c(1,1,2,2)
进入这个:
SELECT * FROM (
SELECT *, ROW_NUMBER() OVER(PARTITION BY ID_CLIENT ORDER BY DISTANCE)
rang FROM DISTANCE
) TAB
WHERE rang < 6
并确保您在CLIENT_ID和DISTANCE列上添加索引