• 締切済み

Oracleでルールベースでの複合索引

数十万件のデータをバッチ処理を行っているのですが、パフォーマンスが悪く困っています。 その原因となりそうな部分について質問します。 テーブルAに複合索引を作ります。 create unique index uk_A on A(AA,AB,AC,AD); このテーブルに検索をかけます。そのときにWhere句に書く列の順序は、パフォーマンスには関係ないのでしょうか? select max(AD) from A where AA=1 and AB=2 and AC=3; としたときと select max(AD) from A where AC=3 and AB=2 and AA=1; としたときの、パフォーマンスの違いです。 このバッチ処理の中で、Aのテーブルに多数のデータを追加するために、コストベースにはできません。また、このSQL文は、プロシージャの中で使用しています。 範囲検索の場合のことは、講習でもあったのですが、等価結合のことは出てきませんでした。 どなたかご存知の方宜しくお願いします。

みんなの回答

  • arata
  • ベストアンサー率49% (139/279)
回答No.2

Oracle7.2とかの時代では、そんなこともあったかもしれませんが、現在は、賢いので、Where句に書いてある順番には、影響されません。 数十万件から、抜いた件数が、かなり多い場合、インデックスがあることが邪魔をすることがあります。 それは、インデックス自体がテーブルである関係上、ほとんどのレコードにヒットしてしまう場合は、インデックスを読む分をプラスするのと、テーブル本体を全件なめるのとでは、後者の方がいいことがあるためです。 また、相手にするレコードが多い場合、必然的にネットワークやミドルウェアが扱うデータ量が増え、Oracle自体の検索スピードより、その部分のボトルネックが影響している場合もありますので、ストアドプロシージャを使って、DB側で処理するようにすると改善する場合もあります。

msystem
質問者

お礼

回答ありがとうございます。 >Oracle7.2とかの時代では、そんなこともあったかもしれませんが、現在は、賢いので、Where句に書いてある順番には、影響されません。 CBOでは、順番は関係ないと聞いていたのですが、RBOでも関係ないのですか・・・それは、複合索引だけの話になるのでしょうね。 >数十万件から、抜いた件数が、かなり多い場合、インデックスがあることが邪魔をすることがあります。 そうですね。一応、そのことは検討したのですが、今回の場合は、数十万件中ヒットするのは、最大でも10件程度なので、BTree索引が効果的だと判断して、普通に索引を作成しました。(カーディナリティは0.01%以下) >ストアドプロシージャを使って、DB側で処理するようにすると改善する場合もあります。 質問の中にも書かせていただきましたが、このSQLはプロシージャの中で使用しています。 参考にさせていただきます。

  • selenity
  • ベストアンサー率41% (324/772)
回答No.1

where AC=3 and AB=2 and AA=1; なのに、 create unique index uk_A on A(AA,AB,AC,AD); でいいのですか? 今のWHERE句ならインデックスにADは不要なのでは? 逆にWHERE句にADのパラメータを付加した状態で 試した場合は如何ですか?

msystem
質問者

補足

>where AC=3 and AB=2 and AA=1; >なのに、 >create unique index uk_A on A(AA,AB,AC,AD); >でいいのですか? そこを質問したいのです。EXPLANを見ると、質問の2つのSQL文両方で、uk_AのRangeScanになっています。ただ、ルールベースでは、Where句は右から評価されると聞いたような気がするので、どちらのほうがいいのかを聞きたいのです。 >今のWHERE句ならインデックスにADは不要なのでは? そのとおりです。このSQL文だけなら、インデックスにADは必要ありません。変則的な使い方ですが、この一意索引を、主キーの代わりに使っています。そのためにこの一意索引には、必ずADを入れなければならなくなっています。AA、AB、ACだけの索引を作ってもいいのですが、ディスク領域の無駄だと思い、作っていません。ただ、現状により近い状態をお知らせしたかったので、質問と関係ないかもしれませんが、入れさせていただきました。 >逆にWHERE句にADのパラメータを付加した状態で >試した場合は如何ですか? SQLの結果として、max(AD)をとっているので、指定するとちょっと結果が変わるような・・・。試してみたほうがよいでしょうか?

