Reputation: 688
I have a computed column I use for ordering or filtering, but when there is 1000+ rows it takes too long to execute.
This query is for a booking system to order the Available Dates depending on their prices.
Here is database schema:
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.
The computed column for price on AvailableDate is computed by a function. Price is determined with;
Get Max Price from Prices
Get How many booking there is
Get discount that will be applied depending on number of bookings.
Here is the function query:
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
Execution Plan says 78% of the cost is on: Key Lookup (Clustered) [AvailableDate].[PK_AvailableDate]
My activity monitor says this query is the most expensive one:
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;
Upvotes: 0
Views: 203
Reputation: 108
Can this help you understand the computed columns? http://sqlblog.com/blogs/ben_nevarez/archive/2009/08/10/the-query-optimizer-and-computed-columns.aspx
If DB size and write times are not issues, I would consider to denormalise the schema. That would remove the need for a function to compute at the cost of write times. For example, the dategroup x price x discount could be in one table. The table can be unique & clustered indexed by dategroupid for look up.
Upvotes: 1
Reputation: 174
Always you can try to rewrite this function to inline, you need to remember that multiline-functions are alwyas much slower than inline-functions.
Upvotes: 0
Reputation: 3029
I have tried to re-write your join :
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;
try and let me know if it makes impact.
Upvotes: 0