【Oracle】実行トレース取得

Oracleの実行計画を取得した時のメモ。

sqlplus DBユーザ名/DBパス名@サービス名

SQLPlusにログイン後に測定したいSQLを投げる。

ALTER SESSION SET SQL_TRACE=TRUE;
SELECT COMPANY_CD, USER_ID, SLIP_NO FROM TEST_TBL;
ALTER SESSION SET SQL_TRACE=FALSE;
exit;

tkprofコマンドでトレースファイルから実行計画を取得する。

# DIAGNOSTIC_DESTの初期化パラメータによる
cd $ORACLE_HOME/diag/rdbms/DB名/インスタンス名/trace
# 実行計画を取得
tkprof トレースファイル名 出力ファイル名 explain=DBユーザ名/DBパス名

tkprofはオプションでパフォーマンスの悪い順に並べたりできるようです。

【Oracle】データエクスポートとインポート

Oracleデータ復旧をメモしたので、
ついにでOracleデータエクスポートとインポートメモ。

#!/bin/sh
# 環境設定
DB_INF="DBユーザ名/DBパスワード@サービス名"
# エクスポート
exp ${DB_INF} FILE=[テーブル名].dmp LOG=[テーブル名].log TABLES=([テーブル名]) ROWS=Y INDEXES=Y GRANTS=Y CONSTRAINTS=Y STATISTICS=NONE TRIGGERS=N QUERY="WHERE [カラム名] = '[値]' "
#!/bin/sh
# 環境設定
DB_INF="DBユーザ名/DBパスワード@サービス名"
# インポート
imp ${DB_INF} FILE=[テーブル名].dmp LOG=[テーブル名].log TABLES=([テーブル名]) ROWS=Y INDEXES=Y GRANTS=Y CONSTRAINTS=Y STATISTICS=NONE

オプション一部整理。

  • 実行モード
    FULL/OWNER/TABLES

    FULL:データベース指定
    OWNER:ユーザ指定
    TABLES:テーブル指定
    
  • 移行対象
    ROWS/INDEXES/GRANTS/CONSTRAINTS/TRIGGERS/STATISTICS/TRIGGERS

    ROWS:表データ移行フラグ、Nにすると表定義のみ(デフォルト:Y)
    INDEXES:索引移行フラグ(デフォルト:Y)
    GRANTS:権限移行フラグ(デフォルト:Y)
    CONSTRAINTS:制約移行フラグ(デフォルト:Y)
    STATISTICS:統計情報移行フラグ、移行したくない場合はNONEを指定
    TRIGGERS:トリガー移行フラグ、エクスポート時のみ指定可能(デフォルト:Y)
    
  • その他

    QUERY:エクスポート条件条件
    

【Oracle】データ復旧

Oracleのデータ復旧メモ。
TEST_TBLからデータを削除してコミットしてしまったけど復旧したい。

1.バックアップしたデータからの復旧(全てのバージョン)
2.ログ・マイナーを使用した復旧(Oracle8i以降)
3.フラッシュバック・クエリを使用した復旧(Oracle9i以降)

フラッシュバック・クエリの例を記載します。

CREATE TABLE TMP_TEST_TBL AS SELECT COMPANY_CD, USER_ID, SLIP_NO,
TO_DATE(TO_CHAR(UPD_DT, 'YYYY/MM/DD HH24:MI:SS'), 'YYYY/MM/DD HH24:MI:SS') AS UPD_DT
FROM TEST_TBL AS OF TIMESTAMP (SYSTIMESTAMP - INTERVAL '100' MINUTE);

100分前の状態に戻します。
「AS OF TIMESTAMP」句からフラッシュバック・クエリとなっている。
「SYSTIMESTAMP」はシステムの日時を戻す関数なので、
「SYSTIMESTAMP」から「INTERVAL ‘100’ MINUTE」を引くことで「今から100分前」を表している。
「INTERVAL」には「MINUTE」の他にも「HOUR」や「DAY」を扱えるが、遡るのに限度はあるようです。

INSERT INTO TEST_TBL SELECT COMPANY_CD, USER_ID, SLIP_NO,
TO_DATE(TO_CHAR(UPD_DT, 'YYYY/MM/DD HH24:MI:SS'), 'YYYY/MM/DD HH24:MI:SS') AS UPD_DT
FROM TMP_TEST_TBL

