• ベストアンサー

パフォーマンスについて

次の2つのSQLで10秒前後の開きがあります。 原因は「CD_STS」なのですが、理由がわかりません。 データは700万件あります。 インデックスは「NO_UKE」と「CD_STS」につけています。インデックスは全部で5つあります。 なぜこれほど違いがでるのでしょうか? 原因がわかったのでお客さんに説明したいのですが理由がわからなくて困っています。。 考えられそうな理由があればお願いいたします。 ■即■ select CD_STS from T_STS where CD_KAIIN = 50 and FL_DEL = 0 and NO_UKE = 10 and (CD_STS <= 7 and CD_STS >= 7) ■10秒前後かかる■ select CD_STS from T_STS where CD_KAIIN = 50 and FL_DEL = 0 and NO_UKE = 10 and CD_STS = 7

  • Oracle
  • 回答数3
  • ありがとう数5

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

  • ベストアンサー
回答No.3

#2です。 Oracleオプティマイザはルールベースでしょうか?  ⇒以下のSQLを実行して、 num_rows ~ blocks 列の値が NULL でなければコストベース、   NULL ならばルールベースです。    select table_name, num_rows, avg_row_len, blocks    from user_tables    where table_name = 'T_STS'; ・ルールベースである ・インデックス2(「NO_UKE」)が、インデックス1(「NO_UKE」+「CD_STS」)よりも  後に作成された という前提でアドバイスをさせていただきますと… Oracleオプティマイザは、後に作成されたインデックスを優先して Rangeスキャンを試みようとする傾向があるようです。 ですから、抽出時に使用するインデックスを明示しないと 後に作成されたインデックス2(「NO_UKE」)が選択使用されます。 抽出の条件が複数ある場合、複数項目で構成されるインデックスを使用した方が パフォーマンスが良くなりますので、インデックス1(「NO_UKE」+「CD_STS」)を抽出時に 使用されるよう、オプティマイザに『ヒント』を与えてやれば解決します。 以下のSQLを実行すると、おそらく ■即■ のSQLと同じ実行計画になると思われます。 select /*+ INDEX(T_STS インデックス1の名前) */ CD_STS from T_STS where CD_KAIIN = 50 and FL_DEL = 0 and NO_UKE = 10 and CD_STS = 7; 【まとめ】  ルールベースオプティマイザモードにおいて、複数のインデックスが存在する  テーブルに対して抽出を行う場合、抽出条件によっては単一項目のインデックスよりも  複数項目のインデックスを優先して使用させるよう、明示的に指定することで  パフォーマンスが改善する可能性があります。

参考URL:
http://homepage2.nifty.com/sak/w_sak3/doc/sysbrd/sq_tn03.htm
toshi_200578
質問者

お礼

Oracleオプティマザはルールベースでした。 上記SQLを実行し、おっしゃる通り■即■のSQLと同じ実行計画になります。おかけさまで問題は解決できました。 基本的なところから記述して頂いてかつわかりやすい説明は大変参考になりました。 ありがとうございました。

その他の回答 (2)

回答No.2

こんにちは。 それぞれのSQLを実行した際の実行計画(Execution Plan)は、確認済でしょうか?  ⇒SQL*Plusをお使いで、AUTOTRACE機能が使用可能な環境であれば、    SQL> set autotrace on の後、   SQL*Plus上でSQLを直接実行することで、実行計画が取得できます。 実行計画を見れば、それぞれのSQLを実行した際の違いが 明らかになると思いますよ。

toshi_200578
質問者

お礼

実行計画の方法がわからなくてやってませんでした。 ありがとうございます。 結局は違うインデックスが使われていました。。 インデックス1(「NO_UKE」「CD_STS」)を見ずに インデックス2(「CD_STS」)を見てました。 なぜインデックス1が使われていないのでしょうか? 検索条件で「NO_UKE」「CD_STS」が使われているなら当然にインデックス1が使われると思っているのですが。。 しかしとりあえず一歩進むことができました。 ありがとうございました。

  • iiikkk
  • ベストアンサー率37% (92/247)
