2017-07-10 17 views
0

私は順序付けやフィルタリングに使用する計算列を持っていますが、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. 

は、関数のクエリです:キー参照(クラスタ)[AvailableDate] [PK_AvailableDate]

マイアクティビティモニタ:。

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%が上であると言いますこのクエリは最も高価なものです:

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

実行計画には、キーの参照(クラスタ化)[日付]。[PK_Date] 'xmlとして実行計画を共有してください – TheGameiswar

+0

[日付]とは何ですか?私は[日付]は表示されません。私は[DateGroup]が表示されます。 –

+0

スカラー関数をテーブル値関数にオプションで指定していますか?一般的に、TVF(インラインTVFが好ましい)はスカラーの方が速い。 – Serg

答えて

1

これは計算された列を理解するのに役立ちますか? http://sqlblog.com/blogs/ben_nevarez/archive/2009/08/10/the-query-optimizer-and-computed-columns.aspx

DBサイズと書き込み時間に問題がない場合は、スキーマを非正規化することを検討します。これは、書き込み時間を犠牲にして計算する関数の必要性を排除します。たとえば、dategroup x price x discountを1つのテーブルに入れることができます。ルックアップのためにdategroupidによってインデックスされた一意のテーブル&をクラスタ化することができます。

+0

はい、これも私が思ったことですが、予約の数によって価格が変わるという問題があります。 – erkinyldz

+0

推奨された 'Prabhat G'のような機能を書き直しても速度は向上しましたが、それでもまだ十分に速くはありません。したがって、クライアントと話した後、スキーマの変更を決定し、それを非正規化しました。 – erkinyldz

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; 

私が影響を与えるかどうか教えてください。

+0

これは私のクエリを多くスピードアップしました(ほぼ2倍)。しかし、まだ十分に速くはありません。 1時59分1:05まで – erkinyldz

+0

良い。もう一つは 'パラメータスニッフィング'です。それが実際に影響を与えるかどうかはわかりません。ストアドプロシージャに多くの影響を与えます。入力パラメータとして@ id1、@ group1を宣言し、内部でそれぞれ@ id、@groupに設定するだけです。 –

0

この関数を常にインラインに書き直そうとすると、複数行の関数がインライン関数よりずっと遅いことを覚えておく必要があります。

関連する問題