SQL処理速度改善のための質問

このQ&Aのポイント
  • SQLの処理速度改善に向けて、3つの質問があります。検索条件の絞り込み方法、文字列の比較、TO_CHARの遅さについて教えてください。
  • 検索条件が複数ある場合、絞り込みが早い条件から検索するのが良いのか?文字列の検索において、X <> 'Z'とX > 'Z' and X < 'Z'は同じ結果か?TO_CHARが条件式に入ると遅くなるのか?
  • 3つの質問について回答してください。
回答を見る
  • ベストアンサー

SQLの処理速度改善にむけて

処理速度改善に向けて、3つ質問があります。 解答は1つでも良いのでお願いします。 1.検索条件が複数ある場合、もっとも絞れる物から検索するのが早いのでしょうか?   (Indexはその順番に伴い変更する事を前提)   例: where X = 3 (1000件中10件に絞れる) and Y = 4 (1000件中100件に絞れる) and Z = 5 (1000件中900件に絞れる) 上記のように、より絞れる物から検索する。 2.文字列で検索する場合、以下は同じ結果でしょうか。そしてパターン2の方が早いでしょうか   ・パターン1   where X <> 'Z' ・パターン2   where X > 'Z' and X < 'Z' 3.条件式にTO_CHARが入った場合、indexカラムの場合、遅くなるでしょうか?   下記SQLを直すとした場合、どのように直せるでしょうか? SELECT * from X,Y where TO_CHAR(X.DATE,'YYYYMM') = Y.DATE2(+)

  • evaan
  • お礼率45% (32/71)
  • Oracle
  • 回答数3
  • ありがとう数0

質問者が選んだベストアンサー

  • ベストアンサー
  • nora1962
  • ベストアンサー率60% (431/717)
回答No.1

> 1.検索条件が複数ある場合、もっとも絞れる物から検索するのが早いのでしょうか? 記述の順序には関係ありません。どれか一項目に絞るなら「X」に索引を貼るのが有効です。 > 2.文字列で検索する場合、以下は同じ結果でしょうか。そしてパターン2の方が早いでしょうか そもそも「X <> 'Z'」と「X > 'Z' and X < 'Z'」は同一条件ではありません。後者は常にFALSEです。 > 3.条件式にTO_CHARが入った場合、indexカラムの場合、遅くなるでしょうか? 一般的に関数を用いた項目については索引を使用しません。 しかし、 SELECT * from X,Y where TO_CHAR(X.DATE,'YYYYMM') = Y.DATE2(+) とは SELECT * FROM X LEFT JOIN Y ON TO_CHAR(X.DATE,'YYYYMM') = Y.DATE2 の意味ですから、X側のレコードは索引の有無に限らず全件アクセスされます。 逆にYのDATE2に索引があれば高速化できる余地があります。

evaan
質問者

補足

2は 「where X > 'Z' or X < 'Z'」 の事です。 ご解答ありがとうございました。 他の皆様もご解答、ありがとうございました。

その他の回答 (2)

  • entree
  • ベストアンサー率55% (405/735)
回答No.3

1. (X, Y, Z) で複合索引を張るのであれば、(X, Y, Z) でも、(Z, Y, X) でも変わらないでしょう。 単一列の索引の場合は X を使用するのが最も効率が良いです。 ヒント句を指定しても良いですが、統計情報をちゃんと取得しておけば、 X, Y, Z の各列に索引が張られていても X が使用されるはずです。 2. 以下の2つは同じです。 ・パターン1   where X <> 'Z' ・パターン2   where X > 'Z' or X < 'Z' 3. 書きなおす必要はありません。 Xの結果セット(レコード数)がYと比べて小さい場合は、 Y.DATE2列に索引がない場合は張ることを検討してください。 外部結合でNL結合される場合は、(+)が付いていない方が駆動表、 付いている方が内部表になります。

  • Siegrune
  • ベストアンサー率35% (316/895)
回答No.2

1. where X = 3 and Y = 4 and Z = 5  も where Z = 5 and Y = 4 and X = 3 も同じはずです。 (データベースの内部的なことなのではっきりとはいいませんが、内部的には同じ処理をしていないと  SQLを解析して実際の処理をするところがおかしいとしか思えない。  ・・・Oracle6とか7.0とか古過ぎるversionは?なところもありますが。)  一方、インデックスの作り方では、上のどちらのwhere句でも Z,Y,Xでインデックスを作るより、 X,Y,Zでインデックスを作ったほうが早いはず。 (但し、コストベースの場合はちゃんと統計情報を取っていないと、X = 3 (1000件中10件に絞れる)というのを正しく認識できないこともあります・・・きちんと統計情報を取っていれば問題ないということですが。) 2. ・パターン2   where X > 'Z' and X < 'Z' は   where X > 'Z' or X < 'Z' なら同じでしょう。処理速度もたぶん一緒。 3. 条件式にTO_CHARが入った場合、indexカラムの場合、遅くなるでしょうか? ⇒インデックスを使わなくなります。 TO_CHARが入ったfunctionインデックスを作っておけば、それを使うので、早く処理してくれますが。 SELECT * from X,Y where TO_CHAR(X.DATE,'YYYYMM') = Y.DATE2(+) については、ANo1の方が書いておられるように、Xはインデックスを使っていないので 関数を含んでいようがいまいが、一緒。

