
いつもお世話になっております。
Oracle9i+XP(CPU=PentiumCore2Duo,メモリ=2MB)の環境にて、以下のようなSELECT文なのですが、実行結果が出るまでに約45分もかかってしまいます。
何が悪いのか切り分けるために、以下の副問い合わせのみを切り取ってSQLPLUSで実行してみると15件ずつが約10秒おきに返ってくるという現象が確認できたため、おそらくこの副問い合わせではないかと思っております。
データ件数としては、ZAIテーブルが約6万件、MEISAIテーブルが約12万件、VIEW_ROOM_CALENDERビューが約6千件で、それ以外はしれとります。
一応すべてのテーブルのキーにはインデックスがはられているようです。
色々と調べてautotraceにて実行計画などを見てみましたが正直よくわかりませんでした。
テーブル構造やリレーション、カラム数、レコード長など情報が少なく大変申し訳ないのですが必要であれば提示させていただきますので、SQL文がおかしいとか、ネック部分の調べ方とか、なにかヒントのようなものでも結構ですので、どなたかご教授いただけませんでしょうか?
宜しくお願い致します。
select
D.KANJYA_NO || ',' ||
D.NAME || ',' ||
A.BYOU_NAME || ',' ||
count(COL_PT) || ',' ||
count(COL_OT) || ',' ||
count(COL_ST)
from
(
-- 副問い合わせ
select
B.KANJYA_NO as KAN_NO,
B.KAIKEI_DATE,
G.BYOUTOU_NAME as BYOU_NAME,
(case when C.MASTER_CODE in ('01017' , '01022' , '01025') then B.TOTAL_KAISUU else NULL end) as COL_PT,
(case when C.MASTER_CODE in ('01019' , '01021' , '01023') then B.TOTAL_KAISUU else NULL end) as COL_OT,
(case when C.MASTER_CODE in ('01016' , '01020' , '01024') then B.TOTAL_KAISUU else NULL end) as COL_ST
from
ZAI&1 B
inner join
MEISAI&1 C
on
C.NYUUGAI = B.NYUUGAI
and C.KANJYA_NO = B.KANJYA_NO
and C.ZAI_NO = B.ZAI_NO
and C.KAIKEI_DATE = B.KAIKEI_DATE
and B.KAIKEI_DATE Like '&1' || '%'
and B.NYUUGAI = 2
and B.KANJYA_NO not like '*%'
and C.MASTER_CODE in ('01017','01022','01025','01019','01021','01023','01016','01020','01024')
inner join
NYUUIN_ROOM E
on
C.KANJYA_NO = E.KANJYA_NO
inner join
VIEW_ROOM_CALENDER H
on
E.KANJYA_NO = H.KANJYA_NO
and C.KAIKEI_DATE = H.YYYYMMDD
and lpad(E.ROOM_NO,'10','0') = TO_NUMBER(H.ROOM_NO)
inner join
ROOM_TABLE F
on
E.ROOM_CODE = F.ROOM_CODE
inner join
BYT_TABLE G
on
G.BYOUTOU_CODE = F.BYOUTOU_CODE
) A
inner join
KANJYA D
on
A.KAN_NO = D.KANJYA_NO
group by
D.KANJYA_NO,
D.NAME,
D.BIRTH,
A.BYOUTOU_NAME
;
No.6ベストアンサー
- 回答日時:
>添付について
HELPを見たところ、質問・回答時に添付できるようです。
この質問はいったんクローズし、改めて別質問を追加していただいて、そこに必要なファイルを一式圧縮して添付していただければ良いのではないかと思います。
No.5
- 回答日時:
まだまだ情報不足なのですが、まず確認です。
NYUUIN_CALENDERというテーブルのデータは何件ですか?
ビューに一度アクセスするたびに31回フルアクセスしてしまいますので、
件数が多いとやばいです。(最近件数が増えたとか?)
NESTED LOOPになっているため、駆動表(MEISAI)の件数、このビューにアクセスしてしまいます。明細件数のほうが増えたということもあるかもです。
改善策を考えるためには、ビューの定義をもっと見せてください。
WHERE句で絞り込めるのなら、インデックスを使えるかもですが・・。
あと、プラン表示の結果も後半のアクセスパス(access, filterとか)が省かれているので分析できません・・。
そのまんまのテキストファイルを圧縮して、添付してくれれば全部見れるので、もっと分析可能です。あと、ソース公開に問題なければビュー定義もまるっと見せてください。あと、NYUUIN_CALENDERの定義もできれば。
No.4
- 回答日時:
・ビューを再利用している箇所
すいません、説明が不足でしたね。 VIEW_ROOM_CALENDERがビューであると推察しましたが、ビューが複合ビュー(複数テーブルを結合しているビュー)である場合、そのビューはFROM句では単体で用いるべき、とされています。さらに他のテーブルと結合して使用することを、「複合ビューの再利用」といい、パフォーマンス劣化の原因となりえます。
・結合する列同士の型が違う
もしこんなことでパフォーマンス劣化しているのだったらテーブルの列型をあわせてしまったほうがよいかもですが、列型変更できない事情がある場合は別の手で対処しないと仕方ないですね。
>マテリアライズド・ビューなるものにしてインデックスを張った方がよいのでしょうか?
マテビューは、もし VIEW_ROOM_CALENDERが劣化の原因であればソリューションの候補になりえます(可能性は低いと思いますが・・)が、情報不足でなんともいえません。ソリューションを考えるのは、「分析→原因特定」ができてからですのでね。
私が書いた、実行計画表示はやってみられたのですよね。
その結果を貼り付けてくれたらかなり分析できるのですが、可能ですかね?
「TABLE ACCESS FULLが多い」、というのは劣化プランの特徴のひとつではありますが、もとから件数の少ないテーブルだと問題が無い場合もあります。あと、ROWS、BYTES、COSTの数値に注目してください。これがオプティマイザの見積もり数値ですので。
くわしくはOracleのパフォーマンスチューニングガイドの「実行計画の読み方と理解」という項目を見るとよいです。
この回答への補足
以下、4000バイトを超えるため一部提示させていただきます。
ROWS、BYTES、COSTには数値が入っていないようです。
| Id | Operation | Name | Rows | Bytes | Cost |
| 0 | SELECT STATEMENT | | | | |
|* 1 | TABLE ACCESS BY INDEX ROWID | MEISAI | | | |
| 2 | NESTED LOOPS | | | | |
| 3 | NESTED LOOPS | | | | |
| 4 | NESTED LOOPS | | | | |
| 5 | NESTED LOOPS | | | | |
| 6 | NESTED LOOPS | | | | |
| 7 | VIEW | VIEW_ROOM_CALENDER | | | |
| 8 | UNION-ALL | | | | |
|* 9 | TABLE ACCESS FULL | NYUUIN_CALENDER | | | |
|* 10 | TABLE ACCESS FULL | NYUUIN_CALENDER | | | |
・
・
↑このTABLE ACCESS FULLが31行続きます。
そもそもVIEWを作成する元テーブルのカラムが、以下のようになっており、
「KANJYA_NO, CALENDER_YYYYMM CALENDER_KUBUN, CAL01, CAL02, CAL03, ・・・ CAL31」
これを以下のcreate文にて横に並んだカレンダーを縦に並べるイメージでビューを作成しております。
create view VIEW_ROOM_CALENDER( KANJYA_NO, YYYYMMDD, ROOM_NO) as
(select KANJYA_NO, 20081201, CAL01 from NYUUIN_CALENDER where ~
union all
select KANJYA_NO, 20081202, CAL02 from NYUUIN_CALENDER where ~
union all
select KANJYA_NO, 20081203, CAL03 from NYUUIN_CALENDER where ~
・・・
union all
select KANJYA_NO, 20081231, CAL31 from NYUUIN_CALENDER where ~
)
宜しくお願い致します。
色々とご丁寧にありがとうございます。
>私が書いた、実行計画表示はやってみられたのですよね。
その結果を貼り付けてくれたらかなり分析できるのですが、可能ですかね?
今は環境がありませんので週明けにでもご提示させていただきたいと思いますので宜しくお願い致します。
No.3
- 回答日時:
お礼の回答です。
>他の代替処置が思いつかないので、ご教授いただくことはできますでしょうか?
前述した通り、仕様がわからないのでアドバイスの仕様がありません。
強いて言うなら以下の点で気になります。
・B.KAIKEI_DATEは"DATE型"か"DATETIME型"ではないのですか?LIKEではなく等号、不等号で条件指定できそうな気がするのですが。
・「lpad(E.ROOM_NO,'10','0') = TO_NUMBER(H.ROOM_NO)」ですが、lpadかTO_NUMBERかどちらかは必要ないように思えるのですが、どうなんでしょうか?
「VIEW_ROOM_CALENDER」がおそらくビューだとは思うのですが、何をやっているのか分からないので何とも言えませんが、ここがネックになっているかも知れませんので、単体で使用した時のレスポンスを調べておいたほうが良いかと思います。
他の方がおっしゃられているように、explainで調べるか、クエリーを少しずつ切りだして実行して、何が原因かを調べるのが先決かと思います。
ちなみにindexを新たに張ることに関しては触れていませんでしたが、それはできない感じなのでしょうか?
ご回答ありがとうございます!
>・B.KAIKEI_DATEは"DATE型"か"DATETIME型"ではないのですか?LIKEではなく等号、不等号で条件指定できそうな気がするのですが。
残念ながらKAIKEI_DATEはvarchar2なのです。
>・「lpad(E.ROOM_NO,'10','0') = TO_NUMBER(H.ROOM_NO)」ですが、lpadかTO_NUMBERかどちらかは必要ないように思えるのですが、どうなんでしょうか?
現状では必要ですが、あまり関数は使わない方がよいみたいなので無くせるようにビューの構造を見直してみる価値はありそうですね。
>「VIEW_ROOM_CALENDER」がおそらくビューだとは思うのですが、何をやっているのか分からないので何とも言えませんが、ここがネックになっているかも知れませんので、単体で使用した時のレスポンスを調べておいたほうが良いかと思います。
ここがやはりネックになっていたようです。ビュー作成自体は早いのですが、結合にTABLE ACCESS FULLが頻発しておりました。ビューにインデックスははれないようなので、マテリアライズド・ビューとかにした方がよいのでしょうか?良くわかっていないのですが・・
>ちなみにindexを新たに張ることに関しては触れていませんでしたが、それはできない感じなのでしょうか?
基本的にパッケージなので、勝手にテーブルにインデックスをはってよいかどうかはわからないのです。
No.2
- 回答日時:
SQLを見ただけでまずい可能性があると思われるのは、以下2点です。
1.結合条件の中で関数を使用している
→ 結合するテーブル件数が多い場合、膨大な回数実行される恐れがある
2.ビューを再利用している
→ ビュー内容が複雑である場合、非効率的な処理(ビュー内のクエリをいったん先に処理してひとつのテーブルのように扱う)になることがある。
しかし、SQLだけだと類推しかできません。まずは実行計画を確認しましょう。
実行計画を表示するツールをお持ちじゃないですか?
なければ、以下の処理を実行してみてください。
1.sqlplusで以下のSQL文を実行(数秒で終わります)
explain plan for
[ご質問SQL文]
2.続けて以下のSQLを実行(実行計画表示)
select plan_table_output from table(dbms_xplan.display());
2の結果を見せていただければ、どの部分が遅いかより具体的に分かろうかと思います。
ご回答ありがとうございます!
>1.結合条件の中で関数を使用している
→ 結合するテーブル件数が多い場合、膨大な回数実行される恐れがある
それはごもっともだとは思いますが、結合するカラムどおしの型が異なる場合はどのような代替策がありますでしょうか?
>2.ビューを再利用している
すいません。具体的にどの部分のことなのでしょうか?
ご指摘の手順及びautotraceにて、実行計画を表示してみると、やはりビューにTABLE ACCESS FULL SCANが頻発しているようです。このビュー自体の作成には時間はかかっていませんでしたが。。マテリアライズド・ビューなるものにしてインデックスを張った方がよいのでしょうか?基本的に良くわかっていないのですが、もしご存知でしたらご教授いただけませんでしょうか?
No.1
- 回答日時:
病院内使われるシステムでしょうか?
メモリは"2GB"の間違いですよね?
現在開発中なのか、稼働中のシステムなのか事情は分かりませんが、あまりパフォーマンスを意識したクエリーではないようですね。
気になったことをざっと箇条書きします。
・キーにしかindexを張っていないようなので、件数が多いテーブルで検索条件に使われているものはindexを作成した方が良いでしょう。
・「like」は前方一致ならindexが効くのですが、避けられるのであれば避けた方が良いです。
・「not like」は全件検索になりますので避けた方が良いです。
・「lpad」、「TO_NUMBER」のような関数を使うとindexが効かないので、件数が多いテーブルには使わない方が良いです。
・「group by」に「D.NAME」は必要なのでしょうか?「D.KANJYA_NO」がユニークなら必要なさそうですが。
・引数「&1」がテーブル名にも使われているのですが、テーブルも「ZAI~」、「MEISAI~」テーブルと言うのが複数存在するということでしょうか?
・結果を結合して1つにしているのが気になります・・・(そうしないといけない事情があるのでしょうが)
その他細かいことはER図やテーブル構成を見てみないと分かりません。
個人的には、ORACLEにはできるだけ重い作業をさせず、データを受け取ったプログラム側で対処した方がパフォーマンスが良いと思っています。
ご回答ありがとうございます!
>・「like」は前方一致ならindexが効くのですが、避けられるのであれば避けた方が良いです。
・「not like」は全件検索になりますので避けた方が良いです。
・「lpad」、「TO_NUMBER」のような関数を使うとindexが効かないので、件数が多いテーブルには使わない方が良いです。
他の代替処置が思いつかないので、ご教授いただくことはできますでしょうか?
>・「group by」に「D.NAME」は必要なのでしょうか?「D.KANJYA_NO」がユニークなら必要なさそうですが。
特に不要だとは思いますが、selectされる項目なので、group byに入れているだけです。
・引数「&1」がテーブル名にも使われているのですが、テーブルも「ZAI~」、「MEISAI~」テーブルと言うのが複数存在するということでしょうか?
はい、複数存在します。引数はバッチファイルより渡されます。
>・結果を結合して1つにしているのが気になります・・・(そうしないといけない事情があるのでしょうが)
>個人的には、ORACLEにはできるだけ重い作業をさせず、データを受け取ったプログラム側で対処した方がパフォーマンスが良いと思っています。
本SQL文は他プログラムを使用せず、sqlplusにて流してspoolコマンドにてcsv出力をするという簡易的な統計帳票になります。
今までもこのようなSQL文は多々作成していたのですが、長くても1分以内で終わっていたので、何か根本的な誤りがあるのかと思っておりましたが、、、地道につぶしていくしかなさそうですね。。
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
似たような質問が見つかりました
- Oracle SQL update方法 2 2022/06/22 14:07
- Oracle 下記のsqlで取得されるレコード以外を取得する方法ありますでしょうか。 SELECT B.番号, B 2 2022/04/20 23:21
- PHP コメント機能に返信欄を矢印で追加したい 1 2022/05/09 21:17
- その他(プログラミング・Web制作) Pythonで会員サイトの自動ログイン ID Nameがない 1 2022/12/16 02:09
- Visual Basic(VBA) ローマ字、ハイフン付きの並び替え ローマ字抽出方法 Excelマクロ 4 2022/04/01 14:10
- その他(プログラミング・Web制作) Rでのスクリプトのご相談 3 2022/12/08 16:22
- PostgreSQL 画像とカテゴリーを出力したいのですが、取得の条件を付ける方法がわかりません。 2 2022/05/01 18:03
- JavaScript 1日1回引けるJavaScriptおみくじについて 1 2022/12/12 22:28
- Visual Basic(VBA) 【Excel VBA】自動メール送信の機能追加 5 2022/09/29 12:53
- その他(SNS・コミュニケーションサービス) 自分のpcがハッキングされたようなメールが来たのですがどうすればいいですか? 4 2022/10/02 16:14
関連するカテゴリからQ&Aを探す
おすすめ情報
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
エラーを起こす方法
-
truncate tableを使って複数の...
-
オラクルのUPDATEで複数テーブル
-
既にテーブルが存在する場合の...
-
CASEでBETWEEN制約
-
複数レコードの複数フィールド...
-
データ削除とSQL*Loaderでのイ...
-
【SQL】他テーブルに含まれる値...
-
フラグをたてるってどういうこ...
-
SELECT INTOで一度に複数の変数...
-
sqlに記述できない文字
-
UPDATEで既存のレコードに文字...
-
'modify' 付近に不適切な構文が...
-
SQLサーバに対するSQL文で抽出...
-
複数の条件に該当する結果を、...
-
SELECT文の結果をDEFINEの値と...
-
既存データをINSERT文にして出...
-
結合したテーブルをSUMしたい
-
CSVファイルを読み込んでテーブ...
-
T-SQLで任意の箇所で強制終了す...
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
truncate tableを使って複数の...
-
オラクルのUPDATEで複数テーブル
-
エラーを起こす方法
-
テーブル定義書(Oracle) 【IX】...
-
CASEでBETWEEN制約
-
既にテーブルが存在する場合の...
-
データ削除とSQL*Loaderでのイ...
-
任意のテーブルをdrop tableしたい
-
貸家のデータベース
-
AccessからOracle DB(View)を...
-
oracle ora-02298
-
Where句のNot条件をAnd条件にし...
-
テーブルDROPできないのです。。。
-
テーブルに変更があったらCSV出力
-
accessのデータをoracleへinser...
-
1テーブルに対して別々の条件...
-
select文の結果から新しいテー...
-
フィールド数が異なるテーブル...
-
[materialized]マテリアライズ...
-
複数レコードの複数フィールド...
おすすめ情報