このブログを検索

2011年8月22日月曜日

REDOログファイルのサイズ変更をする

REDOログファイルのサイズ変更の基本的な考え方は次の通りです。
・REDOログファイルのサイズ変更は不可
・変更は、新規追加(別ファイル)し、不要のものを削除する
・削除は、STATUS=ACTIVEだとできない
・削除は、内容がアーカイブREDOファイルとして出力されていないとできない
・OMF(Oracle Managed Files)を未使用の場合、物理削除も必要
・RACの場合、インスタンス単位でサイズや個数を変えることはできる

まず、REDOログファイルを確認します。
   THREAD#     GROUP#     MBYTES STATUS     MEMBER
---------- ---------- ---------- ---------- ------------------------------
         1          1       1024 INACTIVE   +DATA/redo/redo111.dbf
         1          1       1024 INACTIVE   +LOG/redo/redo112.dbf
         1          2       1024 ACTIVE     +DATA/redo/redo121.dbf
         1          2       1024 ACTIVE     +LOG/redo/redo122.dbf
         1          3       1024 CURRENT    +DATA/redo/redo131.dbf
         1          3       1024 CURRENT    +LOG/redo/redo132.dbf
         2          4       1024 INACTIVE   +LOG/redo/redo212.dbf
         2          4       1024 INACTIVE   +DATA/redo/redo211.dbf
         2          5       1024 ACTIVE     +LOG/redo/redo222.dbf
         2          5       1024 ACTIVE     +DATA/redo/redo221.dbf
         2          6       1024 CURRENT    +LOG/redo/redo232.dbf
         2          6       1024 CURRENT    +DATA/redo/redo231.dbf

次に、新規REDOログファイルを追加します。
ここでは、2ノードRACを想定し、1GB→2GBのサイズ変更を行います。
$ sqlplus sys as sysdba
SQL> ALTER DATABASE ADD LOGFILE THREAD 1 GROUP 7 ('+DATA/redo/redo141.dbf', '+LOG/redo/redo142.dbf') SIZE 2G;
SQL> ALTER DATABASE ADD LOGFILE THREAD 1 GROUP 8 ('+DATA/redo/redo151.dbf', '+LOG/redo/redo152.dbf') SIZE 2G;
SQL> ALTER DATABASE ADD LOGFILE THREAD 1 GROUP 9 ('+DATA/redo/redo161.dbf', '+LOG/redo/redo162.dbf') SIZE 2G;

SQL> ALTER DATABASE ADD LOGFILE THREAD 2 GROUP 10 ('+DATA/redo/redo241.dbf', '+LOG/redo/redo242.dbf') SIZE 2G;
SQL> ALTER DATABASE ADD LOGFILE THREAD 2 GROUP 11 ('+DATA/redo/redo251.dbf', '+LOG/redo/redo252.dbf') SIZE 2G;
SQL> ALTER DATABASE ADD LOGFILE THREAD 2 GROUP 12 ('+DATA/redo/redo261.dbf', '+LOG/redo/redo262.dbf') SIZE 2G;

追加したら、REDOログファイルを強制的にローテートし、追加したREDOログがCURRENTになるまで繰り返します。
REDOログファイルはノードごとにあるので各ノードで実行します。
[oracle@sssdb1 ~]$ sqlplus sys as sysdba
SQL> alter system switch logfile;

[oracle@sssdb1 ~]$ sqlplus sys as sysdba
SQL> alter system switch logfile;

削除したいREDOログファイルをINACTIVEにし、アーカイブREDOログファイルを出力します。
SQL> ALTER SYSTEM CHECKPOINT;

不要になったREDOログファイルを削除します。
SQL> ALTER DATABASE DROP LOGFILE GROUP 1;
SQL> ALTER DATABASE DROP LOGFILE GROUP 2;
SQL> ALTER DATABASE DROP LOGFILE GROUP 3;

SQL> ALTER DATABASE DROP LOGFILE GROUP 4;
SQL> ALTER DATABASE DROP LOGFILE GROUP 5;
SQL> ALTER DATABASE DROP LOGFILE GROUP 6;

OMF(Oracle Managed Files)を利用していない場合、物理ファイルの削除をします。
この例では、ASMのファイルを削除します。
$ export ORACLE_SID=+sss011
$ asmcmd
ASMCMD> cd DATA/REDO
ASMCMD> rm REDO111.DBF
ASMCMD> rm REDO122.DBF
ASMCMD> rm REDO133.DBF
ASMCMD> rm REDO211.DBF
ASMCMD> rm REDO222.DBF
ASMCMD> rm REDO233.DBF

ASMCMD> cd ../../LOG/REDO
ASMCMD> rm REDO112.DBF
ASMCMD> rm REDO122.DBF
ASMCMD> rm REDO132.DBF
ASMCMD> rm REDO212.DBF
ASMCMD> rm REDO222.DBF
ASMCMD> rm REDO233.DBF

REDOログファイルを一覧表示する

REDOログファイルを一覧表示します。
set pages 10000
set lines 120
COL MEMBER FORMAT A30
COL STATUS FORMAT A10
SELECT LOG.THREAD#,LOG.GROUP#,
    LOG.BYTES/1024/1024 AS MBYTES,
    LOG.STATUS,LOG.ARCHIVED,LOGFILE.MEMBER 
 FROM   V$LOG LOG,V$LOGFILE LOGFILE
 WHERE LOG.GROUP# = LOGFILE.GROUP#
 ORDER BY THREAD#,GROUP#;
実行結果は次の通りです。
この例では2ノードRAC、3グループ、各1GBです。

STATUS=CURRECTが現在使用中のREDOログファイルです。
ACTIVEが使ったことがあるがアーカイブされていないもの、INACTIVEはアーカイブ済のものです。
UNUSEDはREDOログファイル追加後などまったく未使用のものです。

THREAD#     GROUP#     MBYTES STATUS     MEMBER
---------- ---------- ---------- ---------- ------------------------------
         1          1       1024 INACTIVE   +DATA/redo/redo111.dbf
         1          1       1024 INACTIVE   +LOG/redo/redo112.dbf
         1          2       1024 ACTIVE     +DATA/redo/redo121.dbf
         1          2       1024 ACTIVE     +LOG/redo/redo122.dbf
         1          3       1024 CURRENT    +DATA/redo/redo131.dbf
         1          3       1024 CURRENT    +LOG/redo/redo132.dbf
         2          4       1024 INACTIVE   +LOG/redo/redo212.dbf
         2          4       1024 INACTIVE   +DATA/redo/redo211.dbf
         2          5       1024 ACTIVE     +LOG/redo/redo222.dbf
         2          5       1024 ACTIVE     +DATA/redo/redo221.dbf
         2          6       1024 CURRENT    +LOG/redo/redo232.dbf
         2          6       1024 CURRENT    +DATA/redo/redo231.dbf

2011年7月1日金曜日

スワップしづらいようにRMANバックアップをする

担当案件では、RMAN→tar→圧縮→2GBファイル分割という手順でバックアップファイルを作成していました。
ですが、tarと圧縮にてOSのファイルキャッシュを大量に消費するため、スワップの発生が問題になっていました。

というのは、DBサーバのメモリのほとんどをSGAおよびOracleプロセスに割り当てていたためです。
ファイル操作用のOSファイルキャッシュが不足してスワップ→さらに負荷上昇という悪循環でした。

そこで、OSファイルキャッシュが効かないように、RAWデバイス側で圧縮およびファイル分割まですることにしました。
ファイル分割が終わるまでの時間は長くなりましたが、スワップは発生しなくなりました。

ここでは、バックアップセットを圧縮し、バックアップピースの最大サイズを2GBに制限する設定をします。
分割ファイル名が重複しないよう、formatでピース番号を指定するよう注意してください。
CONFIGURE DEFAULT DEVICE TYPE TO DISK;
CONFIGURE DEVICE TYPE DISK BACKUP TYPE TO COMPRESSED BACKUPSET;
CONFIGURE CHANNEL DEVICE TYPE DISK MAXPIECESIZE 2G;

backup database format
  '${BKUPDIR}/%d_database_full_%T_%s_%p.bkp'
  tag = 'full_database_backup';

出力したファイルは次のようになります。
-rw-r--r-- 1 backup backup 2.0G  6月 27 07:27 201106/s01db3/S01_database_full_20110627_4730_1.bkp
-rw-r--r-- 1 backup backup 2.0G  6月 27 07:33 201106/s01db3/S01_database_full_20110627_4730_2.bkp
-rw-r--r-- 1 backup backup 2.0G  6月 27 07:40 201106/s01db3/S01_database_full_20110627_4730_3.bkp
-rw-r--r-- 1 backup backup 139M  6月 27 07:41 201106/s01db3/S01_database_full_20110627_4730_4.bkp
-rw-r--r-- 1 backup backup 2.0G  6月 27 07:47 201106/s01db3/S01_database_full_20110627_4731_1.bkp
-rw-r--r-- 1 backup backup 2.0G  6月 27 07:52 201106/s01db3/S01_database_full_20110627_4731_2.bkp
-rw-r--r-- 1 backup backup 2.0G  6月 27 07:58 201106/s01db3/S01_database_full_20110627_4731_3.bkp
-rw-r--r-- 1 backup backup 470M  6月 27 08:01 201106/s01db3/S01_database_full_20110627_4731_4.bkp
-rw-r--r-- 1 backup backup 1.4M  6月 27 08:01 201106/s01db3/S01_database_full_20110627_4732_1.bkp

共有プールをクリアする

共有プールをインスタンス単位でクリアすることができます。
ただし、キャッシュヒット率が激減し、一時的にパフォーマンスダウンが予想されるのでタイミングに注意。
RACの場合は、一度に全ノードクリアするのではなく、クリア後ある程度キャッシュがたまってきてからの方がベターです。

共有プールのサイズが大きすぎるとエージアウトした際のロック(ラッチ)の時間が長くなり、DBサーバの応答が遅くなります。
この例のようにsql area(SQL数)が多いことが根本原因なのでアプリを直すべきですが、障害対応として紹介します。
(とはいえ、リスクの方が大きいので僕はめったにクリアしません)
共有プールのラッチは、CPU使用率もI/O負荷も上昇しないので検知しづらく潜在リスクは非常に高いと思っています。

まず、現状の共有プールの状況を確認します。
set pages 10000
set lines 120
set time on
col name for a40
select * from (
 select name, bytes from v$sgastat
 where pool = 'shared pool'
 order by bytes desc
) where rownum <= 20;
例えば、次のようにsql areaが3.5GBほどあるインスタンスをクリアすることにします。
NAME                                          BYTES
---------------------------------------- ----------
sql area                                 3690078544
free memory                               957169136
PCursor                                   637214224
CCursor                                   623044928
library cache                             499544096
sql area:PLSQL                            268971096
gcs resources                             233915744
gcs shadows                               140065792
kglsim object batch                       137342016
db_block_hash_buckets                      94371840
kglsim heap                                82446336
Cursor Stats                               64968688
ASH buffers                                30408704
transaction                                19464072
ges enqueues                               18813632
trace buffer                               16891904
ges big msg buffers                        15936168
KCL name table                             12582912
event statistics per sess                  12296000
FileOpenBlock                              11575096
共有プールのクリアはインスタンスごとにalter systemします。
$ sqlplus sys as sysdba
SQL> alter system flush shared_pool;
次のようにsql areaが消え、free memoryが増加します。
NAME                                          BYTES
---------------------------------------- ----------
free memory                              6376176928
gcs resources                             233915744
kglsim object batch                       191237088
library cache                             152614448
gcs shadows                               140065792
kglsim heap                               108622080
db_block_hash_buckets                      94371840
Cursor Stats                               85479368
sql area                                   44653328
ASH buffers                                30408704
transaction                                19490568
ges enqueues                               18813632
trace buffer                               16891904
ges big msg buffers                        15936168
KCL name table                             12582912
event statistics per sess                  12296000
FileOpenBlock                              11575096
CCursor                                    11276472
ges resource                               11221136

2011年6月15日水曜日

Oracle SCN(System Commit Number)を調べる

Oracleは、SCN(System Commit Number)という内部的なタイムスタンプによりデータの整合性をとっています。
バックアップデータを時間指定してリカバリする際に使うことがあります。

current_scnは今現在、checkpoint_change#はcheckpoin済みのSCNです。
col current_scn for 999999999999999
col checkpoint_change# for 999999999999999
select current_scn,checkpoint_change# from v$database;
実行結果は次の通りです。
     CURRENT_SCN CHECKPOINT_CHANGE#
---------------- ------------------
     35521648642        33022114382
いつのSCNでリカバリすればいいかわからない場合、日時からあたりをつけることができます。
timestamp_to_scn関数で概算SCNを求められます。
col SCN for 999999999999999
select timestamp_to_scn(to_date('2011/06/15 12:00:00','yyyy/mm/dd hh24:mi:ss')) as SCN
from dual;
実行結果は次の通りです。
             SCN
----------------
     33021237709

マテビューのマスタ側テーブルの更新時刻を調べる

マテビューで簡易レプリケーションしている場合、マスタ側かレプリケーション側か問題を切り分ける時に使います。
マスタ側にてスナップショットを取得した時刻を表示します。
この時刻が更新されてもレプリケーション側に反映されない場合、次の問題が考えられます。
・ネットワーク
・DBリンク(サーバ間マテビューの場合)
・レプリケーション側のリフレッシュグループが止まっている
など
slog$はSYS権限が要るので注意が必要です。
set pages 10000
set lines 110
col mowner for a15
col master for a30
alter session set nls_date_format='yyyy/mm/dd hh24:mi:ss';
select mowner, master, snaptime from slog$
 where master='M01_PCCOMMONUSER' and mowner='M01XXXUSER'
 order by snaptime;
実行結果は次の通りです。
MOWNER          MASTER                         SNAPTIME
--------------- ------------------------------ -------------------
M01XXXUSER      M01_PCCOMMONUSER               2011/06/15 14:17:47

INVALIDオブジェクトを探す

INVALIDになっているオブジェクトを探します。
パッチ(PSUなど)を当てた時はdba_objectsを調べるかと思います。
僕はスキーマ単位で作業することが多いのでuser_objectsをよく使います。
set pages 10000
set lines 110
col object_name for a30
col status for a10
alter session set nls_date_format='yyyy/mm/dd hh24:mi:ss';
select object_name, status, object_type, created, last_ddl_time, temporary
from dba_objects
where status='INVALID'
order by object_name;
実行結果は次の通りです。
OBJECT_NAME        STATUS     OBJECT_TYPE   CREATED             LAST_DDL_TIME       T
------------------ ---------- ------------- ------------------- ------------------- -
LOGIC_ITOTEST      INVALID    PROCEDURE     2009/11/13 14:47:16 2009/12/30 18:55:32 N
STATSPACK          INVALID    SYNONYM       2009/12/14 11:48:27 2010/07/30 22:13:47 N
VIEW_EXPIRATION4   INVALID    VIEW          2010/05/17 17:15:14 2010/12/16 16:16:43 N

ASMディスクグループの容量や使用率を調べる