回答No.1

回答ではないのですが。 インデックスを貼ってあるものをwhereの頭に持ってきたほうが、パフォーマンスが良いって聞いたことがあります。 今回の件には当てはまりませんが。 すいません。

toshi_200578
質問者

お礼

ありがとうございます。 インデックスはつけてるんですが、目的のインデックスが使用されてなかったみたいでした。

関連するQ&A

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

    現在1つのSQLで10秒程度かかります。 データが700万件あるのでそれが原因というのもありますが、それにしても遅いです。 以下のSQLです。 select CD_STS from T_STS where NO_UKE = '20000' and CD_STS = '07' インデックスに「NO_UKE」と「CD_STS」で作成しています。 なにかいい方法はありませんか?

  • 目的のインデックスが使用されない・・。

    以下のSQLではインデックス1を使用してほしいのですがインデックス2が使われています。 インデックス1を使用されるように変更する方法を 教えてください。 インデックス1:「NO_UKE」「CD_STS」 インデックス2:「CD_STS」 select CD_STS from T_STS where NO_UKE = 10 and CD_STS = 7

  • 性能の改善について

    以下の(1)のSQLと(2)のSQLで性能が全然違います。原因は明示的に「1」を取得するようにしているからなのですが、改善する方法はないでしょうか? (1)SQL(遅い) SELECT 1, /*+ INDEX(T_UKERUI T_UKERUIP1) */ T.NO_UKE FROM T_UKE T ,M_OFF O ,M_KAI K WHERE T.CD_OFR = O.CD_OFR AND T.CD_KAIIN = K.CD_KAIIN AND T.CD_STS IN (3, 4) AND T.CD_SHIP = 0001 AND T.NO_ADDNO = 0 (1)SQL(速い) SELECT /*+ INDEX(T_UKERUI T_UKERUIP1) */ T.NO_UKE FROM T_UKE T ,M_OFF O ,M_KAI K WHERE T.CD_OFR = O.CD_OFR AND T.CD_KAIIN = K.CD_KAIIN AND T.CD_STS IN (3, 4) AND T.CD_SHIP = 0001 AND T.NO_ADDNO = 0

  • PostgreSQLのphpPgAdminを使って

    お世話になります。 PostgreSQL8.4.8のphpPgAdmin3.5.3を使ってデータを削除する際に 先ずデータをSELECT で表示させて確認後、 SQL編集 で SELECTを DELETE に書き換えて実行しましたが以下エラーが出ます ≪一覧確認用≫一覧表示はできました。 SELECT "kaiin_no","tenpo_no","tenpo_name" FROM "public"."store_table" WHERE "kaiin_no" IN ('1234',2222'); ≪削除用≫SELECT  → DELETEに変更 → 実行 → 以下エラー DELETE "kaiin_no","tenpo_no","tenpo_name" FROM "public"."store_table" WHERE "kaiin_no" IN ('1234',2222'); ≪エラー内容≫ ERROR: syntax error at or near "," LINE 1: SELECT COUNT(*) AS total FROM (DELETE "kaiin_no","tenpo_no",... ^ 文: SELECT COUNT(*) AS total FROM (DELETE "kaiin_no","tenpo_no","tenpo_name" FROM "public"."store_table" WHERE "kaiin_no" IN ('1234','2222')) AS sub 文法エラーのようなのですが 一覧が出来ているのに なぜ削除が出来ないのか 初心者で恐縮ですが ご教示頂ければ幸いです。

  • 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文のEXISTSについて

    DBはmysql5.0を使っています。 以下のSQL文を、EXISTSを境に2つに分解することはできないでしょうか?? SELECT ROUND(SUM(IFNULL(T.DAIKIN,0) - IFNULL(T.TESURYO,0))/10000,1) INTO v_PRICE2 FROM TORIHIKI AS T WHERE T.TORIHIKI_KBN = '1' AND EXISTS (SELECT * FROM TORIHIKI AS T2 WHERE T2.TORIHIKI_DATE >= F_DATE AND T2.TORIHIKI_DATE <= T_DATE AND T2.TORIHIKI_KBN = '2' AND T2.KEHAI_CD = LPAD(v_SOBA_CD,5,'0') AND T2.KAIIN_SBT = v_KAIIN AND T.SEIRI_NO = T2.SEIRI_NO AND ROUND((IFNULL(T2.DAIKIN,0) + IFNULL(T2.TESURYO,0))/10000,1) >= p_MIN AND ROUND((IFNULL(T2.DAIKIN,0) + IFNULL(T2.TESURYO,0))/10000,1) < p_MAX );

  • sedに関する質問

    ★以下のファイルがあるとします。 SQL> select count(*) from koumoku where no = 1052 and mid =2; COUNT(*) ---------- 7 SQL> select count(*) from koumoku where no = 1053 and mid =3; COUNT(*) ---------- 4 SQL> select count(*) from setumei where no = 1054 and mid =2; COUNT(*) ---------- 9 SQL> select count(*) from setumei where no = 1055 and mid =7; COUNT(*) ---------- 5 SQL> select count(*) from imi where no = 1056 and mid =2; COUNT(*) ---------- 9 SQL> select count(*) from imi where no = 1057 and mid =6; COUNT(*) ---------- 3 ★ここでsedコマンドを利用して、 koumoku COUNT(*) ---------- 7 koumoku COUNT(*) ---------- 4 setumei COUNT(*) ---------- 9 setumei COUNT(*) ---------- 5 imi COUNT(*) ---------- 9 imi COUNT(*) ---------- 3 のように取り出したいのですが、方法が分からないので、 誰か教えてもらえますか?宜しくお願いします。

  • 4つのテーブルから、該当する項目を一度に検索したい。重複除く

    4つのテーブルから、それぞれ違う条件で検索し、該当する項目名NO を探したいのですが、どのようなselect文を書くと効率よく検索できる のでしょうか?また、重複NOは除きたいのです。 良かったら教えて下さい。 例えば、テーブル名:test1,test2,test3,test4とあった場合、 一度に該当するNOを拾い出す方法があれば、教えて下さい。 1.select no from test1 where code = '' and day < 20041118; 2.select no from test2 where day < 20041118; 3.2.select no from test3 where data != '' and day < 20041118; 4.select no from test4 where day > 20041018 and day < 20041118;

  • 特定カラムの値を変更したいのですが

    お世話になります。DB初心者です。 現在 、PostgreSQLのphpPgAdminを使っていまして 以下のようなDBがあり kaiin_no  t_name   t_chiket -------+-------+---------- 1001    太郎     なし 1002    次郎     なし 1003    三郎     なし 1004    四朗     あり 1005    五朗     あり 以下のようなSQLで目的のデータを表示できるのは解ったのですが SELECT "kaiin_no","t_name","t_chiket" FROM "public"."store_table" WHERE "kaiin_no" IN ('1001','1002','1003'); kaiin_no '1001','1002','1003' の t_chiket を 「なし」 から 「あり」 に変更すする方法をご教授いただけますでしょうか? お手数をおかけしますがよろしくお願いいたします。

  • サブクエリーのパフォーマンスについて

    こんばんわ。 ある書籍にサブクエリーを【1】より【2】にした方がパフォーマンスがいいと書いてありました。 パフォーマンスがいい理由を教えて頂けないでしょうか?? 【1】 UPDATE Absenteeism SET severity_points= 0, reason_code = 'long term illness' WHERE EXISTS (SELECT * FROM Absenteeism AS A2 WHERE Absenteeism.emp_id = A2.emp_id AND Absenteeism.absent_date = (A2.absent_date + INTERVAL '1' DAY)); 【2】 UPDATE Absenteeism AS A1 SET severity_points = 0, reason_code = 'long term illness' WHERE EXISTS (SELECT * FROM Absenteeism AS A2 WHERE A1.emp_id = A2.emp_id AND (A2.absent_date + INTERVAL '1' DAY) = A1.absent_date); よろしくお願いします。 以上