如果有条件选择更多列,为什么此SQL语句会增加执行时间?

时间:2018-11-06 21:23:39

标签: sql-server tsql sql-server-2008-r2

我有一个脚本,其中包含多个写入临时表的查询。每个查询都建立在前一个查询的基础上,通过获取前一个查询的结果并对其进行其他处理。写入#Data2后,脚本将在1秒内运行。

在写入#Data2的查询之后的下一个查询根据称为@show的用户参数有条件地选择要显示的列。当我有条件地仅选择1列(请参见下文)时,此过程将在大约1秒钟内完成。

select
    (case when 1 in (select use_object from dbo.DelimitedSplit8K(@show,','))  
             then d.vend_num            
             else null 
     end) vend_num
into 
    #Show
from
    #Data2 d

但是,当我对53列进行此操作时,查询执行时间变为1分39秒(请参见下文)。为什么是这样?从理论上讲,查询应仅决定是否包含该列。为什么这在计算上会很昂贵?

select

      (case when 1 in(select use_object from dbo.DelimitedSplit8K(@show,','))  then d.vend_num          else null end)          vend_num
    , (case when 2 in(select use_object from dbo.DelimitedSplit8K(@show,','))  then d.terms_code        else null end)          terms_code
    , (case when 3 in(select use_object from dbo.DelimitedSplit8K(@show,','))  then d.last_purch        else null end)          last_purch
    , (case when 4 in(select use_object from dbo.DelimitedSplit8K(@show,','))  then d.purch_ytd         else null end)          purch_ytd
    , (case when 5 in(select use_object from dbo.DelimitedSplit8K(@show,','))  then d.pay_ytd           else null end)          pay_ytd

    , (case when 6 in(select use_object from dbo.DelimitedSplit8K(@show,','))  then d.vend_remit        else null end)          vend_remit
    , (case when 7 in(select use_object from dbo.DelimitedSplit8K(@show,','))  then d.curr_code         else null end)          curr_code
    , (case when 8 in(select use_object from dbo.DelimitedSplit8K(@show,','))  then d.bank_code         else null end)          bank_code
    , (case when 9 in(select use_object from dbo.DelimitedSplit8K(@show,','))  then d.pay_type          else null end)          pay_type
    , (case when 10 in(select use_object from dbo.DelimitedSplit8K(@show,',')) then d.pur_acct          else null end)          pur_acct

    , (case when 11 in(select use_object from dbo.DelimitedSplit8K(@show,',')) then d.vendname          else null end)          vendname
    , (case when 12 in(select use_object from dbo.DelimitedSplit8K(@show,',')) then d.fax_num           else null end)          fax_num
    , (case when 13 in(select use_object from dbo.DelimitedSplit8K(@show,',')) then d.telex_num         else null end)          telex_num
    , (case when 14 in(select use_object from dbo.DelimitedSplit8K(@show,',')) then d.pay_hold          else null end)          pay_hold
    , (case when 15 in(select use_object from dbo.DelimitedSplit8K(@show,',')) then d.pay_hold_date     else null end)          pay_hold_date

    , (case when 16 in(select use_object from dbo.DelimitedSplit8K(@show,',')) then d.pay_hold_reason   else null end)          pay_hold_reason
    , (case when 17 in(select use_object from dbo.DelimitedSplit8K(@show,',')) then d.sitename          else null end)          sitename
    , (case when 18 in(select use_object from dbo.DelimitedSplit8K(@show,',')) then d.siteaddress       else null end)          siteaddress
    , (case when 19 in(select use_object from dbo.DelimitedSplit8K(@show,',')) then d.city              else null end)          city
    , (case when 20 in(select use_object from dbo.DelimitedSplit8K(@show,',')) then d.state             else null end)          state

    , (case when 21 in(select use_object from dbo.DelimitedSplit8K(@show,',')) then d.zip               else null end)          zip
    , (case when 22 in(select use_object from dbo.DelimitedSplit8K(@show,',')) then d.county            else null end)          county
    , (case when 23 in(select use_object from dbo.DelimitedSplit8K(@show,',')) then d.country           else null end)          country
    , (case when 24 in(select use_object from dbo.DelimitedSplit8K(@show,',')) then d.FSMAApproved      else null end)          FSMAApproved
    , (case when 25 in(select use_object from dbo.DelimitedSplit8K(@show,',')) then d.FSMAAuditDatetime else null end)          FSMAAuditDatetime

    , (case when 26 in(select use_object from dbo.DelimitedSplit8K(@show,',')) then d.FSMAAuditEditor   else null end)          FSMAAuditEditor
    , (case when 27 in(select use_object from dbo.DelimitedSplit8K(@show,',')) then d.vend_seq          else null end)          vend_seq
    , (case when 28 in(select use_object from dbo.DelimitedSplit8K(@show,',')) then d.interaction_id    else null end)          interaction_id
    , (case when 29 in(select use_object from dbo.DelimitedSplit8K(@show,',')) then d.interaction_stat  else null end)          interaction_stat
    , (case when 30 in(select use_object from dbo.DelimitedSplit8K(@show,',')) then d.topic             else null end)          topic

    , (case when 31 in(select use_object from dbo.DelimitedSplit8K(@show,',')) then d.Uf_CheckLevel     else null end)          Uf_CheckLevel
    , (case when 32 in(select use_object from dbo.DelimitedSplit8K(@show,',')) then d.approbation_type  else null end)          approbation_type
    , (case when 33 in(select use_object from dbo.DelimitedSplit8K(@show,',')) then d.submitted_date    else null end)          submitted_date
    , (case when 34 in(select use_object from dbo.DelimitedSplit8K(@show,',')) then d.approver          else null end)          approver
    , (case when 35 in(select use_object from dbo.DelimitedSplit8K(@show,',')) then d.approval_date     else null end)          approval_date   

    , (case when 36 in(select use_object from dbo.DelimitedSplit8K(@show,',')) then d.rejector          else null end)          rejector
    , (case when 37 in(select use_object from dbo.DelimitedSplit8K(@show,',')) then d.rejection_date    else null end)          rejection_date
    , (case when 38 in(select use_object from dbo.DelimitedSplit8K(@show,',')) then d.vendstat          else null end)          vendstat
    , (case when 39 in(select use_object from dbo.DelimitedSplit8K(@show,',')) then d.po_num            else null end)          po_num
    , (case when 40 in(select use_object from dbo.DelimitedSplit8K(@show,',')) then d.po_orderdate      else null end)          po_orderdate

    , (case when 41 in(select use_object from dbo.DelimitedSplit8K(@show,',')) then d.po_stat           else null end)          po_stat
    , (case when 42 in(select use_object from dbo.DelimitedSplit8K(@show,',')) then d.po_invnum         else null end)          po_invnum
    , (case when 43 in(select use_object from dbo.DelimitedSplit8K(@show,',')) then d.po_invdate        else null end)          po_invdate
    , (case when 44 in(select use_object from dbo.DelimitedSplit8K(@show,',')) then d.poi_line          else null end)          poi_line
    , (case when 45 in(select use_object from dbo.DelimitedSplit8K(@show,',')) then d.poi_release       else null end)          poi_release

    , (case when 46 in(select use_object from dbo.DelimitedSplit8K(@show,',')) then d.poi_item          else null end)          poi_item
    , (case when 47 in(select use_object from dbo.DelimitedSplit8K(@show,',')) then d.poi_stat          else null end)          poi_stat
    , (case when 48 in(select use_object from dbo.DelimitedSplit8K(@show,',')) then d.qty_ordered       else null end)          qty_ordered
    , (case when 49 in(select use_object from dbo.DelimitedSplit8K(@show,',')) then d.qty_received      else null end)          qty_received
    , (case when 50 in(select use_object from dbo.DelimitedSplit8K(@show,',')) then d.due_date          else null end)          due_date

    , (case when 51 in(select use_object from dbo.DelimitedSplit8K(@show,',')) then d.rcvd_date         else null end)          rcvd_date
    , (case when 52 in(select use_object from dbo.DelimitedSplit8K(@show,',')) then d.poi_itemdesc      else null end)          poi_itemdesc
    , (case when 53 in(select use_object from dbo.DelimitedSplit8K(@show,',')) then d.u_m               else null end)          u_m

into #Show

from

    #Data2 d

1 个答案:

答案 0 :(得分:2)

您可以以更简单的方式执行此操作,而无需涉及另一个临时表,也无需调用此昂贵的函数53次:

DECLARE @show varchar(255) = '1,3';

SELECT vend_num   = MIN(CASE y.value WHEN 1 THEN d.vend_num   END),
       terms_code = MIN(CASE y.value WHEN 2 THEN d.terms_code END),
       last_purch = MIN(CASE y.value WHEN 3 THEN d.last_purch END)--,
       -- ...
FROM #Data2 AS d 
OUTER APPLY dbo.DelimitedSplit8K(@show,',') AS y;

我当然同意上面的评论,您应该考虑table-valued parameters而不是传递逗号分隔的字符串;那么您可以加入对抗TVP的行列,而不必进行任何昂贵的拆分。

如果您真的很喜欢使用函数,则应查看其中几个拆分函数的性能测试,并考虑采用更好的替代方法(请参见thisthis)。

在SQL Server 2016(和Azure SQL数据库)中,您将能够使用STRING_SPLIT(),这是令人惊讶的性能出色的本机选项。参见thisthisthisthis