v$asm_diskgroupでディスクグループの情報を得られます。
RATIOが一定量を超えないように監視スクリプトを作成しています。
set pages 10000
set linesize 100
col name format a20
col total_mb for 999,999,999
col free_mb for 999,999,999
col ratio for 999.99
col state for a10
select group_number, name, total_mb, free_mb,
  round(((total_mb-free_mb)/total_mb)*100 ,2) as ratio,
  state
from v$asm_diskgroup;
実行結果は次の通り。
GROUP_NUMBER NAME                     TOTAL_MB      FREE_MB   RATIO STATE
------------ -------------------- ------------ ------------ ------- -----------
           1 DATA                      708,468      500,535   29.35 CONNECTED
           2 LOG                       493,804      481,292    2.53 CONNECTED

2011年6月14日火曜日

表領域にオブジェクトが残っているか調べる

使っていない表領域のはずなのに何かが残ってる・・・というときの調査です。
セグメントのサイズを確認するの応用です。

Oracleは、スキーマのデフォルト表領域とは別の表領域にオブジェクトを作成することができます。
そのため、うっかりミス等でこういうことが起こりえます。

dba_segmentsを表領域で検索し、スキーマ(OWNER)およびセグメント名を表示します。
set pages 10000
set lines 100
col owner for a30
col segment_name for a30
col type for a10
select owner,segment_name,segment_type as type from dba_segments
where tablespace_name='SSS01_S_DATA'
order by owner,segment_name;

実行例は次の通りです。
一番下のTESTUSERは、テスト用スキーマなのですが、誤ってこの表領域に作られてしまっています。
(人名や日付がついていたり酷いですね・・・)
OWNER                          SEGMENT_NAME                   TYPE
------------------------------ ------------------------------ ----------
SSS01D01USER                   BAK_FILE2_20101220             TABLE
SSS01D01USER                   M01_BATCHSTATE                 TABLE
SSS01D01USER                   SYS_C00157262                  INDEX
SSS01D01USER                   T01_FILEACCESSBATCH2_M         TABLE
SSS01D01USER                   T01_MAGICAPPITEM2_KEN          TABLE
SSS01D01USER                   T01_MAGIC_APPITEM_LIMIT2_KEN   TABLE
TESTUSER                       TEMP_USERLIST                  TABLE

シングルDBでサービスを追加する

Oracle RACではサービスという論理的な接続先を作ることにより、ノードごとに負荷特性の分離をすることができます。
例えば、APPサービスでWebサイトの処理、BATCHサービスで夜間バッチの処理、などです。
※物理的なノードとはレイヤが少し違います。

シングルDBでもサービスを追加することができます。
用途としては次のようなことが考えられますが、たぶん他にもあるでしょう。
(専用サーバ接続と共用サーバ接続を使い分けるとかできるんでしょうか)
・AWR(STATSPACKのようなもの)をサービスごとに分ける(EEなのでやったことありません)
・再インストールしたら、インスタンス名を間違えた

以前、やってしまったのが2番目。
サービス名は、デフォルトではインスタンス名を引き継ぎます。
そのため、サービス名が変わってしまったためクライアントから接続エラーが発生しました。
クライアント側は変更したくないとの要望があったため、サービス名を追加しました。

手順は次にようにします。

まずはサービス名を確認します。
SQL> show parameter service_name
NAME                                 TYPE        VALUE
------------------------------------ ----------- ------------------------------
service_names                        string      SSS01DB2

次に、サービス名を追加します。
今回は、間違えてしまったサービス名は残したまま、OODEVを追加します。
ALTER SYSTEM SET service_names='SSS01DB2','OODEV' SCOPE=BOTH;

追加されたかどうか確認します。
SQL> show parameter service_name

NAME                                 TYPE        VALUE
------------------------------------ ----------- ------------------------------
service_names                        string      SSS01DB2, OODEV


余談ですが、RACでのサービス追加コマンドsrvctl start serviceは、内部的にalter system setしているだけです。
(アラートログを見るとわかります)

LIKE句でアンダースコアをマッチングさせる

OracleのLIKE句では、'_'(アンダースコア)は任意の1文字でマッチングします。
アンダースコアそのものをマッチングしたい場合は、ESCAPE句を使います。

例として表領域のデータファイル情報を取得します。
SQL> set pages 10000
set lines 120
col tablespace_name for a20
col file_name for a50
col bytes for 999,999,999,999
select tablespace_name,file_name,bytes,status from DBA_DATA_FILES
where tablespace_name like 'SSS01+_S+_%' escape '+'
order by tablespace_name,file_name;
実行結果は次の通りです。
TABLESPACE_NAME   FILE_NAME                                      BYTES STATUS
----------------- ----------------------------------- ---------------- ---------
SSS01_S_DATA      +DATA/database/sss01_s_data_01.dbf     2,147,483,648 AVAILABLE
SSS01_S_DATA      +DATA/database/sss01_s_data_02.dbf     2,147,483,648 AVAILABLE
SSS01_S_IDX       +DATA/database/sss01_s_idx_01.dbf      1,589,641,216 AVAILABLE
SSS01_S_IDX       +DATA/database/sss01_s_idx_02.dbf      1,588,592,640 AVAILABLE
SSS01_S_IDX       +DATA/database/sss01_s_idx_03.dbf      1,073,741,824 AVAILABLE
SSS01_S_IDX       +DATA/database/sss01_s_idx_04.dbf      1,073,741,824 AVAILABLE

6行が選択されました。

2011年4月27日水曜日

Oracle RAC Standard Edition(SE)を使ってみて気づいたこと

※個人の感想に基づいています・・・

まずは、ストレージ共有型クラスタであること。
MySQL Clusterとは違い、データを1箇所に保管するストレージ共有型です。
ストレージの冗長化をストレージ側でしなければならないのが、最大の弱点だと思ってます。
代替ストレージ機を用意しておけばダウンタイムを減らせますが、ハードウェア交換が必要なので1時間単位のダウンは避けられません。
そもそもSEを買うような案件ではそこまで予算がありません。
EEはライセンスおよびサポート費用だけで価格がひと桁変わりますからね・・・。

スタンバイDBにレプリケーションしようにも、Enterprise Edition(EE)でなければできません。
増分バックアップやアーカイブREDOログファイルバックアップをするにしても、分単位でのバックアップは現実的ではないと思います


次、ライセンスのCPU制限
SE RACでは、物理CPUの最大数が4つまでです。ライセンス
いまどき1CPUのサーバはあまり使わないので、2CPUだとノードの最大数が2つまで。
これが何を意味するかというと、failoverが運任せになりうることです。

RACは、ノード間の通信可否結果を投票ディスクというファイルとして共有型ストレージに格納しています。
クラスタソフトウェアは、この投票ディスクを元に多数決で孤立=ネットワーク障害サーバを検知します。
ノードが2台だと多数決にならずどちらか一方をOS再起動します。
そのため、正常稼動しているノードを再起動してしまう可能性があります。

RACは3ノード以上で使うのがお薦めです。


最後に、商用であること。
SEだけの話ではありませんが、購入してみないとサポートを受けられない、購入してみないとどんな特性の製品かわからないことです。
SQL文の数が多すぎるとラッチ待機のせいでSGAを増やせば増やすほどパフォーマンスが落ちる、など買う前にはわからなかったことが多いです。


まとめると、EEでない限りOracle RACは使いたくないな、と。
今の案件、MySQLに移設したいなー。

2011年4月22日金曜日

ASMのファイルシステムを直接操作する

ASMにはASMのファイルシステムを操作するシェル、asmcmdが用意されています。
使い方はORACLE_SIDをASMにしてasmcmdを起動するだけ。
cdやlsだけでなくrmやduもあって非常に便利。
ASMCMD> help
       :
        commands:
        --------
        cd
        du
        find
        help
        ls
        lsct
        lsdg
        mkalias
        mkdir
        pwd
        rm
        rmalias
ASMディスクグループへディスクを追加するではSQLで確認していますが、容量確認だけであればasmcmdの方が楽です。
$ export ORACLE_SID=+sss01
$ asmcmd
ASMCMD> lsdg
State    Type    Rebal  Unbal  Sector  Block       AU  Total_MB  Free_MB  Req_mir_free_MB  Usable_file_MB  Offline_disks  Name
MOUNTED  EXTERN  N      N         512   4096  1048576    476843   334069                0          334069              0  DATA/
MOUNTED  EXTERN  N      N         512   4096  1048576    143055   130125                0          130125              0  LOG/

findも使えます。
要らないオンラインREDOログを削除する前の確認くらいにしか使いませんが。
ASMCMD> find -t ONLINELOG log redo1*.dbf  
+log/REDO/REDO1012.DBF
+log/REDO/REDO1022.DBF
+log/REDO/REDO1032.DBF
+log/REDO/REDO1042.DBF
+log/REDO/REDO1052.DBF
+log/REDO/REDO1062.DBF

2011年4月21日木曜日

ASMディスクグループへディスクを追加する

ASMはディスクグループという仮想的なディスクで管理しています。
それによりRAWデバイスの追加を容易にしています。

ここでは、データ領域用のディスクグループを拡張します。

まず、RAWデバイスを作成し、パーミッションを設定します。
この例ではDevice-Mapperを使っていますが説明は省きますが、環境によってはdmのパーミッション設定は要らないかもしれません。
# vi /etc/rc.d/rc.local
(下記追記)
chown oracle:oracle /dev/mapper/dm002
chmod 660 /dev/mapper/dm002

raw /dev/raw/raw9 /dev/mapper/dm002
chown oracle:oracle /dev/raw/raw9
chmod 660 /dev/raw/raw9

次に、パラメータasm_diskstringに追加したいRAWデバイス名が含まれているか確認します。
asm_diskstringは、アクセス許可するRAWデバイス名を記述します。
注意として、OracleインスタンスではなくASMインスタンスに接続する必要があります。
$ export ORACLE_SID=+sss01
$ sqlplus sys as sysdba
SQL> show parameter asm_diskstring

NAME                                 TYPE
------------------------------------ ---------------------------------
VALUE
------------------------------
asm_diskstring                       string
/dev/raw/raw[6-7]

raw9にはアクセスできない設定になっているので、ASMインスタンスの初期化パラメータファイルに追記します。
ASMを再起動すると、設定が有効になります。
asm_diskstring='/dev/raw/raw[6-7]'
        ↓
asm_diskstring='/dev/raw/raw[6-9]'

ASMからRAWデバイスにアクセスできるようになりました。
次のように追加したいディスクグループを確認します。
GNAMEがディスクグループ名、DNAMEが各RAWデバイスにつけられた論理ディスク名です。
$ export ORACLE_SID=+sss01
$ sqlplus sys as sysdba
SQL>
column GNAME FORMAT a15
column DNAME FORMAT a15
select g.name as gname,d.name as dname
 from v$asm_disk d,v$asm_diskgroup g
 where d.group_number=g.group_number order by g.name,d.name

GNAME           DNAME
--------------- ---------------
DATA            DATA_DG1
DATA            DATA_DG2
LOG             LOG_DG1
LOG             LOG_DG2

ディスクグループへの追加は次の通りです。
$ export ORACLE_SID=+sss01
$ sqlplus sys as sysdba
SQL> ALTER DISKGROUP DATA ADD DISK '/dev/raw/raw9' NAME DATA_DG3


GNAME           DNAME
--------------- ---------------
DATA            DATA_DG1
DATA            DATA_DG2
DATA            DATA_DG3
LOG             LOG_DG1
LOG             LOG_DG2

2011年4月10日日曜日

権限付与の特徴

Oracleの権限付与には、次の特徴があります。
・システム権限とオブジェクト権限の2種類ある
・ロールにロールを付与することもできる
・権限付与だけでなくcreate user等で表領域割り当て(quota)が必要
・UNLIMITED TABLESPACEはシステム表領域を操作できてしまう
・grant文はロールと権限を混在して記述できない
・ストアド内部ではロールの権限は無視される

まず1つ目。
・システム権限とオブジェクト権限の2種類ある
MySQLでいう、グローバルレベルとテーブルレベルのようなものです。
インスタンス全体の権限と、オブジェクト(テーブル、ビュー、パッケージ、ストアド等)の権限です。
テーブルもパッケージもすべて「オブジェクトの1種」という、Oracleの特徴的な考え方がよく表れていると思います。

次、ロールの再帰的付与が可能です。
・ロールにロールを付与することもできる
例を挙げると、IMP_FULL_DATABASEロールはSELECT_CATALOG_ROLEロールを付与しています。

次はquota。
・ロールにロールを付与することもできる
スキーマの表領域へのアクセス制限を確認するにあるように、権限とその対象は別々の設定なので注意が必要です。

次は特徴というより注意です。
・UNLIMITED TABLESPACEはシステム表領域を操作できてしまう
UNLIMITED TABLESPACEはquota設定を無視するのでできるだけ付与しないほうが安全かと思います。

その次もGRANT設定上の注意です。
・grant文はロールと権限を混在して記述できない
理由はわからないのですが、カンマ区切りで同時に付与しようとするとエラーになるようです。

最後に、一番ハマりやすい特徴です。
・ストアド内部ではロールの権限は無視される
この仕様のせいで、せっかくロールで管理したい権限をスキーマに対していちいち付与しなくてはならないです。
みなさんはどういう管理してるんでしょうかね・・・。
Webフロント用のスキーマ、バッチ用スキーマと使い分けてるんでしょうか。

UNDO表領域の縮小

UNDO表領域は 縮小できない場合があります。
UNDO表領域を拡張するデータファイルのサイズを縮小するで触れている通り、断片化しやすい表領域のためです。
自動拡張してしまった場合は、特に断片化が進んでいて縮小できないことが多いです。

また、UNDO表領域は削除することもできません。
そこで、縮小は、一時的に作ったUNDO表領域に切り替えてから古いものを再作成する必要があります。

まずは、今の表領域を確認します。
容量は、表領域の使用状況で確認します。
この例だと、32GBいっぱいまで自動拡張してますね・・・。
SQL> show parameter undo_tablespace
NAME                                 TYPE
------------------------------------ ---------------------------------
VALUE
------------------------------
undo_tablespace                      string
UNDOTBS1

TABLESPACE_NAME             SIZEMB   USEDMB   FREEMB   RATIO AUTO
------------------------- -------- -------- -------- ------- ----
UNDOTBS1                    32,749       80   32,669     .25 YES

次に、一時的なUNDO表領域を作成し、切り替えます。
SQL> create undo tablespace UNDOTMP datafile '/DATA/DATABASE/UNDOTMP1.DBF' size 1G AUTOEXTEND ON;
SQL> alter system set undo_tablespace='UNDOTMP' sid='sss01dev';

SQL> show parameter undo_tablespace
NAME                                 TYPE
------------------------------------ ---------------------------------
VALUE
------------------------------
undo_tablespace                      string
UNDOTMP

切り替え後の、サイズの大きいUNDO表領域は再作成します。
SQL> drop tablespace UNDOTBS1 including contents and datafiles;
SQL> create undo tablespace UNDOTBS1 datafile '/DATA/DATABASE/UNDOTBS101.DBF' size 4G;

最後に、再作成したUNDO表領域に切り戻します。
SQL> alter system set undo_tablespace='UNDOTBS1' sid='sss01dev';

SQL> show parameter undo_tablespace
NAME                                 TYPE
------------------------------------ ---------------------------------
VALUE
------------------------------
undo_tablespace                      string
UNDOTBS1

