PostgreSQL-varchar 열의 크기를 더 작은 길이로 변경하십시오.


153

ALTER TABLE정말 큰 테이블 (약 3 천만 행) 의 명령에 대한 질문이 있습니다 . 해당 열 중 하나 varchar(255)는 varchar(40)입니다. 로 크기를 조정하고 싶습니다 . 기본적으로 다음 명령을 실행하여 열을 변경하고 싶습니다.

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

프로세스가 매우 길더라도 문제가 없지만 ALTER TABLE 명령 동안 내 테이블을 더 이상 읽을 수없는 것 같습니다. 더 똑똑한 방법이 있습니까? 어쩌면 새 열을 추가하고 이전 열의 값을 복사하고 이전 열을 삭제하고 마지막으로 새 열의 이름을 바꾸겠습니까?

어떤 단서라도 대단히 감사하겠습니다! 미리 감사드립니다.

참고 : PostgreSQL 9.0을 사용합니다.


11
분명하게 : resizing테이블이 적은 공간을 차지하지 않을 것입니까?
— AH

내 경우에도 열의 최대 크기는 255 대신 40 자 (옥텟)입니다.
— Labynocle

16
varchar(255)PostgreSQL에 말하면 실제 길이가 40 바이트 인 값에 255 바이트를 할당 하지 않습니다 . 40 바이트를 할당합니다 (일부 내부 오버 헤드). be changed by the ALTER TABLE` 할 유일한 것은 PG에서 오류를 발생시키지 않고 해당 열에 저장할 수있는 최대 바이트 수입니다.
— AH


답변:


73

데이터를 변경하지 않고 PostgreSQL 테이블의 열 크기 조정 에서이를 수행하는 방법에 대한 설명이 있습니다 . 데이터베이스 카탈로그 데이터를 해킹해야합니다. 이 작업을 공식적으로 수행하는 유일한 방법은 ALTER TABLE을 사용하는 것입니다. 앞에서 언급했듯이 변경이 실행되는 동안 전체 테이블이 잠기고 다시 작성됩니다.

이를 변경하기 전에 문서 의 문자 유형 섹션 을 읽으십시오 . 여기서 알아야 할 모든 종류의 이상한 경우. 길이 점검은 값이 행에 저장 될 때 수행됩니다. 거기에서 하한을 해킹하면 기존 값의 크기가 전혀 줄어들지 않습니다. 변경 후 필드 길이가 40자를 초과하는 행을 찾아 전체 테이블을 스캔하는 것이 좋습니다. 누군가 수동으로 자르는 방법을 알아야합니다. 따라서 누군가가 그 행의 내용을 업데이트하려고하면 시점에서 너무 크게 거부하기 때문에 너무 큰 잠금에서만 다시 잠금을 설정해야합니다. 행의 새 버전을 저장합니다. 사용자에게 즐거움이 뒤 따릅니다.

VARCHAR은 PostgreSQL에 존재하는 끔찍한 유형으로, SQL 표준의 관련 끔찍한 부분 만 준수합니다. 다중 데이터베이스 호환성에 신경 쓰지 않는다면 데이터를 TEXT로 저장하고 길이를 제한하는 제약 조건을 추가하십시오. 이 테이블 잠금 / 재 작성 문제없이 변경할 수 있으며, 약한 길이 검사보다 무결성 검사를 더 많이 수행 할 수 있습니다.


답변 감사합니다. 나는 당신의 링크를 확인합니다. 내 모든 콘텐츠의 최대 크기는 40 자이므로 수동 크기 확인에 대해 걱정하지 않아도됩니다. VARCHAR이 lentgh를 확인하는 것이 더 낫다고 믿었 기 때문에 TEXT에 대한 제약에 대해 더 읽어야합니다. :)
— Labynocle

6
varchar 길이 변경은 테이블을 다시 쓰지 않습니다. CHECK CONSTRAINT와 정확히 동일하게 전체 테이블에 대한 제약 조건 길이를 확인하면됩니다. 길이를 늘리면 수행 할 작업이 없으면 다음 삽입 또는 업데이트 만 더 큰 길이를 허용합니다. 길이를 줄이고 모든 행이 새로운 작은 구속 조건을 통과하면 Pg는 다음 삽입 또는 업데이트가 새 길이 만 쓸 수 있도록하는 것 외에 추가 조치를 취하지 않습니다.
— Maniero

3
@bigown, 명확히하기 위해, 귀하의 진술은 이전 문장이 아닌 PostgreSQL 9.2 이상에만 해당 됩니다.
— MatheusOl

12
링크가 이제 죽었습니다.
— raarts


100

PostgreSQL 9.1에는 더 쉬운 방법이 있습니다

http://www.postgresql.org/message-id/162867790801110710g3c686010qcdd852e721e7a559@mail.gmail.com

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) |

6
더 큰 크기 (30> 10)를 지정하기 때문에 작동합니다 . 크기가 작 으면 내가했던 것과 같은 오류가 발생 합니다.
— Matthieu

2
포스트 그레스해야 하지 당신은 ALTER 표 쿼리를 통해 VARCHAR 크기를 낮출 경우 오류가 발생 하지 않는 한 더 많은 행 중 하나가 새 크기를 초과하는 값을 포함합니다.
— 에게

@Tell, 흥미 롭습니다. 이것은 Postgres가 테이블을 전체 스캔하거나 통계에서 최대 크기를 유지한다는 의미입니까?
— Matthieu

47

좋아, 아마 파티에 늦었을 수도 있지만 ...

귀하의 경우에 열의 크기를 조정할 필요가 없습니다!

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에 동일한 방식으로 저장됩니다 .


8
"왜"에 대한 정보를 추가하기에 너무 늦지 않았습니다! 이 모든 정보에 감사드립니다
— Labynocle

때로는 데이터베이스 구조에서 일관성을 유지해야합니다. 두 개의 열에 관계가 없더라도 개념 관점에서 관계를 가질 수 있습니다 (예 : 모델 EAV 체크 아웃).
— Alexandre

36

VARCHAR을 32에서 8로 자르려고 시도하고 동일한 문제에 직면했습니다. ERROR: value too long for type character varying(8) . 고객의 선택에 따라 다른 DBMS로 전환해야하는 자체 제작 JPA와 유사한 구조를 사용하고 있기 때문에 가능한 한 SQL에 가깝게 유지하고 싶습니다 (PostgreSQL이 기본 구성). 따라서 시스템 테이블을 변경하는 트릭을 사용하고 싶지 않습니다.

나는 : 의 USING진술을 사용하여 끝내었다 ALTER TABLE.

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

@raylu가 지적했듯이 ALTER테이블에 대한 독점 잠금을 획득하므로 다른 모든 작업은 완료 될 때까지 지연됩니다.


2
이 ALTER테이블에 독점 잠금을 획득하고 다른 모든 작업을 방지합니다
— raylu

8

redshift postgresql에서 새 열을 추가하고 이전 열을 새 것으로 교체하면 자세한 내용은이 링크를 참조하십시오 https://gist.github.com/mmasashi/7107430

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;

7

다음 은 Greg Smith가 설명하는 페이지 의 캐시 입니다. 또한 죽는 경우, alter 문은 다음과 같습니다 :

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

테이블이 TABLE1 인 경우 열은 COL1이며이를 35 자로 설정하려고합니다 (링크에 따라 레거시 목적에 +4가 필요하며, 주석에서 AH가 참조하는 오버 헤드 일 수 있음).


7

변경 사항을 트랜잭션에 넣은 경우 테이블을 잠그면 안됩니다.

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

이것은 400k 개 이상의 행이있는 테이블에서 몇 초 만에 빠르게 타오르는 데 효과적이었습니다.


5
명시 적 트랜잭션 랩퍼가 ALTER명령문의 잠금 동작을 변경하는 이유는 무엇 입니까? 그렇지 않습니다.
— Erwin Brandstetter

트랜잭션 래퍼 유무에 관계없이 큰 차이가 있음을 알 수 있습니다.
— jacktrade

2
교장 선생님의 답변이 틀립니다. 명시 적 트랜잭션 래퍼가없는 DDL 문은 트랜잭션 내부에서 암시 적으로 실행됩니다. 명시 적 트랜잭션의 유일한 가능한 효과는 명시 적 까지 잠금이 더 오래 유지된다는 것 COMMIT입니다. 래퍼는 동일한 트랜잭션에 더 많은 명령을 추가하려는 경우에만 의미가 있습니다.
— Erwin Brandstetter

당신은 완전히 옳습니다, 그러나 나는 주장 : 스스로 시도하고 계속하십시오. 그런 다음 왜 같은 방식으로 작동하지 않는지 묻습니다.
— jacktrade

Postgres 9.3에서 도움이되지 않았습니다.
— 누 메논

1

크기를 변경하는 매우 쉬운 방법, 즉 "import javax.validation.constraints"의 일부인 @Size (min = 1, max = 50) 주석을 찾았습니다. "import javax.validation.constraints.Size;"

@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),

.....

)

게시물 주셔서 감사합니다! 게시물에 서명 / 태그 라인을 사용하지 마십시오. 사용자 상자는 서명으로 계산되며 프로필을 사용하여 자신에 대한 정보를 게시 할 수 있습니다. 서명 / 슬로건에 자주 묻는 질문
— 앤드류 바버

당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.