【问题标题】:Re-writing/Optimising T-SQL Stored Procedure with subqueries使用子查询重写/优化 T-SQL 存储过程
【发布时间】:2014-11-09 19:13:43
【问题描述】:

我有一个存储过程,现在我不是一个 DBA,所以我只是想知道这是否被认为是不好的做法,因为我有很多子查询具有基本相同的代码。

我应该改用表变量还是临时表?

我还必须将第二个查询重写为动态 SQL,因为我只想包含基于标志的联合,因此临时表在这里会更容易。

感谢大家的帮助

CREATE TABLE #Days(theDate datetime, DayAsString varchar(15))

CREATE TABLE #temp(id int identity(1,1),trip_date datetime, trip_return datetime, iteration int, weeknumber int)

IF @SpecificDay = 0
Begin 
    INSERT INTO #Days 
            SELECT [date] ,DATENAME(dw,[date])
                FROM dbo.Calendar C 
                WHERE [Date] BETWEEN @start AND @end
                     AND C.[WkDName] in (select distinct siDay.Name
                                                from schedule s
                                                join ScheduleItemIntervalMap sim on s.schedule_id = sim.scheduleid
                                                join scheduleInterval sint       on sim.scheduleIntervalID = sint.id
                                                left join ScheduleItem siDay     on sim.scheduleDayItemId = siDay.id            
                                                where s.schedule_id = @schedule_id
                                                ) --@wkDName
                     AND C.[Month] in (select distinct siMonth.Id
                                                from schedule s
                                                join ScheduleItemIntervalMap sim on s.schedule_id = sim.scheduleid
                                                join scheduleInterval sint       on sim.scheduleIntervalID = sint.id                                
                                                join ScheduleItem siMonth        on sim.ScheduleMonthItemId = siMonth.id
                                                where s.schedule_id =  @schedule_id
                                                ) --@Month
                     AND C.[WkNo] in (select distinct sint.Id
                                                from schedule s
                                                join ScheduleItemIntervalMap sim on s.schedule_id = sim.scheduleid
                                                join scheduleInterval sint       on sim.scheduleIntervalID = sint.id                                
                                                join ScheduleItem siDay        on sim.ScheduleDayItemId = siDay.Id
                                                where s.schedule_id =  @schedule_id)          --@first last etc @occurence
                Union all --include the last occurence of the month
                SELECT [date] ,DATENAME(dw,[date])
                FROM dbo.Calendar CLast
                WHERE [Date] BETWEEN @start AND @end
                     AND CLast.[WkDName] in (select distinct siDay.Name
                                                from schedule s
                                                join ScheduleItemIntervalMap sim on s.schedule_id = sim.scheduleid
                                                join scheduleInterval sint       on sim.scheduleIntervalID = sint.id
                                                left join ScheduleItem siDay     on sim.scheduleDayItemId = siDay.id            
                                                where s.schedule_id =  @schedule_id
                                                ) --@wkDName
                     AND CLast.[Month] in (select distinct siMonth.Id
                                                from schedule s
                                                join ScheduleItemIntervalMap sim on s.schedule_id = sim.scheduleid
                                                join scheduleInterval sint       on sim.scheduleIntervalID = sint.id                                
                                                join ScheduleItem siMonth        on sim.ScheduleMonthItemId = siMonth.id
                                                where s.schedule_id =  @schedule_id
                                                ) --@Month
                     AND CLast.[Last] = 1
    END 
ELSE --Specific date has been specified or last has been selected
    INSERT INTO #Days 
    select distinct [date] ,DATENAME(dw,[date]) from 
    (
        SELECT *
        FROM dbo.Calendar C 
        WHERE [Date] BETWEEN @start AND @end
             AND C.[Month] in (select distinct siMonth.Id
                                        from schedule s
                                        join ScheduleItemIntervalMap sim on s.schedule_id = sim.scheduleid
                                        join scheduleInterval sint       on sim.scheduleIntervalID = sint.id                                
                                        join ScheduleItem siMonth        on sim.ScheduleMonthItemId = siMonth.id
                                        where s.schedule_id = @schedule_id) --@Month
             AND C.[Day] in (select distinct sint.Name
                                        from schedule s
                                        join ScheduleItemIntervalMap sim on s.schedule_id = sim.scheduleid
                                        join scheduleInterval sint       on sim.scheduleIntervalID = sint.id                                
                                        join ScheduleItem siMonth        on sim.ScheduleMonthItemId = siMonth.id
                                        where s.schedule_id = @schedule_id
                                        AND sint.Name <> 'Last'
             )
        Union all --include the last occurence of the month IF LAST
        SELECT *
        FROM dbo.Calendar CLast
        WHERE [Date] BETWEEN @start AND @end
             AND CLast.[Month] in (select distinct siMonth.Id
                                        from schedule s
                                        join ScheduleItemIntervalMap sim on s.schedule_id = sim.scheduleid
                                        join scheduleInterval sint       on sim.scheduleIntervalID = sint.id                                
                                        join ScheduleItem siMonth        on sim.ScheduleMonthItemId = siMonth.id
                                        where s.schedule_id = @schedule_id
                                        ) --@Month
                                        AND [Date] in (select LDtOfMo from dbo.Calendar 
                                                        WHERE [Date] BETWEEN @start AND @end)
            ) as x


Begin 
        INSERT INTO #temp(trip_date,trip_return,iteration,weeknumber)
        SELECT 
            theDate + CAST(@timeout AS DATETIME),theDate+ CAST(@timeback AS DATETIME),@WeekNo,DATEPART(wk, theDate+CAST(@timeout AS DATETIME))
        FROM
            #Days           
        END

【问题讨论】:

  • 我倾向于使用相关的 EXISTS 子查询而不是 IN 子查询。您可能会尝试该方法以查看您获得不同且更优化的执行计划。在许多情况下,优化器足够聪明,可以为语义相同的查询生成最佳计划。
  • 除了@Dan说的,最起码把DISTINCT拿出来……
  • 干杯@dan,我会尝试 EXISTS。我认为 EXISTS 会在发现事件后继续前进,而不是 IN 返回所有结果?
  • @Aaron 我认为使用 distinc 会提高性能,因为只有一个结果,还是会产生更多开销?我应该把它留给分析器来删除重复项吗?
  • 它必须进行排序以消除重复 - 很可能会增加排序工作的成本不仅仅是以查询其余部分固有的任何有效排序顺序返回行 - 特别是因为这些行实际上并不是物化了。

标签: sql sql-server tsql subquery


【解决方案1】:

既然你重复做同样的JOIN;您可能可以在JOIN 中转换这些子查询,如下所示

INSERT INTO #Days 
        SELECT DISTINCT C.[date] ,DATENAME(dw,C.[date])
            FROM dbo.Calendar C 
            left join ScheduleItem si
            ON si.Name = C.[WkDName]
            AND si.Id = C.[Month]
            JOIN ScheduleItemIntervalMap sim ON sim.scheduleDayItemId = si.id
            JOIN schedule s ON s.schedule_id = sim.scheduleid
            JOIN scheduleInterval sint on sim.scheduleIntervalID = sint.id
            AND sint.Id = C.[WkNo]
            where s.schedule_id = @schedule_id
            AND C.[Date] BETWEEN @start AND @end 

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-11-04
    • 2018-04-03
    相关资源
    最近更新 更多