2011-10-25 11 views
1

私はT-SQLクエリを使用しています。SQL ServerのT-SQLクエリの最適化

私はEntityAddressテーブルを持っており、郵送先住所がある場合は住所を取り戻したいと考えています。

特定のエンティティに複数のアドレスが存在することがあります。プライマリメールアドレスtinyintが設定されている場合もありますが、時にはそうでない場合もあります。ここには5つのデフォルトのメーリングアドレスにフラグが設定されているか、フラグが設定されていません。

これは、実際にこの時間を稼ぐ必要がある11k行で約20秒で実行されます。

SELECT 
    e.*, addr.* 
FROM 
    [Entity] e 
    --Address does not always exist 
    --PrimaryAddress is a Not Null TinyInt, sometimes this flag is enable twice for a given entity. 
LEFT OUTER JOIN 
    [Address] addr ON addr.[EntityID] = e.[EntityID] 
    AND addr.Code = 'MAILING'   
    AND addr.[AddressID] = (
     --This remove duplicates but add's a long delay(15 seconds) to execution time. 
     SELECT Top 1 a.[AddressID] 
     FROM [Address] AS a 
     WHERE a.Code = 'MAILING' 
     AND a.[EntityID] = e.[EntityID]  
     ORDER BY a.[PrimaryAddress] DESC) 

また、私は

種類これは、クエリの簡易版である サイモンジャクソン

+0

サードパーティのデータベースであり、変更が「サポートされていません」。 – Simon

+0

@ marc_sでは、インデックスを変更せずにパフォーマンスをチューニングすることができる多くの選択肢があります。 – HLGEM

答えて

1

に関してはどちらか:(二つのテーブルに任意のインデックスを追加できないことに留意すべきでI同じ行を返すと思います。(テストされていない)。これはあなたのバージョンよりも高速になる場合、私は言うことができない。あなたは私に言う。

SELECT 
    e.*, 
    addr.* 
FROM 
    [Entity] e 
    OUTER APPLY (
       SELECT TOP(1) * 
       FROM addr as a 
       WHERE a.Code = 'MAILING' 
       AND a.[EntityID] = e.[EntityID] 
       ORDER BY a.[PrimaryAddress] DESC 
      ) as addr 
+0

ありがとうございましたこれは改良されたものを持っています、目立って、それが実行されたときは約14秒、2回目には2秒まででした。 – Simon

+0

@Simon:DBCC FREEPROCCACHEなどを使用してキャッシュをクリーンアップしてから実行してください。 – sll

+0

DBCC FREEPROCCACHE、まあ、23分20秒のアウターで、元のものを使用します。多くの階層化されたビューがあります。 – Simon

0

は、SQL Server 20上にある場合05またはそれ以降のバージョンは、次の手順を試みることができる:

WITH ranked AS (
    SELECT 
    *, 
    rn = ROW_NUMBER() OVER (PARTITION BY EntityID ORDER BY [PrimaryAddress] DESC) 
    FROM [Address] 
    WHERE Code = 'MAILING' 
) 
SELECT 
    e.*, a.* 
FROM [Entity] e 
    LEFT JOIN [Address] a ON a.[EntityID] = e.[EntityID] AND a.rn = 1 

このクエリの結果はあなたのその上で1つの小さな違いがあります:1年代および/またはNULL sのrnの一つの追加の列が存在することになりますその中に。しかし、マスクされたSELECTリストは、最初はプロダクションクエリでは推奨されていないので、それが問題ではないと考えています。それが非プロダクションスクリプトの場合は、余分なカラムがほとんどありません。

参照:

+0

これは、欠落したインデックスを置くことができるCTEではなく、一時テーブルで行うことができます。 – HLGEM

+0

このタイプのクエリをテストしたところ、平均して9秒でした。共有してくれてありがとう。 – Simon

1

あなたはSELECT *を使用して停止することができ、あなたは二回、エンティティIDを戻ってきているし、それは、サーバーおよびネットワークリソースの両方の無駄です。そして、あなたは正直なところ、他のフィールドのすべてを必要としていますか?あなたが必要としないものはすべて削除してください。とにかく、選択コード*を実動コードで使用しないでください。

あなたは苦渋の行ごとに実行します相関サブクエリを持って、使用してみてくださいではなく、参加する:

SELECT  e.*, addr.* 
FROM  [Entity] e  
LEFT JOIN (SELECT addr.* 
      FROM [Address] a 
      JOIN  
       (SELECT Top 1 a.[AddressID]   
       FROM [Address] AS a   
       WHERE a.Code = 'MAILING'   
       AND a.[EntityID] = e.[EntityID]    
       ORDER BY a.[PrimaryAddress] DESC) dedup 
        ON a.address_id = dedup.address_id) addr 
    ON addr.[EntityID] = e.[EntityID] 

そして再びがSELECT *を使用しないでください、私はあなたのフィールドを知らないか、私はそれらを指定しているだろう上記。

もちろん、これを修正する実際の方法は、ひどく設計されたデータベースを修正することです。複数のプライマリアドレスを許可するべきではありません(トリガーによってこれを強制します)、重複した重複タスクを削除する必要はありません。私はあなたのケースではこれが不可能であることを認識していますが、他の誰かが設計上の欠陥について考えるかもしれません。これはサードパーティの製品であるため、1つのプライマリアドレスのみを許可するように修正するよう要求します。結局のところ、十分な人々が文句を言うと、彼らはそうかもしれません。

+0

フィードバックをいただきありがとうございます。あなたの結合をテストしました。平均して6秒かかります:) – Simon

+0

私は事を単純に保ち、キーフィールドに焦点を当てるために*を追加しました。それでも、ここで使用されているテーブルとフィールドの名前は実際のものを反映していません。私が使っているものを見れば、答えはその問題ではなく慣習になるのではないかと心配しています。 あなたの時間と助けてくれてありがとう。 – Simon

+0

これは、最も速いパフォーマンスの向上を示したので、これをマークしました。 私は@ Mikael-Erikssonの答えが好きですし、その構文もシンプルですが、私のクエリでは数秒遅くなります。 – Simon