2008年11月17日月曜日

[Oracle][SQL]テンポラリテーブルについて

リカバリ不要なワークテーブルとかに使う。

<特徴>
・REDOログを生成しないので高速にDML処理できる。
・生成したレコードは、生成したセッションからのみ参照できる。
・コミット後もしくはセッション終了後、データは削除(TRUNCATE)される。
・一時表領域を使用する。


<制限事項>
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

<定義登録方法>
▼SQL文
CREATE GLOBAL TEMPORARY TABLE 表1
(
 列名 データ型...
)
ON COMMIT[DELETE ROWS | PRESERVE ROWS]
;

▼テンポラリテーブルのレコードをクリアするタイミングを設定する。
・DELETE ROWS
トランザクション終了時にデータをクリアする。

・PRESERVE ROWS
セッション終了時にデータをクリアする。
※外部アプリがDB接続をコネクションプーリングしている場合、要注意かも。


[Appendix]
・統計情報はどうなる?

2008年11月14日金曜日

[Oracle][SQL]外部結合に関する制約

外部結合演算子(+)を使用する際には、色々結合条件に制約がある。
今日は、たまたまぶちあたった問題についてのメモ。
結合条件に複数項目を指定してる場合、全て外部結合にしなくてはならない。


▼表定義
例えば、こんな表があったとする。

[表1]
CREATE TABLE EMP(
EMP_CD CHAR(8),
EMP_NAME VARCHAR2(100),
DEPT_CD CHAR(8),
DELETE_FLG CHAR(1)
);

[表2]
CREATE TABLE DEPT(
DEPT_CD CHAR(8),
DEPT_NAME VARCHAR2(100),
DELETE_FLG CHAR(1)
);


▼問題点
で、こんなSQLを実行したとする。

[問題のSQL]
1 SELECT
2 E.EMP_CD,
3 D.DEPT_NAME
4 FROM
5 EMP E,
6 DEPT D
7 WHERE E.DEPT_CD = D.DEPT_CD(+)
8 AND D.DELETE_FLG = '0'
9 ;

この場合、外部結合にしたくても、内部結合となってしまう。
EMP表のDEPT_CDが、DEPT表に存在しない場合でもEMP表のレコードは表示したい、
という意図で、7行目に「e.DEPT_CD = d.DEPT_CD(+)」外部結合として記述したが、
8行目の「d.DELETE_FLG = '0'」により外部結合の要件を満たさなくなる。


▼解決方法
で、問題のSQLをうまいこと外部結合にしたい場合はこう書く必要がある。

[解決のSQL]
1 SELECT
2 e.EMP_CD,
3 d.DEPT_NAME
4 FROM
5 EMP e,
6 (SELECT * FROM DEPT WHERE DELETE_FLG ='0') d
7 WHERE e.DEPT_CD = d.DEPT_CD(+)
8 ;

ということで、今回の様に、予め特定条件でフィルタできる場合は
FROM句にてインラインビューとして取得するのが吉。


▼APPENDIX
その他の制限については今後加筆予定。

2008年11月5日水曜日

[Oracle]Materialized View を高速に完全リフレッシュ

以下のコマンドにより、非常に高速に完全リフレッシュを行うことができる。

[コマンド]
DBMS_MVIEW.REFRESH('MVEW_NAME','c',NULL,TRUE,FALSE,1,0,0,FALSE,FALSE);

[注意]
リフレッシュ処理の間、他トランザクションから当該Materialized Viewを参照した場合、0件として表示されるため、読み取り一貫性を保障する必要がある場合注意が必要である。

[方式]
通常の完全リフレッシュでは、Materialized Viewは実体を持つ(結局はテーブルなのだけれど)ため、実体に対してDELETE→INSERT処理となる処理を、TRUNCATE→INSERT処理に変更してリフレッシュする。

なぜ、上記コマンドでDELETEからTRUNCATE処理に変更されるかについては、今後追記する。オンライン開局中よりもオフライン処理中に使うことが多いかもしれない。

2008年11月4日火曜日

[Oracle]PL/SQLにおける自律型トランザクション宣言

プロシージャ中に以下の宣言を追加することで、プロシージャを自律型トランザクションを定義することができる。プロシージャのみ独立してトランザクションを完結したい場合に使用する。逆に、自律型トランザクションでないプロシージャ内で、トランザクションを確定した場合、呼び出し元のトランザクションも確定するので注意。

[実装方法]
・自律型トランザクションプラグマを宣言する。
→PRAGMA AUTONOMOUS_TRANSACTION;

[メリット]
・呼び出し元のトランザクションに依存せずに処理を進めることができる。
→例)ログテーブルにエラーメッセージを出力する。
・ロック時間の短縮が期待できる
→プロシージャ中のDMLが対象とするオブジェクトのロック時間が短くなる。
・SELECT文中でも使用できる
→通常、SELECT文中で呼び出す関数にDMLが含まれるとエラーとなる。

[制限]
・プロシージャ中でトランザクションを確定する必要がある。
→トランザクションが確定しない場合、処理はロールバックし、呼び出し元に例外が通知される。

