MyDumperを使ってみた
MySQLのデータインポートツールMyDumper
を試したのでメモ。
- mysqldump・・・データのエクスポート・インポートをシングルスレッドで実行
- mydumper・・・データのエクスポート・インポートをパラレルスレッドで実行
エクスポートしたファイルごとにパラレルで実行する。デフォルトはテーブル単位でパラレル化。
巨大なテーブルがあればデータをチャンクごとに分けファイルを分散することで高速に実行してくれる。
インストール
- yumでインストール
yum install https://twindb.com/twindb-release-latest.noarch.rpm yum install mydumper
- 確認
$ mydumper --version mydumper 0.6.2, built against MySQL 5.6.25
もし、libmysqlclient.so.18
がないよ。って言われた場合はyumでMySQL5.6をインストール(5.1ではだめ)。
または、libmysqlclient.so.18
がある場所にLD_LIBRARY_PATH
で設定。
コマンド
- mydumper・・・export用コマンド
- myloader・・・import用コマンド
試す
DB容量:280G(内130Gが1つのテーブル)
export DB設定
- MySQL5.6
- stop slaveして実行する
import DB設定
EXPORT
- 10スレッドでGZ圧縮してチャンクサイズ10000000行で取得。
注意:exportはスキーマの指定はフルまたは1つのスキーマになってしまうので複数スキーマを指定することはできない。
-Tオプションでテーブル単位で指定可能。information_schema.tables
で複数のスキーマから取得する方法を教わったのでそちらで実行。
time mydumper -u root -p 'xxxxxxx' -S /var/lib/mysql/mysql.sock -e -t 10 -c -o /tmp/dump_dir -r 10000000 -s 5000000 -T $(mysql -sse"set group_concat_max_len=10240; select aa from (select 1,group_concat(concat(table_schema,'.',table_name)) as aa from information_schema.tables where table_schema in ('main','sub1','sub2','sub3','sub4') group by 1) a") real 43m41.139s user 220m16.990s sys 3m0.312s
約44分
- 1スレッドかつチャンク分けなしでやった場合は約4時間20分かかった。
出力ファイル確認
できたファイルはこんな感じで分かれている。
$ ls -ltr /tmp/dump_dir 合計 45721788 ・ ・ -rw-rw-r-- 1 mysql mysql 679 6月 1 16:00 2016 main.table1.sql.gz -rw-rw-r-- 1 mysql mysql 169 6月 1 16:00 2016 main.table2.sql.gz -rw-rw-r-- 1 mysql mysql 185 6月 1 16:00 2016 main.table3.sql.gz -rw-rw-r-- 1 mysql mysql 76932 6月 1 16:00 2016 main.table4.sql.gz -rw-rw-r-- 1 mysql mysql 208327 6月 1 16:00 2016 main.table5.sql.gz -rw-rw-r-- 1 mysql mysql 1505960 6月 1 16:00 2016 sub1.subtable1.sql.gz -rw-rw-r-- 1 mysql mysql 768276450 6月 1 16:06 2016 sub1.subtable2.00000.sql.gz -rw-rw-r-- 1 mysql mysql 750226866 6月 1 16:06 2016 sub1.subtable2.00001.sql.gz -rw-rw-r-- 1 mysql mysql 770132442 6月 1 16:07 2016 sub1.subtable2.00002.sql.gz
通常はテーブル単位でのファイルだが、チャンク分けしていると連番でファイルも分かれている。
- スレーブとして起動したい場合は
metadata
ファイルを確認するとポジション情報が記載してある
$ vim /tmp/dump_dir/metadata 1 Started dump at: 2016-06-01 16:00:13 2 SHOW MASTER STATUS: 3 Log: mysql-bin.000275 4 Pos: 120 5 6 SHOW SLAVE STATUS: 7 Host: 192.168.1.2 8 Log: mysql-bin.000438 9 Pos: 944084446 10 11 Finished dump at: 2016-06-01 16:39:00
IMPORT
- 16スレッドで実行
$ time myloader -d /tmp/dump_dir -u root -p 'xxx' -S /var/lib/mysql/mysql.sock -t 16 real 525m31.015s user 299m14.828s sys 3m8.467s
約8時間45分
- チャンク分けなしのものを16スレッドで実行した場合。 結局全DB量の半分近くを占めているテーブルがシングル実行になるので遅い。
$ time myloader -d /tmp/dump_dir -u root -p 'xxx' -S /var/lib/mysql/mysql.sock -t 16 real 1541m14.572s user 245m43.989s sys 2m23.104s
約25時間
よって、チャンク分けをうまくすればmydumper結構使える。
注意
- ibdata1のサイズが大きくなる。
50%はinsert bufferが占めていた。セカンダリインデックスを後で貼るようにしてくれたらいいのにな。
*8.1G* 6月 3 01:01 2016 ibdata1 こうなるので注意。
OEM再作成のエラー対処方法
RMANで別ホストに移行した時にOEMの作成でいろいろ嵌ったのでメモ。
emca -config dbcontrol db -repos recreate実行時
パターン1
設定: ORA-01031: ???????-?????????? ・ ・ ・ 2014/10/09 9:58:40 oracle.sysman.emcp.util.GeneralUtil initSQLEngineLoacly 設定: SQLEngine created successfully and connected 2014/10/09 9:58:40 oracle.sysman.emcp.ParamsManager checkListenerStatusForDBControl 設定: ORA-01031: ???????-?????????? 2014/10/09 9:58:40 oracle.sysman.emcp.EMConfig perform 情報: この操作は/opt/app/oracle/cfgtoollogs/emca/orcl/emca_2014_10_09_09_57_46.logでロギングされています。 2014/10/09 9:58:40 oracle.sysman.emcp.EMConfig perform 致命的: リスナーが起動していないか、データベース・サービスがリスナーに登録されていません。リスナーを起動し、データベース・サービスを登録し、EM Configuration Assistantを再度実行してください。 詳細は、/opt/app/oracle/cfgtoollogs/emca/orcl/emca_2014_10_09_09_57_46.logにあるログ・ファイルを参照してください。 構成を完了できませんでした。 詳細は、/opt/app/oracle/cfgtoollogs/emca/orcl/emca_2014_10_09_09_57_46.logにあるログ・ファイルを参照してください。
- 設定: ORA-01031: ???????-??????????→権限が不足しているエラー
- パスワードファイルがなかったのでをコピーまたは作成してあげて再実行
パターン2
・ ・ 2014/10/14 18:59:33 oracle.sysman.emcp.ParamsManager getLocalListener 警告: oracle-test-dbのリスナーを取得中にエラーが発生しました 2014/10/14 18:59:37 oracle.sysman.emcp.util.DBControlUtil secureDBConsole 情報: Database Controlの保護中(少し時間がかかります)... ・ ・
- listener.oraからデフォルトリスナーLISTENER(1521)の記述がなかった。
パターン3
2014/10/14 18:59:37 oracle.sysman.emcp.util.DBControlUtil secureDBConsole 情報: Database Controlの保護中(少し時間がかかります)... 2014/10/14 18:59:41 oracle.sysman.emcp.util.PlatformInterface executeCommand 警告: /opt/app/oracle/product/11.2.0.4/dbhome_1/bin/emctl secure dbconsole -host oracle-test-db -sid orcl の実行中のエラ ー 2014/10/14 18:59:41 oracle.sysman.emcp.EMDBPostConfig performConfiguration 警告: Database Controlの保護中にエラーが発生しました。 2014/10/14 18:59:41 oracle.sysman.emcp.EMDBPostConfig setWarnMsg 情報: Database Controlの保護中にエラーが発生しました。Database Controlが非セキュア・モードで起動されています。Database Controlを保護するには、次のコマンドを実行してください。 1) 環境変数ORACLE_UNQNAMEを一意のデータベース名に設定します 2) /opt/app/oracle/product/11.2.0.4/dbhome_1/bin/emctl stop dbconsole 3) /opt/app/oracle/product/11.2.0.4/dbhome_1/bin/emctl config emkey -repos -sysman_pwd < SYSMANユーザーのパスワード > 4) /opt/app/oracle/product/11.2.0.4/dbhome_1/bin/emctl secure dbconsole -sysman_pwd < SYSMANユーザーのパスワード > 5) /opt/app/oracle/product/11.2.0.4/dbhome_1/bin/emctl start dbconsole EMキーを保護するには、/opt/app/oracle/product/11.2.0.4/dbhome_1/bin/emctl config emkey -remove_from_repos -sysman_pwd < SYSMANユーザーのパスワード >を実行します 2014/10/14 18:59:41 oracle.sysman.emcp.util.DBControlUtil startOMS 情報: Database Controlの起動中(少し時間がかかります)... 2014/10/14 18:59:51 oracle.sysman.emcp.EMDBPostConfig performConfiguration 情報: Database Controlは正常に起動されました 2014/10/14 18:59:51 oracle.sysman.emcp.EMDBPostConfig performConfiguration 情報: >>>>>>>>>>> Database ControlのURLはhttp://oracle-test-db:1158/emです <<<<<<<<<<< Database Controlの保護中にエラーが発生しました。Database Controlが非セキュア・モードで起動されています。Database Controlを保護するには、次のコマンドを実行してください。 1) 環境変数ORACLE_UNQNAMEを一意のデータベース名に設定します 2) /opt/app/oracle/product/11.2.0.4/dbhome_1/bin/emctl stop dbconsole 3) /opt/app/oracle/product/11.2.0.4/dbhome_1/bin/emctl config emkey -repos -sysman_pwd < SYSMANユーザーのパスワード > 4) /opt/app/oracle/product/11.2.0.4/dbhome_1/bin/emctl secure dbconsole -sysman_pwd < SYSMANユーザーのパスワード > 5) /opt/app/oracle/product/11.2.0.4/dbhome_1/bin/emctl start dbconsole EMキーを保護するには、/opt/app/oracle/product/11.2.0.4/dbhome_1/bin/emctl config emkey -remove_from_repos -sysman_pwd < SYSMANユーザーのパスワード >を実行します
- OEMの起動はできたがレポジトリが壊れていて接続できなかった。
emca -deconfig dbcontrol db -repos drop
emca -config dbcontrol db -repos create
で解決
Oracle shrinkする上での注意点
Oracleを使用していると、断片化がつらい。
頻繁に更新しているインデックスの断片化が特につらい。
そして表領域を圧迫していく。。
そういう時にEnterpriseEditionであればindex rebuild online
なんてできるけど、
StandardEditionだとできないのでshrink
で対応。
以下のように記述する。
ALTER INDEX indexname SHRINK SPACE;
このshrinkはSEでもオンラインで可能なので、いいんですが注意が必要。
1. ディスク領域
アーカイブログが大量に出力されるのでディスク領域に注意が必要。
単純なディスクサイズの問題もあるし、もし高速リカバリエリアにアーカイブログを保存している場合は使用率の確認が必要。
高速リカバリエリアのサイズを確認しながら、またはdf
コマンドで確認しながらshrinkする。
- 確認SQL
>SELECT nvl(SUM(PERCENT_SPACE_USED),0) FROM v$flash_recovery_area_usage; NVL(SUM(PERCENT_SPACE_USED),0) ------------------------------ 32.86
2. UNDO領域の使用率
shrink中はUNDO領域の使用も大幅に増える。
UNDO領域を食い潰すと更新できずにセッションが詰まる、自動拡張にしていても拡張のタイミングで更新が待たされセッションが詰まる。
よって、UNDO領域の使用率がいっぱいにならないように確認しながら、UNDO領域のパージを待ったりして進める必要あり。
- 確認SQL
select to_char(sysdate,'YYYY/MM/DD HH24:MI:SS') "TIME", round("USED_SIZE(MB)", 3) "USED(MB)", round("TBS_SIZE(MB)", 3) "TBS(MB)", round("USED_SIZE(MB)"/"TBS_SIZE(MB)" * 100, 3) "USAGE(%)" from (select sum(BYTES)/1024/1024 "USED_SIZE(MB)" from DBA_UNDO_EXTENTS where STATUS in ('ACTIVE', 'UNEXPIRED') and TABLESPACE_NAME = 'UNDOTBS1') , (select sum(BYTES)/1024/1024 "TBS_SIZE(MB)" from DBA_DATA_FILES where TABLESPACE_NAME = 'UNDOTBS1') ;
SQLの参考
第28回 UNDO表領域の管理~保存期間の自動チューニング~
3. 解放時のロック
SHRINK SPACE
を実施してると断片化を解消している処理の間は行ロックなので、ほぼオンライン。
しかし、その空いたエクステントを解放するときはテーブルロックをとるので解放する領域が大きいとセッションが詰まってこれまた大変なことに。。。
SHRINK SPACE COMPACT
にすることで、エクステントを解放はせずに断片化だけ解消するのでセグメントのサイズは変わらないが、
空いた領域を再利用してくれるので増加は抑えられる。
または、SHRINK SPACE COMPACT
をしておいて、負荷の少ない時間帯に解放してあげるのが良い。
以上のことを踏まえて、うちではこの辺を自動化して運用してます。
RMANで同一サーバ上にデータベースを複製する
あるOracleDBを同一サーバ上に複製させるメモ。
環境は12cSE2。
現在、稼動中のインスタンス名をtestdb
、複製先DBをcopydb
とする。
準備
- 初期化パラメータをコピーして、リネーム
cp -p $ORACLE_HOME/dbs/inittestdb.ora $ORACLE_HOME/dbs/initcopydb.ora
- パスワードファイルコピー
cp -p $ORACLE_HOME/dbs/orapwtestdb $ORACLE_HOME/dbs/orapwcopydb
- 初期化パラメータの編集 コントロールファイルの場所であったり、SGAのサイズであったり調整する。
・ *.audit_file_dest='/opt/app/oracle/admin/copydb/adump' *.control_files='/opt/app/oracle/oradata/copydb/control01.ctl' ・
- 初期化パラメータで編集した存在しないディレクトリがあれば作成する
$ mkdir -p {/opt/app/oracle/admin/copydb/adump,/opt/app/oracle/oradata/copydb}
- /etc/oratabに記述して環境変数を変更しやすくしておく
$ vim /etc/oratab testdb:/opt/app/oracle/product/12.1.0/dbhome_1:N copydb:/opt/app/oracle/product/12.1.0/dbhome_1:N
複製する
静的リスナーを設定して起動、copydbにアクセスできるようにする
今回はLISTENER2
を作成。
vim $ORACLE_HOME/network/admin/listener.ora LISTENER2 = (DESCRIPTION_LIST = (DESCRIPTION = (ADDRESS = (PROTOCOL = TCP)(HOST = localhost)(PORT = 1522)) (ADDRESS = (PROTOCOL = IPC)(KEY = EXTPROC1522)) ) ) SID_LIST_LISTENER2= (SID_LIST= (SID_DESC= (SID_NAME=copydb) (ORACLE_HOME=/opt/app/oracle/product/12.1.0/dbhome_1) ) ) $ lsnrctl start LISTENER2 ・ ・ サービスのサマリー... サービス"copydb"には、1件のインスタンスがあります。 インスタンス"copydb"、状態UNKNOWNには、このサービスに対する1件のハンドラがあります... ・ ・
copydb
インスタンス起動
$ . oraenv ORACLE_SID = [testdb] ? copydb The Oracle base remains unchanged with value /opt/app/oracle $ sqlplus / as sysdba SQL> startup nomount; ORACLEインスタンスが起動しました。
RMANから接続してインスタンス起動
testdb
に接続。
$ . oraenv ORACLE_SID = [copydb] ? testdb $ rman target / ターゲット・データベース: TESTDB (データベースID=2695979559)に接続されました
copydb
に接続。パスワードファイルをコピーしておいたのでtestdb
と同じパスワード。
RMAN> connect auxiliary sys/oracle@localhost:1522/copydb 補助データベース: COPYDBに接続されました(マウントされていません)
複製開始する。
事前にデータファイルの場所を確認しておき、SET NEWNAME
で変更する。
RMAN> RUN { SET NEWNAME FOR DATAFILE 1 TO '/opt/app/oracle/oradata/copydb/system01.dbf'; SET NEWNAME FOR DATAFILE 3 TO '/opt/app/oracle/oradata/copydb/sysaux01.dbf'; SET NEWNAME FOR DATAFILE 4 TO '/opt/app/oracle/oradata/copydb/undotbs01.dbf'; SET NEWNAME FOR DATAFILE 5 TO '/opt/app/oracle/oradata/copydb/soe.dbf'; SET NEWNAME FOR DATAFILE 6 TO '/opt/app/oracle/oradata/copydb/users01.dbf'; SET NEWNAME FOR TEMPFILE 1 TO '/opt/app/oracle/oradata/copydb/temp01.dbf'; duplicate target database to copydb; } ・ ・ データベースがオープンしました。 作成したサーバー・パラメータ・ファイルを削除できません Duplicate Dbが完了しました(完了時間: 2016/07/04 22:17:17) ・ ・
これで完了できた。
オンラインREDOログの場所などは事前に指定してもいいし、あとでリネームしてもよい。
基表にSELECT権限がないVIEWに対して実行計画を取得する
基表に対してSELECT権限がないVIEWに対してEXPLAIN PLAN FOR
を使用して実行計画を取得しようとすると
SQL> explain plan for select * from test.test1_view; explain plan for select * from test.test1_view * 行1でエラーが発生しました。: ORA-01039: ビューの基礎オブジェクトに対する権限が不十分です。
基表にSELECT権限があればEXPLAIN PLAN FOR
も問題なくできますが、
基表にアクセスさせたくないためにVIEWしたので基表にSELECT権限付与することなく実行計画を取得する方法を考えた。
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR())
を使えばできることがわかった。
ただし、DBMS_XPLANパッケージを使用するにいくつかの動的ディクショナリビューにSELECT権限を付与することが必要。
DBMS_XPLANパッケージは、パッケージ所有者(SYS)ではなく、コール・ユーザーの権限で実行されます。テーブル・ファンクションDISPLAY_CURSORを使用するには、V$SQL_PLAN、V$SESSIONおよびV$SQL_PLAN_STATISTICS_ALL.の各固定ビューに対するSELECT権限が必要です。
DISPLAY_CURSOR機能を使用する場合、コール・ユーザーには、固定ビューV$SQL_PLAN_STATISTICS_ALL、V$SQLおよびV$SQL_PLANに対するSELECT権限が必要です。権限がない場合は、エラー・メッセージが表示されます。
権限を付与する。
grant select on V_$SESSION to texplain; grant select on V_$SQL_PLAN to texplain; grant select on V_$SQL_PLAN_STATISTICS_ALL to texplain; grant select on V_$SQL to texplain;
試す。
SQL>select count(*) from test.test1_view; COUNT(*) ---------- 100 SQL>SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR()); PLAN_TABLE_OUTPUT SQL_ID 0fn9jb84xq0a4, child number 0 ----------------- ------------------------------------- select count(*) from test.test1_view Plan hash value: 2932712509 --------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | --------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | | | 3 (100)| | | 1 | TABLE ACCESS FULL| TEST1 | 100 | 2600 | 3 (0)| 00:00:01 | --------------------------------------------------------------------------- Note ----- - dynamic sampling used for this statement (level=2)
無事取得完了。でもこうすると実際にクエリが発行されちゃうのと基表名とかはわかっちゃうのか。。
あと、クエリの実行キャンセルしても実行計画を取得できるからいいね。
SQL>select count(*) from test.test1_view where id=1; select count(*) from test.test1_view where id=1; * 行1でエラーが発生しました。: ORA-01013: ユーザーによって現行の操作の取消しがリクエストされました SQL>SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR()); PLAN_TABLE_OUTPUT ----------------------------------------------- SQL_ID 5twf49nt4gjdw, child number 0 ------------------------------------- select count(*) from puli.test1_view where id=1 Plan hash value: 1249660229 ----------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | ----------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | | | 1 (100)| | | 1 | SORT AGGREGATE | | 1 | 13 | | | |* 2 | INDEX UNIQUE SCAN| SYS_C0061810 | 1 | 13 | 1 (0)| 00:00:01 | ----------------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 2 - access("ID"=1)