SQL IN()対OR


23

私は今日書いたクエリをWHERE使っていました

item_desc = 'item 1'
OR item_desc = 'item 2'
OR item_desc = 'item 3'
OR item_desc = 'item 4'

上記は15分間実行され、何も返されませんでしたが、次の結果は1.5分で結果セットが得られました

item_desc IN (
'item 1'
,'item 2'
,'item 3'
,'item 4'
)

これをSQLで実行しましたが、なぜOR(アイテムのリスト)がORステートメントよりもはるかに高速に実行されるのか疑問に思っています。

-編集-SQL Server 2008、この情報を最初から入力していないことをおforびします。

以下は、ORステートメントを使用したクエリ全体です。

DECLARE @SD DATETIME
DECLARE @ED DATETIME
SET @SD = '2013-06-01';
SET @ED = '2013-06-15';

-- COLUMN SELECTION
SELECT PV.PtNo_Num AS 'VISIT ID'
, PV.Med_Rec_No AS 'MRN'
, PV.vst_start_dtime AS 'ADMIT'
, PV.vst_end_dtime AS 'DISC'
, PV.Days_Stay AS 'LOS'
, PV.pt_type AS 'PT TYPE'
, PV.hosp_svc AS 'HOSP SVC'
, SO.ord_no AS 'ORDER NUMBER'
--, SO.ent_dtime AS 'ORDER ENTRY TIME'
--, DATEDIFF(HOUR,PV.vst_start_dtime,SO.ent_dtime) AS 'ADM TO ENTRY HOURS'
, SO.svc_desc AS 'ORDER DESCRIPTION'
, OSM.ord_sts AS 'ORDER STATUS'
, SOS.prcs_dtime AS 'ORDER STATUS TIME'
, DATEDIFF(DAY,PV.vst_start_dtime,SOS.prcs_dtime) AS 'ADM TO ORD STS IN DAYS'

-- DB(S) USED
FROM smsdss.BMH_PLM_PtAcct_V PV
JOIN smsmir.sr_ord SO
ON PV.PtNo_Num = SO.episode_no
JOIN smsmir.sr_ord_sts_hist SOS
ON SO.ord_no = SOS.ord_no
JOIN smsmir.ord_sts_modf_mstr OSM
ON SOS.hist_sts = OSM.ord_sts_modf_cd

-- FILTER(S)
WHERE PV.Adm_Date BETWEEN @SD AND @ED
AND SO.svc_cd = 'PCO_REMFOLEY'
OR SO.svc_cd = 'PCO_INSRTFOLEY'
OR SO.svc_cd = 'PCO_INSTFOLEY'
OR SO.svc_cd = 'PCO_URIMETER'

AND SO.ord_no NOT IN (
    SELECT SO.ord_no
    FRROM smsdss.BMH_PLM_PtAcct_V PV
    JOIN smsmir.sr_ord SO
    ON PV.PtNo_Num = SO.episode_no
    JOIN smsmir.sr_ord_sts_hist SOS
    ON SO.ord_no = SOS.ord_no
    JOIN smsmir.ord_sts_modf_mstr OSM
    ON SOS.hist_sts = OSM.ord_sts_modf_cd
    WHERE OSM.ord_sts = 'DISCONTINUE'
    AND SO.svc_cd = 'PCO_REMFOLEY'
    OR SO.svc_cd = 'PCO_INSRTFOLEY'
    OR SO.svc_cd = 'PCO_INSTFOLEY'
    OR SO.svc_cd = 'PCO_URIMETER'
)
ORDER BY PV.PtNo_Num, SO.ord_no, SOS.prcs_dtime

ありがとうございました、


10
クエリプランを見ましたか?

1
これは非常に実装固有です。どのDBMSを使用していますか?
ジェームズアンダーソン

クエリプランを見ていませんでした。これがクエリ固有であるか、それとも実際の問題であるかはわかりませんでした。
MCP_infiltrator

3
@MCP_infiltratorしたがって、ロジックが同等ではないため、実行プランは同等ではありません。OR上記の実際のクエリで使用するように使用する場合、エンジンを短絡させることができます。 WHERE A AND B OR CCが真の場合、A AND Bが偽であっても真と評価されます。WHERE A and B OR C OR D OR E OR Fあなたが上記のように言うなら、それAND は除外することができます。実際の同等のロジックは、OR上記のシリーズをカッコ内にカプセル化するため、セットとして扱われますWHERE A AND (B OR C OR D OR E)。これがanのIN処理方法です。
JNK

5
SQL Serverの演算子の優先順位はANDORに処理されるため、上記のクエリは同等ですWHERE (OSM.ord_sts = 'DISCONTINUE' AND SO.svc_cd = 'PCO_REMFOLEY') OR SO.svc_cd = 'PCO_INSRTFOLEY' OR SO.svc_cd = 'PCO_INSTFOLEY' OR SO.svc_cd = 'PCO_URIMETER'。つまり、最後の3つの条件のいずれかが真の場合、残りの評価を短絡することができます。
JNK

