如何减少SQL查询执行时间

时间:2016-11-25 09:47:58

标签: sql-server tsql pivot sqlperformance

declare @SQL      nvarchar(max)
       ,@Columns1 nvarchar(max)
       ,@Columns2 nvarchar(max);

set @Columns1 = N'';

set @Columns2 = N'';

select @Columns1 += iif(@Columns1 = '',quotename(Columns1),N','+quotename(Columns1))
from (select Month+' Count  of TonerQty' as Columns1
      from MPSSell
      where Month is not null
            and Month != ''
            and Country in(select *
                            from [dbo].[UF_CSVToArray]('Hong Kong,South Korea,New Zealand,Philippines,Australia,India')
                           )
      group by Month
     ) as colPvt1;

select @Columns2 += iif(@Columns2 = '',quotename(Columns2),N','+quotename(Columns2))
from
     (select Month+' Count  of PL' as Columns2
      from
           MPSSell
      where Month is not null
            and Month != ''
            and Country in(select *
                            from [dbo].[UF_CSVToArray]('Hong Kong,South Korea,New Zealand,Philippines,Australia,India')
                           )
      group by Month
     ) as colPvt2;

set @SQL = N'
select result1.Country
        ,['+stuff(@Columns1,1,1,'')
        +', ['+stuff(@Columns2,1,1,'')
        +' from(SELECT *
                FROM (Select Country
                            ,Month + '' Count  of TonerQty'' as Columns1
                            ,TonerQty as opValue1
                        from MPSSell 
                        where Country is not null
                            and Country != ''''
                            and Month is not null
                            and Month != ''''
                            and Country in(Select *
                                            from [dbo].[UF_CSVToArray](''Hong Kong,South Korea,New Zealand,Philippines,Australia,India'')
                                            )
                        group by Country
                                ,Month
                                ,TonerQty
                        ) as resPvt1
PIVOT(Count(opValue1) FOR Columns1 IN( ['+stuff(@Columns1,1,1,'')+')) as p
) as result1

join (SELECT *
        FROM (Select Country
                    ,Month + '' Count  of PL'' as Columns2
                    ,PL as opValue2
                from MPSSell 
                where Country is not null
                    and Country != ''''
                    and Month is not null
                    and Month != ''''
                    and Country in(Select *
                                    from [dbo].[UF_CSVToArray](''Hong Kong,South Korea,New Zealand,Philippines,Australia,India'')
                                    )
                group by Country
                        ,Month
                        ,PL
                ) as resPvt2
        PIVOT(Count(opValue2) FOR Columns2 IN  ( ['+stuff(@Columns2,1,1,'')+')) as p
        ) as result2
    on result1.Country=result2.Country';

exec sp_executesql
     @SQL;

这是我的SQL数据透视查询工作正常,但执行时间太长。请帮助我如何减少执行时间。

Estimated Execution plan in Google Drive

Estimated plan on pastetheplan.com

Actual plan on pastetheplan.com

2 个答案:

答案 0 :(得分:2)

1

注意WHERE ... IN (SELECT...),不要多次做同样的事情,帮助服务器了解你想要实现的目标:

declare @countries table (country <actual type>)

insert into @countries (country)
Select <actual col>
from [dbo].[UF_CSVToArray](''Hong Kong,South Korea,New Zealand,Philippines,Australia,India'')

之后到处使用:

...
where exists(select 1 from @countries cc where cc.country = mps.country)
...

2

两个查询的来源之间有什么区别?无。

select @Columns1 += iif(@Columns1 = '',quotename(Columns1),N','+quotename(Columns1))
from (select Month+' Count  of TonerQty' as Columns1
      from MPSSell
      where Month is not null
            and Month != ''
            and Country in(select *
                            from [dbo].[UF_CSVToArray]('Hong Kong,South Korea,New Zealand,Philippines,Australia,India')
                           )
      group by Month
     ) as colPvt1;

select @Columns2 += iif(@Columns2 = '',quotename(Columns2),N','+quotename(Columns2))
from
     (select Month+' Count  of PL' as Columns2
      from
           MPSSell
      where Month is not null
            and Month != ''
            and Country in(select *
                            from [dbo].[UF_CSVToArray]('Hong Kong,South Korea,New Zealand,Philippines,Australia,India')
                           )
      group by Month
     ) as colPvt2;

转换为

select @Columns1 += iif(@Columns1 = '',quotename(Month+' Count  of TonerQty'),N','+quotename(Month+' Count  of TonerQty')),
      @Columns2 += iif(@Columns2 = '',quotename(Month+' Count  of PL'),N','+quotename(Month+' Count  of PL'))
from
     (select DISTINCT Month
      from MPSSell mps
      where Month is not null
            and Month != ''
            and exists(select 1 from @countries cc where cc.country = mps.country)
     ) as colPvt2;

现在您只扫描源表中的月份列表一次。

3

从其他地方获取月份列表(缓存,参数,更短的表)。并且只扫描源表一次 - 在最后检索数据的位置。

答案 1 :(得分:0)

使用PIVOT子句的某些数据透视查询可以从HASH GROUP查询提示中受益。尝试在动态查询结束时指定OPTION(HASH GROUP)。有关详细信息,请参阅Query Hints

另一个可能的性能改进是不使用PIVOT子句来转动,而是转向老式的方式。如果您在互联网上搜索sql server old-school pivot,可以找到几个这样的例子,但这里有关于Stack Overflow的one example如何完成。