2011-10-11 21 views
88

Gerçekten büyük bir tabloda (yaklaşık 30 milyon satır) ALTER TABLE komutu hakkında bir sorum var. Onun sütunlarından biri varchar(255) ve ben bir varchar(40) için yeniden boyutlandırmak istiyorum. Temelde, aşağıdaki komutu çalıştırarak köşemi değiştirmek istiyorum: süreç çok uzun ama benim masa ALTER tablo komutu sırasında artık okunabilir görünüyorsaPostgresql - bir varchar sütununun boyutunu değiştir

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

sorunum yok. Daha akıllı bir yol var mı? Belki yeni bir sütun ekleyin, eski sütundan değerleri kopyalayın, eski sütunu bırakın ve nihayet yeni olanı yeniden adlandırın.

Herhangi bir ipucu büyük takdir edilecektir! Teşekkürler,

Not: PostgreSQL 9.0 kullanıyorum.

+8

Sadece açık olmak gerekirse: Biliyorsunuz, 'yeniden boyutlandırma' tablonun daha az yer kaplamasına neden olmayacak mı? –

+0

Benim durumumda bile mi? Sütun en fazla 40 karakterlik (octet) 255 yerine mi olacak? – Labynocle

+10

PostgreSQL için varchar (255) 'derseniz, gerçek uzunluk 40 bayt olan bir değer için 255 bayt ayırır. 40 bayt (artı bazı iç ek yükler) tahsis edecektir. "ALTER TABLE" ile değiştirilecek tek şey, PG'den hata almadan o sütunda depolayabileceğiniz maksimum bayt sayısıdır. –

cevap

58

Resize a column in a PostgreSQL table without changing data adresinde bunun nasıl yapılacağı hakkında bir açıklama bulunmaktadır. Veritabanı kataloğu verilerini kesmelisin. Bunu resmi olarak yapmanın tek yolu, ALTER TABLE ile gerçekleşiyor ve yaptığınız gibi, değişikliğin devam ederken tüm tabloyu kilitleyip yeniden yazacağını belirttiniz.

Bunu değiştirmeden önce belgelerin Character Types bölümünü okuduğunuzdan emin olun. Burada bilmeniz gereken her türlü garip durum. Uzunluk kontrolü, değerler satırlarda saklandığında yapılır. Orada bir alt sınırını keserseniz, bu mevcut değerlerin boyutunu küçültmez. Değişikliği yaptıktan sonra alanın uzunluğunun> 40 karakter olduğu satırları arayan tüm tabloyu taramak akıllıca olacaktır. Bunları manuel olarak nasıl kırpacağınızı anlamanız gerekecek - bu yüzden sadece büyük boyutlu olanlarda bazı kilitleri geri yüklüyorsunuz - çünkü birisi bu satırdaki herhangi bir şeyi güncellemeye çalıştığında, şimdi bunu çok büyük olarak reddedecektir. satırın yeni sürümünü saklar. Hilarity kullanıcı için devam ediyor.

VARCHAR, PostgreSQL'de yalnızca SQL standardının ilgili korkunç bölümüne uymak için kullanılan korkunç bir türüdür. Çok veritabanlı uyumluluğa önem vermiyorsanız, verilerinizi TEXT olarak saklamayı düşünün ve uzunluğunu sınırlamak için bir kısıtlama ekleyin. Bu tablo kilidi/yeniden yazma sorunu olmadan etrafında değiştirebileceğiniz kısıtlamalar ve sadece zayıf uzunluk kontrolünden daha fazla bütünlük denetimi yapabilirler.

+0

Cevabınız için teşekkür ederiz. Bağlantınızı kontrol edeceğim. Tüm boyut içeriğim maksimum 40 karaktere sahip olduğu için manuel boyut kontrolü konusunda endişelenmiyorum.TEXT ile ilgili kısıtlama hakkında daha fazla bilgiye ihtiyacım var çünkü VARCHAR'ın lentgh'yi kontrol etmek için daha iyi olduğuna inanıyorum :) – Labynocle

+0

OP'nin problemini düzeltmeyen tehlikeli tavsiyeler ... – Sergey

+3

Değişim varchar uzunluğu tabloyu yeniden yazmaz. Kısıtlama uzunluğunu tam olarak tüm tabloya karşı KONTROL KONTROLÜ olarak kontrol edin. Uzunluğu arttırırsanız yapılacak bir şey yoktur, sadece sonraki ekleme veya güncellemeler daha büyük uzunlukları kabul eder. Uzunluğu azaltırsanız ve tüm satırlar yeni küçük kısıtlamayı geçirirse, Pg yeni eklemenin yazılması için sonraki eklere veya güncelleştirmelere izin vermenin yanı sıra başka bir işlem yapmaz. – Maniero

7

Burada, Greg Smith. Tarafından paylaşılan sayfa the cache. Eğer 35 karakterden (4 uyarınca eski amaçlar için gereklidir bunu ayarlamak istediğiniz

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

, sütun col1 ve: yanı ölür durumda, alter deyimi şuna benzer linke, muhtemelen yorumlarda AH tarafından belirtilen genel gider).

