我有以下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])
答案 0 :(得分:0)
在编写SQL代码时,看起来更整洁无关紧要。从性能的角度来看,看起来优雅的东西通常是最差可能的解决问题的方法。
确定哪种方法最好的唯一方法是首先确保您测试的两种方式返回相同的结果,然后对它们进行性能测试并检查执行计划(或在mySQL中解释)。使查询更好的技术也是数据库特定的。在SQL Server中最有效的性能调整可能是Oracle中最糟糕的可能性。
答案 1 :(得分:0)
有时候,使用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])