SQL> drop tablespace UNDOTMP including contents and datafiles;

2011年4月5日火曜日

SQLをトレースしTKPROFで整形する

EXPLAINで実行計画がわかりますが、バインド変数を使ったSQLの場合はデータ(レコード)を特定できないため、正確な実行計画が得られません。
ここでは実際に実行したSQLをトレースをすることにより実行計画を取得します。

次のように、トレースをONにして実行します。
var vcarrier number
var vleader number
exec :vcarrier := 2
exec :vleader := 2
alter session set timed_statistics=true;
alter session set events '10046 trace name context forever, level 12';

SELECT
    *
FROM
    (SELECT
        rank() over (ORDER BY tt.regist_dt DESC) as rn,
        tt.team_nm AS team_nm ,
        tt.member_cnt AS member_cnt ,
        tt.team_status_id AS team_status_id ,
        tt.pr_comment AS pr_comment ,
        tt.team_id AS team_id ,
        tm.user_id AS user_id ,
        tt.regist_dt AS regist_dt ,
        wearing_avatar_kind,
        avatar_id,
        gender,
        avatar_session
    FROM
        T01_Test2 tt ,
        T01_TestMember2 tm ,
        T01_UserMyTest2 my
    WHERE
        tt.carrier_id = :vcarrier     AND
        tm.user_id = my.user_id     AND
        tt.team_id = tm.team_id     AND
        tm.leader_flg = :vleader
    ORDER BY
        tt.regist_dt DESC
    )
WHERE
    rn BETWEEN 1 AND
    30;

alter session set events '10046 trace name context off';
alter session set timed_statistics=false;
EVENT 10046のレベルは4種類あります。
level  1   alter session set sql_trace=trueと同じ
level  4   level 1にバインド変数情報
level  8   level 1に待機イベント情報
level 12   level 4 + level 8
実行後、DBサーバにトレースファイルが出力されています。
そのトレースファイルそのままだと読みづらいので、TKPROFというツールで整形します。
$ ls -tlr /opt/app/oracle/admin/sss01dev/udump/ | tail -1
$ sudo scp /opt/app/oracle/admin/sss01dev/udump/sss01dev_ora_21243.trc snwdev1:/home/ito/tmp/
$ tkprof sss01dev_ora_21243.trc test.trc
ただし、TKPROFはバインド情報を無視するので必要であればトレースファイルを直接確認します。
$ grep -A4 "^ Bind" sss01dev_ora_21243.trc 
 Bind#0
  oacdty=02 mxl=22(22) mxlc=00 mal=00 scl=00 pre=00
  oacflg=03 fl2=1000000 frm=00 csi=00 siz=48 off=0
  kxsbbbfp=2b818341b4c0  bln=22  avl=02  flg=05
  value=2
 Bind#1
  oacdty=02 mxl=22(22) mxlc=00 mal=00 scl=00 pre=00
  oacflg=03 fl2=1000000 frm=00 csi=00 siz=0 off=24
  kxsbbbfp=2b818341b4d8  bln=22  avl=02  flg=01
  value=2
整形したファイル例は次の通りです。
TKPROF: Release 10.2.0.4.0 - Production on 火 4月 5 11:25:10 2011

Copyright (c) 1982, 2007, Oracle.  All rights reserved.

Trace file: sss01dev_ora_29755.trc
Sort options: default

********************************************************************************
count    = number of times OCI procedure was executed
cpu      = cpu time in seconds executing 
elapsed  = elapsed time in seconds executing
disk     = number of physical reads of buffers from disk
query    = number of buffers gotten for consistent read
current  = number of buffers gotten in current mode (usually for update)
rows     = number of rows processed by the fetch or execute call
********************************************************************************

SELECT
    *
FROM
    (SELECT
        rank() over (ORDER BY tt.regist_dt DESC) as rn,
        tt.team_nm AS team_nm ,
        tt.member_cnt AS member_cnt ,
        tt.team_status_id AS team_status_id ,
        tt.pr_comment AS pr_comment ,
        tt.team_id AS team_id ,
        tm.user_id AS user_id ,
        tt.regist_dt AS regist_dt ,
        wearing_avatar_kind,
        avatar_id,
        gender,
        avatar_session
    FROM
        T01_Team2 tt ,
        T01_TeamMember2 tm ,
        T01_UserMyRoom2 my
    WHERE
        tt.carrier_id = :vcarrier     AND
        tm.user_id = my.user_id     AND
        tt.team_id = tm.team_id     AND
        tm.leader_flg = :vleader
    ORDER BY
        tt.regist_dt DESC
    )
WHERE
    rn BETWEEN 1 AND
    30

call     count       cpu    elapsed       disk      query    current        rows
------- ------  -------- ---------- ---------- ---------- ----------  ----------
Parse        1      0.00       0.00          0          0          0           0
Execute      1      0.00       0.00          0          0          0           0
Fetch       31      0.14       0.14          0       6097          0          30
------- ------  -------- ---------- ---------- ---------- ----------  ----------
total       33      0.14       0.14          0       6097          0          30

Misses in library cache during parse: 0
Optimizer mode: ALL_ROWS
Parsing user id: 113  

Rows     Row Source Operation
-------  ---------------------------------------------------
     30  VIEW  (cr=6097 pr=0 pw=0 time=140143 us)
   1153   WINDOW SORT PUSHED RANK (cr=6097 pr=0 pw=0 time=141286 us)
   1153    HASH JOIN  (cr=6097 pr=0 pw=0 time=129360 us)
   1164     TABLE ACCESS FULL T01_TEAM2 (cr=227 pr=0 pw=0 time=166 us)
   1153     HASH JOIN  (cr=5870 pr=0 pw=0 time=123033 us)
   1153      TABLE ACCESS FULL T01_TEAMMEMBER2 (cr=253 pr=0 pw=0 time=4643 us)
  86413      TABLE ACCESS FULL T01_USERMYROOM2 (cr=5617 pr=0 pw=0 time=86469 us)


Elapsed times include waiting on following events:
  Event waited on                             Times   Max. Wait  Total Waited
  ----------------------------------------   Waited  ----------  ------------
  SQL*Net message to client                      32        0.00          0.00
  SQL*Net message from client                    32        0.00          0.02



********************************************************************************

OVERALL TOTALS FOR ALL NON-RECURSIVE STATEMENTS

call     count       cpu    elapsed       disk      query    current        rows
------- ------  -------- ---------- ---------- ---------- ----------  ----------
Parse        1      0.00       0.00          0          0          0           0
Execute      1      0.00       0.00          0          0          0           0
Fetch       31      0.14       0.14          0       6097          0          30
------- ------  -------- ---------- ---------- ---------- ----------  ----------
total       33      0.14       0.14          0       6097          0          30

Misses in library cache during parse: 0

Elapsed times include waiting on following events:
  Event waited on                             Times   Max. Wait  Total Waited
  ----------------------------------------   Waited  ----------  ------------
  SQL*Net message to client                      79        0.00          0.00
  SQL*Net message from client                    79       15.53         23.49


OVERALL TOTALS FOR ALL RECURSIVE STATEMENTS

call     count       cpu    elapsed       disk      query    current        rows
------- ------  -------- ---------- ---------- ---------- ----------  ----------
Parse        0      0.00       0.00          0          0          0           0
Execute      0      0.00       0.00          0          0          0           0
Fetch        0      0.00       0.00          0          0          0           0
------- ------  -------- ---------- ---------- ---------- ----------  ----------
total        0      0.00       0.00          0          0          0           0

Misses in library cache during parse: 0

    1  user  SQL statements in session.
    0  internal SQL statements in session.
    1  SQL statements in session.
********************************************************************************
Trace file: sss01dev_ora_29755.trc
Trace file compatibility: 10.01.00
Sort options: default

       1  session in tracefile.
       1  user  SQL statements in trace file.
       0  internal SQL statements in trace file.
       1  SQL statements in trace file.
       1  unique SQL statements in trace file.
     263  lines in trace file.
       0  elapsed seconds in trace file.

2011年4月4日月曜日

RACのサービス名一覧フル表示する

RACのサービス状況は、crs_statというコマンドで表示することが出来ます。
オプション-tでサマリ一覧表示ができますが、長い文字列は途中で切れてしまいます。

そこで、パイプなどを使ってサービス名をフル表示することができます。
$ crs_stat | awk '{print $1 "="  $4; }' RS="" FS="\n" | awk '{ printf "%-50s%s\n",$2,$4}' FS="="
ora.sss01.SSS01DBBATCH.cs                         ONLINE on sssdb1
ora.sss01.SSS01DBBATCH.sss011.srv                 ONLINE on sssdb1
ora.sss01.SSS01DBBATCH.sss012.srv                 ONLINE on sssdb2
ora.sss01.SSS01DBBATCH1.cs                        ONLINE on sssdb1
ora.sss01.SSS01DBBATCH1.sss011.srv                ONLINE on sssdb1
ora.sss01.SSS01DBBATCH2.cs                        ONLINE on sssdb2
ora.sss01.SSS01DBBATCH2.sss012.srv                ONLINE on sssdb2
ora.sss01.SSS01DBE.cs                             ONLINE on sssdb1
ora.sss01.SSS01DBE.sss011.srv                     ONLINE on sssdb1
ora.sss01.SSS01DBE.sss012.srv                     ONLINE on sssdb2
ora.sss01.SSS01DBI.cs                             ONLINE on sssdb1

2011年4月3日日曜日

マテリアライズドビューの自動同期を設定する

マテリアライズドビューの自動同期は、リフレッシュグループというジョブに対象テーブルを登録することにより実行されます。
自動同期は、1テーブルでも同期に失敗したら、リフレッシュグループまるごと同期がストップすることが特徴です。
そのため、スキーマ単位でリフレッシュグループを作るか、クリティカルな業務テーブルをひとまとめにするといいと思います。

次のように作成します。
ここでは1分インターバルのリフレッシュグループにします。
BEGIN
 DBMS_REFRESH.MAKE (
 name => 'SSS01DBEUSER.REFRESH_E',
 list => '',
 next_date => sysdate,
 interval => 'sysdate + 1/24/60*1440',
 implicit_destroy => FALSE,
 rollback_seg => '',
 push_deferred_rpc => TRUE,
 refresh_after_errors => FALSE);
END;
/
削除は次のようにします。
BEGIN
 DBMS_REFRESH.DESTROY (
 name => 'SSS01DBEUSER.REFRESH_E');
END;
/

シーケンスキャッシュのサイズを変更する

STATSPACKや待機しているセッションを調べるでenq: SQ - contentionが目立つ場合、シーケンスキャッシュが不足している場合があります。

担当案件にてユーザプロセスが急増したことがありますが、その際、ユーザプロセスのIDキャッシュサイズが小さいためにenq: SQ - contentionが多発しました。
(そもそもの原因はアプリケーションでしたが、急場しのぎのために設定変更しました)

今回の例では、ユーザプロセスのID発行に関わるキャッシュのサイズを大きくします。
ただし、これは諸刃の剣なので十分注意してください。
理由は、キャッシュサイズが大きくなるということは、キャッシュを使いきってリフレッシュする時のロック時間が長くなるということです。

まず、現在の設定値CACHE_SIZEを確認します。
set pages 10000
set lines 120
col SEQUENCE_OWNER for a15
col SEQUENCE_NAME for a15
select * from dba_sequences where sequence_name in ('AUDSES$','IDGEN1$');

SEQUENCE_OWNER  SEQUENCE_NAME    MIN_VALUE  MAX_VALUE INCREMENT_BY CYC ORD CACHE_SIZE LAST_NUMBER
--------------- --------------- ---------- ---------- ------------ --- --- ---------- -----------
SYS             IDGEN1$                  1 1.0000E+27           50 N   N         2000  3.9574E+10
SYS             AUDSES$                  1 2000000000            1 Y   N         2000  1448207982
次のように値を10倍にします。
SQL> ALTER SEQUENCE SYS.AUDSES$ CACHE 20000;
SQL> ALTER SEQUENCE SYS.IDGEN1$ CACHE 20000;

sqlplusのログインプロンプトを変更する

開発や本番など、サーバが増えてくると怖いのがログインミス。
そこで、ログインプロンプトを弄ってみました。

まず、環境変数SQLPATHで設定ファイルを指定します。
ここでは、Linuxアカウントのホームディレクトリにします。
$ grep SQLPATH .bashrc
export SQLPATH=~
sqlplusは、ログインした時にlogin.sqlを実行するので、次のように記述します。
ここでは、ログインユーザ、インスタンス名、時刻を表示します。
$ cat login.sql 
set time on
set pages 10000
set lines 120
column sid0 new_value sid1
column user new_value uid1
select user from dual;
select rtrim(instance_name,chr(0)) sid0 from v$instance;
set sqlprompt '&uid1@&sid1>'
ログインするとこうなります。
最初にうつくしくないものが表示されるがきにしない。
(表示しない方法もありますがめんどうなので調べてません・・・)
$ sqlplus sss01dbiuser/sss01dbiorbital@SSS01DEV
USER
------------------------------
SSS01DBIUSER


SID0
--------------------------------------------------------------------------------
sss01dev

16:30:44 SSS01DBIUSER@sss01dev>

マテリアライズドビューの自動同期対象テーブルを探す

マテリアライズドビューの自動同期対象を探します。
自動同期のジョブは、リフレッシュグループにあるテーブルに対して実行します。
ジョブとリフレッシュグループの紐付けはマテリアライズドビューの同期エラーを解決するを参照。

リフレッシュグループのテーブル一覧は次の通り。
set pages 10000
set lines 120
column RNAME FORMAT a20
column NAME FORMAT a40
select r.job,r.rname,c.name,c.broken
 from DBA_REFRESH r, DBA_REFRESH_CHILDREN c
 where r.REFGROUP=c.REFGROUP
  and r.rowner='INDEP1USER'
実行例は、次の通り。
わかりにくいですが、BROKEN=Nであれば自動同期をします。
JOB RNAME                NAME                                     BRO
---------- -------------------- ---------------------------------------- ---
       118 REFRESH_INDEP1       TBL_CONSENTLOG1                          N
       118 REFRESH_INDEP1       TBL_EXPORTCONSENTLOG                     N
       118 REFRESH_INDEP1       TBL_MYROOMCOMMENT1                       N
       118 REFRESH_INDEP1       TBL_MYROOMCOMMENTCONSENT1                N
       118 REFRESH_INDEP1       TBL_USERMYROOMCOMMENT1                   N
       118 REFRESH_INDEP1       TBL_USERMYROOMCOMMENTCONSENT1            N

2011年3月25日金曜日

自動アナライズの実行時刻を変更する

Oracleは定期的にアナライズをすることにより、実行計画の精度を上げるのが基本です。
10gではGATHER_STATS_JOBという自動アナライズ機能がデフォルトでONになっています。
とはいえ、たびたびアナライズをするとパフォーマンスダウンにつながるため、 GATHER_STATS_JOBは次のオブジェクトに対して実施します。
統計情報を取得していないオブジェクト
統計情報が失効(レコードが10%が変更された)オブジェクト
私の担当Webサイトでは、ジョブスケジューリングの設定変更をしています。
というのは、デフォルト設定のままだと平日22時および土曜日0時にしか実行されないためです。
担当サイトの高負荷時間帯は毎日22~25時なので、負荷の低い毎日14時に実行しています。