関連するQ&A

  • オラクルで外部結合

    オラクル8iを使用しています。 テーブルを外部結合する場合のパフォーマンスについてお聞きしたいのですが、 下の二つのSQL文でパフォーマンスは変わってくるのでしょうか? (外部結合記号(+)を=の前後につけた場合) SELECT 項目 FROM テーブル1 A, テーブル2 B WHERE A.項目1 = B.項目1(+); SELECT 項目 FROM テーブル1 A, テーブル2 B WHERE B.項目1(+) = A.項目1;

  • ORACLEでwhere句の検索順序

    Oracle9i windows2000です。 以下のようなテーブルがあります。 table_a ----------------------- id   NUMBER(10,0) NOT NULL, sort   NUMBER(10,0) NOT NULL, name   VARCHAR(10), text   VARCHAR(255) この条件で、以下のふたつのSELECT文を発行した時、パフォーマンスが良いのはどちらですか? Oracleでは後ろから検索されると聞いたことがあるのですが本当でしょうか? ※idにプライマリキー、 id,sortにインデックスが貼ってあります。 (1)SELECT text FROM table_a WHERE id = 1 AND sort = 2 AND name = 'a' (2)SELECT text FROM table_a WHERE name = 'a' AND sort = 2 AND id = 1

  • Oracle SQL DELETE文のレスポンス

    いつもお世話になっております。 この度は、手前のSQL文において DELETE文のレスポンスが上がらずに難儀しています。 現在DELETE処理はバッチにて行っています。 最初にSELECTにて抽出を行ったものをバックアップにとり、 次は同様の条件でDELETE文で処理しています。 この際に、SELECTでは1秒程度で済んだ処理が、 DELETE文ではレスポンスが返ってこないという状況です。 何がまずいのか、どう工夫すればいいのか 色々変えてみましたがレスポンスは改善されません。 SQLと条件は以下です。 【SQL文】 SELECT 複数の項目 FROM TABLEA A WHERE NOT Exists(SELECT 'X' FROM TABLEB B WHERE A.ITEMNO = B.ITEMNO) AND NOT Exists(SELECT 'X' FROM TABLEC C WHERE A.ITEMNO = C.ITEMNO AND to_char(LAST_DAY(ADD_MONTHS(SYSDATE,-4)),'YYYYMMDD') < C.REPYMD) AND NOT Exists (SELECT 'X' FROM TABLEA2 A2 WHERE A.ITEMNO = A2.ITEMNO AND to_char(LAST_DAY(ADD_MONTHS(SYSDATE,-4)),'YYYYMMDD') < to_char(A2.CREATEDATE,'YYYYMMDD')) AND NOT Exists(SELECT 'X' FROM TABLEC C WHERE A.ITEMNO != C.ITEMNO AND to_char(LAST_DAY(ADD_MONTHS(SYSDATE,-4)),'YYYYMMDD') < to_char(A.CREATEDATE,'YYYYMMDD')) 上記のSELECT文の後に処理されるDELETE文は 「SELECT 複数の項目 FROM TABLEA A」 ⇒ DELETE FROM TABLEA A としたもので、 条件は全てSELECT文と同様のものを使用しています。 ◆条件を言葉で明記すると以下のようになります。 1.Bテーブルに存在するものは削除対象外とする 2.AテーブルのアイテムIDとCテーブルのアイテムIDは一致する。   AテーブルのCREATEDATEとCテーブルのREPYMDのいずれかが3ヶ月以内のアイテムは   削除対象外とする 3.AテーブルもしくはCテーブルにしか存在しない場合は、各日付が3ヶ月以内のアイテムは   削除対象外とする 以上のようになっています。 どなたかアドバイスをいただければ幸いです。 宜しくお願い致します。

  • アクセスVBAでオラクルにつないだときのSQL記載方法

    教えてください。 アクセスのVBAでオラクルにつないで命令を発行しています。 検索がしたいのですが、 stSQL = "select * from DB where AA = '" & n1 & "'" は、うまくいきますが、あいまい検索の場合はどのようにかけばよいでしょうか? stSQL = "select * from DB where AA = '" & n1% & "'"とか、 stSQL = "select * from DB where AA = '" & n1 & "' & "%"" とかはうまくいきません。 そもそも、"や&や'の意味がいまいちわかっていないのですが・・、 どなたかあいまい検索の記載方法をご伝授下さい。 宜しくお願いします。

  • Select文のパフォーマンスについて

    Select文のパフォーマンスについて質問です。 (1)select * from table1 where col1='00001' and kbn in (1,2,3,4) (2)select * from table1 where col1='00001' and (kbn = 1 or kbn = 2 or kbn = 3 or kbn = 4) (1)と(2)ではどちらがパフォーマンスがよいのでしょうか? SQLServer2008

  • 【至急】SQLの結合について教えてください。

    select * from A where ab = '1' and cd = '2' select ef from B where ab = '1' and cd = '2' and ef = '3' 至急質問させてください。 上記SQLを結合したいです。(Oracleです) 取得したいデータはAのテーブルの全項目で、 取得条件として、Bのテーブルの項目ef = '3' だったらという条件を加えたいです。 キー項目は両テーブルとも同じ(ab, cd)です。 どのようなSQLがスマートでしょうか。。 無知で申し訳ございませんが、ご教授いただけますと幸いです。 よろしくお願いいたします。

  • 3テーブル外部結合方法について

    3つのテーブルを外部結合したいのですが・・・、 こんがらがってしまいました。 A,B,Cの3テーブルがあり、A,B,Cの順に外部結合 (LEFT OUTER JOIN)したいのですが、 A,BのテーブルについてはWhere句の条件指定が 必要です。 Select From (Select AA.a From A AA Where b = xxxx) BB Left Outer Join (Select CC.b From B CC Where c = eeee and BB.a = CC.b) On ???? こんな感じでつまづいてしまいました・・・

  • SQLについて教えてください

    お世話になっております。 以下、取得したい内容です。 この内容に対して、どのようにSQLを書けばよいか良いか教えて頂きたいです。 (1)DBの全テーブルに対して特定のカラムを取得したい。(カラム名はA,Bとする) (2)取得したカラム.Aに格納されている各値に対して、カラム.Bの各レコードの項目には何の値が格納されているか知りたい。 DBはオラクルですが、オラクルでしか使えないSQL構文はつかないようにしたいです。 自分で考えたSQLは、 SELECT A,B FROM * GROUP BY A,B ですが、そもそも全テーブルを指定する際に使用するのが、「*」では正しくないような気もします。 説明がつたなくて申し訳ございません。 宜しくお願い致します。 ・テーブルイメージ テーブル.test1 +--------+------+ | No | A | B | +--------+------+ | 01 |AA| 1 | | 02 |AA| 1 | | 03 |AB| 2 | | 04 |AB| 2 | | 05 |AC| 3 | | 06 |AC| 3 | | 07 |AC| 3 | +--------+------+ テーブル.test2 +--------+------+ | No | A | B | +--------+------+ | 01 |AA| 1 | | 02 |AA| 1 | | 03 |AB| 2 | | 04 |AB| 2 | | 05 |AC| 1 | | 06 |AC| 3 | | 07 |AC| 3 | +--------+------+ テーブル.test3 +--------+------+ | No | A | B | +--------+------+ | 01 |AA| 3 | | 02 |AA| 1 | | 03 |AC| 2 | | 04 |AC| 3 | +--------+------+

  • 最後のデータを含むレコード1行 MYSQL

    お世話になります。 最後の日にちを含むレコード全ての抽出方法がどうしてもわかりません。 id name date amount 1 AA 3/1 5 2 BB 3/1 5 3 CC 3/1 5 4 AA 3/2 7 5 BB 3/2 4 6 AA 3/3 1 これを、select * from テーブル group by name とすると、 id name date amount 1 AA 3/1 5 2 BB 3/1 5 3 CC 3/1 5 select id, name, max(date),amount from テーブル group by name とすると、 id name date amount 1 AA 3/3 5 2 BB 3/2 5 3 CC 3/1 5 望んでいる結果はこうです。最後のdateを含むレコード全てです。 id name date amount 3 CC 3/1 5 5 BB 3/2 4 6 AA 3/3 1 select * from テーブル as a where a.date=(select max(b.date) From テーブル as b where a.id=b.id); このようにしましたが、データの数が膨大なのですごく時間がかかってしまいます。 他、シンプルな方法はないでしょうか。 よろしくお願いします。 MYSQL バージョン5.0.45

  • SQLで'ABC'をDBの'AB'にHIT

    sqlite3をVC++2013で扱っています。 もしかしたら、単純な方法があるのかもしれないので質問させてください。 DBに渡す文字が'ABC'でDB内のデータ'AB'にHITさせたいと思っています。 現状思いつく方法は select * from テーブル where キー like 'A%'; select * from テーブル where キー like 'AB%'; select * from テーブル where キー like 'ABC%'; と渡す文字を一文字ずつ増やして検索して row数が0以上の一番小さい数のデータを取得するという方法しか思いつかないのですが。 何か良い方法はありますでしょうか?