【问题标题】:How can I optimize the query that using function in select statement?如何优化在 select 语句中使用函数的查询?
【发布时间】:2015-01-21 23:12:35
【问题描述】:

让我给你看我的代码。

这是我的功能 那返回我的日期时间。

  ALTER FUNCTION GoldenMemebr(@clubid uniqueidentifier ) returns datetime
  WITH SCHEMABINDING
   as
  begin
 DECLARE @TEMP TABLE 
 (
 TRANSTIME DATETIME,
 TOTSCORE  BIGINT,
 CLUBID uniqueidentifier
 )
INSERT INTO @TEMP (CLUBID,TRANSTIME,TOTSCORE)

 SELECT ClubProfileId, TransactionTimeStamp, 
 SUM(Points) OVER (ORDER BY TransactionTimeStamp) totalamount 
 FROM  
  dbo.CardTransaction CT
 inner join dbo.CardTransactionLog CL 
 on CL.CardTransactionLogId =   CT.CardTransactionLogId
 and ClubProfileId = @clubid

  order by CL.TransactionTimeStamp 

declare @ti datetime
set @ti = 
(
 SELECT top 1 TRANSTIME  
 FROM @TEMP 
WHERE TOTSCORE >= 12000 
order by TRANSTIME asc

)
 return @ti
 end

这是我的查询

select FirstName,LastName,
SUM(Points) as score,   dbo.GoldenMemebr(cp.ClubProfileId) as ExactTime 
from ClubProfile cp join CardTransaction ct
on ct.ClubProfileId = cp.ClubProfileId
where MembershipType = 1
group by FirstName,LastName,dbo.GoldenMemebr(cp.ClubProfileId)

这个查询需要 14 秒 38 条记录(太可怕了)

如何优化?

【问题讨论】:

    标签: sql-server optimization


    【解决方案1】:

    通过不创建和填充临时表并删除无用的“ORDER BY”,我试图改进您的功能:

    ALTER FUNCTION GoldenMemebr
    (
      @clubid uniqueidentifier
    ) returns datetime
    WITH SCHEMABINDING
      as
    begin
    ;WITH CTE AS
    (
      SELECT 
        TransactionTimeStamp, 
        SUM(Points) OVER (ORDER BY TransactionTimeStamp) totalamount 
      FROM  
        dbo.CardTransaction CT
      JOIN dbo.CardTransactionLog CL 
      ON
        CL.CardTransactionLogId =   CT.CardTransactionLogId and
        ClubProfileId = @clubid
    )
    SELECT top 1 @ti = TransactionTimeStamp
    FROM CTE
    WHERE totalamount >= 12000
    ORDER BY totalamount asc
    
    RETURN @ti
    end
    

    在 TransactionTimeStamp 和 CardTransactionLogId 上有索引也可能会提高性能。

    【讨论】:

      【解决方案2】:

      如何将此函数改为内联表值函数?

      看看这是否有助于为您指明更好的方向。请注意,您必须先删除您的函数,因为您无法进行更改并将其从标量更改为 iTVF。

          ALTER FUNCTION GoldenMemebr(@clubid uniqueidentifier ) returns table
      WITH SCHEMABINDING as
          RETURN
          with Totals as
          (
              SELECT TransactionTimeStamp
                  , SUM(Points) OVER (ORDER BY TransactionTimeStamp) as totalamount 
              FROM dbo.CardTransaction CT
              inner join dbo.CardTransactionLog CL on CL.CardTransactionLogId = CT.CardTransactionLogId
                  and ClubProfileId = @clubid
          )
      
          select top 1 TransactionTimeStamp
          from Totals
          where totalamount > 12000
          order by CL.TransactionTimeStamp 
      
      
          GO
      
          select FirstName
              , LastName
              , SUM(Points) as score
              , gm.TransactionTimeStamp as ExactTime 
          from ClubProfile cp 
          join CardTransaction ct on ct.ClubProfileId = cp.ClubProfileId
          cross apply dbo.GoldenMember(cp.ClubProfileId) gm
          where MembershipType = 1
          group by FirstName
              , LastName
              , gm.TransactionTimeStamp
      

      【讨论】:

        【解决方案3】:

        您的代码很慢,因为它正在执行RBAR(Row By Agonizing Row) 操作,因为每个 frikkin 行都会调用该函数。尝试摆脱函数并将整个逻辑包装到查询中。这是我的尝试(虽然未经测试)

        select MIN(TRANSTIME) TransTime, ClubProfileId  into #temp from 
        (
         SELECT ClubProfileId, TransactionTimeStamp TransTime, 
         SUM(Points) OVER (ORDER BY TransactionTimeStamp) totalamount 
         FROM  
          dbo.CardTransaction CT
         inner join dbo.CardTransactionLog CL 
         on CL.CardTransactionLogId =   CT.CardTransactionLogId
        
        )A where totalamount >= 12000
        
        
        create  index ix_id on #temp(ClubProfileId) include (TRANSTIME)
        
        select FirstName
        ,LastName
        ,SUM(Points) as score
        ,t.TransTime ExactTime 
        from ClubProfile cp join CardTransaction ct
        on ct.ClubProfileId = cp.ClubProfileId
        join #temp t on t.ClubProfileId = cp.ClubProfileId
        where MembershipType = 1
        group by FirstName,LastName,t.TransTime
        

        我更喜欢临时表而不是 CTE,因为它提供了重用的灵活性并且可以在其上添加索引。

        【讨论】:

          猜你喜欢
          • 2017-03-13
          • 2016-02-06
          • 2014-01-07
          • 2019-12-31
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2019-12-15
          相关资源
          最近更新 更多