【问题标题】:SQL-query task, decision?SQL查询任务,决定?
【发布时间】:2010-04-01 20:21:10
【问题描述】:

MS SQL Server 2005 中有一个汇率表:

ID |当前 |价格 |日期
1   |美元   | 30      | 01.10.2010
3   |英镑   | 45      | 07.10.2010
5   |美元   | 31      | 08.10.2010
7   |英镑   | 46      | 09.10.2010
9   |美元   | 32      | 12.10.2010
11 | |英镑   | 48      | 03.10.2010

速率实时更新,表中有超过 10 亿行。

它需要编写一个 SQL 查询,它将提供每种货币的最新汇率。
我的决定是:

SELECT c.[id],c.[curr],c.[rate],c.[date]    
FROM [curr_rate] c, (SELECT curr, MAX(date) AS rate_date FROM [curr_rate] 
      GROUP BY curr) t
WHERE c.date = t.rate_date AND c.curr = t.curr
ORDER BY c.[curr] ASC

是否可以编写不带子查询的查询并与派生表连接?

【问题讨论】:

    标签: sql sql-server-2005 tsql optimization


    【解决方案1】:

    不,我认为不会。你有关于 CURR 和日期的索引吗?

    【讨论】:

    • 为表选择主索引 - 这是此问题的子任务。我认为 PRIMARY INDEX 应该包含来自 CURR 和 DATE 文件。
    【解决方案2】:

    在调整此查询时,整理索引可能比 SQL 语法更重要。

    可能值得将子查询方法与 CTE 进行比较:

    ;WITH currCTE
    AS
    (
            SELECT id
                   ,curr
                   ,rate
                   ,date
                   ,ROW_NUMBER() OVER (PARTITION BY curr
                                       ORDER BY date desc
                                      ) AS rn
            FROM [curr_rate]
    )
    SELECT id
           ,curr
           ,rate
           ,date
    FROM currCTE
    WHERE rn = 1
    

    如果表PK在id上,并且行总是按日期顺序添加到表中,则在排名函数的ORDER BY子句中使用id而不是日期可能会获得更好的性能。

    【讨论】:

    • 这只是一个问题/任务 - 面试前的工作。现在,我认为没有子查询和加入任务的决定。
    【解决方案3】:

    您的查询不使用子查询,因此无需更改。子查询是返回单个值的 SELECT 查询,嵌套在 SELECT、INSERT、UPDATE 或 DELETE 语句或另一个子查询中。子查询可以在任何允许使用表达式的地方使用。见Subquery Fundamentals

    您的查询正在使用派生表,也称为内联视图,您已将其命名为“t”。

    我会从摆脱古老的连接语法开始:

    SELECT 
        c.[id],c.[curr],c.[rate],c.[date]    
        FROM [curr_rate] c
            INNER JOIN (SELECT
                            curr, MAX(date) AS rate_date
                            FROM [curr_rate] 
                            GROUP BY curr
                       ) t ON c.curr = t.curr AND c.date = t.rate_date 
        ORDER BY c.[curr] ASC
    

    但它将具有相同的执行计划。您可以将派生表移动到 CTE 中,但这与派生表几乎相同。

    如果您在以下位置创建索引视图,查询可能会运行得更快:

    SELECT
        curr, MAX(date) AS rate_date
        FROM [curr_rate] 
        GROUP BY curr
    

    在 curr+MAX(date) 上有一个索引。如果您在 [curr_rate].curr+date 上有一个索引,您的查询将具有更好的性能并且是:

    SELECT 
        c.[id],c.[curr],c.[rate],c.[date]    
        FROM [curr_rate] c
            INNER JOIN [curr_rate_max_view] t ON c.curr = t.curr AND c.date = t.rate_date 
        ORDER BY c.[curr] ASC
    

    【讨论】:

      【解决方案4】:

      不知道可以避免sub-select,但是可以避免join甚至group by

      SELECT id, curr, rate, date
      FROM curr_rate r
      WHERE date = (
             SELECT MAX(date)
               FROM curr_rate
              WHERE curr = r.curr
            )
      ORDER BY curr ASC
      

      我不知道这会如何。

      【讨论】:

      • 这个查询是我的第一个决定,但我想我的查询在性能上会更好(更快)。谁知道,哪一个性能更好(更好)?
      • 这很难说,@Sirius。您应该始终测试查询的性能。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-05-01
      • 2021-12-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-02-28
      相关资源
      最近更新 更多