2

私たちの環境では、1 つの手順の実行に時間がかかります。手順を確認しました。以下に概要を示します-

  1. 手順には、選択ブロック (約 24) のみが含まれます。各選択の前に、データが存在するかどうかを確認しています。はいの場合はデータを選択し、そうでない場合は別のことを行います。例えば ​​:

    -- Select block 1 --
    IF EXISTS (SELECT 1 FROM table1 t1
              INNER JOIN table2 t2
              ON t1.col1=t2.col1
              WHERE t1.col2='someValue' AND t2.col2='someValue'
              )
    BEGIN
       SELECT t1.col1,t2.col2,t2.col3 FROM table1 t1
       INNER JOIN table2 t2
       ON t1.col1=t2.col1
       WHERE t1.col2='someValue' AND t2.col2='someValue'
    END
    ELSE
    BEGIN
      SELECT 'DEFAULT1', 'DEFAULT2', 'DEFAULT3'
    END
    
    
    -- Select block 2 --
    IF EXISTS (SELECT 1 FROM table1 t1
              INNER JOIN table2 t2
              ON t1.col1=t2.col1
              WHERE t1.col5='someValue' AND t2.col5='someValue'
              )
    BEGIN
       SELECT t1.col5,t2.col6,t2.col7 FROM table1 t1
       INNER JOIN table2 t2
       ON t1.col1=t2.col1
       WHERE t1.col5='someValue' AND t2.col5='someValue'
    END
    ELSE
    BEGIN
      SELECT 'DEFAULT1', 'DEFAULT2', 'DEFAULT3'
    END        
    

どういうわけか、IF EXISTS ブロック内で使用されるクエリを 1 つのクエリに結合し、いくつかの変数に値を設定して、どの条件が true を返すかを識別できるようにすれば、実行時間を短縮できるという結論に達しました。そしてパフォーマンスを向上させます。

私の考えは正しいですか?それを行うオプションはありますか?他のオプションを提案できますか?

Microsoft SQL Server 2005 を使用しています。

[編集: 追加] - すべての select ステートメントは、異なる同じ列タイプを返しません。また、すべての select ステートメントが必要です。24 個の if ブロックがある場合、プロシージャは 24 個の結果セットを返す必要があります。

[追加した]

もう1つお聞きしたいのですが、以下のどれがより速く実行されますか-

  1. SELECT 1 FROM table1 t1 INNER JOIN table2 t2 ON t1.col1=t2.col1 WHERE t1.col2='someValue' AND t2.col2='someValue'
  2. SELECT COUNT(1) FROM table1 t1 INNER JOIN table2 t2 ON t1.col1=t2.col1 WHERE t1.col2='someValue' AND t2.col2='someValue'
  3. SELECT TOP 1 1 FROM table1 t1 INNER JOIN table2 t2 ON t1.col1=t2.col1 WHERE t1.col2='someValue' AND t2.col2='someValue'

ありがとう。カルティック

4

3 に答える 3

2

選択クエリのパフォーマンスを向上させるには... where句で使用している列に「インデックス」を作成します

あなたが使用しているように

WHERE t1.col2='someValue' AND t2.col2='someValue' 
WHERE t1.col5='someValue' AND t2.col5='someValue'

col2col5にデータベース インデックスを作成します。


一時テーブル 一時テーブルを使用して結果を格納できます。同じクエリを24回使用しているため、最初に以下のクエリの結果を一時テーブルに保存します(必要に応じて構文を修正してください)

insert into temp_table (col2, col5)
SELECT col1, col5 FROM table1 t1
          INNER JOIN table2 t2
          ON t1.col1=t2.col1

一時テーブルを使用してチェックします

-- Select block 1 --
IF EXISTS (SELECT 1 FROM temp_table
          WHERE t1.col2='someValue' AND t2.col2='someValue'
          )
BEGIN
   SELECT t1.col1,t2.col2,t2.col3 FROM table1 t1
   INNER JOIN table2 t2
   ON t1.col1=t2.col1
   WHERE t1.col2='someValue' AND t2.col2='someValue'
END

-- Select block 2 --
IF EXISTS (SELECT 1 FROM temp_table1
          WHERE t1.col5='someValue' AND t2.col5='someValue'
          )
