2011-01-12 8 views
0

以下のスクリプトをコピーして貼り付けてください。サブクエリー作成クエリースロー

DECLARE @MainTable TABLE(MainTablePkId int) 
INSERT INTO @MainTable SELECT 1 
INSERT INTO @MainTable SELECT 2 

DECLARE @SomeTable TABLE(SomeIdPk int, MainTablePkId int, ViewedTime1 datetime) 
INSERT INTO @SomeTable SELECT 1, 1, DATEADD(dd, -10, getdate()) 
INSERT INTO @SomeTable SELECT 2, 1, DATEADD(dd, -9, getdate()) 
INSERT INTO @SomeTable SELECT 3, 2, DATEADD(dd, -6, getdate()) 

DECLARE @SomeTableDetail TABLE(DetailIdPk int, SomeIdPk int, Viewed INT, ViewedTimeDetail datetime) 
INSERT INTO @SomeTableDetail SELECT 1, 1, 1, DATEADD(dd, -7, getdate()) 
INSERT INTO @SomeTableDetail SELECT 2, 2, NULL, DATEADD(dd, -6, getdate()) 
INSERT INTO @SomeTableDetail SELECT 3, 2, 2, DATEADD(dd, -8, getdate()) 
INSERT INTO @SomeTableDetail SELECT 4, 3, 1, DATEADD(dd, -6, getdate()) 

SELECT m.MainTablePkId, 
     (SELECT COUNT(Viewed) FROM @SomeTableDetail), 
     (SELECT TOP 1 s2.ViewedTimeDetail FROM @SomeTableDetail s2 
               INNER JOIN @SomeTable s1 ON s2.SomeIdPk = s1.SomeIdPk 
               WHERE s1.MainTablePkId = m.MainTablePkId) 
FROM @MainTable m 

このスクリプトは単なるサンプルです。私はSELECTのカラムの長いリストとサブクエリの12+カラムのリストを持っています。私のFrom節には約8つのテーブルがあります。

2000レコードを完全に取得するには21秒かかり、サブクエリを削除すると4秒かかります。

「データベースエンジンチューニングアドバイザー」を使用してクエリを最適化しようとしましたが、新たに推奨されるインデックスと統計情報を追加しようとしましたが、これらの変更によりクエリ時間が悪化します。

注:

私は、これは実際のデータがテーブルの多くは、列を結合が、サブクエリの結果、私たち罰金なしで持っている私の質問を説明するためのテストデータであることを述べてきたように。

助けていただきありがとうございます。

+0

SELECT COUNT(表示されていない)から@SomeTableDetailをテーブル@SomeTableのIDに関連付ける必要がありますか? – Lamak

+0

'TOP 1'は' ORDER BY'なしでランダムな行を得ることを意味します。また、 'COUNT()'サブクエリは@MainTableと相関関係がありますか? –

+0

2番目のサブクエリでは、ORDER BYなしでTOPを使用しています。どのViewedTimeDetailが本当に返されますか?最古の?最新の? –

答えて

2

これはCTEの例ですが、あなたが望むものに近いものの、あなたが望むものに近いものの、始めることができます。

WITH _CountViewed AS 
(
    SELECT COUNT(Viewed) AS Viewed FROM @SomeTableDetail 
), 
_SomeDate AS 
(
    SELECT MAX(s2.ViewedTimeDetail) As ChangeTime, s1.MainTablePkId FROM @SomeTableDetail s2 
               INNER JOIN @SomeTable s1 ON s2.SomeIdPk = s1.SomeIdPk 
               GROUP BY s1.MainTablePkId 
) 
SELECT sd.MainTablePkId, cv.Viewed, sd.ChangeTime FROM _SomeDate sd 
    OUTER APPLY _CountViewed cv 
+0

ありがとう@Erin、それを手に入れました。 – Kashif

2

相関サブクエリはrow-by-agoniziong-rowを実行しますが、本質的にはprocに多くのカーソルがあります。それらを結合(または派生テーブルまたはCTEへの結合)に変更します。 パフォーマンス基準からの相関サブクエリを使用することは悪いことです。これらは、常に結合、CTEまたは導出された表結合で置き換えることができます。

+0

ありがとう@HLGEM。私はどのようにこれを結合に変えることができるのか分かっていますが、CTEの例を教えてください。私はCommon Table Expressionについて知っていますが、この状況でCTEをどのように使用できるかを理解することはできません。ご協力いただきありがとうございます。 – Kashif

+2

これは非常にあなたがそこまで持っていた何をしていませんが、それは良いスターターexampleWITH _CountViewedでなければなりません (@SomeTableDetail から見てみる \t SELECT COUNT())、 _SomeDate AS ( \t SELECT MAX(AS S2 ChangeTime、@SomeTableDetail S2 INNER FROM s1.MainTablePkIdとして.ViewedTimeDetail)JOIN @SomeTable S1にs2.SomeIdPk = s1.SomeIdPk s1.MainTablePkId ) SELECT sd.MainTablePkId、cv.Viewed、_SomeDate FROM sd.ChangeTime BY GROUP sd \t OUTER APPLY _CountViewed cv – Erin

0

私は少し行間を読んでギャップを埋めようとしていますが、これはあなたが達成しようとしているものに近いかもしれないと思います。

SELECT m.MainTablePkId, SUM(std.Viewed), MAX(std.ViewedTimeDetail) 
    FROM @MainTable m 
     INNER JOIN @SomeTable st 
      ON m.MainTablePkId = st.MainTablePkId 
     INNER JOIN @SomeTableDetail std 
      ON st.SomeIdPk = std.SomeIdPk 
    GROUP BY m.MainTablePkId 
0

彼らは正式にPKとして宣言されていない場合、私はs1.MainTablePkIdとm.MainTablePkId、s2.SomeIdPkとs1.SomeIdPkに索引を作成します。 (SQL Serverによってすでに索引付けされています)

非ロック読み取りは、(nolock)を追加することで実行できます。これは、表をロックしないことによって高速化されます。

SELECT m.MainTablePkId, 
     (SELECT COUNT(Viewed) FROM @SomeTableDetail (nolock)), 
     (SELECT TOP 1 s2.ViewedTimeDetail FROM @SomeTableDetail s2 (nolock) 
               INNER JOIN @SomeTable s1 (nolock) ON s2.SomeIdPk = s1.SomeIdPk 
               WHERE s1.MainTablePkId = m.MainTablePkId) 
FROM @MainTable m (nolock) 
関連する問題