SQL Server循环执行需要太多时间

时间:2015-01-02 04:40:24

标签: sql sql-server database sql-server-2008 mssql-jdbc

我有一个表#TrackPlayedInformation,我正在循环。 #TrackPlayedInformation的示例数据如下:

   ProfileTrackTimeId   JukeBoxTrackId  ProfileId   EndTime                    SessionId    StartTime
         14                  52              33     2014-08-16 05:47:19.410    23424234   2014-08-16 05:45:19.410
         15                  51              33     2014-11-16 05:47:19.410    23424234   2014-08-16 05:45:19.410

我正在循环#TrackPlayedInformation并在每分钟分割开始时间和结束时间之间的时间间隔。新时间将插入物理表TempGraph

TempGraph的结构是

TempGraphId   AirTime                    AirCount
170390        2014-08-16 05:46:19.410       0
170391        2014-08-16 05:47:19.410       0

选中TempGraph(如果不存在),如果存在,则更新aircount,加1,否则作为新条目插入。

查询执行大约需要20分钟才能完成id,日期间隔大约为3个月。有没有更快的方法来实现结果?

我的锻炼查询如下:

USE [SocialMob]
GO
/****** Object:  StoredProcedure [dbo].[pDeleteTempGraph]    Script Date: 01/02/2015 09:00:32 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[pDeleteTempGraph]

AS
BEGIN
print('start')
declare @UserId int
declare @ProfileTrackTimeId int
set @UserId=1048
drop table #TrackPlayedInformation
delete from TempGraph
declare @loopCount int
declare @StartTime datetime
declare @LastDate datetime
declare @tempCount int
declare @EndTime datetime
declare @SaveTime datetime
declare @checkDate datetime
declare @countCheck int

--querying input--
--drop table #TrackPlayedInformation
--declare @UserId int
--set @UserId=33
SELECT ProfileTrackTimeId,ProfileTrackTime.JukeBoxTrackId,ProfileId,EndTime,SessionId,StartTime into #TrackPlayedInformation
 FROM ProfileTrackTime  LEFT JOIN
(SELECT JukeBoxTrackId FROM JukeBoxTrack INNER JOIN 
Album ON JukeBoxTrack.AlbumId=Album.AlbumId WHERE Album.UserId=@UserId) as AllTrackId 
ON ProfileTrackTime.JukeBoxTrackId=AllTrackId.JukeBoxTrackId


set @loopCount=0
declare @count as int
select @count=COUNT(ProfileTrackTimeId) from #TrackPlayedInformation
set @LastDate=GETDATE()--storing current datetime
print('looping starts')
while @loopCount<@count
begin
    select @StartTime=StartTime from #TrackPlayedInformation
    select @EndTime=EndTime from #TrackPlayedInformation
    select @ProfileTrackTimeId=ProfileTrackTimeId from #TrackPlayedInformation

    --select @checkDate=AirTime from TempGraph 
        while @StartTime<=@EndTime
        begin
            set @StartTime=DATEADD(minute,1,@StartTime)

            --checking for duplication
            --SELECT @countCheck= count(TempGraphId) FROM TempGraph WHERE AirTime=@StartTime
            --select @countCheck
            --if (@countCheck<1)
            if not exists(select top 1 TempGraphId from TempGraph where AirTime=@StartTime)
            begin
                --print('inserting')
                insert TempGraph (AirTime,AirCount) values(@StartTime,0)
            end
            else
            begin
                --print('updating')
                update TempGraph set AirCount=AirCount+1 where AirTime=@StartTime
            end
            set @LastDate=@StartTime 
        end

        set @LastDate=DATEADD(MINUTE,1,@LastDate);
    --deleting row from #TrackPlayedInformation
        --print('deleting')
        delete from #TrackPlayedInformation where ProfileTrackTimeId=@ProfileTrackTimeId
        set @loopCount=@loopCount+1 --incrementing looping condition
end

begin
    insert TempGraph (AirTime,AirCount) values(@LastDate,0)
end

begin
    declare @nowdate datetime
    set @nowdate=GETDATE()
    insert TempGraph (AirTime,AirCount) values(@nowdate,0)
end

    select * from TempGraph;
    delete from TempGraph;
END

我试图将时间间隔除以分钟,例如考虑日期2014 01 01 5.40作为开始时间,2014 01 01 5.50作为结束时间。我需要在TempGraph中输入2014 01 01 5.41,2014 01 01 5.42 ,2014 01 01 5.43 ..... upto 2014 01 01 5.50

3 个答案:

答案 0 :(得分:1)

我并不完全清楚你想要完成什么。尽管如此,应尽可能避免SQL中的循环。

您可以考虑UPDATE语句类似于:

UPDATE TempGraph
SET    AirCount = AirCount + 1
WHERE  AirTime BETWEEN @StartTime AND @EndTime

后面跟着&#34;缺少&#34;的记录。倍。如果没有关于此代码目的的更多信息,则很难提供更多帮助。

答案 1 :(得分:1)

我实际上并不了解你要做的事情。以下内容可以帮助您

SELECT * INTO #TEMP
FROM
(
SELECT 14 ProfileTrackTimeId,'2014-08-16 05:47:19.410' StartTime,   '2014-08-16 05:50:19.410' EndTime
UNION ALL
SELECT 14 ProfileTrackTimeId,'2014-08-16 10:20:19.410' StartTime,   '2014-08-16 10:23:19.410' EndTime
UNION ALL
SELECT 20 ProfileTrackTimeId,'2014-08-17 08:10:19.410' StartTime,   '2014-08-17 08:12:19.410' EndTime
UNION ALL
SELECT 20 ProfileTrackTimeId,'2014-08-18 13:59:19.410' StartTime,   '2014-08-18 14:02:19.410' EndTime
)TAB

现在,对于每starttime

,您将获得endtimeProfileTrackTimeId之间的每分钟日期。
;WITH CTE AS
(
   SELECT ProfileTrackTimeId,CAST(StartTime AS DATETIME) FDATES,
   CAST(EndTime AS DATETIME) TDATES
   FROM #TEMP  
   UNION ALL
   SELECT T.ProfileTrackTimeId,DATEADD(MINUTE,1,FDATES),TDATES 
   FROM #TEMP T
   JOIN CTE ON CTE.ProfileTrackTimeId = T.ProfileTrackTimeId
   WHERE FDATES < TDATES
)
SELECT DISTINCT ProfileTrackTimeId,FDATES 
FROM CTE
ORDER BY ProfileTrackTimeId,FDATES
OPTION (MaxRecursion 0)

如有任何改变,请通知我。

答案 2 :(得分:0)

要在startTime和EndTime之间创建序列,可以使用带有nodes()方法的模式。要执行插入和更新操作,您可以使用MERGE语句。以下示例说明如何执行此操作。

ALTER PROC [dbo].[pDeleteTempGraph]
AS
BEGIN

    IF OBJECT_ID('tempdb..#seq') IS NOT NULL DROP TABLE #seq
    CREATE TABLE #seq(AirTime datetime, AirCount int)

    ;WITH cte AS
    (
     SELECT *, CAST(REPLICATE(CAST('<M></M>' AS varchar(MAX)),ISNULL(DATEDIFF(MINUTE, StartTime, EndTime), 1)) AS xml) AS xmlCol
     FROM #TrackPlayedInformation t1
     ),cte2 AS
    (  
     SELECT DATEADD(MINUTE, ROW_NUMBER() OVER(PARTITION BY profileTrackTimeId ORDER BY StartTime), StartTime) AS AirTime
     FROM cte CROSS APPLY xmlCol.nodes ('/M') AS Split(M)
     )
     INSERT #seq
     SELECT AirTime, COUNT(*) AS AirCount
     FROM cte2
     GROUP BY AirTime

     MERGE TempGraph AS TARGET
     USING (           
            SELECT AirTime, AirCount
            FROM #seq           
            ) AS SOURCE ON TARGET.AirTime = SOURCE.AirTime
     WHEN MATCHED THEN UPDATE SET AirCount = TARGET.AirCount + SOURCE.AirCount
     WHEN NOT MATCHED BY TARGET THEN
     INSERT(AirTime, AirCount)
     VALUES(SOURCE.AirTime, SOURCE.AirCount);

     SELECT *
     FROM TempGraph

     DELETE FROM TempGraph

END

但是在您的特定情况下,MERGE语句可能过多,并且表#seq就足够了。无论如何,如果你有一个额外的UPSERT逻辑,最好用MERGE语句来做。