これで助かったことがあるので、メモ。

【Oracle】実行中のセッションとSQL

実行中のセッションとSQLを確認します。

  • 実行中のセッション

    SELECT SID, SERIAL#, USERNAME, STATUS, MACHINE, PROGRAM, SQL_ID FROM V$SESSION WHERE USERNAME IS NOT NULL AND SID != USERENV('SID');
    
  • 実行中のSQL

    SELECT SQL_TEXT FROM V$SQLTEXT WHERE SQL_ID='実行中のセッションで確認したSQLIDを指定する。';
    

【Oracle】インスタンスの起動停止とリスナーの起動停止

Oracleのインスタンスの起動停止とリスナーの起動停止の方法です。

  • インスタンス起動

    su - oracle
    ※パスワードなし
    sqlplus / as sysdba
    
    startup
    

    以下の内容が画面に出力されます。

    ORACLEインスタンスが起動しました。
    
    Total System Global Area  413372416 bytes
    Fixed Size                  2227040 bytes
    Variable Size             306185376 bytes
    Database Buffers          100663296 bytes
    Redo Buffers                4296704 bytes
    データベースがマウントされました。
    データベースがオープンされました。
    
  • リスナー起動

    su - oracle
    ※パスワードなし
    lsnrctl start listener
    

    listenerを省略するとデフォルトリスナーを指定したことになります。

  • リスナー停止

    su - oracle
    ※パスワードなし
    lsnrctl stop listener
    

    listenerを省略するとデフォルトリスナーを指定したことになります。

  • インスタンス停止

    su - oracle
    ※パスワードなし
    sqlplus / as sysdba
    
    shutdown
    

    以下の内容が画面に出力されます。

    データベースがクローズされました。
    データベースがディスマウントされました。
    ORACLEインスタンスがシャットダウンされました。
    
  • インスタンス停止(セッションがすべてINCACTIVEになるのを待つ場合)
    immediateをつけることで以下の動作となる。

    新しい接続は許可されず、新しいトランザクションは開始できません。
    すべての未コミットのトランザクションは、ロールバックされます。
    現在データベースに接続しているユーザーが切断されるのを待機しません。
    既存の接続を全て切断しますが、SQL実行中やロールバック中などのアクティブなセッションが存在すると、その完了を待機します。
    1時間たっても完了しない場合、「ORA-01013」が発生する。
    

    「ORA-01013」が発生すると既に新規セッションを受け付けていないため、
    どのセッションが残っているのか調査が難しいため、セッションが残っているかを確認してからの方が良い。

    shutdown immediate
    
  • インスタンス停止(ACTIVEやKILLEDセッションが合っても強制終了したい場合)

    shutdown abort
    

【LDAP】LDAP操作

LDAP操作に関するメモ。

  • データ抽出

    ldapsearch -h IPアドレス -p ポート番号 -1 -B -F ": " -D cn=XXXXX -w パスワード -z 0 -b o=YYYYY, c=ZZ "(&(objectClass=テーブル名)(属性名=値))" >> result.ldif
    

    オプション補足。

    -h:IPアドレスを指定
    -p:ポート番号を指定
    -1:なんだっけこれ
    -B:BASE64をデコード
    -F:属性名と値との間に指定文字列を出力
    -D:バインドするdnを指定
    -w:パスワードを指定
    -z:検索のサイズ言語を指定(0で制限なし?)
    -b:基本識別名を指定
    
  • dnごと削除

    dn: 属性名=値, ou=AAAAA, o=YYYYY,  c=ZZ
    changetype: delete
    
  • dnの属性を削除

    dn: 属性名=値, ou=AAAAA, o=YYYYY,  c=ZZ
    changetype: modify
    delete:属性名
    
  • dnの属性の値を削除

    dn: 属性名=値, ou=AAAAA, o=YYYYY,  c=ZZ
    changetype: modify
    delete:属性名
    属性名:値
    

    属性がマルチバリューの場合、特定の値のみを削除できる。

  • dnに属性を追加

    dn: 属性名=値, ou=AAAAA, o=YYYYY,  c=ZZ
    changetype: modify
    add:属性名
    属性名:値
    
  • 属性の値を書き換え

    dn: 属性名=値, ou=AAAAA, o=YYYYY,  c=ZZ
    changetype: modify
    replace:属性名
    属性名:値
    

    replaceする属性がない場合、addと同じ動作になる。

  • dnを追加

    dn: 属性名=値, ou=AAAAA, o=YYYYY,  c=ZZ
    changetype: add
    objectClass: テーブル名
    objectClass: top
    属性名1:値1
    属性名2:値2
    ・・・略
    

    changetypeがmodifyではなく、addになっている。

