日期:2014-05-17  浏览次数:20496 次

大数据量下的查找最新的几条数据的通用方法
原文地址
http://blog.csdn.net/xuexiaodong2009/article/details/7938679
由于项目需要,需要获取一组数据的的最新一条数据,表结构如下:

[sql] view plaincopy
CREATE TABLE [dbo].[WUSU_SUOLITest_Table](  
    [ID] [bigint] IDENTITY(1,1) NOT NULL,  
    [ReceiveTime] [datetime] NULL,  
    [GroupID] [bigint] NOT NULL,  
    [DataValue] [float] NULL,  
    [SensorCode] [char](10) NOT NULL,  
)  
在这个表上只有两种操作,插入和查询,没有删除和更新。而且同一种设备,随着id列的变大,ReceiveTime也随着变大。
每一个不同的SensorCode代表了一个设备,目前有50个设备,每30秒上报一次数据,ReceiveTime代表上报数据的时间,现在需要获取每一个设备最新一次的数据,
  开始我使用如下的查询语句:  

[sql] view plaincopy
select * from  WUSU_SUOLITest_Table where id in (select max(id) from  WUSU_SUOLITest_Table group by SensorCode )  
 在数据量比较小时,是没有问题的,但数据量特别大时,这种方式,目前一天的数据就超过了14万,有很大的延时,即使在id上有聚集索引,SensorCode上使用了分区,依然没有多大作用。时间主要花费到了group by上。
  实在想不多到什么好的而解决方法,就只能在此表上创建一个触发器,每次插入数据时就把最新的数据放在了一个临时表,又有临时表最多只有50条数据,速度当然就很好了。 

[sql] view plaincopy
create TRIGGER [dbo].[UpdateWUSU_LastOriginalDataSUOLI]  
   ON  [dbo].[WUSU_SUOLITest_Table]  
   AFTER  INSERT  
AS   
BEGIN     
    declare @SensorCode char(10), @DataValue float ,@ReceiveTime datetime ,@GroupID bigint  
      
    select @SensorCode=SensorCode,@DataValue=DataValue,@ReceiveTime=ReceiveTime,@GroupID=GroupID from inserted  
      update WUSU_LastOriginalData set DataValue=@DataValue,ReceiveTime=@ReceiveTime,GroupID=@GroupID  
          where SensorCode=@SensorCode  
END  
当然这是为了获取各种设备最新的一条数据,如果要获取最新的两条数据,最多也就是100条记录,一次类推,只需要把上边的触发器修改一下就可以。

但还有没有更好的方式,在不修改表结构的情况下?目前还没有想到。
------最佳解决方案--------------------
参考大版的整理

--1、用于查询重复处理记录(如果列没有大小关系时2000用生成自增列和临时表处理,SQL2005用row_number函数处理)

--> --> (Roy)生成測試數據
 
if not object_id('Tempdb..#T') is null
    drop table #T
Go
Create table #T([ID] int,[Name] nvarchar(1),[Memo] nvarchar(2))
Insert #T
select 1,N'A',N'A1' union all
select 2,N'A',N'A2' union all
select 3,N'A',N'A3' union all
select 4,N'B',N'B1' union all
select 5,N'B',N'B2'
Go


--I、Name相同ID最小的记录(推荐用1,2,3),方法3在SQl05时,效率高于1、2
方法1:
Select * from #T a where not exists(select 1 from #T where Name=a.Name and ID<a.ID)

方法2:
select a.* from #T a join (select min(ID)ID,Name from #T group by Name) b on a.Name=b.Name and a.ID=b.ID

方法3:
select * from #T a where ID=(select min(ID) from #T where Name=a.Name)

方法4:
select a.* from #T a join #T b on a.Name=b.Name and a.ID>=b.