Postgresql - varchar sütununun boyutunu daha düşük bir uzunluğa değiştirin


162

ALTER TABLEGerçekten büyük bir tablodaki komutla ilgili bir sorum var (neredeyse 30 milyon satır). Sütunlarından biri a varchar(255)ve onu a olarak yeniden boyutlandırmak istiyorum varchar(40). Temel olarak, aşağıdaki komutu çalıştırarak sütunumu değiştirmek istiyorum:

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

İşlem çok uzunsa sorunum yok ama görünen o ki tablom ALTER TABLEkomut sırasında okunabilir değil . Daha akıllıca bir yol var mı? Belki yeni bir sütun ekleyin, eski sütundan değerleri kopyalayın, eski sütunu bırakın ve sonunda yenisini yeniden adlandırın?

Not: PostgreSQL 9.0 kullanıyorum.


11
Açık olmak resizinggerekirse : Bu , masanın daha az yer kaplamasına neden olmaz?
AH

benim durumumda bile? Yani sütunun 255 yerine maksimum 40 karakter (yani sekizli) boyutuna sahip olacağını mı söylüyorum?
Labynocle

16
Derseniz varchar(255)PostgreSQL için o zaman olacak değil gerçek uzunluğu 40 byte bir değer için 255 bayt tahsis. 40 bayt (artı bir miktar dahili ek yük) tahsis edecektir. be changed by the TABLO'U DEĞİŞTİRECEK tek şey , PG'den hata almadan o sütunda saklayabileceğiniz maksimum bayt sayısıdır.
AH


Bir güncelleme için buradaki cevaba göz atın dba.stackexchange.com/questions/189890/…
Evan Carroll

Yanıtlar:


77

PostgreSQL tablosundaki bir sütunu verileri değiştirmeden yeniden boyutlandırma bölümünde bunun nasıl yapılacağına dair bir açıklama vardır . Veritabanı katalog verilerini kırmanız gerekir. Bunu resmi olarak yapmanın tek yolu ALTER TABLE kullanmaktır ve sizin de belirttiğiniz gibi, değişiklik çalışırken tüm tabloyu kilitleyecek ve yeniden yazacaktır.

Bunu değiştirmeden önce belgelerin Karakter Türleri bölümünü okuduğunuzdan emin olun . Burada dikkat edilmesi gereken her türlü tuhaf durum. Uzunluk kontrolü, değerler satırlara kaydedildiğinde yapılır. Orada daha düşük bir sınırı aşarsanız, bu mevcut değerlerin boyutunu hiç azaltmaz. Değişikliği yaptıktan sonra alanın uzunluğunun> 40 karakter olduğu satırları aramak için tüm tablo üzerinde bir tarama yapmanız akıllıca olacaktır. Bunları manuel olarak nasıl keseceğinizi bulmanız gerekecek - yani sadece büyük boy kilitlerde bazı kilitleri geri alacaksınız - çünkü birisi o satırdaki herhangi bir şeyi güncellemeye çalışırsa, o noktada onu çok büyük olduğu için reddedecektir. satırın yeni sürümünü saklamaya gider. Kullanıcı için neşe doğar.

VARCHAR, PostgreSQL'de yalnızca SQL standardının ilişkili korkunç kısmına uymak için var olan korkunç bir türdür. Çoklu veritabanı uyumluluğunu önemsemiyorsanız, verilerinizi TEXT olarak depolamayı düşünün ve uzunluğunu sınırlandırmak için bir kısıtlama ekleyin. Bu tablo kilitleme / yeniden yazma problemi olmadan değiştirebileceğiniz kısıtlamalar ve zayıf uzunluk kontrolünden daha fazla bütünlük kontrolü yapabilirler.


1
Cevap için teşekkür ederim. Bağlantınızı kontrol edeceğim. Manuel boyut kontrolü konusunda endişelenmiyorum çünkü tüm içeriğim maksimum 40 karakter boyutunda. TEXT üzerindeki kısıtlama hakkında daha fazla bilgi okumam gerekiyor çünkü
VARCHAR'ın lentgh'i

6
Varchar uzunluğunu değiştir, tabloyu yeniden yazmaz. Yalnızca KISITLAMAYI KONTROL EDİN gibi tüm tabloya göre kısıt uzunluğunu kontrol eder. Uzunluğu artırırsanız yapacak bir şey yoktur, hemen sonraki ekleme veya güncellemeler daha büyük uzunluğu kabul eder. Uzunluğu azaltırsanız ve tüm satırlar yeni daha küçük kısıtlamayı geçerse, Pg sonraki eklemelerin veya güncellemelerin yalnızca yeni uzunluğu yazmasına izin vermenin yanı sıra başka bir işlem yapmaz.
Maniero

3
@bigown, sadece açıklığa kavuşturmak için, ifadeniz yalnızca PostgreSQL 9.2+ için geçerlidir , eskileri için değil.
MatheusOl

12
Bağlantı artık öldü.
raarts

Bunun nasıl çalıştığı hakkında daha fazla bilgi için dba.stackexchange.com/questions/189890/… adresini ziyaret
Evan Carroll

101

PostgreSQL 9.1'de daha kolay bir yol var

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
Yalnızca daha büyük bir boyut (30> 10) belirttiğiniz için çalıştığını unutmayın . Boyut daha küçükse, sahip olduğumla aynı hatayı alırsınız .
Matthieu

2
Postgres gerektiğini değil ALTER TABLE sorgusu aracılığıyla varchar boyutunu düşürmek ederseniz bir hata olmadıkça fazla satır biri yeni boyutu aşan bir değer içerir.
söyle

