【问题标题】:Multiple Joins on Temporary Table OR Subquery in SQL 2008SQL 2008 中临时表或子查询的多个连接
【发布时间】:2010-08-13 13:38:07
【问题描述】:

我有以下 SQL,它在一系列日期中获取每一天的季节,然后按开始和结束日期对每个季节进行分组,并包含夜数。它的作用并不重要,但我的问题是哪个更好,我在下面完成它的方式或每次在第二个查询中使用 @dateSeasons 时将第一个 select 语句用作子查询。两种方式似乎运行相同,但这种方式看起来更整洁。

DECLARE @dateSeasons TABLE ([date] date, seasonID int)

INSERT INTO @dateSeasons
SELECT D.[date], S.ID
FROM @dates AS D
CROSS APPLY (

    SELECT TOP 1 ID
    FROM dbo.Seasons
    WHERE bookingID = @bookingID 
    AND D.[date] BETWEEN startDate AND endDate
    ORDER BY ID DESC

) AS S


SELECT MIN([date]), endDate, DATEDIFF(DAY, MIN([date]), DATEADD(DAY, 1, endDate)), seasonID
FROM (

    SELECT S1.seasonID, S1.[date], (

        SELECT MAX([date])
        FROM @dateSeasons S2
        WHERE S2.seasonID = S1.seasonID
        AND NOT EXISTS (

            SELECT NULL
            FROM @dateSeasons S3
            WHERE S3.[date] < S2.[date]
            AND S3.[date] > S1.[date]
            AND S3.seasonID <> S1.seasonID

        )

    ) AS endDate
    FROM @dateSeasons S1
) AS results
GROUP BY endDate, seasonID
ORDER BY MIN([date])

【问题讨论】:

  • “它做什么并不重要” - 我想你会的!通常,人们会告诉你他们对问题的感知解决方案,而不是他们试图解决的实际问题。
  • 是的,显然这对我很重要,但对我提出的问题并不重要。
  • 哪个更好将高度依赖于特定的 RDBMS、表结构、索引和数据的大小分布。您的问题中没有指定这些。确定两个查询中哪一个更好的最佳方法通常是在查看 RDBMS 提供给您的任何查询统计信息和查询计划的同时,相互测试它们。至于米奇的评论和您的回复,这通常很重要,因为哪个更好的答案通常是“以上都不是”。
  • +1 汤姆。 @CL4NCY,Mich 和 Tom 的意思是,如果您不想在这里发帖,您可能应该让这些人帮助确定什么是重要的,什么不是。您认为次要的事情可能对您数据库中的查询执行计划至关重要。

标签: sql join temp-tables


【解决方案1】:

看起来整洁与编写 SQL 代码无关。从性能的角度来看,看起来优雅的东西通常是最差可能的解决问题的方法。

确定哪种方法最好的唯一方法是首先确保您测试的两种方法返回相同的结果,然后对它们进行性能测试并检查执行计划(或在 mySQL 中解释)。使查询更好的技术也是特定于数据库的。在 SQL Server 中对性能优化最有效的方法在 Oracle 中可能是最差的。

【讨论】:

    【解决方案2】:

    有时您可以通过使用common table expression (CTE) 获得更好的性能:

    WITH
    dateSeasons ([date], [seasonID])
    AS
    (
        SELECT D.[date], S.ID
        FROM @dates AS D
        CROSS APPLY (
    
            SELECT TOP 1 ID
            FROM dbo.Seasons
            WHERE bookingID = @bookingID 
            AND D.[date] BETWEEN startDate AND endDate
            ORDER BY ID DESC
    
        ) AS S
    )
    
    SELECT MIN([date]), endDate, DATEDIFF(DAY, MIN([date]), DATEADD(DAY, 1, endDate)), seasonID
    FROM (
    
        SELECT S1.seasonID, S1.[date], (
    
            SELECT MAX([date])
            FROM dateSeasons S2
            WHERE S2.seasonID = S1.seasonID
            AND NOT EXISTS (
    
                SELECT NULL
                FROM dateSeasons S3
                WHERE S3.[date] < S2.[date]
                AND S3.[date] > S1.[date]
                AND S3.seasonID <> S1.seasonID
    
            )
    
        ) AS endDate
        FROM dateSeasons S1
    ) AS results
    GROUP BY endDate, seasonID
    ORDER BY MIN([date])
    

    【讨论】:

    • 根据我的经验,当基础表被正确索引时,CTE 可以正常工作。这种情况很少发生(不是因为索引被忽略,就像 SQL 中的所有内容一样,索引是一种平衡行为),除非一个人在设计良好且内部一致的数据库上工作,这 - 再次,根据我的经验 - 将是一个数据回购主要建立。用于报告/分析(集市、仓库...)。没有什么反对 CTE 的,但是当处于紧张状态时,它的指数会有所不同。只是在寻求此解决方案时要记住。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-02-07
    • 2023-02-25
    • 2018-06-20
    • 2017-09-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多