回答:


28

オレスキの答えは間違っています。SQL Server 2008の場合、INリストは一連のORステートメントにリファクタリングされます。たとえばMySQLでは異なる場合があります。

両方のクエリの実際の実行プランを生成した場合、それらは同一になると確信しています。

おそらく、2番目に実行したため、2番目のクエリはより速く実行されました。、最初のクエリは既にデータベースからすべてのデータページを取得し、IOコストを支払っていました。2番目のクエリは、メモリからすべてのデータを読み取り、はるかに高速に実行できました。

更新

分散の実際のソースは、クエリが同等でない可能性があります。OR以下の2つの異なるリストがあります。

WHERE PV.Adm_Date BETWEEN @SD AND @ED
AND SO.svc_cd = 'PCO_REMFOLEY'
OR SO.svc_cd = 'PCO_INSRTFOLEY'
OR SO.svc_cd = 'PCO_INSTFOLEY'
OR SO.svc_cd = 'PCO_URIMETER'

以降

 WHERE OSM.ord_sts = 'DISCONTINUE'
    AND SO.svc_cd = 'PCO_REMFOLEY'
    OR SO.svc_cd = 'PCO_INSRTFOLEY'
    OR SO.svc_cd = 'PCO_INSTFOLEY'
    OR SO.svc_cd = 'PCO_URIMETER'

これらの両方のWHERE句で、演算子の優先順位(ANDがORの前に処理される)は、エンジンによって実行される実際のロジックが次のとおりであることを意味します。

WHERE (ConditionA AND ConditionB)
OR ConditionC
OR ConditionD
OR ConditionE

ORリストをIN式で置き換えると、ロジックは次のようになります。

WHERE ConditionA
AND (ConditionB OR ConditionC OR ConditionD OR ConditionE)

これは根本的に異なります。


2
@MCP_infiltratorまあ、それは仮定を立てることの問題です:)実際に両方の実行計画を取得し、違いがあるかどうかを確認する必要があります。
JNK

4
高度なDBの質問がある場合は、データベース管理者に質問することもできます -完全な開示、私はそこのモデレーターですが、それが高度なSQLまたはSQL最適化の質問である場合、特にSQL Server
JNK

1
私は2つの実行計画を見たところ、それらはまったく異なります。ORステートメントを使用したクエリは、クラスター化インデックススキャンのコストの68%を占めます。INステートメントは26%であり、実行ステップも少ないようです。
MCP_infiltrator

3
@MCP_infiltrator必要ありません。元の投稿に対する私のコメントをご覧ください。 実際のクエリの句には他の条件があるため、上記のs INと同等ではありません。基本的に、クエリは異なる結果を返します。ORWHERE
JNK

3
@MCP_infiltrator DBA.SEに同一の質問を投稿する必要はありません。JNKが回答しました(そして、同様の回答が得られます)。 (あなたの質問)あなたが望むものをコメントボックスに記載する。MODが面倒を見てくれます。
ypercubeᵀᴹ

7

伝える最良の方法は、のようなものを使用して実際のクエリプランを調べることですEXPLAIN。これにより、DBMSが何をしているのかが正確にわかり、なぜそれがより効率的であるかをよりよく知ることができます。

そうは言っても、DBMSシステムは2つのテーブル間の操作(結合など)に非常に優れています。オプティマイザの時間の多くは、クエリのこれらの部分に費やされます。これらの部分は一般に高価であるためです。

たとえば、DBMSはそのINリストをソートし、のインデックスを使用してitem_desc、結果を非常に迅速にフィルタリングできます。最初の例のように多数の選択項目をリストするとき、その最適化を行うことはできません。

を使用するINと、即席のテーブルを作成し、これらのより効率的なテーブル結合技術を使用してフィルタリングします。

編集:OPが特定のDBMSについて言及する前に、この回答を投稿しました。これは、SQL Serverがこのクエリを処理する方法ではないことが判明しましたが、他のDBMSシステムでは有効な場合があります。より具体的で正確な回答については、JNKの回答を参照してください。


私は、カーディナリティがそれと多くの関係があると想像します。それはIN、それはそれで100件のレコードを持つ副選択、または千だった場合は非常に高速ではないでしょう。
ロバートハーヴェイ

@RobertHarveyはい、それはおそらく本当ですが、私はそれがそれほど悪くなるとは思わないでしょう。
オレクシ

ありがとう@Oleksi DBMSがINステートメントを即席リストにすることを知りませんでした
-MCP_infiltrator

1
-1-SQL Serverでは、INステートメントはテーブルに変換されず、一連のORs と同様に扱われます。
JNK

2
@ Katana314 EXPLAINが(OPが使用している)SQL Serverのキーワードである場合、私はあなたに同意しますが、そうではありません。
JNK
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.