失敗は一時の恥

パッケージソフト開発をしているプログラマが気の赴くままに何かを投稿するブログ.

アンチウイルスソフトと同居した PostgreSQL の奇行

概要

仕事で PostgreSQL を使っているのですが,奇妙な動作をすることが稀にあります. 奇妙な動作といっても,PostgreSQL 自体の不具合というではなく,アンチウイルスソフトとの競合で発生している事象だと思われる類のものです.

稀に発生すると,問題の切り分けに非常に労力を割かれて嫌な思いをしたりもするので,備忘録ついでにブログに書いておこうと思います.

観測された事象

大きく 2 つあります.

1. テーブルの主キーのインデックスが壊れる

主キーと適当なカラムを持つテーブルがありました:

id | value 
---+------
1  | 'one'
2  | 'two'

このテーブルに対して,values を条件に SELECT 文を発行すると意図した結果が得られるのですが,id を条件にすると意図せぬ結果が得られるということがありました.

postgres=# SELECT * FROM table WHERE value = 'one';
(1 行 SELECT される)
id | value 
---+------
1  | one
postgres=# SELECT * FROM table where id = 1;
(1 行も SELECT されない(!))

この状況を見るに,レコードは確かに存在しているが,条件に指定したときに SELECT できるカラムとできないカラムの違いとは何……と考えた結果として「インデックスがおかしい」という結論になりました.

この事象への対処としては,reindexdb コマンドを使ってインデックスを作り直すことで解決することができました.

このケースでは,主キーで SELECT もできないのですが,主キーで UPDATE もやはりできないので,「対象レコードは存在するのに操作しても値が変わらないのは……?マルチスレッドで FOR UPDATE したり SKIP LOCKED したりする実装にバグがあるの???」といった見当違いな予想 (実際にはそこには問題はなかった) から調査を開始して結論にたどり着くまでが一苦労でした.

2. 外部キー制約を犯した行が挿入される

tableB から tableA へ外部キー制約を張っているのですが,制約を犯した行が鎮座しているという事象がありました.

tableA:

id | value 
---+------
1  | 'one'
2  | 'two'

tableB:

id  | comment | foreign_key
----+---------+------------
100 | 'hello' | 1
101 | 'world' | 3 (こんな id は tableA にない(!))

この事象が起きたとき,外部キー制約を犯した行を DELETE しようとしたり,外部キーとして存在するはずの行を INSERT したりしようとしたのですが,どちらも「外部キー制約違反」となり押すも引くもできない状態になってしまいました. 最終的に,テーブルの DROP を強行するくらいしか取れる選択肢がありませんでした.

これももしかするとインデックスが壊れたことで発生した事象なのかもしれません.

事象が観測された環境

僕の経験の範囲ですが,以下の組み合わせて上述の事象を経験しました.

アンチウイルスソフト自体は他の製品でも問題になることはあるのかもしれません.

基本的には,業務で開発環境として使っている Windows マシン (会社の情報管理規定によりウイルスバスターのインストール必須) やテスト環境において起きており,DB が壊れてもデータ消して作り直せばいいでしょくらいのノリではありました (顧客環境で顧客のインストールしたアンチウイルスソフトで問題が起こることがなかったとは言ってない).

PostgreSQLアンチウイルスソフトに関する情報

PostgreSQL Wiki にはアンチウイルスソフトを同居させると意図せぬ挙動をするという旨の記載があるし,アンチウイルスソフトの説明にもデータベースソフトを監視するなと書いてある情報は見つかります. 使おうとするソフトの説明書きをよく読めということですね.

所感

DB があり得ない状態になっていると,コードを追っても理解できないようなエラーをアプリケーションが出すので,原因の特定に大変苦労します.

ふつうに過ごしていると DB が壊れているなんてことはなかなかないとは思うのですが,不可思議なエラーを目にしたら先入観を取っ払って普段は考えないようなところに問題があるのでは?と疑ってみるのも必要ですね.