まず、GATHER_STATS_JOBがMAINTENANCE_WINDOW_GROUPというジョブグループで動いていることを確認します。
col JOB_NAME for a30
col SCHEDULE_NAME for a40
select JOB_NAME ,SCHEDULE_NAME from DBA_SCHEDULER_JOBS;

JOB_NAME                       SCHEDULE_NAME
------------------------------ ----------------------------------------
AUTO_SPACE_ADVISOR_JOB         MAINTENANCE_WINDOW_GROUP
GATHER_STATS_JOB               MAINTENANCE_WINDOW_GROUP
FGR$AUTOPURGE_JOB
PURGE_LOG                      DAILY_PURGE_SCHEDULE
MGMT_STATS_CONFIG_JOB
MGMT_CONFIG_JOB                MAINTENANCE_WINDOW_GROUP
次に、MAINTENANCE_WINDOW_GROUPのスケジュール内容を確認します。
set pages 10000
set lines 120
col WINDOW_NAME for a20
col REPEAT_INTERVAL for a80
col DURATION for a30
select WINDOW_NAME ,REPEAT_INTERVAL ,DURATION from DBA_SCHEDULER_WINDOWS;

WINDOW_NAME          REPEAT_INTERVAL
-------------------- --------------------------------------------------------------------------------
DURATION
------------------------------
WEEKNIGHT_WINDOW     freq=daily;byday=MON,TUE,WED,THU,FRI;byhour=22;byminute=0; bysecond=0
+000 08:00:00

WEEKEND_WINDOW       freq=daily;byday=SAT,SUN;byhour=0;byminute=0;bysecond=0
+000 48:00:00
設定は次のようにします。
exec DBMS_SCHEDULER.SET_ATTRIBUTE('WEEKNIGHT_WINDOW','repeat_interval','freq=daily;byday=MON,TUE,WED,THU,FRI;byhour=15;byminute=0; bysecond=0');
exec DBMS_SCHEDULER.SET_ATTRIBUTE('WEEKNIGHT_WINDOW','duration','+000 05:00:00');

exec DBMS_SCHEDULER.SET_ATTRIBUTE('WEEKEND_WINDOW','repeat_interval','freq=daily;byday=SAT,SUN;byhour=15;byminute=0;bysecond=0');
exec DBMS_SCHEDULER.SET_ATTRIBUTE('WEEKEND_WINDOW','duration','+000 05:00:00');
実行されたかどうかは、スケジューラの履歴で確認できます。
なお、この例はRAC環境なのでインスタンス単位で表示されます。
set pages 10000
set lines 120
col job_name for a25
col status for a10
col START_DATE for a20
col END_DATE for a20
SELECT 
  TO_CHAR(ACTUAL_START_DATE, 'YYYY/MM/DD HH24:MI:SS') AS "START_DATE",
  TO_CHAR(LOG_DATE, 'YYYY/MM/DD HH24:MI:SS') AS "END_DATE",
  JOB_NAME,STATUS,INSTANCE_ID
 FROM DBA_SCHEDULER_JOB_RUN_DETAILS
 WHERE JOB_NAME in ('AUTO_SPACE_ADVISOR_JOB','GATHER_STATS_JOB')
 ORDER BY ACTUAL_START_DATE,JOB_NAME;

 START_DATE           END_DATE             JOB_NAME                  STATUS     INSTANCE_ID
-------------------- -------------------- ------------------------- ---------- -----------
2011/02/23 14:00:02  2011/02/23 14:05:19  AUTO_SPACE_ADVISOR_JOB    SUCCEEDED            2
2011/02/23 14:00:02  2011/02/23 14:09:55  GATHER_STATS_JOB          SUCCEEDED            2
2011/02/24 14:00:02  2011/02/24 14:05:39  AUTO_SPACE_ADVISOR_JOB    SUCCEEDED            2
2011/02/24 14:00:02  2011/02/24 14:10:30  GATHER_STATS_JOB          SUCCEEDED            2
2011/02/25 14:00:01  2011/02/25 14:11:04  GATHER_STATS_JOB          SUCCEEDED            1
2011/02/25 14:00:02  2011/02/25 14:05:38  AUTO_SPACE_ADVISOR_JOB    SUCCEEDED            2
2011/02/26 14:00:00  2011/02/26 14:09:39  GATHER_STATS_JOB          SUCCEEDED            1
2011/02/26 14:00:00  2011/02/26 14:05:40  AUTO_SPACE_ADVISOR_JOB    SUCCEEDED            1

2011年3月17日木曜日

実行計画(EXPLAIN)を取得する

クエリの実行計画を取得するには2ステップ必要です。
(1)explainしてその結果を保存する
(2)保存結果を表示する
まずexplainすると、その結果はPLAN_TABLEに保存されます。
SQL> explain plan for select user_id from T01_AQUA1_APPITEM_LIMIT1;

Explained.
結果は、標準スクリプトでテーブル内容を表示できます。
SQL> @?/rdbms/admin/utlxpls.sql

PLAN_TABLE_OUTPUT
----------------------------------------------------------------------------------------------
Plan hash value: 4246935464

----------------------------------------------------------------------------------------------
| Id  | Operation         | Name                     | Rows  | Bytes | Cost (%CPU)| Time     |
----------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |                          |  7421K|    42M|  9167   (2)| 00:01:50 |
|   1 |  TABLE ACCESS FULL| T01_AQUA1_APPITEM_LIMIT1 |  7421K|    42M|  9167   (2)| 00:01:50 |
----------------------------------------------------------------------------------------------
表関数がサポートされている9i(9iR2?)以上は、DBMS_XPLANパッケージでさらに詳細な情報を表示することもできます。
3つ目の引数を'ALL'にするとパラレルクエリやカラム情報も表示します。
SQ> SELECT PLAN_TABLE_OUTPUT FROM TABLE(DBMS_XPLAN.DISPLAY('plan_table',null,'all'));
PLAN_TABLE_OUTPUT
----------------------------------------------------------------------------------------------
Plan hash value: 4246935464

----------------------------------------------------------------------------------------------
| Id  | Operation         | Name                     | Rows  | Bytes | Cost (%CPU)| Time     |
----------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |                          |  7421K|    42M|  9167   (2)| 00:01:50 |
|   1 |  TABLE ACCESS FULL| T01_AQUA1_APPITEM_LIMIT1 |  7421K|    42M|  9167   (2)| 00:01:50 |
----------------------------------------------------------------------------------------------

Query Block Name / Object Alias (identified by operation id):
-------------------------------------------------------------

   1 - SEL$1 / T01_AQUA1_APPITEM_LIMIT1@SEL$1

Column Projection Information (identified by operation id):
-----------------------------------------------------------

   1 - "USER_ID"[NUMBER,22]

2011年3月10日木曜日

UNDO表領域を拡張する

表領域の自動拡張設定をしていれば自動的に拡張されますがパフォーマンスが落ちるので適度なサイズにした方がいいです。
注意として次の2つ。
・UNDO表領域のデータファイルは1つだけ
・UNDO表領域は縮小できない(ことが多い)
・UNDO表領域の最大サイズは32GB
まずデータファイル名を確認します。
set pages 10000
set lines 120
col NAME for a40
col bytes for 999,999,999,999
select file#, bytes, name from v$datafile where upper(name) like '%UNDO%';

     FILE#            BYTES NAME
---------- ---------------- ----------------------------------------
         2   11,188,305,920 /DATA/DATABASE/UNDOTBS101.DBF
サイズを拡張します。
ALTER DATABASE DATAFILE '/DATA/DATABASE/UNDOTBS101.DBF' RESIZE 16G;

2011年3月7日月曜日

オブジェクトの依存関係を確認する

ビューが参照しているテーブルをdropすると、そのビューはINVALIDになります。
Oracleはオブジェクト同士の依存関係を管理しているためです。
set pages 10000
set lines 120
col REFERENCED_NAME for a30
col TYPE for a20
col NAME for a30
select referenced_name,type,name from user_dependencies
where referenced_name in ('M01_DOWNLOADITEM','M01_MACHINE')
order by referenced_name,type,name;
実行結果は次の通り。
REFERENCED_NAMEが参照されているオブジェクト、NAMEが影響を受ける(INVALIDになりうる)オブジェクトです。
REFERENCED_NAME                TYPE                 NAME
------------------------------ -------------------- ------------------------------
M01_DOWNLOADITEM               FUNCTION             L_ITEMPUBLISHLOG
M01_DOWNLOADITEM               VIEW                 V_CATEGORYLIST
M01_MACHINE                    VIEW                 V_CATEGORYLIST

共有プールのサイズ変更履歴を確認する

例えばWebリクエストと分析系バッチなど、特性が違いすぎる処理を実行しているとします。
自動共有メモリ管理(ASMM)を使っている場合、Oracleは共有プールとデータベースバッファの最適化に迷ってしまうことがあります。
特性の異なる最適化を繰り返してしまうのは、本当の意味で最適化とは言えません。

メモリ(SGA)のリサイズ結果を判断の1つにすることができます。
set time on 
set pages 10000
set lines 120
col component for a25
col oper_type for a12
col parameter for a25
alter session set nls_date_format='yyyy/mm/dd hh24:mi:ss';
select component,oper_type,parameter,modsize,end_time from (
  select row_number() over (order by end_time desc) as rn,
    component,oper_type,parameter,(final_size-initial_size) as modsize,end_time
  from v$SGA_RESIZE_OPS
) where rn<=20;
実行結果は次の通り。 OPER_TYPEは増減(GROW/SHRINK)です。 頻度や量(MODSIZE)を確認するといいと思います。
COMPONENT                 OPER_TYPE    PARAMETER                    MODSIZE END_TIME
------------------------- ------------ ------------------------- ---------- -------------------
shared pool               SHRINK       shared_pool_size          -100663296 2011/03/05 04:14:31
DEFAULT buffer cache      GROW         db_cache_size              100663296 2011/03/05 04:14:31
shared pool               SHRINK       shared_pool_size          -100663296 2011/03/05 03:01:26
DEFAULT buffer cache      GROW         db_cache_size              100663296 2011/03/05 03:01:26
DEFAULT buffer cache      SHRINK       db_cache_size             -100663296 2011/03/04 18:57:11
shared pool               GROW         shared_pool_size           100663296 2011/03/04 18:57:11
shared pool               SHRINK       shared_pool_size          -100663296 2011/03/04 04:32:11
DEFAULT buffer cache      GROW         db_cache_size              100663296 2011/03/04 04:32:11
DEFAULT buffer cache      SHRINK       db_cache_size             -201326592 2011/03/03 16:12:45
shared pool               GROW         shared_pool_size           201326592 2011/03/03 16:12:45

REDOログスイッチの完了時刻を確認する

更新処理によりREDOログファイルがいっぱいになると、REDOログファイルはローテートされます
これをログスイッチと呼びます。
1時間に1度を目処に考えていますが、頻繁に発生するとパフォーマンスが落ちるのでチューニングが必要です。

ログスイッチのタイミングはアラートログから調べることができます。
$ grep -B1 "LGWR switch" $ORACLE_BASE/admin/sss01/bdump/alert_sss011.log | tail -1000 | grep "Mar  6"

Sun Mar  6 00:29:08 2011
Sun Mar  6 02:07:04 2011
Sun Mar  6 02:07:43 2011
Sun Mar  6 07:31:04 2011
Sun Mar  6 07:32:33 2011
Sun Mar  6 13:57:04 2011
Sun Mar  6 13:58:38 2011
Sun Mar  6 18:57:06 2011
Sun Mar  6 18:58:25 2011
ログスイッチはロックによる待機を最小限にするため、次の順に処理します。
1)REDOログファイルのローテート
2)古いREDOログファイルをアーカイブREDOログファイルとして書き出す(アーカイブログモード)
アーカイブログモードでログスイッチが高頻度すぎると、ディスクI/Oが発生してパフォーマンスが低下します。
アーカイブREDOログファイルへの書き出しが完了しないと、そのREDOファイルは次回REDOログとして利用できません。
最悪の場合、REDOログファイルのローテートが1周してもアーカイブREDOログファイルへの書き出しが完了しません。
そうなると、利用出来るREDOログがなくなるため、ローテート待ちでデータベースがロックします。

注意として、アラートログの時刻はローテートが完了した時刻です。
アーカイブREDOログの書き出し完了時刻もチェックするといいと思います。
set pages 10000
set lines 100
alter session set nls_date_format='yyyy/mm/dd hh24:mi:ss';
select SEQUENCE#,COMPLETION_TIME from (
  select row_number() over (order by COMPLETION_TIME desc) as rn,
    SEQUENCE#, COMPLETION_TIME from v$archived_log
) where rn<=10

 SEQUENCE# COMPLETION_TIME
---------- -------------------
      2750 2011/03/07 00:21:59
      2656 2011/03/06 18:58:26
      2749 2011/03/06 18:58:25
      2748 2011/03/06 18:58:24
      2655 2011/03/06 18:58:22
      2747 2011/03/06 13:58:39
      2654 2011/03/06 13:58:39
      2746 2011/03/06 13:58:36
      2653 2011/03/06 13:58:32
      2652 2011/03/06 07:32:34

2011年3月4日金曜日

システム権限とオブジェクト権限を確認する

Oracleにはシステム権限とオブジェクト権限の2種類あります。
権限をロールとしてひとまとめにすることもでき、ロールにロールを付与することもできます。
注意として、権限だけではデフォルト表領域以外は、スキーマの表領域へのアクセス制限を確認する設定が必要です。
また、grantはロールと権限を混在して記述できません。
もっとも注意しなければならないのは、ストアド内部ではロールの権限は無視されることです。

スキーマやロールに付与したシステム権限を確認します。
set pages 10000
set lines 100
col grantee for a20
col privilege for a30
select grantee,privilege from dba_sys_privs
where grantee='SSS01DBUSER'
order by grantee,privilege;

GRANTEE              PRIVILEGE
-------------------- ------------------------------
SSS01DBUSER          ALTER ANY TABLE
SSS01DBUSER          CREATE ANY INDEX
SSS01DBUSER          CREATE ANY MATERIALIZED VIEW
SSS01DBUSER          CREATE ANY PROCEDURE
SSS01DBUSER          CREATE ANY SEQUENCE
SSS01DBUSER          CREATE ANY TABLE
SSS01DBUSER          CREATE ANY TRIGGER
SSS01DBUSER          CREATE ANY VIEW
SSS01DBUSER          CREATE PROCEDURE
SSS01DBUSER          CREATE SEQUENCE
SSS01DBUSER          CREATE SESSION
SSS01DBUSER          CREATE TABLE
SSS01DBUSER          CREATE TRIGGER
SSS01DBUSER          DELETE ANY TABLE
SSS01DBUSER          DROP ANY INDEX
SSS01DBUSER          DROP ANY MATERIALIZED VIEW
SSS01DBUSER          DROP ANY PROCEDURE
SSS01DBUSER          DROP ANY SEQUENCE
SSS01DBUSER          DROP ANY TABLE
SSS01DBUSER          DROP ANY TRIGGER
SSS01DBUSER          DROP ANY VIEW
SSS01DBUSER          EXECUTE ANY PROCEDURE
SSS01DBUSER          GLOBAL QUERY REWRITE
SSS01DBUSER          INSERT ANY TABLE
SSS01DBUSER          RESUMABLE
SSS01DBUSER          SELECT ANY SEQUENCE
SSS01DBUSER          SELECT ANY TABLE
SSS01DBUSER          UPDATE ANY TABLE
スキーマやロールに付与したロールを確認します。
set pages 10000
set lines 100
col grantee for a20
col granted_role for a20
select grantee,granted_role from dba_role_privs
where grantee='SSS01DBUSER'
order by grantee,granted_role;

