2017-04-01 19 views
0

ここではC#プログラマーです。私はパフォーマンスの向上と効率的な実行を可能にする従来のアプリケーションのうちの1つで、長いSQL Serverプロシージャを編集するように指示されています。私のルートが手近なシナリオのために取るのが最善であるなら、私はいくつかの確認に感謝します。SQL Server:クエリを最適化する

SCENARIO

それが原因の元デザイナーによる両方のコードとDB賢明な設計に異例の一つです。検索グリッドでは、ユーザが選択したオプションと文字列/単語 "Warranty"の連結値とtbl.warranty.warrantyId値自体に基づいて、tbl.docsに "保証書"が生成されているかどうかを確認する必要があります。

この 'Warranty'の値+ tbl.warranty.warrantyIdは、tbl.docs.nameという列の値と同じですが、残念ながら2つのテーブルを結合/リンクする唯一の方法です。

保証ドキュメントは、保証ごとに複数回生成することができます。

パラメータ@IsGeneratedは、エンドユーザがフィルタリングを行うかどうかを選択するユーザオプションです。ここで

は、説明のためのいくつかの人口のデータがあります:

tbl.warranty

| warrantyId | name  | createdDate    | 
|------------|-------------|-------------------------| 
| 456  | Warranty 1 | 2002-04-01 12:14:53.330 | 
| 1000  | Warranty 2 | 2002-04-01 12:14:53.327 | 
| 1701  | Warranty 3 | 2002-04-01 12:14:53.333 | 
| 2456  | Warranty 4 | 2002-04-01 12:14:53.327 | 
| 3556  | Warranty 5 | 2002-04-01 12:14:53.330 | 

tbl.docs

| docId  | name   | createdDate    | 
|------------|--------------|-------------------------| 
| 1   | Warranty1000 | 2006-11-25 13:33:31.093 | 
| 2   | Warranty456 | 2015-02-11 13:33:31.100 | 
| 3   | Warranty1000 | 2012-05-17 13:33:31.097 | 
| 4   | Warranty1000 | 2017-01-11 13:33:31.097 | 
| 5   | Warranty1701 | 2017-03-14 13:33:31.100 | 
| 6   | Warranty456 | 2017-03-15 13:33:31.100 | 

だから、あなたが見ることができます:

  • warrantyId千ヘクタールwarrantyId 456はwarrantyIds 3556および2456で二回
  • 保証は、全くそうで...

