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

时间:2015-01-21 13:05:09

标签: sql-server optimization

让我告诉你我的代码。

这是我的功能          这让我回到了约会时间。

  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条记录(非常糟糕)

我怎样才能优化它?

3 个答案:

答案 0 :(得分:0)

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

答案 1 :(得分:0)

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

看看这是否有助于指明您的方向。请注意,您必须首先删除您的功能,因为您无法进行更改并将其从标量更改为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

答案 2 :(得分:0)

您的代码很慢,因为它正在执行RBAR(按行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上的临时表,因为它提供了重用的灵活性,并且可以在其上添加索引。