我对SQL中的表设计/查询效率有疑问。
我有两个表,表A包含客户端列表,表B包含客户端ID,以及上次从客户端收到消息的时间。
客户端的数量正在增长,并且在每千个客户端中,每个客户端至少每分钟发送一次消息,有时更多,有时更少,但是平均而言,大约是每分钟一次。
表B的增长相当快。
问题是这样的:我希望能够提取所有客户及其上次看到的日期和时间的列表。
问题是随着表的增长,查询的执行时间越来越长,并且需要扫描表A和B中的所有行。
我在表B中引入了一个新列,它只是一个日期类型列,并在其上创建了非聚集,非唯一的索引,但是似乎没有太大区别。
查询是:
SELECT [TableA].[Client_ID] ISNULL(R.Most_Recent_TimeStamp, '2000-01-01') AS Most_Recent_Comms
FROM [TableA]
LEFT JOIN (SELECT [TableB].[Client_ID], MAX([TableB].[Time_Stamp]) AS Most_Recent_TimeStamp FROM [TableB] WITH(NOLOCK) GROUP BY [TableB].[Client_ID]) AS R ON [TableA].[Client_ID] = R.Client_ID
执行时间以数十秒为单位。当我包含相当数量的WITH(NOLOCK)语句时,情况有所改善。您可以想象,随着时间的推移和TableB的增长,执行时间将会增长。
我认为这不是正确的方法。
我确信有更好的方法。如何创建视图或另一个表并编写触发器,该触发器将在每次向TableB中插入一行时更新新表。新表将始终保持最新状态,并且可以调用简单的SELECT查询。
我建议以下之一:
SELECT b.ClientId, MAX(b.TimeStamp)
FROM TableB b
GROUP BY b.ClientId;
这假定所有客户端都在TableB
中。如果没有:
SELECT a.ClientId, b.TimeStamp
FROM TableA OUTER APPLY
(SELECT b.*
FROM TableB b
WHERE b.Client_Id = a.Client_Id
ORDER BY b.TimeStamp DESC
) b;
对于两个查询,您都希望在TableB(ClientId, TimeStamp)
上建立索引。