関連するQ&A

  • 【SQL】TO_DATEについて

    いつもお世話になっております。 DATE型の二つのカラム(仮に、abcとxyz)があり、条件句において、月までで、abc>xyzの条件をつけたいと考えています。 現在、以下のようなソースを考えているのですが、うまくいきません。 TO_NUMBER(TO_CHAR(abc,'YYYYMM'))>TO_NUMBER(TO_CHAR(xyz,'YYYYMM')) お力をお貸しいただけませんでしょうか。 よろしくお願いします。

  • SQL 副問い合わせ

    以下のaテーブルのcardidと、bテーブルのnoが同じで、 かつ、bテーブルのryodtmが前月のデータを抽出する以下のsqlを、 aテーブルのcardidが、bテーブルのnoと同じで、かつ、ryodtmが前月分、 または、cテーブルのchangcardと同じで、かつ、ryodtmが前月分のを抽出する場合、 どうすればいいでしょうか? select * from a where cardid in ( select distinct(no) from b where kdncresbt ='1' and ryodtm >= TO_CHAR(ADD_MONTHS(TRNC(SYSDATE,'MONTH'), -1),'YYYYMM' ) || '01' and ryodtm < TO_CHAR(SYSDATE,'YYYYMM') || '01' )

  • SQL文で質問です

    SQL文で質問です。 テーブルA X NUMBER型 Y DATE型(年月日と時間) テーブルB Z NUMBER型 W DATE型(年月日) A,BをAを主テーブルとして外部結合し、同じ年月日でBには無いデータ を取得したいのですが、 SELECT A.X FROM A,B WHERE A.X = B.Z(+) AND A.Y = B.W(+) AND B.Z IS NULL; というSQL文を実行すると、テーブルAには時間まで登録されているので 実際には取得したいデータが存在しても 「レコードが選択されませんでした」 になってしまいます。このため、 SELECT A.X FROM A,B WHERE A.X = B.Z(+) AND TO_DATE(A.Y,'YYYY/MM/DD') = TO_DATE(B.W,'YYYY/MM/DD')(+) AND B.Z IS NULL; としてみたところ、今度は3行目で 「ORA-00936: 式がありません」 というエラーになってしまいます。 外部結合にしたことがエラーの原因のようなのですが、DATE型の項目を キーにして外部結合にするにはどうすれば良いのでしょうか?

  • 【SQL】複数行から最大値の取得

    以下のSQLを実行すると ENDDATE      PNO 2013/02/01 00000001 2013/02/01 00000002 2013/02/03 00000001 2013/02/01 00000003 2013/02/05 00000002 2013/02/01 00000001 2013/02/02 00000002 の様になります。 これを ENDDATE      PNO 2013/02/03 00000001 2013/02/01 00000003 2013/02/05 00000002 の様にENDDATEの最大値のみを残しPNOが重複しないものを抽出したいです。 以下のSQLをどの様に修正すれば可能でしょうか? ==SQL================================================== SELECT CO1.ENDDATE,AD1.PNO FROM COMMON CO1,ADMADMISSION AD1 WHERE CO1.DETAILOF IN ('10') AND AD1.CURRENTWARD=:CURRENTWARD AND CO1.STARTDATE BETWEEN TO_CHAR(TO_DATE(:CURRENTDATE)-:ENDLINE,'YYYY/MM/DD') AND TO_CHAR(TO_DATE(:CURRENTDATE)+:DEADLINE,'YYYY/MM/DD') UNION SELECT CO2.ENDDATE,CO2.PNO FROM COMMON CO2,ADMADMISSION AD2 WHERE CO2.DETAILOF IN ('10') AND AD2.CURRENTWARD=:CURRENTWARD AND CO2.ENDDATE BETWEEN TO_CHAR(TO_DATE(:CURRENTDATE)-:ENDLINE,'YYYY/MM/DD') AND TO_CHAR(TO_DATE(:CURRENTDATE)+:DEADLINE,'YYYY/MM/DD') UNION SELECT CO3.ENDDATE,CO3.PNO FROM COMMON CO3,ADMADMISSION AD3 WHERE CO3.DETAILOF IN ('10') AND AD3.CURRENTWARD=:CURRENTWARD AND :CURRENTDATE BETWEEN CO3.STARTDATE AND CO3.ENDDATE

  • SQLチューニング

    教えて下さい。 検索文のWHERE句を設定、 (1)INDEX付きの項目を1つだけ指定する。 <例>WHERE 項目a = 'a' --対象件数少 (2)INDEX付きの項目を複数個指定する。 <例>WHERE 項目a = 'a' --対象件数少 AND 項目A = 'A' --対象件数多 どちらが検索速度は速いのですか? ご解答よろしくお願いいたします。

  • SQL where区で(-1)を使用したい

    SQL文のwhere区で(-1)を使用したいのですがどなたかアドバイスお願いします。 SQLをプロシージャにして検索条件を引数で渡そうと考えています。 検索したくない引数には(-1)を入れて渡したいです。 select * from X where X.1 = 'QQQ' and (引数 = -1 or X.2 = 引数) といった感じで、引数で(-1)を渡した場合 (-1 = -1 or X.2 = -1) となりwhere区で使用しない様作成したいと思っています。 この方法ではDATETIME型に対してはエラーとなるため出来ません。 良い方法は無いでしょうか。 よろしくお願いします。

  • 2つの情報を1つのSQLで取得する方法について

    お世話になります。 SQL文で、下記内容のデータを取得する方法がわかりません。 ・TESTテーブルからA、B、Cの3項目のデータを取得する。 ・但し、この中のC項目については、WHERE句の条件を満たす データの最大値を取得する。 ・項目AおよびBの取得条件は、項目Cと同一条件とする。 ・目的は、項目AおよびBに関しては、WHERE句の条件を満たす  全てのレコードを取得し、項目Cにおいては最大値のみ取得したい。 上記内容を取得しようと考えた場合、 現時点で下記のSQL文を作成して実行しましたが、 うまくデータが取得できません。 SELECT A, B, C FROM TEST WHERE C = (SELECT MAX(C) FROM TEST) AND Z = 'xxxxx' AND Y = 'x' AND X = 'Y' ※項目X, Y, ZはTESTテーブルのカラムです ※上記SQLを、A、Bのみ取得用とCのみ取得用に   それぞれ分解して実行すると、それぞれの結果は   正常に取得できます。 2つの結果を1つのSQLで取得することは可能でしょうか? どなたかご教授願えますか?よろしくお願いいたします。

  • Oracle データベース SQL

    質問させてください。 SQLについて教えてください。 SELECT文を作っていて、WHERE句で データを追加した日の指定(INSERT_DATE)を本日、というのをしたいと思っているのですが、なかなかできません。 格納するデータ型は、CHAR型なので WHERE INSERT_DATE =  TO_CHAR(SYSDATE, 'YYYYMMDD') で、試したのですができません…。 SQL実行はするのですが、該当なしになります。 教えていただければ、助かります。

  • oracle SQL

    売上情報を日別に集計して抽出しようと考えております。 その際に売上が存在しない日のレコードも纏めて抽出したいと考えております。 以下のように日付一覧を副問合せで生成し、left joinすれば良いかと 考えたのですが、結果は売上が存在するレコードしか抽出されません。 下記のSQLでは何が原因で全日付が抽出されないのか分る方がいらっしゃいましたらご教授頂けますと幸いです。 select 売明.商品コード, 売伝.納品日, 月日.全日, -- TO_CHAR(売伝.納品日,'DY') AS 曜日, TO_CHAR(月日.全日,'DD') AS 日, TO_CHAR(月日.全日,'DY') AS 曜日 -- count(売明.商品コード) AS 売上回数 from 売上伝票データ 売伝, 売上明細データ 売明, ( SELECT TO_DATE('20180401', 'YYYYMMDD') + ROWNUM - 1 AS 全日 FROM ALL_CATALOG WHERE TO_DATE('20180401', 'YYYYMMDD') + ROWNUM - 1 <= TO_DATE('20180430', 'YYYYMMDD') ORDER BY 1 ) 月日 where 売伝.納品日 BETWEEN TO_DATE('20180401','YYYY/MM/DD') AND TO_DATE('20180430','YYYY/MM/DD') AND 月日.全日 = 売伝.納品日(+) AND 売伝.売上伝票番号 = 売明.売上伝票番号 AND 売明.商品コード = '009405'

  • 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ヶ月以内のアイテムは   削除対象外とする 以上のようになっています。 どなたかアドバイスをいただければ幸いです。 宜しくお願い致します。