【Oracle】Oracle導入

  • Oracle取得
    Oracleを導入したくなったので、VMware上のCentOSに導入します。
    導入するバージョンは「Oracle Database XE」です。
    Oracle 11gの無料版でLinuxは64bit版のみのようです。

    インストールするのにCentOSに下記が必要。

    glibcは2.3.4-2.41以上
    makeは3.80以上
    binutilsは2.16.91.0.5以上
    gccは4.1.2以上
    libaioは0.3.104以上
    
  • Oracle導入
    yumコマンドでインストール済のパッケージを全て確認します。

    yum list installed
    
    glibc.x86_64            2.12-1.107.el6_4.5
    make.x86_64             1:3.81-20.el6
    binutils.x86_64         2.20.51.0.2-5.36.el6
    gcc.x86_64              4.4.7-3.el6
    libaio.x86_64           0.3.107-10.el6
    

    問題なしということで、インストール作業を進めます。
    このOracleは外とは繋がないので、専用ユーザは作成せずにいきました。

    Linux64bit版のzipファイルをCentOSにアップロードします。

    cd /home/ユーザ名/oracle
    unzip oracle-xe-11.2.0-1.0.x86_64.rpm.zip
    

    Disk1ディレクトリの中に解凍されているので、
    中にあるrpmパッケージをインストールします。

    cd Disk1
    rpm -ivh oracle-xe-11.2.0-1.0.x86_64.rpm
    
    準備中...                ########################################### [100%]
    
    This system does not meet the minimum requirements for swap space.  Based on
    the amount of physical memory available on the system, Oracle Database 11g
    Express Edition requires 1976 MB of swap space. This system has 1854 MB
    of swap space.  Configure more swap space on the system and retry the
    installation.
    
    エラー: %pre(oracle-xe-11.2.0-1.0.x86_64) scriptlet failed, exit status 1
    エラー:   install: スクリプト %pre の実行に失敗しました (2)。oracle-xe-11.2.0-1.0 をスキップします。
    

    失敗・・・。
    スワップ領域が不足しているようです。。
    スワップ領域を調べてみることに。

    swapon -s
    

    既にいくつかスワップ領域を消費していました。
    ずっとサスペンドだったからでしょうか。
    再起動するとスワップ領域の消費が0になりました。
    というわけで、再度インストールします。

    cd Disk1
    rpm -ivh oracle-xe-11.2.0-1.0.x86_64.rpm
    
    準備中...                ########################################### [100%]
       1:oracle-xe              ########################################### [100%]
    Executing post-install steps...
    You must run '/etc/init.d/oracle-xe configure' as the root user to configure the database.
    

    無事インストールできました。

  • Oracle導入後の設定
    次に「/etc/init.d/oracle-xe configure」を実行しろと記載があるので、実行します。

    /etc/init.d/oracle-xe configure
    

    ポート:XXXX(デフォルトの8080は他と競合しそうなので変えました。)
    リスナー:1522(気分で変えました。)
    DBパスワード:パスワード
    OS起動時に自動起動:y

    Oracleの環境変数は下記で確認できます。

    view /u01/app/oracle/product/11.2.0/xe/bin/oracle_env.sh
    

    Oracleを使うユーザに適用しておきます。

    vi /etc/profile
    
    下記内容を最終行に追加
    . /u01/app/oracle/product/11.2.0/xe/bin/oracle_env.sh
    
  • Oracle導入後の動作確認(サーバ側)
    TeraTermを再起動し、「/etc/profile」を読み込みなおし、
    動作確認を行います。
    インストール時にOracleユーザとしてsystemが作られています。

    sqlplus system/パスワード@サービス名
    

    SQLに接続できれば成功です。
    インストール時のファイルを削除しておきます。

    rm -fr /home/ユーザ名/oracle
    

    無料版なのにプロシージャまで試せるようなので、なかなか満足です。
    インストール手順詳細は下記参照。
    http://docs.oracle.com/cd/E36055_01/install.112/b66469/toc.htm#CIHHJEHF

  • Oracle導入後の動作確認(クライアント側)
    VMwareをインストールしているPCにもOracleクライアントをインストールし
    sqlplusで接続できるように
    サーバ側のリスナーポートを開放しておきます。

    iptables -I INPUT 23 -p tcp -m tcp --dport 1522 -j ACCEPT
    

    23は「iptables -L –line-numbers」で確認し、
    挿入したい行番号の次番号を指定しました。