1
@ Söyle, ilginç. Bu, Postgres'in tabloyu tam olarak taradığı anlamına mı geliyor, yoksa bir şekilde maksimum boyutu istatistiklerinde mi tutuyor?
Matthieu

48

Tamam, muhtemelen partiye geç kaldım, AMA ...

KASANIZDAKİ KOLONU YENİDEN BOYUTLAMAYA GEREK YOK!

Postgres, diğer bazı veritabanlarından farklı olarak, dizeyi sığdırmak için yalnızca yeterli alanı kullanacak kadar akıllıdır (daha uzun dizeler için sıkıştırma kullanıldığında bile), bu nedenle sütununuz VARCHAR (255) olarak bildirilse bile - 40 karakterlik dizeleri saklıyorsanız sütun, alan kullanımı 40 bayt + 1 bayt ek yük olacaktır.

Kısa bir dizge için depolama gereksinimi (126 bayta kadar), 1 bayt artı gerçek dizedir ve karakter durumunda boşluk doldurma içerir. Daha uzun dizelerin 1 yerine 4 bayt ek yükü vardır. Uzun dizeler sistem tarafından otomatik olarak sıkıştırılır, bu nedenle diskteki fiziksel gereksinim daha az olabilir. Çok uzun değerler, daha kısa sütun değerlerine hızlı erişimi engellememeleri için arka plan tablolarında da saklanır.

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

VARCHAR'daki boyut özelliği, yalnızca eklenen değerlerin boyutunu kontrol etmek için kullanılır, disk düzenini etkilemez. Aslında, VARCHAR ve TEXT alanları Postgres'te aynı şekilde saklanır .


8
"Neden" hakkında daha fazla bilgi eklemek için asla çok geç! Tüm bu bilgiler için teşekkür ederim
Labynocle

Bazen veritabanınızın yapısında tutarlı olmanız gerekir. 2 sütunun bir ilişkisi olmasa bile, kavram açısından bir ilişkisi olabilir, örneğin EAV modelini kontrol edin.
Alexandre

38

Bir VARCHAR'ı 32'den 8'e düşürmeye ve ERROR: value too long for type character varying(8). Mümkün olduğunca SQL'e yakın kalmak istiyorum çünkü müşterinin tercihlerine göre farklı DBMS'ye geçmek zorunda kalabileceğimiz kendi kendine yapılmış JPA benzeri bir yapı kullanıyorum (PostgreSQL varsayılan olanıdır). Bu nedenle, Sistem tablolarını değiştirme hilesini kullanmak istemiyorum.

Aşağıdaki USINGifadeyi kullanmayı bitirdim ALTER TABLE:

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

@Raylu'nun belirttiği gibi, ALTERmasaya özel bir kilit alır, böylece diğer tüm işlemler tamamlanana kadar ertelenir.


2
ALTERMasa ve bulunanları engeller diğer tüm işlemleri özel bir kilit edinme
raylu

8

Redshift postgresql'de yeni sütun eklemek ve yenisini benim için çalışılan eski ile değiştirmek, daha fazla ayrıntı için bu bağlantıya bakın 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 tarafından açıklanan sayfanın önbelleği burada . Bunun da ölmesi durumunda, alter ifadesi şöyle görünür:

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

Tablonuz TABLO1 olduğunda, sütun COL1'dir ve bunu 35 karaktere ayarlamak istiyorsanız (bağlantıya göre eski amaçlar için +4 gereklidir, muhtemelen AH tarafından yorumlarda belirtilen ek yük).


7

değişikliği bir işleme koyarsanız, tablo kilitlenmemelidir:

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

Bu, 400.000'den fazla satır içeren bir masada birkaç saniye hızla parlayarak benim için çalıştı.


5
Açık işlem sarmalayıcısının ALTERifadenin kilitleme davranışını değiştirmesini neden bekliyorsunuz ? Öyle değil.
Erwin Brandstetter

işlem sarmalayıcısı olsun veya olmasın, kendinizi deneyin, büyük bir fark göreceksiniz.
jacktrade

2
Cevabınız asıl yanlış. Açık işlem sarmalayıcısı olmayan herhangi bir DDL ifadesi, bir işlemin içinde örtük olarak çalışır. Açık işlemin tek olası etkisi, kilitlerin açık olana kadar daha uzun süre tutulmasıdır COMMIT. Sarmalayıcı, yalnızca aynı işleme daha fazla komut eklemek istiyorsanız anlamlıdır.
Erwin Brandstetter

tamamen haklısın, ama ısrar ediyorum: kendini dene, devam et. ve sonra neden aynı şekilde çalışmadığını sorun.
jacktrade

Postgres 9.3'te yardımcı olmadı.
Noumenon

1

Boyutu değiştirmenin çok kolay bir yolunu buldum, yani "import javax.validation.constraints" yani "import javax.validation.constraints.Size;" nin bir parçası olan @Size (min = 1, max = 50) ek açıklaması

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

.....

)

Gönderiniz için teşekkürler! Lütfen gönderilerinizde imza / slogan kullanmayın. Kullanıcı kutunuz imzanız olarak sayılır ve profilinizi, kendinizle ilgili istediğiniz herhangi bir bilgiyi göndermek için kullanabilirsiniz. İmzalar / sloganlar hakkında SSS
Andrew Barber

0

Aşağıdaki alter tablosunu çalıştırmayı deneyin:

ALTER TABLE public.users 
ALTER COLUMN "password" TYPE varchar(300) 
USING "password"::varchar;
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.