GRANTEE              GRANTED_ROLE
-------------------- --------------------
SSS01DBUSER          SSS01APP
SSS01DBUSER          CONNECT
スキーマやロールに付与したオブジェクト権限を確認します。
set pages 10000
set lines 100
col grantee for a20
col owner for a10
col table_name for a30
col privilege for a20
select grantee,owner,table_name,privilege from dba_tab_privs
where grantee like 'SSS01DBUSER'
order by grantee,table_name,privilege;

GRANTEE      OWNER      TABLE_NAME      PRIVILEGE
------------ ---------- --------------- -----------
SSS01DBUSER  SYS        DBMS_LOCK       EXECUTE
ログインしているスキーマのシステム権限を確認します。
set pages 10000
set lines 100
col privilege for a30
select privilege from user_sys_privs order by privilege;

2011年3月3日木曜日

データベースファイルのサイズを縮小する

NOMOUNT状態で作業します。
ただし、ASMはOPEN状態でできます。
縮小できるのは連続領域のみで、最後のBLOCK_ID以降が縮小可能領域です。
まずはデータファイル名を調べます。
$ sqlplus sys as sysdba
SQL> set pages 10000
set lines 120
col tablespace_name for a20
col file_name for a50
col bytes for 999,999,999,999
select tablespace_name,file_name,bytes,status from DBA_DATA_FILES
where tablespace_name='SSS01_I_DATA'
order by tablespace_name,file_name;

TABLESPACE_NAME  FILE_NAME                            BYTES          STATUS
---------------- ------------------------------------ -------------- ---------
SSS01_I_DATA     /DATA/DATABASE/SSS01_I_DATA_01.DBF    2,147,483,648 AVAILABLE
SSS01_I_DATA     /DATA/DATABASE/SSS01_I_DATA_02.DBF    2,147,483,648 AVAILABLE
SSS01_I_DATA     /DATA/DATABASE/SSS01_I_DATA_03.DBF    2,147,483,648 AVAILABLE
SSS01_I_DATA     /DATA/DATABASE/SSS01_I_DATA_04.DBF    2,147,483,648 AVAILABLE
データファイルの最終ブロックを検索します。
col TABLESPACE_NAME for a20
select * from dba_free_space where tablespace_name = 'SSS01_I_DATA'
order by file_id,block_id;

TABLESPACE_NAME         FILE_ID   BLOCK_ID      BYTES     BLOCKS RELATIVE_FNO
-------------------- ---------- ---------- ---------- ---------- ------------
SSS01_I_DATA                  4          9    8388608       1024            4
SSS01_I_DATA                  4      24201    1048576        128            4
SSS01_I_DATA                  4      25353 1938817024     236672            4
SSS01_I_DATA                  5       3465 2118123520     258560            5
SSS01_I_DATA                  6       1929   65011712       7936            6
SSS01_I_DATA                  6      33801 1869611008     228224            6 
SSS01_I_DATA                  7        137    1048576        128            7
SSS01_I_DATA                  7       1417 2134900736     260608            7
これは、BLOCK_IDから始まる空き連続領域を意味します。
FILE_ID = 4のデータファイルを例にとると、25353 - 1 = 25352ブロックまでは最低限必要なデータファイルのサイズです。
この例では1ブロック = 4KBの環境なので、25353 x 4KB = 約100MBまで縮小ができます。
縮小手順は次の通り。
alter database datafile '/DATA/DATABASE/SSS01_I_DATA_01.DBF' resize 100M

追記:2011/04/28
ASMでなくても、nomountではなくOPEN状態で実行できました。
10gとかからそうなったんでしょうか・・・。

SGAの大きさを変更する

SGAはインスタンスの再起動が必要です。
まず現在の設定を確認します。
SQL> show parameter sga_
NAME             TYPE         VALUE
---------------- ------------ ------
sga_max_size     big integer  1536M
sga_target       big integer  1536M
SGAサイズsga_max_sizeは動的変更(scope=both)できません。
初期化パラメータをサーバパラメータファイルで管理している、かつ、SGAの自動共有メモリ管理(ASMM)を使っている場合、sga_targetは動的変更できます。
SQL> alter system set sga_max_size = 4G scope=spfile
SQL> alter system set sga_target = 4G scope=spfile

SQL> shutdown immediate
Database closed.
Database dismounted.
ORACLE instance shut down.

SQL> startup
ORACLE instance started.

Total System Global Area 4294967296 bytes
Fixed Size                  2089472 bytes
Variable Size            3707768320 bytes
Database Buffers          570425344 bytes
Redo Buffers               14684160 bytes
Database mounted.
Database opened.
作業後、確認します。
SQL> show parameter sga_
NAME             TYPE         VALUE
---------------- ------------ ------
sga_max_size     big integer  4G
sga_target       big integer  4G

2011年3月2日水曜日

長時間実行しているセッションを調べる

何かしらの待機により残ったままのセッションおよびそのSQLを調べます。
新規、かつ、実行途中のSQLexecutions=0のままなので、除算エラーにならないようにしています。
set time on
set pages 10000
set lines 100
set long 20000
col program for a50
col username for a20
col status for a10
col sql_fulltext for a100
alter session set nls_date_format='yyyy/mm/dd hh24:mi:ss';
select s.sid,s.serial#,s.username,s.logon_time,s.status,
  q.sharable_mem,q.elapsed_time/nvl(nullif(executions,0),1)/1000/1000 as executions,
  s.program,
  replace(replace(replace(q.sql_fulltext,chr(9),''),chr(10),' '),'  ',' ') as sql
from v$session s,v$sqlstats q
where s.sql_id=q.sql_id and username<>'SYS'
order by s.logon_time desc
;
実行結果は次の通り。
SID    SERIAL# USERNAME             LOGON_TIME          STATUS     SHARABLE_MEM EXECUTIONS
------ ---------- -------------------- ------------------- ---------- ------------ ----------
PROGRAM
--------------------------------------------------
SQL
--------------------------------------------------------------------------------
   476       9190 SSS01DBIUSER         2011/03/02 17:33:06 INACTIVE          16408 .001146854
httpd@sssweb24.sss.co.jp (TNS V1-V3)
select user_id,item_id,item_count,to_char( update_dt, 'yyyy/mm/dd hh24:mi:ss')
 as update_dt from TBL_StartAvatar1 where item_id=:i
tem_id1 and user_id=:user_id2 and item_count>:item_c
ount3 order by update_dt desc

2011年3月1日火曜日

データベースリンクを確認する

set pages 10000
set lines 110
col owner for a10
col db_link for a30
col username for a20
col host for a10
select * from dba_db_links;
実行結果は次の通り。
OWNER      DB_LINK              USERNAME     HOST       CREATED
---------- -------------------- ------------ ---------- --------
PUBLIC     SSS01_MASTER_SYNC    MASTERUSER   SSS01      10-07-14

データベースリンクの同時オープン数を変更する

DBリンクはセッションあたりの接続数が制限されています。
初期値は4。
同時に4つ以上のDBリンクを使うことは多くはないはずなので、足りない場合、まずはアプリケーションの対策をした方がいいと思います。
まずは現在の設定を確認します。
SQL> show parameter open_links

NAME                       TYPE          VALUE
-------------------------- ------------- ------
open_links                 integer       4
alter systemで変更します。
静的な設定なので再起動が必要です。
SQL> alter system set open_links=8 scope=spfile;

2011年2月25日金曜日

似て非なるSQLを探す

Oracleは意識的にプレースホルダを使わないと、共有プールのSQL領域を食いつぶしてSQLのキャッシュ率が悪くなります。
SGAを増やす手段もありますが、数ギガ規模にまで増やすとキャッシュの吐き出し(エージアウト)をしている間、SQLキャッシュ全体をロック(ラッチ)されて処理を何も受け付けなくなります。
そこで、リテラル値が含まれているSQLを定期的に探すといいでしょう。
この例では、SQL文を前方一致100文字だけで比較していますが、アプリケーションによっては50~150文字など調整するといいかと思います。
CNTが多いものを最優先に対応するといいでしょう。
select "Stmt",cnt,"Mem/count","Exec" from (
  SELECT row_number() over (order by count(*) desc) as rn,
      substr(sql_text,1,100) "Stmt", count(*) cnt,
      sum(sharable_mem)/count(*)    "Mem/count",
      sum(executions)      "Exec"
  FROM v$sqlstats
  GROUP BY substr(sql_text,1,100)
  HAVING count(*) > 10
) where rn<=100;
実行例は次の通り。
Stmt                                                                                    CNT  Mem/count       Exec
-------------------------------------------------------------------------------- ---------- ---------- ----------
    SELECT     msfr.free_rankavg_id,     msfr.free_rankavg_nm,     msfr.event_id       4308 36555.0975       4312
,     msfr.team_flg,

