如何优化在 select 语句中使用函数的查询?

How can I optimize the query that using function in select statement?

让我给你看我的代码。

这是我的职能 return 我的约会时间 .

  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 条记录(太糟糕了)

我该如何优化它?

通过不创建和填充临时 table 并删除无用的 "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 上建立索引也可能会提高性能。

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

看看这是否能帮助您找到更好的方向。请注意,您必须先删除函数,因为您无法进行更改并将其从标量更改为 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

您的代码很慢,因为它正在执行 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 相比,我更喜欢临时 table,因为它提供了重用的灵活性,并且可以在其上添加索引。