2011-03-10 9 views
2

を行きますテーブルスキャン。SQLクエリは、私は2つのテーブルを持っている代わりに、インデックスベースのスキャン全表をスキャン

Execution Plan 
---------------------------------------------------------- 
Plan hash value: 2290496975 
---------------------------------------------------------------------------- 
| Id | Operation   | Name | Rows | Bytes | Cost (%CPU)| Time  | 
---------------------------------------------------------------------------- 
| 0 | SELECT STATEMENT |  | 3737 | 97162 | 85 (3)| 00:00:02 | 
|* 1 | FILTER   |  |  |  |   |   | 
| 2 | TABLE ACCESS FULL| BIG | 74718 | 1897K| 85 (3)| 00:00:02 | 
|* 3 | TABLE ACCESS FULL| SMALL |  1 |  4 |  3 (0)| 00:00:01 | 
---------------------------------------------------------------------------- 

Predicate Information (identified by operation id): 
--------------------------------------------------- 

1 - filter("ID"=45 OR EXISTS (SELECT /*+ */ 0 FROM "SMALL" "SMALL" 

      WHERE "ID"=:B1)) 

3 - filter("ID"=:B1) 

インデックスをスキャンするために常にクエリを書き換えることができる方法はありますか?このような

+1

タイプミスがあることです - –

+0

それはそのデータ型の文字列関連(VARCHAR2など)ではない列にLIKEを使用するための誤りだろうと思いましただからあなたは45から始まるIDを望んでいますか? 45,45029,451のように? –

+0

はいjonあなたは正しいです – Ajitesh

答えて

-1

何かがうまくいくかもしれない:

select * 
    from big_table big 
where id like '45%' 
    or exists (select id from small_table where id = big.id); 
+0

こんにちはSunil私はそれを試みましたが、同じ結果を得ました実行計画 | ID |オペレーション|名前| |行| |コスト(%CPU)|時間| ------------------------------------------------- --------------------------- | 0 | SELECTステートメント| | 3737 | 97162 | 85(3)| 00:00:02 | | * 1 |フィルター| | | | | | | 2 |テーブルアクセスFULL |ビッグ| 74718 | 1897K | 85(3)| 00:00:02 | | * 3 |テーブルアクセスFULL | SMALL | 1 | 4 | 3(0)| 00:00:01 | – Ajitesh

3

ノー、ノー、ノー。

インデックスを使用しないことをお勧めします。幸いなことにオラクルはそれよりスマートです。

IDは数字です。 45,450,451,452,4501,45004,4500003などのID値を持つ可能性がありますが、インデックスにはこれらの値がどこにでも散在します。あなたがID BETWEEN 450 AND 459のような条件を満たしていれば、インデックスを使う価値があります。

インデックスを使用するには、インデックスを上から下にスキャンする必要があります(各IDをLIKE比較を行う文字に変換する)。次に、一致するものについては、NAME列を取得するために離脱する必要があります。

インデックスとテーブルの間を行き来することを躊躇するのではなく、テーブルをスキャンするのが簡単ですばやく(75,000行はそれほど大きくない)

+2

スポットがオンです。それを行う方法は、IDを文字列に変換する関数ベースのインデックスになります。そうすれば、LIKEはより良い言葉を求めて「正しく」行動します。 – lll

1

他のものは正しいですが、そのような数値列は使用しないでください。

実際には、この場合に(パフォーマンス)問題を引き起こすのはOR <subquery>です。私はそれがバージョン11で異なるかどうか分からないが、バージョン10gr2まで、それは基本的に相関サブクエリを持つネストされたループであるフィルタ操作を引き起こす。あなたの場合、数値列をvarcharとして使用すると、テーブル全体がスキャンされます。あなたはこのようなあなたのクエリを書き直すことができ

:あなたのテストケースでは

select * 
    from big 
where id like '45%' 
union all 
select * 
    from big 
    join small using(id) 
where id not like '45%'; 

、私は大きなと9小規模で174000行の行数で終わります。 クエリの実行には1211399回の整合性があり、7秒かかります。 私の質問を0,7秒間実行し、542の一貫性のある取得を使用します。

私のクエリのための計画を説明している:

-------------------------------------------------------------------- 
| Id | Operation      | Name | Rows | Cost (%CPU)| 
--------------------------------------------------------------------- 
| 0 | SELECT STATEMENT    |  | 8604 | 154 (6)| 
| 1 | UNION-ALL     |  |  |   | 
|* 2 | TABLE ACCESS FULL   | BIG | 8603 | 151 (4)| 
| 3 | NESTED LOOPS    |  |  1 |  3 (0)| 
|* 4 | TABLE ACCESS FULL   | SMALL |  1 |  3 (0)| 
| 5 | TABLE ACCESS BY INDEX ROWID| BIG |  1 |  0 (0)| 
|* 6 |  INDEX UNIQUE SCAN   | BIG_PK |  1 |  0 (0)| 
--------------------------------------------------------------------- 

Predicate Information (identified by operation id): 
--------------------------------------------------- 

    2 - filter(TO_CHAR("ID") LIKE '45%') 
    4 - filter(TO_CHAR("SMALL"."ID") NOT LIKE '45%') 
    6 - access("BIG"."ID"="SMALL"."ID") 


Statistics 
---------------------------------------------------------- 
      1 recursive calls 
      0 db block gets 
     542 consistent gets 
      0 physical reads 
      0 redo size 
     33476 bytes sent via SQL*Net to client 
     753 bytes received via SQL*Net from client 
     76 SQL*Net roundtrips to/from client 
      0 sorts (memory) 
      0 sorts (disk) 
     1120 rows processed 
関連する問題