我有一个用于排序或过滤的计算列,但是当有1000多行时,执行时间太长。
此查询适用于预订系统,可根据价格订购可用日期。
这是数据库架构:
AvailableDates has one DateGroup
DateGroup has many Prices
DateGroup has many Discounts
Each Discount contains 3 columns. MinPerson, MaxPerson, DiscountPercentage
AvailableDates has many BookingGroups.
BookingGroups has many Bookings.
BookingGroups has a computed column that calculates how many bookings there are.
AvailableDate的计算价格列由函数计算。价格由;确定;
Get Max Price from Prices
Get How many booking there is
Get discount that will be applied depending on number of bookings.
这是函数查询:
FUNCTION [dbo].[fn_datePrice]
(
@id INT,
@groupId INT
)
RETURNS decimal(19, 5)
AS
BEGIN
declare @price decimal(19,5), @discount decimal(19,5), @numOfPeople INT
SELECT @numOfPeople= b.NumberOfPeople FROM BookingGroup b
WHERE b.DateId = @id and b.Status != 'Expired';
if (@numOfPeople is null or @numOfPeople < 1)
SET @numOfPeople = 1;
SELECT @price = MAX(pr.Price),
@discount = disc.DiscountPercentage
FROM DateGroup dateGroup
LEFT JOIN Prices pr on pr.GroupId = dateGroup.Id
LEFT JOIN Discounts disc on disc.GroupId = dateGroup.Id and @numOfPeople BETWEEN disc.MinPeople and disc.MaxPeople
WHERE dateGroup.Id = @groupId
GROUP BY dateGroup.Id, disc.DiscountPercentage;
if (@discount is null)
return @price
return @price * (100 - @discount) / 100
END;
GO
执行计划表示78%的费用已开启:密钥查找(已集群)[可用日期]。[PK_AvailableDate]
我的活动监视器说这个查询是最昂贵的查询:
SELECT @price = MAX(pr.Price),
@discount = disc.DiscountPercentage
FROM DateGroup dateGroup
LEFT JOIN Prices pr on pr.GroupId = dateGroup.Id
LEFT JOIN Discounts disc on disc.GroupId = dateGroup.Id and @numOfPeople BETWEEN disc.MinPeople and disc.MaxPeople
WHERE dateGroup.Id = @groupId
GROUP BY dateGroup.Id, disc.DiscountPercentage;
答案 0 :(得分:1)
这可以帮助您理解计算列吗? http://sqlblog.com/blogs/ben_nevarez/archive/2009/08/10/the-query-optimizer-and-computed-columns.aspx
如果数据库大小和写入时间不是问题,我会考虑对模式进行非规范化。这将消除以写入时间为代价计算功能的需要。例如,dategroup x price x discount可以在一个表中。桌子可以是独一无二的。聚集由dategroupid索引以查找。
答案 1 :(得分:0)
我试图重新编写您的加入:
SELECT @price = MAX(pr.Price),
@discount = disc.DiscountPercentage
FROM DateGroup dateGroup
LEFT JOIN Prices pr on pr.GroupId = dateGroup.Id
LEFT JOIN Discounts disc on disc.GroupId = dateGroup.Id
WHERE (@numOfPeople BETWEEN disc.MinPeople and disc.MaxPeople)
AND (dateGroup.Id = @groupId)
GROUP BY dateGroup.Id, disc.DiscountPercentage;
尝试让我知道它是否会产生影响。
答案 2 :(得分:0)
总是可以尝试将此函数重写为内联,您需要记住多行函数比内联函数慢得多。