web-dev-qa-db-ja.com

Postgresql-varchar列のサイズを変更する

本当に大きなテーブル(約3000万行)のALTER TABLEコマンドについて質問があります。その列の1つはvarchar(255)で、サイズをvarchar(40)に変更したいと思います。基本的に、次のコマンドを実行して列を変更します。

ALTER TABLE mytable ALTER COLUMN mycolumn TYPE varchar(40);

プロセスが非常に長い場合は問題ありませんが、ALTER TABLEコマンドの実行中にテーブルが読み取れなくなったようです。もっと賢い方法はありますか?新しい列を追加し、古い列から値をコピーし、古い列を削除して、最後に新しい列の名前を変更することもできますか?

どんな手がかりも大歓迎です!前もって感謝します、

注:私はPostgreSQL 9.0を使用しています。

123
Labynocle

データを変更せずにPostgreSQLテーブルの列のサイズを変更する でこれを行う方法の説明があります。データベースカタログデータをハッキングする必要があります。これを公式に行う唯一の方法は、ALTER TABLEを使用することです。既に述べたように、変更は実行中にテーブル全体をロックして書き換えます。

これを変更する前に、ドキュメントの Character Types セクションを必ず読んでください。ここで注意すべきあらゆる種類の奇妙なケース。値が行に格納されると、長さのチェックが行われます。そこの下限をハックしても、既存の値のサイズはまったく減少しません。テーブル全体をスキャンして、変更後にフィールドの長さが40文字を超える行を検索することをお勧めします。誰かがその行の何かを更新しようとすると、その時点でそれが大きすぎるとして拒否されるため、それらを手動で切り捨てる方法を把握する必要があります-したがって、大きすぎるものだけでいくつかのロックに戻ります行の新しいバージョンを保存します。ユーザーの陽気が続きます。

VARCHARは、SQL標準の関連するひどい部分に準拠するためだけにPostgreSQLに存在するひどい型です。マルチデータベースの互換性を気にしない場合は、データをTEXTとして保存し、その長さを制限する制約を追加することを検討してください。このテーブルロック/リライトの問題なしに変更できる制約は、単なる弱い長さのチェックよりも多くの整合性チェックを実行できます。

64
Greg Smith

PostgreSQL 9.1にはもっと簡単な方法があります

http://www.postgresql.org/message-id/[email protected]

CREATE TABLE foog(a varchar(10));

ALTER TABLE foog ALTER COLUMN a TYPE varchar(30);

postgres=# \d foog

 Table "public.foog"
 Column |         Type          | Modifiers
--------+-----------------------+-----------
 a      | character varying(30) |
75
sir_leslie

OK.

ケースの列のサイズを変更する必要はありません!

Postgresは、他のデータベースとは異なり、文字列に合わせて十分なスペースのみを使用するのに十分なスマートです(長い文字列の圧縮を使用しても)。したがって、列がVARCHAR(255)として宣言されている場合でも-40文字の文字列を格納する場合列の場合、スペース使用量は40バイト+ 1バイトのオーバーヘッドになります。

短い文字列(最大126バイト)のストレージ要件は、1バイトに実際の文字列を加えたもので、文字の場合はスペースの埋め込みが含まれます。長い文字列には1ではなく4バイトのオーバーヘッドがあります。長い文字列はシステムによって自動的に圧縮されるため、ディスク上の物理的要件は少なくなります。非常に長い値もバックグラウンドテーブルに格納されるため、短い列値への迅速なアクセスを妨げません。

http://www.postgresql.org/docs/9.0/interactive/datatype-character.html

VARCHARのサイズ指定は、挿入される値のサイズを確認するためにのみ使用され、ディスクレイアウトには影響しません。実際、 VARCHARおよびTEXTフィールドはPostgresでも同じ方法で保存されます

43
Sergey

VARCHARを32から8に切り捨てて、ERROR: value too long for type character varying(8)を取得しようとすると、同じ問題に直面していました。私は顧客の選択に応じて異なるDBMSに切り替える必要があるかもしれない自作のJPAのような構造を使用しているため、可能な限りSQLに近づけたいと思っています(PostgreSQLがデフォルトです)。したがって、システムテーブルを変更するトリックは使いたくありません。

ALTER TABLEUSINGステートメントの使用を終了しました。

ALTER TABLE "MY_TABLE" ALTER COLUMN "MyColumn" TYPE varchar(8)
USING substr("MyColumn", 1, 8)

@rayluが述べたように、ALTERはテーブルの排他ロックを取得するため、他のすべての操作は完了するまで遅延されます。

30
Matthieu

Greg Smithによって記述されたページの キャッシュ です。それが死ぬ場合でも、alterステートメントは次のようになります。

UPDATE pg_attribute SET atttypmod = 35+4
WHERE attrelid = 'TABLE1'::regclass
AND attname = 'COL1';

テーブルがTABLE1である場合、列はCOL1であり、35文字に設定する必要があります(リンクに応じてレガシー目的のために+4が必要です。おそらく、コメントでA.H.が参照するオーバーヘッド)。

7
Tom

新しい列を追加して新しい列を古い列に置き換えると、redshift postgresqlで詳細についてこのリンクを参照してください https://Gist.github.com/mmasashi/71074

BEGIN;
LOCK users;
ALTER TABLE users ADD COLUMN name_new varchar(512) DEFAULT NULL;
UPDATE users SET name_new = name;
ALTER TABLE users DROP name;
ALTER TABLE users RENAME name_new TO name;
END;
6
spats

トランザクションに変更を加えた場合、テーブルはロックされません。

BEGIN;
  ALTER TABLE "public"."mytable" ALTER COLUMN "mycolumn" TYPE varchar(40);
COMMIT;

これは、40万行を超えるテーブルで数秒で高速に動作しました。

6
jacktrade

サイズを変更する非常に簡単な方法、つまり「import javax.validation.constraints」、つまり「import javax.validation.constraints.Size;」の一部であるアノテーション@Size(min = 1、max = 50)を見つけました。

@Size(min = 1, max = 50)
private String country;


when executing  this is hibernate you get in pgAdmin III 


CREATE TABLE address
(
.....
  country character varying(50),

.....

)
1
Tito