注意:この作業を行うにあたって、心構えとしては
・運用中のzabbixが不安定になる覚悟をする。
・バックアップを取ったデータベースがなければ、過去データはすべて破棄する覚悟。
・作業を行った直後は問題がなかったとしても、特殊なデータや状況が発生した時に、データ破損してしまうことを受け入れる覚悟。
これらのことが許容できる環境の持ち主か、どうにもせっぱつまっていて、上記のリスクに比べたら相当に致命的な状況まで追い込まれている人じゃない限り、やらないほうが良い作業だと思っています。※技術力向上のためにやれるなら幸せかもですが。
今回は以前作ったスクリプトを変更して、INSERT文じゃなく、functionを呼び出すように作ります。
■スクリプトの変更点
■変更前
1 2 3 4 5 6 7 8 9 10 11 12 13 | # INSERT文を作成 SQL="INSERT INTO ${TRENDS_TABLE} ( clock,itemid,num,value_min,value_avg,value_max )" SQL="${SQL} VALUES ( ${CLOCK},${ITEMID},1,${VALUE},${VALUE},${VALUE} )" IFS=' ' #区切り文字を初期化 #echo ${SQL} ${SQL_CLI} -c "${SQL}" IFS=, #区切り文字を,に。 done IFS=' ' #区切り文字を初期化 rm -f ${DL_CSV} |
■変更後
付け加えと変更
1 2 | SQL_TEXT=/tmp/PAST_ELE.${NOW_DATE}.sql TRENDS_TABLE='trends_uint_debug' |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | # 関数の呼び出しを作成 SQL="SELECT insert_past_trends(\'${TRENDS_TABLE}\'::text,${ITEMID},${CLOCK},${VALUE});" IFS=' ' #区切り文字を初期化 echo ${SQL} >> ${SQL_TEXT} IFS=, #区切り文字を,に。 done IFS=' ' #区切り文字を初期化 # 実行 ${SQL_CLI} -f "${SQL_TEXT}" rm -f ${DL_CSV} rm -f ${SQL_TEXT} |
■テーブルバックアップ
# pg_dump -U pgsql -t trends_uint_debug zabbix > trends_uint_debug.20110801.dmp |
■起動コマンド
# time sh ./past_ele_forecast.batch.sh 22497 '2011/7/3,2:00' | less insert_past_trends -------------------- UPDATE OK (1 row) insert_past_trends -------------------- INSERT OK (1 row) real 0m20.865s user 0m6.786s sys 0m14.634s |
UPDATEは手動でキックしたデータです。INSERTがいっぱい出ていました。time は| lessの場合ちょっと長く出るので、|head の時に計測です。
でも、ここまで来るのに、INSERTのチェックをしていなかったのは片手落ちですね。
かなり、functionのバグが多くて、本格的に直したのはこのフェイズになってからというのが
自分を許せないところです。
■エラー例
1 2 3 4 | PL/pgSQL FUNCTION "insert_past_trends" line 34 AT EXECUTE statement psql:/tmp/PAST_ELE.1312205240.SQL:4395: ERROR: permission denied FOR relation trends_uint_debug CONTEXT: SQL statement "SELECT * FROM trends_uint_debug AS t WHERE t.itemid= 22498 AND t.clock = 1309626000" PL/pgSQL FUNCTION "insert_past_trends" line 34 AT EXECUTE statement |
所有者が管理者だった。(\d+ でみています。)
1 2 3 4 | PUBLIC | trends_uint | TABLE | zabbix | 135 MB | PUBLIC | trends_uint_debug | TABLE | pgsql | 111 MB | PUBLIC | trends | TABLE | zabbix | 63 MB | PUBLIC | trends_debug | TABLE | pgsql | 51 MB | |
ついでに、今のtrends_uint などのテーブルサイズが分かって便利なのを今更ながらに発見。
1 | PUBLIC | history_uint | TABLE | zabbix | 213 MB | |
これもでかいけどそれほどじゃない感じが。
213MBもメモリに乗ったかな…?これは分割できたら良いなと思います。
これで解決。
zabbix=# ALTER TABLE trends_debug OWNER TO zabbix; zabbix=# ALTER TABLE trends_uint_debug OWNER TO zabbix; |
psql:/tmp/PAST_ELE.1312205622.SQL:4395: ERROR: query string argument OF EXECUTE IS NULL CONTEXT: PL/pgSQL FUNCTION "insert_past_trends" line 83 AT EXECUTE statement |
UPDATEのSQLでエラー。
ここにきて致命的なミス。SELECTで引っかからない場合、INSERTのロジックが動かない。
そういえば、IF NOT FOUND の条件判定はおかしいと気付く。
SELECTで既存データがなかった場合・・・を判定基準して書いてしまっているのに、
正常動作として動作したものと考えてテストを行っている。
こんな感じで判定基準を変えてみるもNG
ELSIF COUNT(exist_trends_uint) > 0 AND input_table = 'trends_uint_debug' THEN --test table 'trends_uint_debug' |
exist_trends_uint の変数を書き出してみた。
zabbix=# SELECT insert_past_trends('trends_uint_debug'::text,22498,1293807600,30580000000); NOTICE: exist_trends_uint_debug (,,,,,) ERROR: query string argument OF EXECUTE IS NULL CONTEXT: PL/pgSQL FUNCTION "insert_past_trends" line 84 AT EXECUTE statement |
これは…1行ある!
判定を IS NOT NULL に変更。
ELSIF exist_trends_uint IS NOT NULL AND input_table = 'trends_uint_debug' THEN --test table 'trends_uint_debug' |
INSERTに処理は移ったけれど、エラー。
zabbix=# SELECT insert_past_trends('trends_uint_debug'::text,22498,1293807600,30580000000); NOTICE: exist_trends_uint_debug (,,,,,) ERROR: syntax error AT OR near "1293807600" LINE 1: INSERT INTO trends_uint_debug (1293807600,22498,1,3058000000... ^ QUERY: INSERT INTO trends_uint_debug (1293807600,22498,1,30580000000,30580000000,30580000000) CONTEXT: PL/pgSQL FUNCTION "insert_past_trends" line 95 AT EXECUTE statement |
INSERT INTO VALUESのVALUES を書き忘れている!
SQL := 'INSERT INTO '|| input_table || ↓ SQL := 'INSERT INTO '|| input_table || ' VALUES '|| zabbix=# SELECT insert_past_trends('trends_uint_debug'::text,22498,1293807600,30580000000); NOTICE: exist_trends_uint_debug (,,,,,) insert_past_trends -------------------- INSERT OK (1 ROW) |
psql:/tmp/PAST_ELE.1312207190.SQL:1: ERROR: duplicate key VALUE violates UNIQUE constraint "trends_uint_debug_pkey" CONTEXT: SQL statement "INSERT INTO trends_uint_debug VALUES (1293807600,22498,1,30580000000,30580000000,30580000000)" |
テストで入れてしまったから・・・ってUPDATEに行くはず?
PL/pgSQL FUNCTION "insert_past_trends" line 95 AT EXECUTE statement insert_past_trends -------------------- INSERT OK (1 ROW) insert_past_trends -------------------- INSERT OK (1 ROW) REAL 0m20.995s USER 0m6.758s sys 0m14.725s |
さらに、バグとしてはitemid とclockが入れ替わっていたり。
zabbix=# SELECT * FROM trends_uint_debug WHERE value_min = 30580000000 limit 10; itemid | clock | num | value_min | value_avg | value_max ------------+-------+-----+-------------+-------------+------------- 1293807600 | 22498 | 1 | 30580000000 | 30580000000 | 30580000000 1295200800 | 22498 | 1 | 30580000000 | 30580000000 | 30580000000 1293807600 | 22497 | 1 | 30580000000 | 30580000000 | 30580000000 |
zabbix=# SELECT insert_past_trends('trends_uint_debug'::text,22497,1293807600,30580000000); insert_past_trends -------------------- INSERT OK (1 ROW) zabbix=# SELECT insert_past_trends('trends_uint_debug'::text,22497,1293807600,30580000000); insert_past_trends -------------------- UPDATE OK (1 ROW) |
ようやく正常に…長かったような。