VMwareの仮想PCネットワーク構成

やはり気になってしまい、見直してみました。
RaspbainとCentOSですが、そもそもネットワークが繋がっているのかと
Raspbainからpingを飛ばしてみました。

ping CentOSのIP
PING XXX.XXX.XXX.XXX (XXX.XXX.XXX.XXX) 56(84) bytes of data.
From ZZZ.ZZZ.ZZZ.ZZZ icmp_seq=5 Destination Host Unreachable

「Destination Host Unreachable」はIPに該当するマシンはあるけど
到達できないことを示しているようです。
メインPCからは何も考えずに接続できてるから意識してませんでしたが、
そもそもRaspbainとCentOSはネットワークが異なる場所に存在・・・。

ルーター:192.168.XX.1
メインPC:192.168.XX.2
Raspbain:192.168.XX.3
VMnet8(メインPCのVMWare用アダプタ):192.168.YY.1
CentOS:192.168.YY.2

調べてみるとVMWare上のゲストOSはNAT接続からブリッジ接続にかえると
メインPCと同じネットワーク上(192.168.XX.x)に持ってこれるようです。

ただしゲストOSから外部に接続しようとした場合、
ブリッジ接続にかえたことで通信時に仮想MACアドレスを利用するので、
ルーターから不正扱い受けたりすることもあるそうですが、
ゲストOSでは外部に接続する予定はないので無視。

【変更前】

ルーター (192.168.XX.1)
 ├ メインPC (192.168.XX.2) ─ VMnet8 (192.168.YY.1)
 │                └ CentOS (192.168.YY.2)
 └ Raspbain (192.168.XX.3)

【変更後】

ルーター (192.168.XX.1)
 ├ メインPC (192.168.XX.2)
 ├ Raspbain (192.168.XX.3)
 └ CentOS (192.168.XX.4)

【設定方法】

VMWareの[Player]-[取外し可能デバイス]-[ネットワークアダプタ]-[設定]を選択。
ネットワーク接続で「NAT」から「ブリッジ」のラジオボタンを選択。
「アダプタの設定」ボタンを押下する。
利用しているNICにチェックを入れ「OK」ボタンを押下。
最後に「OK」ボタンを押下。
ホストOS、ゲストOSともに再起動する。

これでRaspbainからCentOSにpingが飛んだので、再度昨日の設定を復活させ
Webアプリに繋いでみたところ、Tomcatの処理だけCentOSで処理できました。

ルーター:これまで通り80、443をRaspbainに向けているだけで、8009の設定不要。
Raspbain:FWそのまま。
CentOS:FWで80のポートを開ける。8009の設定不要。

平日はCentOS立ち上げていないので、
結局Raspbainだけで処理するわけですが、色々満足しました。

【Eclipse】Eclipseのwarファイル出力

プロジェクトを右クリックし、エクスポートから「Web」-「WARファイル」を選択。
Webプロジェクト名:任意名
宛先:任意の出力ファイル名

画面に従いそのままwarファイルを出力しようとすると
「モジュール名が無効です。」とエラーが出て出力できない・・・。
原因はTomcatプロジェクトになっているからで、
動的Webプロジェクトに変更すれば良いので、手順をメモしておきます。

プロジェクトを右クリックし、プロパティから「プロジェクト・ファセット」を選択。
変な英字リンクをクリックするとチェックボックスがたくさんある画面が開くので、
「Xdoclet付き動的Webプロジェクト」を選択してから下記の通り修正。

Java:1.7 バージョンを変更しました。
JavaScript:1.0 チェックボックスを付けました。
WebDoclet:チェックボックスを外しました。
動的Webモジュール:2.4

上記設定を行い、「適用」ボタン押下。
設定が完了するとプロジェクトに地球儀がついて、warファイル出力が出来るように。

ついでにjarファイルの配置メモ。

