在SQL Server性能中处理非常大的表

时间:2017-08-24 19:35:56

标签: sql-server performance sql-server-2016 clustered-index non-clustered-index

我在处理数据库中的一个非常大的表时遇到了一些麻烦。在谈论这个问题之前,让我们谈谈我想要实现的目标。

我有两个源表:

  • 来源1: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中保留非聚簇排序索引时,事情变得更好了。

那么非聚集排序索引在这种情况下不起作用?

但是当我使用聚集索引时,我在加载数据时遇到了其他问题,我在开始加载过程之前有点被删除了。

那你觉得怎么样?我们如何处理这种表,以便能够在没有性能问题的情况下选择,插入或更新数据?

非常感谢

2 个答案:

答案 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列上添加索引