【问题标题】:More efficient alternative to subquery子查询的更有效替代方案
【发布时间】:2013-10-09 12:17:27
【问题描述】:

我有许多“实际”和“历史伴侣表”(可以这么说),最后一个结构如下:

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

如果我在 "actual" 表中插入(或更新或删除)记录,触发器会将受影响的记录放入 "history table" 并使用 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'

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


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

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

测试服务器有 20 万条记录,我也有幸使用 DBCC FreeProcCache 和 DBCC DropCleanbuffers 指令。实际工作的服务器有超过 230 万条记录,也没有删除 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'

真实的 61 秒 @ 2'316'890rec,测试中的 4 秒 @ 191'533

拉胡尔的:

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'

真实的 62 秒 @ 2'316'890rec,测试时 4 秒 @ 191'533 几乎相等

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

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'

真实的 76 秒 @ 2'316'890rec,测试中的 5 秒 @ 191'533

到目前为止,原创和 Rahul 的速度最快,而 George 的没那么快。

【问题讨论】:

  • 遇到任何性能问题首先要做的是查看execution plan。可能不是导致性能问题的子查询(通常 SQL Server 将子查询优化为连接或等效项)
  • 请告诉我你的日期不是 varchars 吗?
  • 谢谢你的想法,贾斯汀。似乎 SQL Server 实际上正在将查询优化为 INNER JOIN
  • 不,乔尔。现在是日期时间
  • 你有哪些指标?

标签: sql-server subquery


【解决方案1】:

尝试使用 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'

【讨论】:

    【解决方案2】:

    我认为 row_num() 可能对您有用:

    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
    

    【讨论】:

      猜你喜欢
      • 2017-03-26
      • 2015-08-23
      • 1970-01-01
      • 2016-12-13
      • 1970-01-01
      • 2017-11-06
      • 2021-04-25
      • 1970-01-01
      • 2016-09-08
      相关资源
      最近更新 更多