在sql server中找到特殊值的最快方法

时间:2015-09-14 09:43:38

标签: database sql-server-2008

我使用Sql Server,我有一个返回的查询(我称之为@result) 每天特殊产品的所有输入(IN)和输出(OUT)数据 例如:

+---------+----------+---------+---------+
|RowID    |   Date   |   IN(+) | OUT(-)  |
+---------+----------+---------+---------+
|100      |2001-01-01|50       |0        |
|101      |2001-01-02|20       |0        |
|102      |2001-01-03|0        |10       |
|103      |2001-01-04|0        |60       |
|104      |2001-01-05|15       |0        |
|105      |2001-01-06|35       |0        |
|106      |2001-01-07|0        |7        |
|107      |2001-01-08|0        |25       |
|108      |2001-01-09|0        |18       |
|109      |2001-01-10|50       |0        |

我使用此查询来计算查询中每个日期的保留值:

    With cte1 as (
        Select rowID,date,
        (
        SELECT SUM(in-out) 
        FROM @result T2 WHERE T2.rowid<=T1.rowid
        ) AS remain
        From @result T1
        )
    Select * from cte1

+---------+----------+---------+---------+----------+
|RowID    |   Date   | IN(+)   | OUT(-)  +  remain  +
+---------+----------+---------+---------+----------+
|100      |2001-01-01|50       |0        |50        |
|101      |2001-01-02|20       |0        |70        |
|102      |2001-01-03|0        |10       |60        |
|103      |2001-01-04|0        |60       |0         |
|104      |2001-01-05|15       |0        |15        |
|105      |2001-01-06|35       |0        |50        |
|106      |2001-01-07|0        |7        |43        |
|107      |2001-01-08|0        |25       |18        |
|108      |2001-01-09|0        |18       |0         |
|109      |2001-01-10|50       |0        |50        |

我想找到3个剩余字段等于零的最后一条记录,并将该字段(日期和id)保存在局部变量上。 注意:我对每件产品都有非常多的记录(大约数百万),所有产品的价值都很慢。

我使用此查询:

    With cte1 as (
        Select rowID,date,
        (
        SELECT SUM(in-out) 
        FROM @result T2 WHERE T2.rowid<=T1.rowid
        ) AS remain
        From @result T1
        )
    Select cte1.RowID, cte1.Date 
    From cte1 Where mandeh = 0
    order by cte1.rowID Desc

但这很慢。

问题:

是我查询找到零值的最佳方法,以及我可以采取哪些措施加快查询速度。

感谢。

=============================================== ========================== 这是数据表的结构

Create table    TestSpeed 
        (
            rowID         int identity(1,1) PRIMARY KEY CLUSTERED,
            G_date  SmallDateTime,
            G_Num  integer,
            in_data Numeric(18,2),
            Out_data    Numeric(18,2)
        )

我导出此表的数据,您可以下载并导入数据到表中以获得测试查询速度。 Data For Import

我的最后一个返回特殊值的查询是:

        With cte1 as (
                Select rowID ,G_date,G_Num,in_data,Out_data ,
                (
                SELECT SUM(in_data-Out_data) 
                FROM Testspeed T2 WHERE T2.rowid<=T1.rowid
                ) AS Remain
                From Testspeed T1
            ), 
     cte2 As 
    (
    Select Top 3 * From cte1 
    Where Remain = 0
    Order By rowid Desc
    )
    Select * From cte2

此查询在我的电脑上运行4分钟。

非常感谢

1 个答案:

答案 0 :(得分:0)

我没有加载你的数据,而是一个大约1.5米行的样本。查询耗时约5秒,包括加载样本。

with cte as (
  select rowID    = max(rowID) + 1
       , G_date   = cast ( getdate()     as SmallDateTime)
       , In_calc  = cast ( SUM(in_data)  as numeric(18,2)) 
       , Out_calc = cast ( SUM(out_data) as numeric(18,2)) 
       , In_data  = cast ( 0             as numeric(18,2))
       , Out_data = cast ( 0             as numeric(18,2)) 
       , Remain   = cast ( SUM(in_data) - SUM(out_data) as numeric(18,2)) 
       , Remain0  = 0
  from @result
  union all 
  select rowID    = r.rowID
       , G_date   = r.G_date
       , In_calc  = cast ( cte.in_data  - r.in_data   as numeric(18,2))  
       , Out_calc = cast ( cte.out_data - r.out_data  as numeric(18,2)) 
       , In_data  = cast ( cte.in_data                as numeric(18,2)) 
       , Out_data = cast ( cte.out_data               as numeric(18,2)) 
       , Remain   = cast ( cte.in_data - cte.out_data as numeric(18,2)) 
       , Remain0  = case when cte.in_data <= cte.out_data then cte.Remain0 + 1 else cte.Remain0 end
  from @result r join cte on r.rowID=cte.rowID-1
  where cte.Remain0 < 3
)
select * from cte where Remain0 between 1 and 3
option (maxrecursion=0)  -- <-- if you need more than 100 recursion until you have 3 times zero 

您从当前状态开始并逐行返回,In_dataOut_data是您拥有的金额,并且是计算Remain的基础。 Remain0计算你达到最低点的频率。