如何优化在 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,因为它提供了重用的灵活性,并且可以在其上添加索引。
让我给你看我的代码。
这是我的职能 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,因为它提供了重用的灵活性,并且可以在其上添加索引。