更有效的子查询替代方案

时间:2013-10-09 12:17:27

标签: sql-server subquery

我有很多“实际”和“历史伴侣表”(可以这么说),结尾的结构是这样的:

values|  date_deal | type_deal | num (autoinc)
value1| 01.01.2012 |         i |   1
value1| 02.01.2012 |         u |   2
value2| 02.01.2012 |         i |   3
value2| 03.01.2012 |         u |   4
value1| 04.01.2012 |         d |   5
value2| 05.01.2012 |         u |   6
value2| 08.01.2012 |         u |   7

如果我在“实际”表格中插入(或更新或删除)记录,触发器会将受影响的记录放入“历史记录表” date_deal = Geddate( ),type_deal = i | u | d (分别用于插入,更新和删除触发器)和 num作为autoinc唯一值

所以问题是如何获取在某个日期有效的每个不同值的最后记录,并从最终结果记录中排除type_deal ='d'(因为该记录在那时被从实际表中删除而我们不想要有任何与之相关的事情)

我大多数时间都这样做:

SELECT  *
FROM    t_table1 t1
WHERE   t1.num = (  SELECT  MAX(num)
                    FROM    t_table1 t2
                    WHERE   t2.[values] = t1.[values]
                        AND t2.[date_deal] < @dt)
    AND t1.[type_deal] <> 'D'

但有时效果很慢。我正在寻找更有效的替代方案。请帮忙


所以,更新。 谢谢回复,朋友们。

我已经在实际服务器和测试服务器上进行了一些测试。 为了将这些不同的方法放到同一个联盟中,我决定我们应该从源表中获取所有字段。

测试服务器有200K记录,我也有使用DBCC FreeProcCache的奢侈 和DBCC DropCleanbuffers指令。实际工作服务器有超过2.3M的记录,也没有丢弃buff或缓存的选项,因为..好吧..它正在被真实用户使用。所以它只被扯了一次,我就在那之后得到了结果。

这是两个服务器上的实际查询和时间:

原件:

DECLARE @dt datetime = CONVERT(datetime, '01.08.2013', 104)

SELECT  *
FROM    [CLIENTS_HISTORY].[dbo].[Clients_all_h] c
WHERE   c.num = (   SELECT  MAX(num)
                    FROM    [CLIENTS_HISTORY].[dbo].[Clients_all_h] c2
                    WHERE   c2.[AccountSys] = c.[AccountSys]
                        AND date_deal <= @dt)
    AND c.type_deal <> 'D'

61sec @ 2'316'890rec on real one,4sec @ 191'533 on test

的Rahul的:

SELECT  *
FROM    [CLIENTS_HISTORY].[dbo].[Clients_all_h] c
GROUP BY [all_fields]
HAVING  c.num = (   SELECT  MAX(num)
                    FROM    [CLIENTS_HISTORY].[dbo].[Clients_all_h] c2
                    WHERE   c2.[AccountSys] = c.[AccountSys]
                        AND date_deal <= @dt)
    AND c.type_deal <> 'D'

62sec @ 2'316'890rec on real one,4sec @ 191'533 on test 几乎相等

乔治(有一些重大变化):

SELECT * FROM 
(
SELECT  *,
        ROW_NUMBER() OVER(PARTITION BY accountsys ORDER BY num desc) AS aa
FROM    [CLIENTS_HISTORY].[dbo].[Clients_all_h] c
WHERE   c.date_deal < @dt) as a
WHERE   aa=1
    AND type_deal <> 'D'

76sec @ 2'316'890rec on real one,5sec @ 191'533 on test

到目前为止,原作和Rahul是最快的,乔治的速度不是很快。

2 个答案:

答案 0 :(得分:0)

尝试使用GROUP BY..HAVING CLAUSE

SELECT  *
    FROM    t_table1 t1
    GROUP BY [column_names]
    HAVING   t1.num = (  SELECT  MAX(num)
                        FROM    t_table1 t2
                        WHERE   t2.[values] = t1.[values]
                            AND t2.[date_deal] < @dt)
        AND t1.[type_deal] <> 'D'

答案 1 :(得分:0)

我认为rownum()对您有用,如下所示:

select
   *
from
(
   select
     *,
   row_number() over( partition by date_deal order by num) as aa
      from
   t_table1 t1
   where
     t1.[type_deal] <> 'D'
) as a
where
   aa=1