[サンプル]
CREATE OR REPLACE PROCEDURE PRC_LOGOUTPUT(
Pi_vMSG IN VARCHAR2,
Pi_vPG_ID IN VARCHAR2
)
IS
PRAGMA AUTONOMOUS_TRANSACTION; --プラグマ宣言
BEGIN
INSERT INTO LOGTABLES(MSG, PG_ID, CREATED_ON)
VALUES (Pi_vMSG, Pi_vPG_ID, SYSDATE);
COMMIT; --トランザクションの確定
END;
/

2008年10月13日月曜日

[Oracle]OPatchを使用した個別パッチの適用メモ

先日Oracleに個別パッチを適用したので次回の為にメモを残す。

[手順]
・「opatch lsinventory -detail」にてOracleのパッチ状況を調べる。
・Enterprise Manager Database ConsoleをSTOPする。
・LISTENERをSTOPする。
・インスタンスをSHUTDOWNする。
・OPatchを適用する。
・「opatch lsinventory -detail」にてパッチが適用されたことを確認する。
・インスタンスをSTARTUPする。
・LISTENERをSTARTする。
・Enterprise Manager Database ConsoleをSTARTする。

[備考]
・OPatchは「$ORACLE_HOME/OPatch」に存在する。※注:下記項目参照
・↑のものは古い可能性がある。OPatchは常に最新版のものを使用すること。
・個別パッチ解凍先に移動した状態でOPatchを起動する。

2008年9月21日日曜日

[Oracle]現在使用されているオブジェクトを調べる

ロックされているオブジェクトを調べるのは簡単だど、単純にSELECTされている表などを調べることができないかと思い、色々攻めあぐねた結果、以下のSQLでそれらしい情報を取得できることが判明した。但し、CRUD等どのような操作を行っているかまでは判別できないみたい。(v$sql表と組み合わせてSQL文見れば良いかもだけど、構文解析が大変そう&信頼性がどうなの&処理が重そうなのでやめた)

- - - - - - - - - - - - - - - - - - - - - - - -
select

s.sid --SID

,s.serial# --シリアル番号

,s.username --Oracleログインユーザ名

,o.to_owner --使用してるオブジェクトオーナー

,o.to_name --使用してるオブジェクト名

from v$session s, v$object_dependency o

where s.sql_address = o.from_address

and s.sql_hash_value = o.from_hash

- - - - - - - - - - - - - - - - - - - - - - - -


これは例えば、次の様な状況のときに使用できるんじゃないかな。
僕のライフワークであるMaterialized Viewでのケースを例にしましょうね。


[状況]
・オンライン開局中にMaterialized ViewをTRUNCATEモードでリフレッシュしなければならない。
・リフレッシュ対象のMaterialized Viewに対する他セッションからの読み取り可能性は常にある。

[問題]
・Materialized ViewをTRUNCATEモードでリフレッシュすると、読取一貫性が保証できなくなる。
→他のセッションがMaterialized ViewをSELECTしていた場合でも問答無用でTRUNCATEするからである。これはMaterialized ViewをSELECTしている最中にTRUNCATEモードでのリフレッシュが走ると、TRUNCATEされた時点までのレコードしか読み取らない(しかもエラーにならない)。例えば本来100万件保持するMaterialized Viewなのに、10万件しか読み取らなかったというケースが発生し業務的にありえない状況になる。

[解決方法]
先に紹介したSQLから取得された情報を使用して、Materialized Viewのリフレッシュ処理部品中に、リフレッシュ対象のMaterialized Viewが他セッションから読み取られている場合に、Materialize Viewリフレッシュ処理をWAITする、処理を実装することで回避できる。(とはいいつつもMaterialized ViewをTRUNCATEモードでリフレッシュ中に、他のセッションがSELECTしたら0件が返却されるから、今度は読取セッション側でMaterialized Viewがリフレッシュ中かどうかの調べるロジックが必要になるという罠)

2008年9月20日土曜日

[Oracle]sqlplusw.exeが...いない

自宅のPCではOracle10gExpressEdition環境ですが、sqlplusw.exeがないのです。sqlplus.exeはあるのだけれど。ExpressEditionならではの制限事項なのかな、と思っていたら、sqlplusw.exeはOracle11gR1で廃止されているようです。Oracle10gExpressEditionでsqlplusw.exeが無いのはこの流れを先取りしてるからなのかしらね。

Oracle Database 11gリリース1(11.1)で廃止になったコンポーネント

Oracle Database 10gリリース2(10.2)に付属していた次のコンポーネントは、Oracle Database 11gのインストールでは使用できません。

iSQL*Plus

Oracle Workflow

Oracle Data Mining Scoring Engine

Oracle Enterprise Manager Javaコンソール

SQL*Plusグラフィック・ユーザー・インタフェース


Oracle Enterprise Manager Javaコンソールも廃止されちゃうのか。iSQL*PlusとかOracle Workflowはまあ当然の流れだとしても、sqlplusw.exeとOracle Enterprise Manager Javaコンソールも廃止されるのは切なさ炸裂ですね。sqlplusw.exeのアイコンちょっと可愛かったのに・・・