web-dev-qa-db-ja.com

PostgreSQL DELETE FROMが「エラー:非表示のタプルを削除しようとしました」で失敗する

エラー

無効なタイムスタンプを含むタプルを削除しようとすると

_DELETE FROM comments WHERE date > '1 Jan 9999' OR date < '1 Jan 2000' OR date_found > '1 Jan 9999' OR date_found < '1 Jan 2000';
_

で終わる

_ERROR:  attempted to delete invisible Tuple
_

2009年のメーリングリスト で、OPが修正したまったく同じエラーメッセージについて説明していますが、OPがそれをどのように実行したのか、何が原因となっていたのかについての説明はありませんこのエラー。

Googleでのヒット数の不足とPostgreSQLの限られた知識のため、私は無力です。

腐敗につながったもの

私はPostgreSQL 9.5.5サーバー(〜4TBのデータ、すべてのデフォルト設定、メモリ上限を除いて)をOSカーネルがパニックしたときにDebian 8で実行しました-おそらくスワップが配置されていた/ dev/md1を再構築します。それ以前は、PostgreSQLはディスク容量のほぼすべてを400GBのログファイルで使い果たしていました。 OSが再度起動することはなく、ディスクチェックは問題なかったため、念のため、LiveCDから起動し、各ブロックデバイスをイメージにバックアップしました。/dev/md2から/ディレクトリを正常に再構築し、fsckはクリーンなファイルシステムを示し、PGDATAフォルダーを外部HDDにバックアップしました。

回復を試みるために私がしたこと

Mdデバイスをフォーマットし、OSを新しいpostgresql-9.5と共に再インストールした後、PostgreSQLサーバーを停止し、PGDATAフォルダーをpostgresユーザーに移動して起動し、サーバーを起動しました。すべて正常に動作し、エラーは発生しませんでした。

_pg_dumpall_を開始するとすぐに、

_Error message from server: ERROR:  timestamp out of range
_

私は当然のことながら、問題のあるタプルを削除しようとしましたが、同じ_invisible Tuple_エラーが何度も何度も発生していました。

私が試したもの

まず、破損したページが原因でDELETEクエリが失敗したため、次の設定を行いました。

_zero_damaged_pages = on
ignore_system_indexes = on
enable_indexscan = off
enable_bitmapscan = off
enable_indexonlyscan = off
_

同じクエリをもう一度実行すると、サーバーは同じページを何度もゼロに設定しますが、意味がわかりません。

_invalid page in block 92800 of relation base/16385/16443; zeroing out page
_

私は未定義の順序でフォローしようとしました:

  • _pg_resetxlog -D $PGDATA_はエラーやメッセージを出さずに仕事をしました
  • Pkey制約を含むすべてのインデックスを削除しました
  • CREATE TABLE aaa AS (SELECT * FROM comments);は_Segmentation fault_につながります

    heap_deform_Tuple (Tuple=tuple@entry=0x7f0d1be29b08, tupleDesc=tupleDesc@entry=0x7f0d1a35abe0, values=values@entry=0x7ffd57a5beb0, isnull=isnull@entry=0x7ffd57a65af0 "\001\001")再現可能で、最大9GBのコアダンプが残ります。

  • SELECT COUNT(*) from comments;は_VACUUM comments;_の完了を許可しました。他のテーブルでは同じトリックは機能しません。
  • SELECT COUNT(*) from photos;と_VACUUM photos;_が_ERROR: MultiXactId 302740528 has not been created yet -- apparent wraparound_で終了するようになりました–これは、他のエラーがポップアップしないすべてのテーブルで発生します。

考え

  • _ON CONFLICT_句を使用した大量の(重複の可能性)書き込みによってDBが打撃を受けていました カーネルパニックが発生したときにDBがVACUUMを実行していましたが、_nonexistent MultiXactIds_と_invisible Tuple_で問題を引き起こしているのはそれが残っていると思います
  • データは2年以上の期間にわたってクローラーで収集され、一部を失っても大丈夫です
  • 今私はバックアップをします
  • テーブルとトリガーの間に関係制約はありませんでした

以下は、現時点でのpg_controldataの出力です。