Tomcatプロジェクト:「ファイル」-「新規」-「その他」-「Java」-「Tomcatプロジェクト」

【配置jarファイル】
(1) JREシステムライブラリー7.0
(2) eclipseJP-tomcat-7.0-lib
  ⇒jsp-api.jarファイルやel-api.jarファイル
(3) eclipseJP-workspace-プロジェクト名-WEB-INF-lib
  ⇒poiやmysqlのjarファイル

【Javaのビルド・パス】
(1)、(2)、(3)
動的Webプロジェクト:「ファイル」-「新規」-「動的Webプロジェクト」

【配置jarファイル】
(1) JREシステムライブラリー7.0
(2) WebAppライブラリー
  ⇒(4)と(5)のjarファイル、warファイルをエクスポート時にも利用
(3) EARライブラリー
  ⇒配置なし
(4) eclipseJP-tomcat-7.0-lib
  ⇒jsp-api.jarファイルやel-api.jarファイル
(5) eclipseJP-workspace-プロジェクト名-WEB-INF-lib
  ⇒poiやmysqlのjarファイル

【Javaのビルド・パス】
(1)、(2)、(3)

【Java】ApachePOI

自社出勤簿はExcel管理されており、毎月月末に入力するのが面倒なので
Webから退社時刻だけ入力したら自社出勤簿に保存されるようにPOIを使ってみることに。
利用したPOIは「poi-bin-3.10.1-20140818」です。

自社出勤簿はいまだにExcel2003なのでHSSFXXXのオブジェクトを利用します。
両方を扱えるインターフェースもあるようです。

HSSFXXX:Excel2003のファイルフォーマット(.xls)を扱うオブジェクト
XSSFXXX:Excel2007のファイルフォーマット(.xlsx)を扱うオブジェクト
// Excelファイル取得
POIFSFileSystem filein = new POIFSFileSystem(new FileInputStream(String 入力ファイルのフルパス));

// ワークブック取得
HSSFWorkbook wb = new HSSFWorkbook(filein);
// シート取得
HSSFSheet sheet = wb.getSheet(String シート名);
// 行数取得
HSSFRow row = sheet.getRow(int 行数);

// 列取得(出社時刻用)
HSSFCell cellFirst = row.getCell(int 列数);
// 出社時刻設定
cellFirst.setCellValue(double 出社時刻);

// 列取得(退社時刻用)
HSSFCell cellEnd = row.getCell(int 列数);
// 退社時刻設定
cellEnd.setCellValue(double 退社時刻);

// ワークブック強制再計算
wb.setForceFormulaRecalculation(true);
// Excelファイル保存
wb.write(new FileOutputStream(String 出力ファイルのフルパス));

出社時刻、退社時刻をdouble型にしている理由ですが、
自社出勤簿の出社時刻、退社時刻はExcelのセルを確認すると
ユーザ定義で「h:mm」の時刻形式で、当日勤務時間や残業時間は自動計算されるようになっています。

Excelを使って入力した場合、下記の通りの表示となり、
画面表示:9:00 18:00
セル内値:9:00:00 18:00:00
出勤簿計算結果:正常

それと同じ画面表示、セル内値にしたいので、
Excel側にはシリアル値(1900年1月1日を1として算出した数値)を渡す必要があり、
double型をsetCellValueに渡しています。

// 時
double hh = Double.parseDouble("0900".substring(0,2))*(1.0/24.0);
// 分
double mm = Double.parseDouble("0900".substring(2,4))*(1.0/24.0/60.0);

setCellValueは受け取れる型が下記の通り複数あるので、StringとDateで試してみました。
java.lang.String
java.util.Date
java.util.Calendar
double
boolan
RichTextString

【お試し:String】

cellFirst.setCellValue("09:00");
cellEnd.setCellValue("18:00");

画面表示:09:00 18:00
セル内値:09:00 18:00
出勤簿計算結果:正常
⇒画面表示とセル内値がちょっと違う。

【お試し:Date】

SimpleDateFormat hhmmFormat = new SimpleDateFormat("h:mm");
cellFirst.setCellValue(hhmmFormat.parse("09:00"));
cellEnd.setCellValue(hhmmFormat.parse("18:00"));

画面表示:613655:00 613674:00
セル内値:1970/1/1 9:00:00 1970/1/1 18:00:00
出勤簿計算結果:正常
⇒何か色々違う