2012年12月11日火曜日

Oracle Database作業時のちょっとしたテクニック

最初に
今日は、JPOUG Advent Calendarの11日目のエントリです。
1nmくらい役に立つプレゼントになればと思ってエントリします。


データセンターでのトラブルシュートでは、幾つかの共通する懸念があります。

1.PCが持ち込めない or 通信カードが使えない or サーバからはネット出来ない
2.トラブルシュートなので大体が緊急である
3.同様の障害が再発生した際に対応できるようにしておきたい。

これらの状況下で必要とされるのが「自力」
そんなとき使っているちょっとしたテクニックを紹介したいと思います。

1.PCが持ち込めない or 通信カードが使えない or サーバからはネット出来ない
 DB内の何かを調査するには、データディクショナリ(DBA_)や動的パフォーマンス・ビュー(V$)を
 参照して色々な統計情報を参照します。ただ、あまり使用しないものはなかなか覚えていられません。
 Oracleのリファレンスマニュアルを確認できれば、どのビューのどの列を参照すればいいか分かりますが、
 自PCも使えないし・ネットにも繋がってない。

 みんなが@yoshikawさんの「CUIでOracle Databaseリファレンスマニュアルを参照する」を参考にして、
 マニュアルを見れるようにしておいてくれるととても有難いのですが、なかなかそうもいきません。

 さて、どうするか?

 ディクショナリ一覧表から、関係のありそうなビューを見つけ出します。

SQL> SELECT TABLE_NAME,COMMENTS FROM DICTIONARY
         WHERE TABLE_NAME LIKE '%LINK%';
TABLE_NAME                     COMMENTS
------------------------------ ------------------------------------------------------------
DBA_DB_LINKS                   All database links in the database
DBA_STREAMS_TP_COMPONENT_LINK  DBA Streams Component Link (Streams Topology Links)
USER_DB_LINKS                  Database links owned by the user
ALL_DB_LINKS                   Database links accessible to the user
V$DBLINK                       Synonym for V_$DBLINK
GV$DBLINK                      Synonym for GV_$DBLINK

次に、関係のありそうな表に、どんな列があるのかを調べます。
SQL> DESC[RIBE] DBA_DB_LINKS
名前                                      NULL?    型
----------------------------------------- -------- ----------------
OWNER                                     NOT NULL VARCHAR2(30)
DB_LINK                                   NOT NULL VARCHAR2(128)
USERNAME                                           VARCHAR2(30)
HOST                                               VARCHAR2(2000)
CREATED                                   NOT NULL DATE
※[]内は省略できます。

TABLE_NAME LIKE '%調べたいキーワード%'という形で使用し、
あとは、関係のありそうな列を参照して調査します。

SQL> SELECT OWNER,DB_LINK,USERNAME FROM DBA_DB_LINKS;

これで、DBA_XXやV$XXを覚えて無くても、ある程度必要な情報を調査出来ます。


2.トラブルシュートなので大体が緊急である
 すぐになんとかしなければいけないのに、値の異なる対処SQL文を大量に実行しないといけない。
 でも、ローカルにはいいエディターもないし、ましてやエクセルなんて・・・
 地道にコピペして一部を修正してなんてやってたら、時間がかかってしまう。。。

 さて、どうする?

 SQL文を使用してSQL文を生成します。

 例)APからのセッション数が増えすぎてメモリが枯渇。セッションを破棄したい。
   ※PGA_AGGREGATE_TARGETのない時代はある話でした。。

 SQL> SELECT USERNAME,SID,SERIAL# FROM V$SESSION WHERE USERNAME='SCOTT';

USERNAME     SID    SERIAL#
---------- ----- ----------
SCOTT          8         75
SCOTT          9         39
SCOTT         11         27
SCOTT         12        129
・
・
・

100行が選択されました。
(kill sessionのSQL)
SQL> ALTER SYSTEM KILL SESSION 'SID,SERIAL#';

SIDとSERIAL#を修正して何度も実行する?
SQL> ALTER SYSTEM KILL SESSION '8,75';
システムが変更されました。
SQL> c/8,75/9,39/
1* ALTER SYSTEM KILL SESSION '9,39'
SQL> /
システムが変更されました。

c/修正対象文字列/修正後文字列/で置換できますが、
100回繰り返すのはしんどいし、時間もかかる。
そこで、連結演算子「||」を活用して参照結果からSQL文を生成します。