_pg_control version number:            942
Catalog version number:               201510051
Database system identifier:           6330224129664261958
Database cluster state:               in production
pg_control last modified:             Thu 08 Dec 2016 01:06:22 AM EET
Latest checkpoint location:           1562/8F9F8A8
Prior checkpoint location:            1562/8F7F460
Latest checkpoint's REDO location:    1562/8F9F8A8
Latest checkpoint's REDO WAL file:    000000010000156200000008
Latest checkpoint's TimeLineID:       1
Latest checkpoint's PrevTimeLineID:   1
Latest checkpoint's full_page_writes: on
Latest checkpoint's NextXID:          0/40781255
Latest checkpoint's NextOID:          67798231
Latest checkpoint's NextMultiXactId:  1
Latest checkpoint's NextMultiOffset:  0
Latest checkpoint's oldestXID:        615
Latest checkpoint's oldestXID's DB:   1
Latest checkpoint's oldestActiveXID:  0
Latest checkpoint's oldestMultiXid:   1
Latest checkpoint's oldestMulti's DB: 1
Latest checkpoint's oldestCommitTsXid:0
Latest checkpoint's newestCommitTsXid:0
Time of latest checkpoint:            Thu 08 Dec 2016 01:06:22 AM EET
Fake LSN counter for unlogged rels:   0/1
Minimum recovery ending location:     0/0
Min recovery ending loc's timeline:   0
Backup start location:                0/0
Backup end location:                  0/0
End-of-backup record required:        no
wal_level setting:                    minimal
wal_log_hints setting:                off
max_connections setting:              100
max_worker_processes setting:         8
max_prepared_xacts setting:           0
max_locks_per_xact setting:           64
track_commit_timestamp setting:       off
Maximum data alignment:               8
Database block size:                  8192
Blocks per segment of large relation: 131072
WAL block size:                       8192
Bytes per WAL segment:                16777216
Maximum length of identifiers:        64
Maximum columns in an index:          32
Maximum size of a TOAST chunk:        1996
Size of a large-object chunk:         2048
Date/time type storage:               64-bit integers
Float4 argument passing:              by value
Float8 argument passing:              by value
Data page checksum version:           0
_