BEGIN
   SELECT t1.col5,t2.col6,t2.col7 FROM table1 t1
   INNER JOIN table2 t2
   ON t1.col1=t2.col1
   WHERE t1.col5='someValue' AND t2.col5='someValue'
END
于 2013-10-01T10:25:12.927 に答える
0

クエリの結果をデフォルト値の行に外部結合し、クエリの結果が空の場合はデフォルトに戻すことができます。

SELECT
  col1 = COALESCE(query.col1, defaults.col1),
  col2 = COALESCE(query.col2, defaults.col2),
  col3 = COALESCE(query.col3, defaults.col3)
FROM
  (SELECT 'DEFAULT1', 'DEFAULT2', 'DEFAULT3') AS defaults (col1, col2, col3)
LEFT JOIN
  (
    SELECT t1.col1, t2.col2, t2.col3
    FROM table1 t1
    INNER JOIN table2 t2
    ON t1.col1=t2.col1
    WHERE t1.col2='someValue' AND t2.col2='someValue'
  ) query
  ON 1=1  -- i.e. join all the rows unconditionally
;

サブクエリが実際に NULL を返す可能性があり、それらをデフォルト値に置き換えてはならない場合、メソッドはその形式であなたに合わない可能性があります。その場合、サブクエリがフラグ列 (任意の値) を返すようにします。最終クエリでその列が NULL と評価された場合、それはサブクエリが行を返していないことを意味するだけです。この事実は、次のように CASE 式で使用できます。

SELECT
  col1 = CASE WHEN query.HasRows IS NULL THEN defaults.col1 ELSE query.col2 END,
  col2 = CASE WHEN query.HasRows IS NULL THEN defaults.col2 ELSE query.col2 END,
  col3 = CASE WHEN query.HasRows IS NULL THEN defaults.col3 ELSE query.col2 END
FROM
  (SELECT 'DEFAULT1', 'DEFAULT2', 'DEFAULT3') AS defaults (col1, col2, col3)
LEFT JOIN
  (
    SELECT HasRows = 1, t1.col1, t2.col2, t2.col3
    FROM table1 t1
    INNER JOIN table2 t2
    ON t1.col1=t2.col1
    WHERE t1.col2='someValue' AND t2.col2='someValue'
  ) query
  ON 1=1
;
于 2013-10-02T14:41:33.967 に答える
0

現在の構造はあまり効率的ではありません。事実上、各 "if" ステートメントを実行する必要があり (これにはコストがかかります)、"if" が true を返す場合は、同じ where 句 (高価なビット) を繰り返す必要があります。そして、あなたはこれを24回行います。最悪の場合 (すべてのクエリがデータを返す)、クエリの時間が 2 倍になります。

インデックス作成を確認したと言う - 各クエリが微妙に異なるように見えることを考えると、これを再確認する価値があります。

明らかなことは、アプリケーションをリファクタリングして 24 個の select ステートメントを実行し、データが返されない場合があるという事実に対処することです。これはかなり大規模なリファクタリングです。

それができない場合は、より野心的ではありませんが (より厄介な) リファクタリングを検討してください。データが存在するかどうかを確認し、それまたは同等のデフォルトの結果セットを返す代わりに、ユニオンとして記述します。

   SELECT t1.col1,t2.col2,t2.col3 FROM table1 t1
   INNER JOIN table2 t2
   ON t1.col1=t2.col1
   WHERE t1.col2='someValue' AND t2.col2='someValue'
   UNION  
   SELECT 'DEFAULT1', 'DEFAULT2', 'DEFAULT3'

これにより、where 句にヒットする回数が減りますが、クライアント アプリケーションが「デフォルト」データを除外する必要があることを意味します。

最後の質問に答えるには、クエリ オプティマイザーを実行して実行プランを確認しますが、最初のバージョンが最速だと思います。クエリは、where に一致する最初のレコードが見つかるとすぐに完了します。基準。2 番目のバージョンは、一致するすべてのレコードを見つけてカウントする必要があります。最終バージョンでは、すべてのレコードを検索して最初のレコードを選択する必要があります。

于 2013-10-01T11:10:12.643 に答える