データベース - postgreSQL - 重複行を削除

 クラウディア
1. 概要
2. 状況
3. 重複行削除
4. インデックス作成

1. 概要

 えらいことになっちゃったのであります。  最近バージョンを「postgresSQL 14」から「postgreSQL 16」へ更新したのですが。  前のバージョンでフルバックアップとったものを、インストールしたバージョンへインストールしたのですが。  どうも手違いがあったようなのです。  本ページは、下記のサイトを参考にさせていただきました。
PostgreSQL で重複するデータの内の1件だけを削除する(システム列の ctid を使った削除) #PostgreSQL 」
「重複レコードの削除方法【PostgreSQL】

2. 状況

 どうも、インデックスがなくなったテーブルがあって、本来インデックスで重複しないはずのデータが重複しております。  テーブルをこんな感じで作成しまして。

create table public.contents (
  index integer not null
  , uri text not null
  , document text
  , title text
  , modified timestamp(6) without time zone
  , description text
  , content text
);
 1、2カラムをインデックスにしていたはずなのですが・・・。  インデックスがなくなっているし。  そのせいか、どうも重複行が発生しています。  毎日定期的に動かしている、「SQL」も。

psycopg2.errors.InvalidColumnReference: there is no unique or exclusion constraint matching the ON CONFLICT specification
 てなエラー、「CONFLICT」が発生しております。  確認してみると。

select count(*) from contents;
 count
-------
 62386

select count(*) from (select distinct on (index, uri) * from contents);
 count
-------
 31193
 と、重複行を除くと、ちょうど半分なので、綺麗に(?)すべての行が重複しているようです。  これは、重複行を取り除いてから、インデックスを作成するしかないかな。  とりあえず、現状のバックアップは、とっておきます。

3. 重複行削除

 前項といい、本項といい、本来は、「データベース - SQL 構文」に書くべき内容があるのですが、それは、いずれ機会があれば・・・ということで。  まず、重複行を削除します。

DELETE FROM contents t1
WHERE EXISTS(SELECT *
             FROM   contents t2
             WHERE
			 	 t2.index = t1.index
             AND t2.uri   = t1.uri
             AND t2.ctid > t1.ctid
            )
;
 ここで、参考サイトの説明をそのまま掲載。
PostgreSQL によって暗黙的に定義されている ctid システム列を利用します。ctid は、テーブル内において行の物理的位置を表していて、一意であることを利用します。
 ですって。  実行後に、件数を確認してみます。

select count(*) from contents;
 count
-------
 62386
 綺麗に半分になったようです。

4. インデックス作成

 さて、その上で、インデックスを作成します。

CREATE UNIQUE INDEX contents_key ON public.contents USING btree (index, uri);
 後は、定期的な「SQL」が動作するか、確認します。  翌日確認したら、問題なく動作するように復活したようです。めでたしめでたし・