アップデート

  • 2016年12月9日nonexistent MultiXactIds について読んでいるときに、データベースがクラッシュの瞬間ですが、手動のVACUUMリクエストを処理していました。ディスクに3%しか残っていないことに気付いたので、ウェブサーバーとクローラーをオフラインにしました。大きなファイルがないか_/var/log_を確認する必要がありましたが、誤ってPostgreSQLを非難し、_VACUUM FULL_を試しましたが、デバイスの空き容量が少ないため中止されたことがわかりました。だから私は普通のVACUUMを始めて、それをそのままにしました。
  • 2016年12月14日)GithubからPostgreSQLソースの9.5ブランチをダウンロードし、 heapam.c および/のブロックをコメント化 multixact.c そして、これらのエラーがスローされないことを期待してコンパイルしました。しかし、サーバーは起動しませんでした。APTから取得したものと同じフラグを使用して構成する必要があったからです。約47のフラグがあり、それぞれに明白でない名前の依存関係が必要だったので、私はその考えをあきらめました。
  • 2016年12月16日)関連するページをゼロ設定して、無効なタイムスタンプのタプルを取り除く方法を見つけました。まず、psqlに次のオプションを設定します。

    _\set FETCH_COUNT 1
    \pset pager off
    _

    次に_SELECT ctid, * FROM comments;_を実行します。このようにして、クエリが終了する前に、不正なタプルのctidを吐き出します。次に、そのページをゼロで埋めます:_dd if=/dev/zero of=/var/lib/postgresql/9.5/main/base/16385/16443 bs=8K seek=92803 count=1 conv=notrunc_しかし、このようにゼロに設定された各ページは前のページを中断し、ページ_16442_に無効なタイムスタンプのタプルが含まれるようになります。ここで何が間違っているのかわかりません。

  • 2016年12月16日)_pg_dump -Fc --table photos vw > photos.bak_を試行すると、1.3GB(のうち800GB)が書き込まれた後にセグメンテーション違反が発生します。サーバーログは次のとおりです。

    _2016-12-16 18:48:05 EET [19337-2] LOG:  server process (PID 29088) was terminated by signal 11: Segmentation fault
    2016-12-16 18:48:05 EET [19337-3] DETAIL:  Failed process was running: COPY public.photos (id, owner_id, width, height, text, date, link, thumb, album_id, time_found, user_id, lat, long) TO stdout;
    2016-12-16 18:48:05 EET [19337-4] LOG:  terminating any other active server processes
    2016-12-16 18:48:05 EET [19342-2] WARNING:  terminating connection because of crash of another server process
    2016-12-16 18:48:05 EET [19342-3] DETAIL:  The postmaster has commanded this server process to roll back the current transaction and exit, because another server process exited abnormally and possibly corrupted shared memory.
    2016-12-16 18:48:05 EET [19342-4] HINT:  In a moment you should be able to reconnect to the database and repeat your command.
    2016-12-16 18:48:05 EET [19337-5] LOG:  all server processes terminated; reinitializing
    2016-12-16 18:48:06 EET [29135-1] LOG:  database system was interrupted; last known up at 2016-12-14 22:58:59 EET
    2016-12-16 18:48:07 EET [29135-2] LOG:  database system was not properly shut down; automatic recovery in progress
    2016-12-16 18:48:07 EET [29135-3] LOG:  invalid record length at 1562/A302F878
    2016-12-16 18:48:07 EET [29135-4] LOG:  redo is not required
    2016-12-16 18:48:07 EET [29135-5] LOG:  MultiXact member wraparound protections are now enabled
    2016-12-16 18:48:07 EET [19337-6] LOG:  database system is ready to accept connections
    2016-12-16 18:48:07 EET [29139-1] LOG:  autovacuum launcher started
    _

    ここに短いスタックトレースがあります:

    _#0  pglz_decompress (source=source@entry=0x7fbfb6b99b13 "32;00/0ag4d/Jnz\027QI\003Jh3A.jpg", slen=<optimized out>,
        dest=dest@entry=0x7fbf74a0b044 "", rawsize=926905132)
    #1  0x00007fc1bf120c12 in toast_decompress_datum (attr=0x7fbfb6b99b0b)
    #2  0x00007fc1bf423c83 in text_to_cstring (t=0x7fbfb6b99b0b)
    _

    私はそれを回避する方法を知りません。

  • 2016年12月29日)_SELECT * FROM tablename LIMIT 10000 OFFSET 0_を実行するユーティリティを作成し、オフセットをインクリメントし、無効なタプルを絞り込み、ローカルマシンでデータを正常に複製しましたタプルを除いて(私だけのものを願っています)私は手動で破損しています。サーバーが再起動した場合も待機することになっています。ただし、RAIDに十分なスペースが残っていないため、8 TBのHDDにテーブルスペースslowdiskを作成しました。 _CREATE DATABASE vwslow WITH TABLESPACE slowdisk_を実行しようとすると、エラーが発生しません。

    _2016-12-29 02:34:13 EET [29983-1] LOG:  request to flush past end of generated WAL; request 950412DE/114D59, currpos 1562/A3030C70
    2016-12-29 02:34:13 EET [29983-2] CONTEXT:  writing block 58368001 of relation base/16385/16473
    2016-12-29 02:34:13 EET [29983-3] ERROR:  xlog flush request 950412DE/114D59 is not satisfied --- flushed only to 1562/A3030C70
    2016-12-29 02:34:13 EET [29983-4] CONTEXT:  writing block 58368001 of relation base/16385/16473
    2016-12-29 02:34:13 EET [30005-44212] postgres@vw ERROR:  checkpoint request failed
    2016-12-29 02:34:13 EET [30005-44213] postgres@vw HINT:  Consult recent messages in the server log for details.
    2016-12-29 02:34:13 EET [30005-44214] postgres@vw STATEMENT:  CREATE DATABASE vwslow WITH TABLESPACE slowdisk;
    _

    手動CHECKPOINTでも同じエラーが発生しました。

    サーバーの再起動により、チェックポイントエラーが解消され、ツールを実行できるようになりました。それが機能する場合、私の質問に答え、コードを公開します。

25
Kai

さて、SELECTINSERT INTOのリカバリプロセスを自動化して、範囲をスキップし、サーバーがクラッシュした場合に待機しました。私は最初にそれをNode-でコード化しました-commentsからの損傷を受けていないデータをリッピングしました、そしてまだ続いています。

昨日Golangを試すことにしました。Goコードのリポジトリがここにあります: https://github.com/kaivi/pg_ripper 更新しますすぐにそれは本当に悪いタプルを回避し、それを含む範囲全体をあきらめるだけではありません。

2
Kai