SQL> SELECT 'alter system kill session '''||SID||','||SERIAL#||''';' FROM V$SESSION
     WHERE USERNAME='SCOTT';
'ALTERSYSTEMKILLSESSION'''||SID||','||SERIAL#||''';'
--------------------------------------------------------------------------------
alter system kill session '8,75';
alter system kill session '9,39';
alter system kill session '11,27';
alter system kill session '12,129';
・
・
99行が選択されました。

コピペして実行してもいいですが、
spoolコマンドを使用してスクリプト化するのもありです。
SQL> set pages 2000
SQL> set head off
SQL> set feedback off
SQL> set trimspool on
SQL> spool kill_session.sql
SQL> SELECT 'alter system kill session '''||SID||','||SERIAL#||''';' FROM V$SESSION
  2  WHERE USERNAME='SCOTT';
alter system kill session '8,75';
alter system kill session '9,39';
alter system kill session '11,27';
alter system kill session '12,129';
・
・
・
SQL> spool off
ローカルフォルダに kill_session.sqlというファイルが出来るので、
editコマンドを使用して編集します。
SQL> edit kill_session.sql
Windowsだとノートパッドでファイルが開くので不要な部分を修正します。
Linuxの場合は、
SQL> define _editor=vi でエディターを定義してeditコマンドを実行します。
修正したファイルを実行します。
SQL> @kill_session
システムが変更されました。
システムが変更されました。
・
・
・
手動で繰り返し実行するよりとてもスマートですね。
INDEXのリビルドとか不要オブジェクトのdropとか使い道は様々です。

1.と2.を合わせて使えば、調査に必要な統計情報特定し、CSV形式で出力することも可能です。
SQL> SELECT USERNAME||','||TERMINAL||','||PROGRAM||','||EVENT FROM V$SESSION
  2  WHERE USERNAME IS NOT NULL;

USERNAME||','||TERMINAL||','||PROGRAM||','||EVENT
--------------------------------------------------------------------------------
SCOTT,SHIOSHIO,sqlplus.exe,enq: TX - row lock contention
SCOTT,SHIOSHIO,sqlplus.exe,SQL*Net message from client
SYS,SHIOSHIO,sqlplus.exe,SQL*Net message to client


3.同様の障害が再発生した際に対応できるようにしておきたい。
  後日同様の障害が発生しても、SQL文を生成出来るようにしておきたいですよね。
 作ったSQL文はsaveコマンドを使用してスクリプトとして保存しましょう。

SQL> SELECT 'alter system kill session '''||SID||','||SERIAL#||''';' FROM V$SESSION
  2  WHERE USERNAME='SCOTT';

作ったSQL文を保存します。

SQL> save create_kill_session.sql
file create_kill_session.sqlが作成されました。

SQL> edit create_kill_session.sql


編集例)
==============ここから


-- ローカルフォルダにSCOTTユーザセッションを破棄する ※編集により追記した行
-- kill_session.sqlを生成します。           ※編集により追記した行
-- @kill_session.sqlを実行することにより、           ※編集により追記した行
-- セッションを破棄します。              ※編集により追記した行

set pages 2000                                        ※編集により追記した行
set head off                                          ※編集により追記した行
set feedback off                                      ※編集により追記した行
set term off                                          ※編集により追記した行
set trimspool on                                      ※編集により追記した行
spool kill_session.sql                                ※編集により追記した行

SELECT 'alter system kill session '''||SID||','||SERIAL#||''';' FROM V$SESSION
WHERE USERNAME='SCOTT'
/

spool off                                           ※編集により追記した行
==============ここまで




以上、つらつら書いてきましたが、
他にも有用なSQL*Plusコマンドはありますし、上記setコマンドの内容を知りたい方は
「SQL*Plus®ユーザーズ・ガイドおよびリファレンス」を参照ください。
SQL> help index や help setも有用ですね。
SQL*Plusコマンドを活用したCSVデータ出力方法については、
@s4r_agentさんが初日に「csvってどうやって出力してますか?」というエントリを書いてますので、
併せて見てみてください。

最後に
明日の扉は Masashi_Matsushita さんです。よろしくお願いします。



o<(o'∀')ノ☆*:;;;:*☆Merry Christmas☆*:;;;:*☆ヽ('∀'o)>o

0 件のコメント:

コメントを投稿