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.