select substrb(dump(val,16,0,32),1,120) ep, cnt from (select /*+ no_parallel(t)         308 12900.4416       3365
no_parallel_index(t)

select TABLE_NAME,TABLESPACE_NAME,CLUSTER_NAME,PCT_FREE,PCT_USED,INI_TRANS,MAX_T        170 44840.8471        380
RANS,INITIAL_EXTENT/

select column_name,data_type,data_length,nullable,data_default,data_precision,da        127 48466.2047        310
ta_scale from user_t

 select /*+ no_parallel(t) no_parallel_index(t) dbms_stats cursor_sharing_exact         104 11319.4615       1182
use_weak_name_resl d

SELECT /*+ cursor_sharing_exact */ count(*) FROM  "SYS"."KUPC$DATAPUMP_QUETAB" T        100      12426          0
AB, SYS.DUAL WHERE t

select /*+ no_parallel(t) no_parallel_index(t) dbms_stats cursor_sharing_exact u         93 51273.5484       1069
se_weak_name_resl dy

SELECT /* OPT_DYN_SAMP */ /*+ ALL_ROWS IGNORE_WHERE_CLAUSE NO_PARALLEL(SAMPLESUB         91 17089.3187       1338
) opt_param('paralle

    SELECT     tau.user_id,     tau.aplus_level_no,     taf.appr_stat_cd    FROM         63 19573.8413        252
     aplus001iuser.t

select * from ( select rank() over ( order by last_access_dt desc , rownum) AS r         49 32231.8367        161
n, user_id,uid_2,car

insert into TBL_ObjectiveEventLog (regist_dt,event_id,objective_id,carrier_id,us         34 10804.2353        397
er_id,event_clear_co

SELECT COUNT(DISTINCT BAG_USER_ID), COUNT(DISTINCT CAP_USER_ID) FROM (SELECT CAS         32    22367.5       4622
E MBAG.BAG_KIND WHEN

SELECT COUNT(DISTINCT APL_USER_ID), COUNT(DISTINCT SMS_USER_ID) FROM (SELECT CAS         32   23160.75       4458
E MAPP.SMST_FLG WHEN

select item_id,category_id,item_nm,carrier_1_publish_flg,carrier_2_publish_flg,c         25   13244.16         88
arrier_3_publish_flg

SELECT * FROM (SELECT DISTINCT user_id, 1 as carrier_id, row_number() over( orde         22 17519.6364         65
r by last_adm_dt  )

SELECT alias000$."STYLESHEET" AS STYLESHEET FROM "SYS"."METASTYLESHEET" alias000         20      14730        992
$ WHERE 1 = 1 AND ((

select user_regist_kind1, TO_CHAR(last_adm_dt_kind1,'YYYY/MM/DD HH24:MI:SS') as          20    24929.2         93
last_adm_dt_kind1 fr

SELECT     user_id,     sum(prev_user_point_amt),      sum(user_point_result_amt         18 15337.3333         19
),     trunc(update_

    SELECT     mfri.free_rankavg_incentive_id,     mfri.free_rankavg_id,     mfr         18      15336         18
i.team_flg,     mfri

     sss01dbiuser.         17 22733.6471        291
tbl_usermyroom1

select * from (       select temp_.*, rownum as rownumber_ from (            SEL         16    35747.5        389
ECT         mwp.aplu

select * from (       select temp_.*, rownum as rownumber_ from (            sel         15    34043.2      13478
ect     user_id,

SELECT count(DISTINCT user_id) as datacount FROM MST_User1 WHERE user_id in (SEL         15    14788.8         42
ECT user_id FROM MST

SELECT AP001_ID,USER_ID,AP001_LEVEL_NO,MISSION_COMPLETE_PCT,TOTAL_GAME_CNT,TOTAL         13 27131.0769         87
_COIN_AMT,TOTAL_DECO

select user_id,nick_name,mail,mail_sec,mail_domain,user_name,user_zip,user_pref,         12 29984.6667       5073
user_address,to_char

SELECT AP001_ITEM_ID,AP001_ID,AP001_ITEM_CATEGORY_CD,CARRIER_1_PUBLISH_FLG,CARRI         12       9270         31
ER_1_PUBLISH_DT,CARR

2011年2月24日木曜日

LOBセグメントからテーブル名を探す

LOBはテーブルセグメントとは別管理なので、セグメントのサイズを確認するとSYS_LOB
から始まるセグメント名で表示されます。
shrinkするのにテーブル名を知りたい場合、dba_lobsで探すことができます。
set time on
set pages 10000
set lines 120
col owner for a20
col tablespace_name for a20
col table_name for a30
col column_name for a20
col segment_name for a30
select owner,segment_name,tablespace_name,table_name,column_name from dba_lobs
where segment_name in ('SYS_LOB0000032214C00005$$','SYS_LOB0000032217C00014$$');
実行例は次の通り。
OWNER           SEGMENT_NAME                   TABLESPACE_NAME TABLE_NAME           COLUMN_NAME
--------------- ------------------------------ --------------- -------------------- --------------------
SSS01DBIUSER    SYS_LOB0000032214C00005$$      SSS01_I_DATA    TBL_AAARESTEXT1      AAA_ANS_TEXT
SSS01DBIUSER    SYS_LOB0000032217C00014$$      SSS01_I_DATA    TBL_GENERALENTRY1    GENERALENTRY_FREE

セグメントのサイズを確認する

テーブルやインデックスなどのセグメントは、使ううちに断片化して肥大化します。
定期的にサイズをチェックし、shrinkなどの対策をするといいでしょう。
set time on
 set pages 10000
 set lines 120
 col segment_name for a30
 col tablespace_name for a20
 col bytes for 9,999,999,999
 select tablespace_name,segment_name,bytes from (
   select rank() over (order by bytes desc) rnk,
     tablespace_name,segment_name,bytes from dba_segments
 ) where rnk<=20;
実行例は次の通り。
TABLESPACE_NAME      SEGMENT_NAME                            BYTES
-------------------- ------------------------------ --------------
SSS01_INDPA1_DATA    TBL_CHARGECONSENTLOG1           1,412,431,872
SSS01_MASTERD_DATA   TBL_OBJECTIVESTREAMING01LOG1    1,046,478,848
SSS01_MASTERD_DATA   IXT2_OBJECTIVESTREAMING01LOG1     745,537,536
SSS01_MASTERD_DATA   TBL_MEDIAAPPITEMLOG1              732,954,624
SSS01_MASTERD_DATA   TBL_OBJECTIVESTREAMING01LOG3      495,976,448
SSS01_MASTERD_DATA   TBL_OBJSTREAMING01LOG1_1201       490,733,568
SSS01_MASTERD_DATA   TBL_OBJSTREAMING01LOG1_0101       475,004,928
SSS01_MASTERD_DATA   TBL_OBJSTREAMING01LOG1_0201       452,984,832
SSS01_MASTERD_DATA   TBL_CCACCESS1                     418,381,824
SSS01_MASTERD_DATA   TBL_OBJSTREAMING01LOG1_1101       387,973,120
SSS01_MASTERD_DATA   IXT2_OBJECTIVESTREAMING01LOG3     353,370,112
FUKA_I_DATA          TBL_OBJECTIVESTREAMING011         344,981,504
SSS01_MASTERD_DATA   TBL_MEDIABAGLOG1                  342,884,352
FUKA_I_DATA          TBL_DAILYTEXTMACHINEUPLOAD1       319,815,680
FUKA_I_DATA          TBL_USERSESSION1                  318,767,104
FUKA_I_DATA          TBL_DAILYTEXTTOTALUPLOAD1         279,969,792
SSS01_I_DATA         TBL_USERSESSION1                  264,241,152
FUKA_I_DATA          TBL_CCQUIZ_USER_RESULT1           244,318,208
FUKA_I_IDX           IXT1_DAILYTEXTTOTALUPLOAD1        236,978,176
SSS01_MASTERD_DATA   TBL_OBJSTREAMING01LOG3_0201       227,540,992

2011年2月20日日曜日

データベースファイルを追加し表領域を拡張する

1.データベースファイル名を確認する
$ sqlplus sys as sysdba
SQL> set pages 10000
set lines 120
col tablespace_name for a20
col file_name for a50
col bytes for 999,999,999,999
select tablespace_name,file_name,bytes,status from DBA_DATA_FILES
where tablespace_name='SSS01_I_DATA'
order by tablespace_name,file_name;

TABLESPACE_NAME  FILE_NAME                            BYTES          STATUS
---------------- ------------------------------------ -------------- ---------
SSS01_I_DATA     /DATA/DATABASE/SSS01_I_DATA_01.DBF    2,147,483,648 AVAILABLE
SSS01_I_DATA     /DATA/DATABASE/SSS01_I_DATA_02.DBF    2,147,483,648 AVAILABLE
SSS01_I_DATA     /DATA/DATABASE/SSS01_I_DATA_03.DBF    2,147,483,648 AVAILABLE
SSS01_I_DATA     /DATA/DATABASE/SSS01_I_DATA_04.DBF    2,147,483,648 AVAILABLE
2.データベースファイルを追加する
A)ASMの場合(SE RACなど)
※ASM(RAW)はパスが1文字違うので注意。
$ sqlplus sys as sysdba
ALTER TABLESPACE SSS01_I_DATA
  ADD DATAFILE '+DATA/DATABASE/SSS01_I_DATA_05.DBF' SIZE 2048M AUTOEXTEND ON;
B)ファイルシステムの場合
$ sqlplus sys as sysdba
ALTER TABLESPACE SSS01_I_DATA
  ADD DATAFILE '/DATA/DATABASE/SSS01_I_DATA_05.DBF' SIZE 2048M AUTOEXTEND ON;

Data Pumpによる過去分データをインポートする

今担当している案件では頻繁に過去データの調査があるため、ときどきバックアップから開発DBにインポートしています。
インポートにはData Pumpを使っています。
Recovery Managerではない理由は次の通り。
・インポート先(開発DB)の容量不足でエクスポートデータを置けない
・サーバ間マテリアライズドビューが多数あるので、テーブルとインデックス以外をリカバリしたくない
・週次でRMANフルバックアップという運用をしているため、リカバリがめんどうw
1.はじめに
Oracleには2種類のエクスポート/インポートコマンドがあります。
Data Pumpを使っている理由は、速度とスキーマ変更機能です。
2.作業の流れ
ここでは、マテビューのマスタ側サーバのエクスポートデータをインポートします。
そのままインポートするとマテビューログや統計情報も含まれるので、次の流れで 行います。
(1)バックアップサーバからエクスポートデータをコピー
(2)DDLの抽出ディレクトリの確認
(3)エクスポートデータからDDLだけをファイル出力
(4)DDLファイルを編集し、テーブルおよびインデックス以外を削除
(5)編集したDDLを実行してcreate table|index
(6)エクスポートデータからレコードデータのみをインポート
(7)analyze
(1)バックアップサーバからエクスポートデータをコピー
エクスポートデータのコピー例
$ ssh sssdev1
$ /backup/databasefile/201008/sssdb3/
$ scp sss01_db_i_dp20100820.dmp.gz  oracle@sssdb11:/usr/local/dbdata/
(2)DDLの抽出ディレクトリの確認
ディレクトリ設定がされているか確認します。
ここではEXPDP_DATAを使います。
select * from dba_directories;
OWNER      DIRECTORY_NAME            DIRECTORY_PATH
---------- ------------------------- ---------------------------------------------
SYS        ORACLE_OCM_CONFIG_DIR     /opt/app/oracle/product/10.2.0/db/ccr/state
SYS        DATA_PUMP_DIR             /opt/app/oracle/product/10.2.0/db/rdbms/log/
SYS        EXPDP_DATA                /usr/local/dbdata
(3)エクスポートデータからDDLだけをファイル出力
本番システムで使っていないスキーマにインポートしたい時はremap_schemaが非常に便利です。
remap_tableの方が便利ですが、たしか11gからだったと思います。
ここではtestdocomoという調査用に作ったスキーマに変換します。
$ vi testdocomo.par1_0820 
directory=expdp_data
dumpfile=sss01_db_i_dp20100820.dmp   ★エクスポートしたデータ
logfile=sss01_db_i_sql20100820.log
job_name=job_impdp
sqlfile=sss01_db_i_20100820.sql   ★DDLのファイル出力
remap_schema=sss01docomo:testdocomo   ★別スキーマにも変換可能
remap_tablespace=sss01_i_data:test_i_data   ★別表領域にも変換可能
remap_tablespace=sss01_i_idx:test_i_idx
remap_tablespace=mvlog_i_data:test_i_data
INCLUDE=TABLE:"IN ('T_ACCESS1','T_USER1')"   ★テーブル指定も可能

$ impdp testdocomo/xxxxxxxxxxxx parfile=testdocomo.par1_0820 
(4)DDLファイルを編集し、テーブルおよびインデックス以外を削除
TABLE, INDEX, CONSTRAINT以外を削除します。
特に、マテビューログのSYS用DDLは、元のスキーマ名で設定するので注意。
また、ビットマップインデックスは、通常のインデックスとは別項目で出力することも注意。
vi等で編集して★だけ残します。
$ grep "^-- new obj" sss01_db_i_20100902.sql 
-- new object type path is: SCHEMA_EXPORT/TABLE/TABLE   ★
-- new object type path is: SCHEMA_EXPORT/TABLE/INDEX/INDEX   ★
-- new object type path is: SCHEMA_EXPORT/TABLE/CONSTRAINT/CONSTRAINT   ★
-- new object type path is: SCHEMA_EXPORT/TABLE/INDEX/STATISTICS/INDEX_STATISTICS
-- new object type path is: SCHEMA_EXPORT/TABLE/COMMENT
-- new object type path is: SCHEMA_EXPORT/TABLE/INDEX/FUNCTIONAL_AND_BITMAP/INDEX   ★
-- new object type path is: SCHEMA_EXPORT/TABLE/INDEX/STATISTICS/FUNCTIONAL_AND_BITMAP/INDEX_STATISTICS
-- new object type path is: SCHEMA_EXPORT/TABLE/STATISTICS/TABLE_STATISTICS
-- new object type path is: SCHEMA_EXPORT/TABLE/POST_TABLE_ACTION
-- new object type path is: SCHEMA_EXPORT/TABLE/MATERIALIZED_VIEW_LOG
(5)編集したDDLを実行してcreate table|index
テーブルおよびインデックス作成例
$ sqlplus testdocomo/xxxxxxxxxxxx
SQL> @sss01_db_i_20100820.sql
(6)エクスポートデータからレコードデータのみをインポート
レコードデータのインポート例
$ cat testdocomo.par2_0820 
directory=expdp_data
dumpfile=sss01_db_i_dp20100820.dmp
logfile=sss01_db_i_sql20100820.log
job_name=job_impdp
remap_schema=sss01docomo:testdocomo
remap_tablespace=sss01_i_data:test_i_data
remap_tablespace=sss01_i_idx:test_i_idx
remap_tablespace=mvlog_i_data:test_i_data
CONTENT=DATA_ONLY   ★レコードデータのみを指定
INCLUDE=TABLE:"IN ('T_ACCESS1','T_USER1')"   ★テーブル指定も可能

$ impdp testdocomo/xxxxxxxxxxxx parfile=testdocomo.par2_0820 
(7)analyze
データ量が多いときはやった方が精神衛生上よいです。
analyze table TBL_SG1_0820 compute statistics;   ★インデックスもanalyze

Data Pumpによる過去分データをインポートする

今担当している案件では頻繁に過去データの調査があるため、ときどきバックアップから開発DBにインポートしています。
インポートにはData Pumpを使っています。
Recovery Managerではない理由は次の通り。
・インポート先(開発DB)の容量不足でエクスポートデータを置けない
・サーバ間マテリアライズドビューが多数あるので、テーブルとインデックス以外をリカバリしたくない
・週次でRMANフルバックアップという運用をしているため、リカバリがめんどうw
1.はじめに
Oracleには2種類のエクスポート/インポートコマンドがあります。
Data Pumpを使っている理由は、速度とスキーマ変更機能です。
2.作業の流れ
ここでは、マテビューのマスタ側サーバのエクスポートデータをインポートします。
そのままインポートするとマテビューログや統計情報も含まれるので、次の流れで 行います。
(1)バックアップサーバからエクスポートデータをコピー
(2)DDLの抽出ディレクトリの確認
(3)エクスポートデータからDDLだけをファイル出力
(4)DDLファイルを編集し、テーブルおよびインデックス以外を削除
(5)編集したDDLを実行してcreate table|index
(6)エクスポートデータからレコードデータのみをインポート
(7)analyze
(1)バックアップサーバからエクスポートデータをコピー
エクスポートデータのコピー例
$ ssh sssdev1
$ /backup/databasefile/201008/sssdb3/
$ scp sss01_db_i_dp20100820.dmp.gz  oracle@sssdb11:/usr/local/dbdata/
(2)DDLの抽出ディレクトリの確認
ディレクトリ設定がされているか確認します。
ここではEXPDP_DATAを使います。
select * from dba_directories;
OWNER      DIRECTORY_NAME            DIRECTORY_PATH
---------- ------------------------- ---------------------------------------------
SYS        ORACLE_OCM_CONFIG_DIR     /opt/app/oracle/product/10.2.0/db/ccr/state
SYS        DATA_PUMP_DIR             /opt/app/oracle/product/10.2.0/db/rdbms/log/
SYS        EXPDP_DATA                /usr/local/dbdata
(3)エクスポートデータからDDLだけをファイル出力
本番システムで使っていないスキーマにインポートしたい時はremap_schemaが非常に便利です。
remap_tableの方が便利ですが、たしか11gからだったと思います。
ここではtestdocomoという調査用に作ったスキーマに変換します。
$ vi testdocomo.par1_0820 
directory=expdp_data
dumpfile=sss01_db_i_dp20100820.dmp   ★エクスポートしたデータ
logfile=sss01_db_i_sql20100820.log
job_name=job_impdp
sqlfile=sss01_db_i_20100820.sql   ★DDLのファイル出力
remap_schema=sss01docomo:testdocomo   ★別スキーマにも変換可能
remap_tablespace=sss01_i_data:test_i_data   ★別表領域にも変換可能
remap_tablespace=sss01_i_idx:test_i_idx
remap_tablespace=mvlog_i_data:test_i_data
INCLUDE=TABLE:"IN ('T_ACCESS1','T_USER1')"   ★テーブル指定も可能

$ impdp testdocomo/xxxxxxxxxxxx parfile=testdocomo.par1_0820 
(4)DDLファイルを編集し、テーブルおよびインデックス以外を削除
TABLE, INDEX, CONSTRAINT以外を削除します。
特に、マテビューログのSYS用DDLは、元のスキーマ名で設定するので注意。
また、ビットマップインデックスは、通常のインデックスとは別項目で出力することも注意。
$ grep "^-- new obj" sss01_db_i_20100902.sql 
-- new object type path is: SCHEMA_EXPORT/TABLE/TABLE
-- new object type path is: SCHEMA_EXPORT/TABLE/INDEX/INDEX
-- new object type path is: SCHEMA_EXPORT/TABLE/CONSTRAINT/CONSTRAINT
-- new object type path is: SCHEMA_EXPORT/TABLE/INDEX/STATISTICS/INDEX_STATISTICS
-- new object type path is: SCHEMA_EXPORT/TABLE/COMMENT
-- new object type path is: SCHEMA_EXPORT/TABLE/INDEX/FUNCTIONAL_AND_BITMAP/INDEX
-- new object type path is: SCHEMA_EXPORT/TABLE/INDEX/STATISTICS/FUNCTIONAL_AND_BITMAP/INDEX_STATISTICS
-- new object type path is: SCHEMA_EXPORT/TABLE/STATISTICS/TABLE_STATISTICS
-- new object type path is: SCHEMA_EXPORT/TABLE/POST_TABLE_ACTION
-- new object type path is: SCHEMA_EXPORT/TABLE/MATERIALIZED_VIEW_LOG
(5)編集したDDLを実行してcreate table|index
テーブルおよびインデックス作成例
$ sqlplus testdocomo/xxxxxxxxxxxx
SQL> @sss01_db_i_20100820.sql
(6)エクスポートデータからレコードデータのみをインポート
レコードデータのインポート例
$ cat testdocomo.par2_0820 
directory=expdp_data
dumpfile=sss01_db_i_dp20100820.dmp
logfile=sss01_db_i_sql20100820.log
job_name=job_impdp
remap_schema=sss01docomo:testdocomo
remap_tablespace=sss01_i_data:test_i_data
remap_tablespace=sss01_i_idx:test_i_idx
remap_tablespace=mvlog_i_data:test_i_data
CONTENT=DATA_ONLY   ★レコードデータのみを指定
INCLUDE=TABLE:"IN ('T_ACCESS1','T_USER1')"   ★テーブル指定も可能

$ impdp testdocomo/xxxxxxxxxxxx parfile=testdocomo.par2_0820 
(7)analyze
データ量が多いときはやった方が精神衛生上よいです。
analyze table TBL_SG1_0820 compute statistics;   ★インデックスもanalyze

2011年2月18日金曜日

スキーマの表領域へのアクセス制限を確認する

スキーマ作成および権限付与(grant)をしても、特定の表領域を参照できないときは確認してみるといいでしょう。
表領域への割り当て制限設定がされていないと、権限があっても参照できません。
SQL> SELECT * FROM user_ts_quotas;
MAX_BYTES  ・・・  利用できる上限。負の値は無制限

TABLESPACE_NAME                     BYTES  MAX_BYTES     BLOCKS MAX_BLOCKS DRO
------------------------------ ---------- ---------- ---------- ---------- ---
SSS01_INDEP3_DATA                       0         -1          0         -1 NO
MVLOG_I_DATA                    161480704         -1      19712         -1 NO
SSS01_MASTER_IDX                        0         -1          0         -1 NO
SSS01_HISTORY_IDX                       0         -1          0         -1 NO
SSS01_MASTER_DATA                       0         -1          0         -1 NO
SSS01_HISTORY_DATA                      0         -1          0         -1 NO
SSS01_I_DATA                   4600102912         -1     561536         -1 NO
CCCC01TOWN_DATA                         0         -1          0         -1 NO
MVLOG_I2_DATA                           0         -1          0         -1 YES
SSS01_I_IDX                    3890216960         -1     474880         -1 NO
SSS01_INDEP1_DATA                       0         -1          0         -1 NO
CCCC01TOWN_IDX                          0         -1          0         -1 NO
SSS01_INDEP1_IDX                        0         -1          0         -1 NO
SSS01_INDEP2_IDX                        0         -1          0         -1 NO
SSS01_INDEP2_DATA                       0         -1          0         -1 NO
SSS01_INDEP3_IDX                        0         -1          0         -1 NO

スキーマ(ログインユーザ)を作成する

参照する表領域すべてについて割り当て制限(quota)設定が必要です。
grantで権限付与しても、quotaしないと当該表領域にアクセスできないので注意。
create user cccc01townusr
 identified by XXXXXXXXXX
 default tablespace CCCC01TOWN_DATA
 quota unlimited on CCCC01TOWN_DATA
 quota unlimited on CCCC01TOWN_IDX
 quota unlimited on SSS01_I_DATA
 quota unlimited on SSS01_I_IDX
 temporary tablespace TEMP;

2011年2月17日木曜日

共有プールの利用状況を確認する

負荷特性の異なる処理を混在させている場合、共有プールの変化をウォッチしておくとボトルネックを見つけられることがあります。
sql area   ・・・   SQL文そのもののキャッシュ
CCursor/PCursor   ・・・   カーソルキャッシュ
library cache   ・・・   コンパイル済SQLのキャッシュ
free memory   ・・・   空きメモリ

set pages 10000
set lines 100
set time on
col name for a30
col bytes for 999,999,999,999
select name,bytes from (
 select row_number() over (order by bytes desc) as rn,name,bytes from v$sgastat
 where pool = 'shared pool'
) where rn <= 20;

NAME                                      BYTES
------------------------------ ----------------
sql area                          2,484,421,928
free memory                       1,734,338,672
CCursor                             678,436,864
PCursor                             472,727,184
library cache                       352,787,688
sql area:PLSQL                      346,800,984
kglsim object batch                 182,272,608
gcs resources                       128,586,016
kglsim heap                         104,469,120
Cursor Stats                         98,273,576
gcs shadows                          76,999,136
db_block_hash_buckets                47,185,920
ASH buffers                          30,408,704
ges enqueues                         19,842,976
ges big msg buffers                  15,936,168
trace buffer                         14,057,472
KGLS heap                            13,290,704
event statistics per sess            12,296,000
FileOpenBlock                        11,575,096
ges resource                         11,342,888
似たSQLが多いWebサイト処理と、SQL数が多くなりがちな大量更新バッチを混在させていると次のグラフのようになることがあります。 バッチを実行していない時はfreeがかなり多いためボトルネックを見つけづらいと思います。

2011年2月15日火曜日

推奨パッチの検索

四半期ごとのPSU以外にもクリティカルなバグFixは、My Oracle Supportにて「その他推奨」に分類されます。
ここではOracle社の推奨パッチを検索する方法を紹介します。

1.PSR
最新版は、OiSCトップ(ヘッドライン)の最新パッチ情報-システム製品-に表示されます。
またはOiSCの「パッチ/メディア」タブから当該バージョンで確認することもできます。
OiSC   ・・・   http://support.oracle.co.jp/support/
2.CPU
最新版は、OiSCのトップ(ヘッドライン)の重要技術情報に表示されます。
過去分は後述するPSUと同じように検索します。

3.PSU、PSE
概要情報は、OiSCのKRWON検索で"PSU"→132780を参照します。
パッチ詳細やダウンロードはMy Oracle Supportで取得できます。
My Oracle Support   ・・・   https://support.oracle.com/

パッチと更新版>パッチ検索タブ>Search 
  製品→Oracle Database 
  検索条件を「+」ボタンで増やす 
  リリース→直近のリリース(10.2.0.4.5を探すなら10.2.0.4.4) 
  プラットフォーム→Linux x86-64など
  分類→その他推奨,セキュリティ

  検索後、右上の「検索の編集」で検索条件を保存

2011年2月11日金曜日

適用済パッチのバージョン確認

1.Oracle Database
$ export ORACLE_SID=sss1
$ $ORACLE_HOME/OPatch/opatch lsinventory
Invoking OPatch 10.2.0.4.8

Oracle Interim Patch Installerバージョン10.2.0.4.8
Copyright (c) 2009, Oracle Corporation.  All rights reserved。

Oracleホーム       : /opt/app/oracle/product/10.2.0/db
中央インベントリ : /opt/app/oracle/oraInventory
   元           : /etc/oraInst.loc
OPatchのバージョン    : 10.2.0.4.8
OUIのバージョン       : 10.2.0.4.0
OUIの場所      : /opt/app/oracle/product/10.2.0/db/oui
ログ・ファイルの場所 : /opt/app/oracle/product/10.2.0/db/cfgtoollogs/opatch/opatch2010-02-04_19-29-06午後.log

Patch history file: /opt/app/oracle/product/10.2.0/db/cfgtoollogs/opatch/opatch_history.txt

Lsinventory Output file location : /opt/app/oracle/product/10.2.0/db/cfgtoollogs/opatch/lsinv/lsinventory2010-02-04_19-29-06午後.txt

--------------------------------------------------------------------------------
インストールされた最上位製品(2): 

Oracle Database 10g                                                  10.2.0.1.0
Oracle Database 10g Release 2 Patch Set 3                            10.2.0.4.0  ★PSRのバージョン
このOracleホームには2の製品がインストールされています。

仮パッチ(4) :

Patch  7588384      : applied on Wed Dec 30 19:29:17 JST 2009
Unique Patch ID:  11943540
   Created on 11 Nov 2009, 07:28:48 hrs PST8PDT
   Bugs fixed:
     7588384
   This patch overlays patches:
     8833280
   This patch needs patches:
     8833280
   as prerequisites

Patch  8833280      : applied on Wed Dec 30 17:41:50 JST 2009  ★DB PSUのバージョン
Unique Patch ID:  11733883
   Created on 10 Sep 2009, 06:30:20 hrs PST8PDT
   Bugs fixed:
     6418420, 7835247, 7207654, 7592346, 6724797, 7936993, 7331867, 7552067
     5879114, 5457450, 8344348, 7272297, 7136866, 7196894, 7013124, 7196532
     8568395, 8309587, 7557226, 6509115, 8568397, 8568398, 6052226, 7424804
     6817593, 7553884, 6469211, 7527650, 8309592, 6945157, 6403091, 7552082
     6711853, 8304589, 8199266, 6327692, 5756769, 7460818, 6268409, 6687381
     6972843, 8230457, 6800507, 7027551, 6778714, 6200820, 6645719, 7393804
     3934160, 6683178, 6650256, 7528105, 6378112, 5126719, 7036453, 8426816
     8433026, 7270434, 7172531, 6451626, 8247855, 6874522, 7175513, 6960489
     7341598, 8576156, 6797677, 8342923, 5895190, 7150470, 7593835, 7356443
     7044551, 8227106, 4695511, 7298688, 5747462, 7197445, 5348308, 7937113
     8341623, 7569205, 8409848, 6163771, 6181488, 6375150, 7295780, 6345573
     7033630, 6954722, 7457766, 7309458, 8324577, 6840740, 6804746, 7375611
     8268054, 6988017, 7375613, 8344399, 7340448, 7375617, 8362683, 8251247
     5933656, 6599920, 7238230, 6452375, 6352003, 6833965, 7136489, 6610218
     7612639, 6392076, 5476236, 7609057, 7609058, 6374297, 6193945, 4693355
     7039896, 7432514, 7330909, 6952701, 7190270, 8287155, 7207932, 6802650
     7189447, 6615740, 7155655, 6749617, 7159505, 5727166, 5868257, 7173005
     6917874, 7691766, 7385253, 7225720, 7244238, 7363767, 7257770, 6941717
     8267348, 7710551, 7247217, 8328954, 6681695, 8702276, 8217011, 7661251
     6265559, 6823287, 6991626, 6954829, 5259835, 6500033, 5923486, 7432601
     8534387, 6653934, 7375644, 5147386, 7662491, 6490140, 8331466, 6070225
     5623467, 7396409, 6638558, 7038750, 6838714, 6870937, 7219752, 7263842
     7278117, 6882739, 5404871, 8836667, 8373286, 6678845, 6903051, 7936793
     7155248, 4966512, 7155249, 8836308, 8568402, 8568404, 8568405, 6343150
     6923450, 7643632, 8836671, 6145177, 6640411, 8347704, 8836675, 7155250
     7155251, 8836677, 7155252, 8836678, 7155253, 7155254, 8292378, 6219529
     7411865, 8227091, 8340379, 7276960, 5863926, 7123643, 6413089, 6596564
     6851438, 8836681, 8836683, 8836684, 7579469, 8836686, 7315642, 7494333
     8340383, 8340387, 6926448, 7600026, 6679303, 7197583, 7172752, 7008262
     7477934, 6733655, 6084232, 7499353, 6980597, 6799205, 6014513, 7140204
     7254987, 8833280, 7693128, 6120004, 6051177, 6858062, 7189645, 5630796
     7196863, 7378661, 7378735, 8290506, 6658484, 8309623, 7599944, 7125408
     6987790, 7257461, 5883691, 6919819, 7568556, 6955744, 6857917, 7149004
     6074620, 8283650, 7552042, 6506617, 8287504, 6271590, 5386204, 6976005
     7606362, 7043989, 8309632, 6870047, 8309637, 8309639, 6827260, 6752765
     6024730, 6628122, 8239142, 4637902, 8309642, 7345904, 6994160, 6919764
     7597354, 7523787, 6029179, 6455659, 5231155

Patch  6079224      : applied on Thu Oct 22 15:19:42 JST 2009
   Created on 15 Sep 2008, 03:58:35 hrs PST8PDT
   Bugs fixed:
     6079224

Patch  8436582      : applied on Thu Oct 22 15:11:28 JST 2009
Unique Patch ID:  11560856
   Created on 14 Jul 2009, 11:10:20 hrs IST
   Bugs fixed:
     8436582

複数のノードで構成されるRACシステム
  Local node = sssdb1
  Remote node = sssdb2

--------------------------------------------------------------------------------
OPatch succeeded.

2.Oracle Clusterware
$ export ORACLE_HOME=$ORA_CRS_HOME
$ $ORACLE_HOME/OPatch/opatch lsinventory
Invoking OPatch 10.2.0.4.2

Oracle Interim Patch Installer version 10.2.0.4.2
Copyright (c) 2007, Oracle Corporation.  All rights reserved.

Oracleホーム       : /opt/crs/oracle/product/10.2.0/app
中央インベントリ : /opt/app/oracle/oraInventory
   元           : /etc/oraInst.loc
OPatchのバージョン    : 10.2.0.4.2
OUIのバージョン       : 10.2.0.4.0
OUIの場所      : /opt/crs/oracle/product/10.2.0/app/oui
ログ・ファイルの場所 : /opt/crs/oracle/product/10.2.0/app/cfgtoollogs/opatch/opatch2011-02-11_22-41-09午後.log

Lsinventory Output file location : /opt/crs/oracle/product/10.2.0/app/cfgtoollogs/opatch/lsinv/lsinventory2011-02-11_22-41-09午後.txt

--------------------------------------------------------------------------------
インストールされた最上位製品(2): 

Oracle Clusterware                                                   10.2.0.1.0
Oracle Database 10g Release 2 Patch Set 3                            10.2.0.4.0
このOracleホームには2の製品がインストールされています。

仮パッチ(1) :

Patch  9294403      : applied on Tue May 18 16:09:18 JST 2010  ★CRS PSUのバージョン
   Created on 19 Mar 2010, 18:59:31 hrs PST8PDT
   Bugs fixed:
     9294403

複数のノードで構成されるRACシステム
  Local node = sssdb3
  Remote node = sssdb4

--------------------------------------------------------------------------------
OPatch succeeded.

Oracleパッチの種類

1.用語
PSR・・・Patch Set Release
PSU・・・Patch Set Updates
PSE・・・Patch Set Exception
CPU・・・Critical Patch Updates
OiSC・・・Oracle internet Support Center
MOS・・・My Oracle Support
CRS・・・Cluster Ready Services(現在のClusterware)

2.パッチの種類

3.注意
Oracle RACの場合、DatabaseとClusterwareのパッチは別々で、DB PSUにはCRS PSUが含まれていないこと。
CRS PSUは、PSRと同じバージョンである必要があります。

2011年2月9日水曜日

マテリアライズドビューの同期エラーを解決する

0.はじめに
マテリアライズドビューは、実体を持つビューのこと。
サーバ間レプリケーションとしても使えるが、設定によってはフルスキャンするので安易に使うべきではありません。
履歴系テーブルの集計など、ビューの内容を保存しておきたい場合に有効。
(用語)
マスタ表・・・同期元のテーブル
レプリケーション表・・・同期先のテーブル。マテリアライズドビュー
リフレッシュ・・・マスタ表からレプリケーション表への同期
完全リフレッシュ・・・マスタ表からレプリケーション表へテーブル全件コピー
マテリアライズドビューログ・・・マスタ表の更新履歴。マテビューログ
高速リフレッシュ・・・マテビューログのレプリケーション表への反映
リフレッシュグループ・・・自動リフレッシュでの実行ジョブの単位
rowidマテリアライズドビュー・・・rowidをキーにしたマテビュー。インデックス参照がないので高速

1.アラートログの確認
エラーは、レプリケーション側のDBのアラートログに出力されます。
$ORACLE_BASE/admin/sss01rep/bdump/alert_sss01rep.log

ここでは、rowidマテビューかつ高速リフレッシュ設定をした場合において、マスタ表をtruncateしてしまったケースを取り上げます。
高速リフレッシュは、更新履歴つまりマスタ表の差分情報だけで同期をするため、マスタ表そのものがなくなるとエラーとなります。
また、今回のケースはリフレッシュグループにより自動リフレッシュを行っています。
ORA-12034: "SSS01DBIUSER"."TBL_SITEITEM1"の
マテリアライズド・ビュー・ログは最終リフレッシュよりも新しいものです。

2.対応手順
完全リフレッシュをすることで解決します。
マテビューログは、完全リフレッシュすることにより自動的にtruncateされます。
手動でマテビューログをtruncateしても解決しません。
システムテーブルにあるマテビュー管理テーブルにスナップショット情報が残っているため不整合が発生します。

2-1.自動リフレッシュの失敗によりジョブが停止していないか確認します
BROKEN=Yの場合、停止しています。
失敗してもリトライしてくれますが、FAILURES≧16となるとジョブが停止します。
set time on
set pages 10000
set lines 100
COLUMN BROKEN FORMAT a6
COLUMN SCHEMA_USER FORMAT a20
COLUMN JOB FORMAT 99999
COLUMN WHAT FORMAT a55
alter session set nls_date_format='yyyy/mm/dd hh24:mi:ss';
select JOB,SCHEMA_USER,LAST_DATE,NEXT_DATE,FAILURES,BROKEN,WHAT from dba_jobs;

   JOB SCHEMA_USER          LAST_DATE           NEXT_DATE             FAILURES BROKEN
------ -------------------- ------------------- ------------------- ---------- ------
WHAT
-------------------------------------------------------
    50 SSS01DBIUSER         2011/02/09 22:46:47 2011/02/09 22:47:47          9 N
dbms_refresh.refresh('"SSS01DBIUSER"."REFRESH_I"');

2-2.アラートログでエラーとなっているテーブルをリフレッシュグループから外します
完全リフレッシュ中に、自動同期と処理が重ならないにするためです。
$ sqlplus sss01dbiuser@SSS01REP
SQL> execute dbms_refresh.subtract(name=>'REFRESH_I',list=>'TBL_SITEITEM1')

2-3.必要であればリフレッシュグループを再開します。
高速リフレッシュの場合、リフレッシュグループが停止している間、マテビューログに更新履歴が溜まり続けます。
マテビューログは必ずフルスキャンなので、溜め過ぎてから再開するとリフレッシュが終わらなくなります。
サーバ間マテビューの場合、UNDO関連など別のエラーが発生して2次災害となります。
$ sqlplus sss01dbiuser@SSS01REP
SQL> exec dbms_job.broken(job=>50,broken=>false);
SQL> commit;

2-4.インデックス情報を調べておき、レプリケーション表のインデックスを削除します
インデックスを貼ったままだと、完全リフレッシュが数倍遅くなります。
SQL> drop index IXT1_SITEITEM1;

2-5.完全リフレッシュを行います
sqlplus sss01dbiuser@SSS01REP
SQL> exec dbms_mview.refresh('SSS01DBIUSER.TBL_SITEITEM1', 'c')

2-6.インデックスを再作成します
sqlplus sss01dbiuser@SSS01REP
SQL> create index IXT1_SITEITEM1 on TBL_SITEITEM1 (USER_ID,ITEM_ID) tablespace SSS01_I_IDX;

2-7.リフレッシュグループに再追加
sqlplus sss01dbiuser@SSS01REP
SQL> exec DBMS_REFRESH.ADD ('REFRESH_I','TBL_SITEITEM1');

2-8.リフレッシュグループが停止していたら再開

2-9.自動リフレッシュのインターバルを待ち、FAILURES=0かつBROKEN=Nであることを確認します

2011年2月8日火曜日

ライブラリキャッシュの利用状況を確認する

SQLチューニングをほとんどしていない環境では、SQLの本数が多すぎることがあります。
その場合、データバッファキャッシュよりライブラリキャッシュがボトルネックになるかもしれません。

v$librarycacheのライブラリキャッシュ情報をウォッチするといいでしょう。

ヒット率は95%以上が理想です。
SQLの本数が多い場合、ラッチ(キャッシュのロック)がボトルネックになるのでgethitratioを注視すべきです。
gethitratio・・・ラッチの取得率
pinhitratio・・・キャッシュ(のデータ)の取得率。

set time on
set pages 10000
set lines 120
col namespace for a20
select namespace,gethitratio,pinhitratio from v$librarycache;

実行例は次の通り。
NAMESPACE            GETHITRATIO PINHITRATIO
-------------------- ----------- -----------
SQL AREA              .872027894  .981766737
TABLE/PROCEDURE       .994262842   .97704901
BODY                  .999516938  .998802497
TRIGGER               .915954808  .921656241
INDEX                 .692952564  .828487881
CLUSTER               .990343307  .990707854
OBJECT                         1           1
PIPE                           1           1
JAVA SOURCE           .194444444  .236842105
JAVA RESOURCE         .194444444  .236842105
JAVA DATA                      1           1


なお、10gR2(?)では、たまにhitratioが1000%を超えたりほぼ0%になる不具合(?)があります。

セッションをKILLできない

alter system kill sessionを実行しても、STATUS=KILLEDのままセッションが消えないことがあります。
接続元クライアントを終了させればセッションが消えますが、それでも残っている場合、OSのプロセスを強制終了します。
set time on
set pages 10000
set lines 100
column username format a10
column status format a10
column sid format 99999
column spid format a6
alter session set nls_date_format='yyyy/mm/dd hh24:mi:ss';
select ses.sid,ses.serial#,proc.spid,ses.logon_time,ses.status 
from v$process proc,v$session ses 
where proc.addr=ses.paddr;
実行結果は次の通り。
SPID(プロセス番号)でkillします。
  SID    SERIAL# SPID   LOGON_TIME          STATUS
------ ---------- ------ ------------------- ----------
   555          1 4740   2011/02/07 12:57:00 ACTIVE
   554          1 4742   2011/02/07 12:57:00 ACTIVE
   553          1 4744   2011/02/07 12:57:00 ACTIVE
   552          1 4746   2011/02/07 12:57:00 ACTIVE
   551          1 4748   2011/02/07 12:57:00 ACTIVE
   550          1 4750   2011/02/07 12:57:00 ACTIVE
   549          1 4752   2011/02/07 12:57:00 ACTIVE
   548          1 4754   2011/02/07 12:57:00 ACTIVE
   547          1 4756   2011/02/07 12:57:00 ACTIVE
   546          1 4758   2011/02/07 12:57:00 ACTIVE
   545          1 4760   2011/02/07 12:57:00 ACTIVE
   544          1 4762   2011/02/07 12:57:00 ACTIVE
   540          7 4770   2011/02/07 12:57:10 ACTIVE
   537          2 4806   2011/02/07 12:57:20 ACTIVE
   536          4 4808   2011/02/07 12:57:20 ACTIVE
   527      19899 22096  2011/02/07 23:23:39 ACTIVE

# kill -KILL 22096

2011年2月7日月曜日

待機しているセッションを調べる

DBサーバ作業中にコマンドが返ってこないなど問題のあるセッションを探すのに使うと効果的。
set time on
set pages 10000
set lines 110
col event for a60
col state for a18
col username for a15
col sid for 99999
select w.sid,s.username,w.state,w.event
from v$session s,v$session_wait w
where s.sid=w.sid
  and w.event not like '%Net message % client'
  and w.event not like 'rdbms ipc message';

   SID USERNAME   STATE                EVENT
------ ---------- -------------------- ----------------------------------------------------------
   536            WAITING              Streams AQ: qmn slave idle wait
   537            WAITING              Streams AQ: waiting for time management or cleanup tasks
   540            WAITING              Streams AQ: qmn coordinator idle wait
   548            WAITING              smon timer
   555            WAITING              pmon timer

セッションを一覧表示する

v$sessionは情報が多すぎるので用途によってクエリを使い分けると効果的。

1.接続元とログイン時間を中心に
SQL> 
set pages 10000
set lines 150
COLUMN USERNAME FORMAT a20
COLUMN STATUS FORMAT a10
COLUMN EVENT FORMAT a60
COLUMN PROGRAM FORMAT a50
COLUMN SID FORMAT 99999
alter session set nls_date_format='yyyy/mm/dd hh24:mi:ss';
select sid,serial#,program,username,logon_time,status
from v$session order by logon_time;

   SID    SERIAL# PROGRAM                                       USERNAME   LOGON_TIME          STATUS
------ ---------- --------------------------------------------- ---------- ------------------- ----------
   547          1 oracle@snwdb0.smc.indexweb.co.jp (RECO)                  2011/02/07 12:57:00 ACTIVE
   554          1 oracle@snwdb0.smc.indexweb.co.jp (PSP0)                  2011/02/07 12:57:00 ACTIVE
   553          1 oracle@snwdb0.smc.indexweb.co.jp (MMAN)                  2011/02/07 12:57:00 ACTIVE
   552          1 oracle@snwdb0.smc.indexweb.co.jp (DBW0)                  2011/02/07 12:57:00 ACTIVE
   544          1 oracle@snwdb0.smc.indexweb.co.jp (MMNL)                  2011/02/07 12:57:00 ACTIVE
   545          1 oracle@snwdb0.smc.indexweb.co.jp (MMON)                  2011/02/07 12:57:00 ACTIVE
   546          1 oracle@snwdb0.smc.indexweb.co.jp (CJQ0)                  2011/02/07 12:57:00 ACTIVE
   555          1 oracle@snwdb0.smc.indexweb.co.jp (PMON)                  2011/02/07 12:57:00 ACTIVE
   548          1 oracle@snwdb0.smc.indexweb.co.jp (SMON)                  2011/02/07 12:57:00 ACTIVE
   549          1 oracle@snwdb0.smc.indexweb.co.jp (CKPT)                  2011/02/07 12:57:00 ACTIVE
   550          1 oracle@snwdb0.smc.indexweb.co.jp (LGWR)                  2011/02/07 12:57:00 ACTIVE
   551          1 oracle@snwdb0.smc.indexweb.co.jp (DBW1)                  2011/02/07 12:57:00 ACTIVE
   540          7 oracle@snwdb0.smc.indexweb.co.jp (QMNC)                  2011/02/07 12:57:10 ACTIVE
   537          2 oracle@snwdb0.smc.indexweb.co.jp (q000)                  2011/02/07 12:57:20 ACTIVE
   536          4 oracle@snwdb0.smc.indexweb.co.jp (q001)                  2011/02/07 12:57:20 ACTIVE
   527      19899 sqlplus@codev0.smc.indexweb.co.jp (TNS V1-V3) PERFSTAT   2011/02/07 23:23:39 ACTIVE

2.実行中のイベントを中心に
SQL> 
set pages 10000
set lines 120
COLUMN USERNAME FORMAT a20
COLUMN STATUS FORMAT a10
COLUMN EVENT FORMAT a60
COLUMN SID FORMAT 99999
alter session set nls_date_format='yyyy/mm/dd hh24:mi:ss';
select sid,serial#,username,event from v$session order by logon_time;

   SID   SERIAL# USERNAME   EVENT
------ ---------- ---------- ------------------------------------------------------------
   547         1            rdbms ipc message
   554         1            rdbms ipc message
   553         1            rdbms ipc message
   552         1            rdbms ipc message
   544         1            rdbms ipc message
   545         1            rdbms ipc message
   546         1            rdbms ipc message
   555         1            pmon timer
   548         1            smon timer
   549         1            rdbms ipc message
   550         1            rdbms ipc message
   551         1            rdbms ipc message
   540         7            Streams AQ: qmn coordinator idle wait
   537         2            Streams AQ: waiting for time management or cleanup tasks
   536         4            Streams AQ: qmn slave idle wait
   527     19899 PERFSTAT   SQL*Net message to client

パフォーマンスツールSTATSPACKの利用

STATSPACKは、定期的に取得したスナップショットからDBのパフォーマンス値を取得するツールです。
スナップショットの差分により、v$sysstatなどのように累積値で記録している値の動きをとらえることができます。

1.STATSPACK用表領域の作成
CREATE TABLESPACE PERFSTAT_DATA
  DATAFILE '/DATA/DATABASE/PERFSTAT_DATA.DBF' SIZE 1024M REUSE AUTOEXTEND ON
  EXTENT MANAGEMENT LOCAL UNIFORM SIZE 1M
  SEGMENT SPACE MANAGEMENT AUTO;

2.STATSPACKのインストール
インストール用のコマンドで作成します。
$ sqlplus sys as sysdba
SQL> @$ORACLE_HOME/rdbms/admin/spcreate.sql
default_tablespaceに値を入力してください: PERFSTAT_DATA ★作成した表領域名
Using tablespace PERFSTAT_DATA as PERFSTAT default tablespace.

Choose the PERFSTAT user's Temporary tablespace.

TABLESPACE_NAME
--------------------------------------------------------------------------------
CONTENTS                    DB DEFAULT TEMP TABLESPACE
--------------------------- --------------------------
TEMP
TEMPORARY                   *

temporary_tablespaceに値を入力してください: TEMP

3.スナップショットの作成
スナップショット間隔が短いほど精度は上がります。
ただし、スナップショットの作成には負荷がかかるので1時間ごとが目安です。

$ sqlplus perfstat@SSS01DB
SQL> execute statspack.snap

セグメント(テーブル等)の情報も欲しい時は、スナップショットレベルを7以上にします。
SQL> execute statspack.snap(i_snap_level => 7) 

4.スナップショットの確認
STATSPACKはスナップショットの「差分」で生成するので、スナップショットが2つ以上必要です。
SQL> select snap_id, snap_time from stats$snapshot;

 SNAP_ID   SNAP_TIM
 --------- -----------------
         1 09-10-27 11:50:02
         2 09-10-27 11:50:18

5.STATSPACKレポートの作成
レポート出力用のコマンドを使ってレポートを作成します。
$ sqlplus perfstat@SSS01DB
SQL> @$ORACLE_HOME/rdbms/admin/spreport.sql;
Current Instance
~~~~~~~~~~~~~~~~

   DB Id    DB Name      Inst Num Instance
----------- ------------ -------- ------------
  190003545 SSS01DEV            1 sss01dev
                      :
Instance     DB Name        Snap Id   Snap Started    Level Comment
------------ ------------ --------- ----------------- ----- --------------------
sss01dev     SSS01DEV             1 27 10月 2009 15:2     5
                                    7
                                  2 27 10月 2009 15:3     5
                                    1

Specify the Begin and End Snapshot Ids
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
begin_snapに値を入力してください: 1 ★開始スナップショットID
Begin Snapshot Id specified: 1

end_snapに値を入力してください: 2 ★終了スナップショットID
End   Snapshot Id specified: 2

Specify the Report Name
~~~~~~~~~~~~~~~~~~~~~~~
The default report file name is sp_1_2.  To use this name,
press  to continue, otherwise enter an alternative.

report_nameに値を入力してください:  ★改行あるいは任意のファイル名

6.スナップショットの削除
スナップショットは削除しないと貯まり続けるので、適度に削除します。
スナップショット単位で削除すると負荷上昇やUNDO消費の原因になるので注意が必要です。

6-1.スナップショット単位で削除
$ sqlplus perfstat@SSS01DB
SQL> @?/rdbms/admin/sppurge
(削除開始スナップID):1
(削除終了スナップID):2

6-2.まるごと削除
$ sqlplus perfstat@SSS01DB
SQL> @?/rdbms/admin/sptrunc

SQL> select count(*) from stats$snapshot;
→ゼロ件であることを確認できます。