2016-08-20 1 views
1

ポップクイズ、SQL Serverホットショット:1つのクエリ内で「一定」の検索を効率的に行うことはできますか?

studentサブクエリは何回実行されますか? (少なくとも10行がsomethingであると仮定した場合):

SELECT TOP 10 a, b 
    , (SELECT type_id 
      FROM type 
     WHERE type_code = 'student') student 
    FROM something 

あなたは1を言った場合、私のように、あなたは、SQL Serverは不変スカラーとしてstudentの価値を認識することになると仮定します。

は残念ながら、答えは10です:

Execution plan for inline select and CTE versions

Index seek details for inline and CTE execution plan

私が知っている、私は、CTEを使用します!

WITH codes (student) AS (
    SELECT (SELECT type_id 
       FROM type 
      WHERE type_code = 'student') 
) 
SELECT TOP 10 a, b 
    , student 
    FROM something 
CROSS JOIN codes 

結果はまったく同じです。もちろん

、私は最初の変数にスカラをキャプチャすることにより、所望の効率を得ることができます。

DECLARE @Student tinyint 
SELECT @Student = type_id 
    FROM type 
WHERE type_code = 'student' 

SELECT TOP 10 a, b 
    , @Student student 
    FROM something 

これが唯一のシーク、およびメインクエリプランに何も加えないん

Execution plan for scalar pre-stored in variable

さらに冗長であることに加えて、インラインのテーブル値関数を定義している場合、暗黙のリターンスキーマも作成する必要があります。これは痛みです(エラーのベクトルを追加します)。

サブクエリを1回だけ実行する1つのクエリを書く方法はありますか?このクエリの

+0

、それはこの動作を引き起こしてTOP 10のですか?そしてもしそうなら、TOP 10をサブクエリに入れて、あなたのスカラー定数に 'join'/'append'するために異なるオプションを使用するとどうなりますか? – MatBailie

+0

@MatBailie、それは*面白いです。 「TOP 0」は例を「単純化」するだけでしたが、結果に影響を与えました。私がそれを取り除くと、実際には1つのシークが得られますが、全体の90%のコストで各行に1回実行される「テーブルスプール」も追加されます。これは予期せぬ効果があることを知っているのは良いことですが、受け入れられた答えからの提案は、もともとより簡単で効率的なものになりました。それは、 "MWE"がかなり "M"ではない場合に起こります! – harpo

答えて

2

SELECT TOP 10 a, b, 
     (SELECT type_id FROM type WHERE type_code = 'student' 
    ) as student 
FROM something; 

あなたはtype(type_code, type_id)のインデックスをしたいです。

あなたがFROM句にサブクエリを移動する場合、これは、より効率的かもしれません:

SELECT TOP 10 a, b, 
     t.type_id 
FROM something s CROSS JOIN 
    (SELECT type_id FROM type WHERE type_code = 'student' 
    ) t 

、あるいは関心のうち

SELECT TOP 10 s.a, s.b, t.type_id 
FROM something s JOIN 
    type t 
    ON t.type_code = 'student'; 
+0

問題は、インデックスが使用されていないということではありません(それは、すべての行で*同じ値を検索するために使用されているということです)。私は暗黙のうちにプランが使用されていることを示すインデックスを作成する 'type_code'に' UNIQUE'制約があります。それでも、私はあなたの提案を試みました、そして、私は同じ結果を得ました。 – harpo

+0

@harpo。 。 。右。正しい解決策は、サブクエリを 'FROM'に移動することです。 –

+0

ありがとう、ゴードン!どちらも型テーブルの検索を1回実行します。私は 'CROSS JOIN'が特にCTEバージョンと意味的に区別がつかないと期待しています。実際には複数のコードルックアップがあるので、私はサブセレクトとしてスカラーをそこに作成しました。とにかく、もう一度提案に感謝します! – harpo

関連する問題