SQLの関数を初めて使用しています。最適化に関するヘルプが必要です。私はSQL Server 2016を使用しています。sqlテーブル値関数を最適化する
私の関数は、1年ごとの異なるプロジェクトの従業員の計画時間と終了時間を比較してテーブル変数を返します。しかし、問題は、クエリが30-40秒間に約30,000行をロードしていることです。私は、クエリの最適化に関するいくつかのアドバイスを確認しましたが、私は自分のコードに間違ったものは見つけられません。それを最適化する方法についていくつかアドバイスをいただけますか?
全体機能コード:
CREATE FUNCTION dbo.fnProjectHours(
@Project = '%',
@Task = '%',
@Year INT = 0
)
RETURNS @temp TABLE
(
Year INT, Month INT, Project VARCHAR(20), Task VARCHAR(20),
User VARCHAR(50), PlannedHours Numeric(14,2),
DoneHours Numeric(14,2) id int identity ,
primary key(Year, Project, Task, Month, User, id)
)
AS
BEGIN
SELECT @Year= ISNULL(NULLIF(@Year,0),DATEPART(yy,GETDATE()));
INSERT INTO @t
(
Year, Month, Project, Task, User, PlannedHours, DoneHours
)
SELECT rbh.Year, rbh.Month, rbh.Project, rbh.Task, rbh.User,
rbhp.SumPlan AS PlannedHours, rbhw.SumDone AS DoneHours
FROM
(
SELECT
CASE
WHEN DATEPART(yy, ll.DateStart) IS NULL THEN rbhw.Year
ELSE DATEPART(yy, ll.DateStart)
END AS Year,
CASE
WHEN DATEPART(mm, ll.DateStart) IS NULL THEN DATEPART(mm, rbhw.Date)
ELSE DATEPART(mm, ll.DateStart)
END AS Month,
dbo.wusr_fn_cut(mn.Number, '/') AS Project, ml.Task,
ISNULL(ll.Login,rbhw.Login) AS User
FROM dbo.Nag AS mn WITH (nolock)
INNER JOIN dbo.Lin AS ml WITH (NOLOCK) ON mn.ID = ml.ID
INNER JOIN dbo.LinLogin AS ll WITH (NOLOCK) ON ll.ID = ml.ID
AND ll.LinId = ml.LinId
INNER JOIN dbo.sl_Operator AS o WITH (Nolock) ON ll.Login = o.Login
FULL OUTER JOIN dbo.Hours AS rbhw WITH (NOLOCK)
ON dbo.wusr_fn_cut(mn.Number, '/') = rbhw.Project AND ml.Task = rbhw.Task
AND ll.Login = rbhw.Login AND DATEPART(yy, ll.DateStart) = DATEPART(yy, rbhw.Date)
AND DATEPART(mm, ll.DateStart) = DATEPART(mm, rbhw.Date)
WHERE (mn.Number IS NOT NULL) AND (mn.Status = 0) AND dbo.wusr_fn_cut(mn.Number, '/') LIKE @Project
AND ml.Task LIKE @Task
UNION ALL
SELECT
CASE
WHEN DATEPART(yy, ll.DateStart) IS NULL THEN rbhw.Year
ELSE DATEPART(yy, ll.DateStart)
END AS Year,
CASE
WHEN DATEPART(mm, ll.DateStart) IS NULL THEN DATEPART(mm, rbhw.Date)
ELSE DATEPART(mm, ll.DateStart)
END AS Month,
rbhw.Project, rbhw.Task,
ISNULL(ll.Login,rbhw.Login) AS User
FROM dbo.Nag AS mn WITH (nolock)
INNER JOIN dbo.Hours AS rbhw WITH (NOLOCK)
ON dbo.wusr_fn_cut(mn.Number, '/') = rbhw.Project
INNER JOIN dbo.Lin AS ml WITH (NOLOCK) ON mn.ID = ml.ID
AND rbhw.Task = ml.Task
INNER JOIN dbo.Operator AS o WITH (Nolock) ON rbhw.Login = o.Login
FULL OUTER JOIN dbo.LinLogin AS ll WITH (nolock) ON mn.ID = ll.ID
AND ml.LinId = ll.LinId AND o.Login = ll.Login
AND DATEPART(yy, rbhw.Date)=DATEPART(yy, ll.DateStart)
AND DATEPART(mm, rbhw.Date) = DATEPART(mm, ll.DateStart)
WHERE (rbhw.Project IS NOT NULL) AND (mn.Status = 0) AND (DATEPART(mm, ll.DateStart) IS NULL) AND rbhw.Project LIKE @Project
AND rbhw.Task LIKE @Task
) AS rbh
LEFT JOIN
(
SELECT DATEPART(yy, ll.DateStart) AS Year, DATEPART(mm, ll.DateStart) AS Month,
dbo.wusr_fn_cut(mn.Number, '/') AS Project, ml.Task AS Task,
ll.Login AS LoginLL, SUM(ll.Hours) AS SumPlan
FROM dbo.Nag AS mn WITH (nolock)
INNER JOIN dbo.Lin AS ml WITH (NOLOCK) ON mn.ID = ml.ID
INNER JOIN dbo.LinLogin AS ll WITH (NOLOCK) ON ll.ID = ml.ID
AND ll.LinId = ml.LinId
WHERE mn.Status=0
GROUP BY DATEPART(yy, ll.DateStart),DATEPART(mm, ll.DateStart),dbo.wusr_fn_cut(mn.Number, '/'),ml.Task,ll.Login
) AS rbhp
ON rbh.Project=rbhp.Project AND rbh.Task=rbhp.Task AND
rbh.Year=rbhp.Year AND rbh.Month=rbhp.Month AND rbh.User=rbhp.LoginLL
LEFT JOIN
(
SELECT h.Year, DATEPART(mm, h.Date) AS Month,h.Project AS Project, h.Task AS Task,
h.Login AS LoginRbhw, SUM(h.Hours) AS DoneSum
FROM dbo.Nag AS mn WITH (nolock)
INNER JOIN dbo.Lin AS ml WITH (NOLOCK) ON mn.ID = ml.ID
INNER JOIN dbo.Hours AS h WITH (NOLOCK) ON dbo.wusr_fn_cut(mn.Number, '/') = h.Project
AND ml.Task = h.Task
WHERE mn.Status=0
GROUP BY h.Year,DATEPART(mm, h.Date),h.Project,h.Task,h.Login
) AS rbhw
ON rbh.Project=rbhw.Project AND rbh.Task=rbhw.Task AND
rbh.Year=rbhw.Year AND rbh.Month=rbhw.Month AND rbh.User=rbhw.LoginRbhw
WHERE rbh.Month IS NOT NULL AND [email protected]
GROUP BY rbh.Year, rbh.Month, rbh.Project, rbh.Task, rbh.User,rbhp.SumPlan, rbhw.DoneSum
ORDER BY rbh.Project, rbh.Task, rbh.User, rbh.Month
RETURN
END
rbh
サブクエリが最初LEFT JOINをプロジェクト番号のような列のほとんどの値は、ユーザデータ等
(rbhp
)は時間の和を取得する取得をそのユーザーは、明確なタスクと月のプロジェクトに費やす予定です(返品表の列PlannedHours
)。
2番目のLEFT JOIN(rbhw
)は、ユーザーが特定のタスクと月に実際にプロジェクトに費やした時間の合計(返信表の列DoneHours
)を取得します。
関数をインラインテーブル値関数に変換します。パフォーマンスが向上する可能性があります。 –
これは膨大なクエリです。ソーステーブルはどのようになっていますか?最初にインデックスを最適化することから始めます。テーブルを結合するために使用しているフィールドがインデックスに登録されていることを確認します。 –
SSMSでは、[実際の実行計画を含める]をオンにします。内側のクエリ( 'SELECT'部分)を手動で実行し(適切に変数を宣言して設定する)、クエリプランを見てください。ほとんどの場合、非常に大胆な矢印が表示されている可能性があります。これは、部品を照会すること、最適化が必要なことを指摘しています。多くの場合、索引を作成したり、ロジックを少し変更したりする必要があります。 'JOIN'の条件でカスタム関数を使うことはパフォーマンスキラーでもあります。 – Arvo