19

Bir VARCHAR'ı 32'den 8'e kesmeye ve ERROR: value too long for type character varying(8)'u almaya çalışırken aynı sorunla karşı karşıya kalıyordum. SQL'e olabildiğince yakın kalmak istiyorum çünkü müşterinin seçimlerine göre farklı DBMS'ye geçmek zorunda kalabileceğimiz, kendiliğinden oluşturulmuş JPA benzeri bir yapı kullanıyorum (PostgreSQL varsayılan model). Bu nedenle, Sistem tablolarını değiştirmenin hilesini kullanmak istemiyorum. tablo başka bir program tarafından erişilebilir olup olmadığını ya da masa endeksli ise gerçekten etkileri dikkate almadım

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

:

ben ALTER TABLE içinde USING ifadesini kullanarak sona erdi. Postgres'in otomatik olarak böyle bir şey yaptığını var mı?

ek açıklama @Size yani boyutunu değiştirmek için çok kolay bir şekilde bulduk
1

(min = 1, maksimum = 50) "ithal javax.validation.constraints", yani "ithal javax.validation.constraints parçasıdır .Boyut;"

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

..... 

) 
+0

Yayınınız için teşekkürler! Lütfen gönderilerinizde imzaları/sloganları kullanmayın. Kullanıcı kutunuz imzanız olarak sayılır ve beğendiğiniz kendiniz hakkında herhangi bir bilgi göndermek için profilinizi kullanabilirsiniz. [İmzalar/sloganlar hakkında SSS] (http://stackoverflow.com/faq#signatures) –

40

Tamam, SİZİN HALİNDE sütunu yeniden boyutlandırmak için gerek yok

... Muhtemelen geç partiye değilim, AMA!

Postgres, diğer bazı veritabanlarından farklı olarak, yalnızca dizeyi sığdırmak için yeterli alan kullanacak kadar akıllıdır (hatta daha uzun dizgiler için sıkıştırma kullanarak), böylece sütun VARCHAR olarak bildirilmiş olsa bile (255) - Sütundaki karakter dizileri, alan kullanımı 40 baytlık + 1 bayttır.

kısa dizisinin (126 taneye kadar bayt) için depolama gereksinimi 1 bayt artı durumda karakter boşluk dolgu içerir gerçek bir dize vardır. Daha uzun dizeler, 1 yerine 4 baytlık bir ek yüke sahiptir. Uzun dizeler, sistem tarafından otomatik olarak sıkıştırılır, dolayısıyla diskteki fiziksel gereksinimi daha az olabilir. Çok uzun değerler aynı zamanda arka plan tablolarında saklanan da daha kısa sütun değerlerine hızlı erişimini engellemezler. VARCHAR boyut dağılımı, yalnızca eklenen değerlere boyutunu kontrol etmek için kullanılır

(http://www.postgresql.org/docs/9.0/interactive/datatype-character.html), bu disk düzeni etkilemez. Aslında, VARCHAR and TEXT fields are stored in the same way in Postgres.

+6

"Neden" hakkında daha fazla bilgi eklemek için asla çok geç değil! Tüm bu bilgiler için teşekkürler – Labynocle

+0

Bazen veritabanınızın yapısında tutarlı olmanız gerekir. 2 kolonun bir ilişkisi olmasa bile, örneğin EAV modelini kontrol etmek için konsept açısından bir ilişkiye sahip olabilirler. – Alexandre

4

yeni bir sütun ekleme ve kırmızıya kayma postgresql üzerine, benim için çalıştı eski ile yenisini yerine PostgreSQL 9.1 olarak daha fazla ayrıntı 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; 
49

için bu bağlantıyı bakın daha kolay bir yolu

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

var
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) | 
+4

Bunun yalnızca ** daha büyük ** boyutlarını belirttiğiniz için çalıştığını unutmayın (30> 10). Boyut daha küçükse, [benden aynı hata] alırsınız (http://stackoverflow.com/a/10991954/1098603). – Matthieu

3

Eğer alter bir işleme koyarsanız, tablo kilitlenmemelidir:

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

Bu, hızlı bir şekilde, 400 k'dan fazla satır içeren bir tabloda birkaç saniye yanmaya çalıştı.

+0

Neden açık işlem sarmalayıcısının "ALTER" ifadesinin kilitleme davranışını değiştirmesini bekliyorsunuz? Olmaz. –

+0

Kendinizi deneyin, işlem paketleyicisiyle veya işlemesiz, büyük bir fark göreceksiniz. – jipipayo

+0

Cevabınız ana para biriminde yanlış. Açık işlem sarıcı olmadan herhangi bir DDL ifadesi, bir işlemin içinde örtülü olarak çalışır. Açık işlemin tek olası etkisi, kilitlerin “daha ​​uzun *” - açık “COMMIT” olana kadar tutulmasıdır. Sarıcı, yalnızca aynı işleme daha fazla komut koymak istiyorsanız mantıklıdır. –