目的のアクション(複数可)/結果を(生成されていない生成された3回

  • を生成してsをs)

    ユーザーはフィルタオプションを選択しないように選択することができます。[生成されたすべての保証記録と時間(tbl.docs.createdDate)を表示する必要がありますが、nullのtbl.docs.createdDate(generateddateもしあなたがそれを生成するよう要求されていなければ)、またはmaに基づく最新のレコードX tbl.docs.createdDateそれが持っている場合(generatedDate)]ユーザが[私はドキュメントは、レコードに基づいて生成されているすべての保証レコードを表示する必要がある、ドキュメントがのために生成されている保証にフィルタリングすることができ

    | warrantyId | name   | generatedDate   | 
    |------------|--------------|-------------------------| 
    | 456  | Warranty 1 | 2017-03-15 13:33:31.100 | 
    | 1000  | Warranty 2 | 2017-01-11 13:33:31.097 | 
    | 1701  | Warranty 3 | 2017-03-14 13:33:31.100 | 
    | 2456  | Warranty 4 | NULL     | 
    | 3556  | Warranty 5 | NULL     | 
    

    文字列/単語 "Warranty"と保証IDはdocs.name値と等しくなります。複数のドキュメントを持っている保証は、生成され、私は最新の時間を必要とするユーザーは、[私は避難所」すべての保証レコードを表示する必要がある、ドキュメントがのために生成されていないことを保証にフィルタリングすることができ

    | warrantyId | name   | generatedDate   | 
    |------------|--------------|-------------------------| 
    | 456  | Warranty 1 | 2017-03-15 13:33:31.100 | 
    | 1000  | Warranty 2 | 2017-01-11 13:33:31.097 | 
    | 1701  | Warranty 3 | 2017-03-14 13:33:31.100 | 
    

    ]レコードを生成しました文字列/単語「Warranty」と保証書と同等のドキュメントに基づいて、doc生成レコードがありました。名前]

    | warrantyId | name   | generatedDate   | 
    |------------|--------------|-------------------------| 
    | 2456  | Warranty 4 | NULL     | 
    | 3556  | Warranty 5 | NULL     | 
    

    これは私のスタブです。私は、テーブルテーブルに基づいて一時テーブルを作成し、私のクエリでそれを使用して効率性のための最善のルートではなく、すでに何がこのクエリをボグしていない考え出した。

    IF OBJECT_ID('tempdb..#tmpDocs') IS NOT NULL 
        DROP TABLE #tmpDocs 
    GO 
    
    CREATE TABLE #tmpDocs 
    (
        createdDate datetime not null, 
        name varchar(30) not null 
    ) 
    
    INSERT INTO #tmpDocs (createdDate, name) 
        SELECT createdDate, name 
        FROM docs 
    
    DECLARE @IsGenerated BIT 
    SET @IsGenerated = 0 
    
    SELECT 
        w.warrantyId, 
        w.name, 
        (SELECT TOP 1 d.createdDate 
        FROM #tmpDocs d 
        WHERE d.name = CONCAT('Warranty', w.warrantyId) 
        ORDER BY d.createdDate DESC) AS [generatedDate] 
    FROM 
        warranty w 
    WHERE 
        (@IsGenerated IS NULL OR @IsGenerated = 0 
        OR EXISTS (SELECT * 
           FROM #tmpDocs d 
           WHERE d.name = CONCAT('Warranty', w.warrantyId))) 
            AND (@IsGenerated IS NULL OR @IsGenerated = 1 OR 
             NOT EXISTS (SELECT * 
                FROM #tmpDocs d 
                WHERE d.name = CONCAT('Warranty', w.warrantyId) 
            ) 
           ) 
        ) 
    

    EDITED - ATTEMPT#2

    select 
        w.warrantyId, 
        w.name, 
        d.createdDate as [generatedDate] 
    from warranty w 
    left join #tmpDocs d 
        on d.name = concat('Warranty', w.warrantyId) 
        AND d.createdDate = (SELECT top 1 d.createdDate 
             FROM  #tmpDocs d 
             WHERE d.name = CONCAT('Warranty', w.warrantyId) 
             ORDER BY d.createdDate desc) 
    WHERE 
        (@IsGenerated IS NULL OR @IsGenerated = 0 
        OR EXISTS (SELECT * 
           FROM #tmpDocs d 
           WHERE d.name = CONCAT('Warranty', w.warrantyId)) 
        ) 
        AND (@IsGenerated IS NULL OR @IsGenerated = 1 
        OR NOT EXISTS (SELECT * 
            FROM #tmpDocs d 
            WHERE d.name = CONCAT('Warranty', w.warrantyId) 
         ) 
        ) 
    group by w.warrantyId, d.createdDate, w.name 
    

    実行時間は、私の小さなデータセット私が働いているので、私は推測している、しかし同じです。

    (5行が影響を受けます)

    SQL Server実行時間: CPU時間= 0 ms、経過時間= 0 ms。

    (5行(複数可)の影響を受ける)

    SQL Serverの実行時間: CPU時間= 0秒、経過時間= 0秒。

    このようなことを読んでくれてありがとうございます。代替ルートがある場合(これは、私が編集するprocの単純な側面の1つで、CTEを使用しないためです)、すべてをリファクタリングする時間がありませんその時に)、私はそれを聞いて非常に開いているだろう。この手続きを実行することで、手間がかからないようにすることはできません。

  • 答えて

    0

    これは間違いなく最適です。何らかの権限がある場合は、docテーブルを更新し、保証IDを保証テーブルの保証IDと同じデータ型として追加することをお勧めします。これがオプションでない場合、別の解決策は、両方のクエリ(ドキュメント用と保証用)を分割し、アプリケーションにドキュメント名を含むIN節を生成させることです。

    アプリケーションコードでより適切に処理されるフィルタリングについては、

    次のクエリを実行すると実際にdbに対してクエリを実行することはできません。

    SELECT 
        w.warrantyId, 
        MAX(w.name) as name, 
        MAX(d.createdDate) as generatedDate 
    FROM warranty w 
    LEFT JOIN docs d on d.Name = CONCAT('Warranty', w.warrantyId) 
    GROUP BY w.warrantyId 
    
    +0

    私は非常に感謝しています。私はテーブルの構造を編集することはできません。保証文書が生成されているだけではありません。保存されたprocをすべてフィルタリングし、アプリケーション側でデザイン/ワークフローを編集すると、割り当てられた時間このプロジェクトに与えられたものです。私は基本的にその場所の構造で作業することを余儀なくされています。 – theoryTim

    +0

    あなたが働いているSPの数はわかりませんが、上記のクエリはあなたが探している結果を得るはずです。 あなたの検索結果に最新のドキュメントだけが必要だったのですか、またはドキュメントごとに1つの保証が必要でしたか? – Vee

    +0

    また、テーブルのインデックスを変更することは可能ですか?元の質問には言及していませんでした。通常、最適なインデックスを作成するには、良いインデックスと悪いインデックスが最適です。 – Vee