2017-12-04 10 views
1

他の人が作成したSSRSレポートで使用されているこのクエリがあります。左結合が問題の原因です。私がインナー・ジョイントに変更すると、約15秒で結果が得られます(正しい結果ではありません)。 Left Joinを使用すると、20分後にクエリがキャンセルされます。 Budgets.ProfessionalsとTransactions.Professionalsの両方にインデックスを追加しましたが、パフォーマンスは変わりません。クエリを書き換え、左結合を使用しない方法はありますか?このクエリでは、左結合にはどのような選択肢がありますか?

SELECT 
profs.ProfName as orig 
,profs.Initials 
,DATEPART(year, TransDate) as [Year] 
,SUM(CASE WHEN IsFlatFee = 'Y' OR COALESCE(MT.Admin, 'N') = 'Y' 
    THEN 0.0 
    ELSE Units * (aph.assignedpercent/100) * isnull(B.rate, 0.0) 
    END) AS ctp 
,SUM(CASE WHEN IsFlatFee = 'Y' OR COALESCE(MT.Admin, 'N') = 'Y' 
    THEN 0 
    ELSE Units 
    END * (aph.assignedpercent/100)) AS worked_hours 
,SUM(Value * (aph.assignedpercent/100)) AS worked_value 
, 0 AS billed_hours 
,0 AS billed_value 
,0 AS billed_netamt 
, 0.0 as paid 
, 0.0 as wo 
FROM Transactions Trans 
INNER JOIN Matters Matts ON Trans.matters = Matts.matters 
INNER JOIN MatterTypes MT ON Matts.mattertype = MT.mattertypesdesc 
and MT.Admin <> 'Y' 
INNER JOIN Components Comps ON Comps.components = Trans.components 
and Comps.CompType = 'F' 
INNER JOIN AssignedProfsHistory APH on APH.Matters = Trans.Matters 
and APH.AssignedType = 'Originating' 
and Trans.TransDate between APH.EffectiveDate and 
ISNULL(EndDate,'12/31/2099') 
INNER JOIN Professionals profs on profs.Professionals = APH.Professionals 
    and profs.ProfType = 'Member' 
    and profs.IsActive = 'Y' 
    and profs.IsBillable = 'Y' 
**LEFT join** (SELECT Budgets.Professionals as timekeeper, Budgets.Amount as 
rate, Budgets.PeriodDate 
FROM Matters Matts 
INNER JOIN Budgets ON Matts.matters = Budgets.matters 
    and cast(Budgets.PeriodDate as Date) <= '2017-12-31' 
    AND MONTH('2017-12-31') = MONTH(Budgets.PeriodDate) 
WHERE Matts.MatterID = '99999-99.003') as B 
    *on B.timekeeper = Trans.Professionals* 
    and YEAR(B.PeriodDate) = DATEPART(year, TransDate) 
WHERE cast(transdate as DATE) between dateadd(day, 1, DATEADD(year, -3, 
'2017-12-31')) and '2017-12-31' 
GROUP BY profs.ProfName, profs.Initials, DATEPART(year, TransDate) 
+2

誰もこのような小さな情報で助けてくれる可能性はほとんどありません。ここに含まれるすべてのテーブルの索引を含むテーブル定義と、およその行数を見る必要があります。さらに、実行計画は役立ちますが、可能ではない可能性のあるクエリを完了することができないためです。 –

+1

なぜ 'cast(Budgets.PeriodDate as Date)'という名前でキャストしているのか、なぜなら、 'MONTH(Budgets.PeriodDate)'キャストのない同じフィールドで日付関数を実行するような、/joinはどこのインデックスの使用も無効にすることができるので、関数を実行することには常に注意するべきです。そうでなければ、ショーンは言った。 –

+1

私はLEFT JOINされたテーブルのインデックスを使用していないと思います。おそらく、Budgets.PeriodDateのインデックスがありますが、列(および関連するインデックス)を使用しようとする前に、CASTを実行しています。その時点で、オプティマイザは新しい値がインデックスと同じであるという考えをもはや持っていません。なぜなら、そうでないかもしれないからです。私たちは、あなたのテーブル構造、インデックス、および推定された実行計画を見なければなりません(なぜなら、Seanはあなたが実際のものを持っていないと言っていたからです)。 – indiri

答えて

1

ショーンとアロンが言ったように。潜在的に問題となるものは多すぎます。

あなたは、私が(列名から推測しているように)テキスト列mattertypesdescに参加しているようです。実際、ほとんどの作業はテキスト列に対して行われます。たとえMatts.MatterIDでもテキストです。これはあなたのシナリオでは不可能かもしれませんが、テーブルが整数の主キーを持っていて、それらのテーブルに加わった方が良いでしょう。

とにかく、推測すると....左の結合のサブクエリを一時テーブルに置き換えると、すぐに勝つかもしれません。

ので、クエリを既存の直前に...

SELECT Budgets.Professionals as timekeeper, Budgets.Amount as rate, Budgets.PeriodDate 
INTO #t 
FROM Matters Matts 
INNER JOIN Budgets ON Matts.matters = Budgets.matters 
    and cast(Budgets.PeriodDate as Date) <= '2017-12-31' 
    AND MONTH('2017-12-31') = MONTH(Budgets.PeriodDate) 
WHERE Matts.MatterID = '99999-99.003' 

は、あなたのexisintgクエリで、

SELECT ... 
... 
... 
LEFT JOIN #t as B 
    ON B.timekeeper = Trans.Professionals 
    .... 
1

でサブクエリを置き換えるまた、削除...適用演算子で試すことができます左に結合する&それは状態にあり、外側適用を使用して、外側適用スクリプト内の条件に含める

AND budgets.timekeeper = trans.professionals 
    AND year(budgets.perioddate) = datepart(year, transdate) 

サンプル

OUTER APPLY 
     ( 
        SELECT  budgets.professionals AS timekeeper, 
          budgets.amount  AS rate, 
          budgets.perioddate 
        FROM  matters matts 
        INNER JOIN budgets 
        ON   matts.matters = budgets.matters 
        AND  cast(budgets.perioddate AS date) <= '2017-12-31' 
        AND  month('2017-12-31') = month(budgets.perioddate) 
        AND budgets.timekeeper = trans.professionals 
        AND year(budgets.perioddate) = datepart(year, transdate) 
        WHERE  matts.matterid = '99999-99.003' 

       ) AS b 
0

お返事ありがとうございます。私はあなたの提案を受け取り、解決策を考え出すことができました。 2時間実行した後に強制終了したクエリは、約14秒で終了します。

私はスクリプトの冒頭にcteを作成しました。

;with cte as 
(SELECT Transactions FROM Transactions t 
WHERE cast(t.TransDate as DATE) between dateadd(day, 1, DATEADD(year, -3, 
@EndDate)) and @EndDate) 

次に、CTEをトランザクションにリンクしました。

FROM Transactions Trans 
INNER JOIN cte ON cte.Transactions = Trans.Transactions 

次に、問題の原因となった「where」句を削除できました。

WHERE cast(transdate as DATE) between dateadd(day, 1, DATEADD(year, -3, 
@EndDate)) and @EndDate 
関連する問題