Tabloya nullable sütun eklemenin maliyeti 10 dakikadan fazla


11

Bir tabloya yeni bir sütun eklemek için sorun var.
Birkaç kez çalıştırmayı denedim, ancak 10 dakikadan fazla çalıştıktan sonra, kilit süresi nedeniyle sorguyu iptal etmeye karar verdim.

ALTER TABLE mytable ADD mycolumn VARCHAR(50);

Kullanışlı bilgi:

  • PostgreSQL sürümü: 9.1
  • Sıra sayısı: ~ 250K
  • Sütun sayısı: 38
  • Sıfırlanabilir sütun sayısı: 32
  • Kısıtlama sayısı: 5 (1 PK, 3 FK, 1 UNIQUE)
  • Endeks sayısı: 1
  • İşletim Sistemi türü: Debian Squeeze 64

PostgreSQL'in boş sütunları yönetme şekli hakkında ilginç bilgiler buldum (HeapTupleHeader aracılığıyla).

İlk tahminim, bu tablonun zaten 8 bitlik 32 boş MAXALIGNdeğerli sütun olması nedeniyle , HeapTupleHeader 4 Bayt uzunluğundadır (doğrulanmadı ve nasıl yapılacağını bilmiyorum).

Bu nedenle, yeni bir boş sütun eklemek, yeni bir 8 bit eklemek için her satırda HeapTupleHeader'ın güncellenmesi gerekebilir ve MAXALIGNbu da performans sorunlarına neden olabilir.

Bu yüzden, tahminimin doğru olup olmadığını kontrol etmek için nullable sütun sayısını 31'e düşürmek için null edilebilir sütunlardan birini (gerçekte null edilemeyen) değiştirmeye çalıştım.

ALTER TABLE mytable ALTER myothercolumn SET NOT NULL;

Ne yazık ki, bu değişiklik çok uzun zaman alıyor, 5 dakikadan fazla, bu yüzden de iptal ettim.

Bu performans maliyetine neyin neden olabileceği hakkında bir fikriniz var mı?


1
Size bunun bir parçasını söyleyebilirim: Bir sütun türünü ikili uyumlu olmayan başka bir türe değiştirmek aslında yeni bir sütun oluşturur, verileri kopyalar ve eski sütunu bırakılan olarak ayarlar. Ancak, SET NOT NULLtürü değiştirmez, yalnızca bir kısıtlama ekler - ancak kısıtlama tabloya göre kontrol edilmelidir ve bu da tam bir tablo taraması gerektirir. 9.4 bu vakaların bazılarını daha zayıf kilitler alarak geliştirir, ancak yine de oldukça ağırdır.
Craig Ringer

1
Yavaş çalıştığından şüphelenmeden önce, ALTER TABLE'ın sadece bir kilit beklemediğinden emin olmanız gerekir. Kontrol ettiyseniz soruda belirtin.
Daniel Vérité

Teşekkürler Craig ve Daniel. Alter komutunu çalıştırdığımda, pg_stat_activity'de "true" (beklemede) ifadesiyle görünür, bunun bir kilit beklediği anlamına gelir! Kontrol etmek için iyi bir yol mu? Bu arada, bu değişikliği çalıştırmadan önce her şey yolunda gidiyor, ancak başladıktan birkaç saniye sonra, kilit sayısı artıyor

Daha iyi bir görünüm için sorguyu wiki.postgresql.org/wiki/Lock_dependency_information adresinden deneyin . Ya yapmayı unutan kalıcı işlemler ya da her zaman meşgul eden bu tablo ile ağır aktiviteleriniz var.
Daniel Vérité

Dba.SE'ye daha uygun olabilir.
Erwin Brandstetter

Yanıtlar:


8

Burada birkaç yanlış anlama var:

Boş bitmap olduğu değil yığın tuple'larının başlığının parçası. Belgelere göre:

Sabit boyutlu bir başlık (çoğu makinede 23 bayt kaplar), ardından isteğe bağlı bir boş bitmap ...

32 boş değerli sütununuz iki nedenden dolayı şüpheli:

  • Boş bitmap her satıra eklenir ve yalnızca satırda en az bir gerçek NULLdeğer varsa . Sıfırlanabilir sütunların doğrudan bir etkisi yoktur, yalnızca gerçek NULLdeğerler geçerlidir. Boş bitmap ayrılırsa, her zaman tam olarak ayrılır (tümü veya hiçbiri). Boş bitmap'in gerçek boyutu sütun başına 1 bittir ve sonraki bayta yuvarlanır . Mevcut sos kodu başına:

    #define BITMAPLEN(NATTS) (((int)(NATTS) + 7) / 8)
  • Boş bitmap, yığın demet başlığından sonra ayrılır ve ardından isteğe bağlı bir OID ve ardından satır verileri gelir. Bir OID veya satır verisinin başlangıcı t_hoffbaşlıkta ile gösterilir. Yorum başına kaynak kodu :

    T_hoff öğesinin MAXALIGN öğesinin katı olması gerektiğini unutmayın.

  • Yığın demet başlığından sonra 23 baytlık bir boş bayt vardır. Bu nedenle, 8 sütuna kadar olan satırlar için boş bitmap'in ek bir maliyeti yoktur. Tablodaki 9. sütun ile, başka bir 64 sütun sağlamak için başka t_hoffbir MAXALIGN(genellikle 8) bayt ilerletilir . Yani bir sonraki sınır 72 sütunda olacak.

PostgreSQL veritabanı kümesinin (dahil MAXALIGN) kontrol bilgilerini görüntülemek için, Postgres 9.3'ün Debian makineye tipik kurulumuna örnek:

    sudo /usr/lib/postgresql/9.3/bin/pg_controldata /var/lib/postgresql/9.3/main

Alıntıladığınız ilgili cevaptaki talimatları güncelledim .

Tüm bunlar bir yana, ALTER TABLEifadeniz tüm tabloyu yeniden yazmayı tetiklese bile (ki muhtemelen bir veri türünü değiştirir), 250K gerçekten çok fazla değildir ve herhangi bir yarım terbiyeli makinede saniyeler olur (satırlar alışılmadık derecede büyük olmadıkça) . 10 dakika veya daha fazla, tamamen farklı bir sorunu gösterir. İfadeniz büyük olasılıkla masaya kilitlenmeyi bekliyor.

Artan giriş sayısı, pg_stat_activitydaha fazla açık işlem anlamına gelir - işlemin bitmesini beklemek zorunda olan tabloya (büyük olasılıkla) eşzamanlı erişimi gösterir.

Karanlıkta birkaç atış

Olası masa şişkinliğini kontrol edin , aynı eşzamanlılık sorunlarıyla karşılaşabilecek nazik VACUUM mytableveya daha agresif bir deneyin VACUUM FULL mytable, çünkü bu form aynı zamanda özel bir kilit kazanır. Bunun yerine pg_repack'i deneyebilirsiniz ...

İndeksler, tetikleyiciler, yabancı anahtar veya diğer kısıtlamalarla, özellikle sütunu içerenlerle ilgili sorunları inceleyerek işe başladım. Özellikle bozuk bir dizin söz konusu olabilir mi? Hepsini REINDEX TABLE mytable;veya DROPhepsini deneyin ALTER TABLE ve aynı işlemden sonra tekrar ekleyin .

Komutu gece veya çok fazla yük olmadığında çalıştırmayı deneyin.

Bir kaba kuvvet yöntemi, sunucuya erişimi durdurmak ve daha sonra tekrar denemek olacaktır:

Sabitleyemeden, mevcut sürüme veya özellikle gelecek 9.4 sürümüne yükseltmek yardımcı olabilir . Büyük tablolar ve kilitleme detayları için çeşitli iyileştirmeler yapıldı. Ama DB'nizde kırık bir şey varsa, muhtemelen önce bunu anlamanız gerekir.


2
Neredeyse kesinlikle kilitler. Ancak, bir test olarak, her zaman tablonun bir kopyasını oluşturabilir ve bunu değiştirmeyi deneyebilirsiniz. Bu çok uzun sürmezse, sorunun gerçek değişiklik olmadığını biliyorsunuz.

Açıklamalar için teşekkürler Erwin. Bence haklısın, bu bir kilit sorunu gibi görünüyor. Pg_stat_activity'yi kontrol ettiğimde ALTER'imin "bekleme" doğru olduğunu görebiliyorum. Ne anlayamıyorum ALTER neden masada kilit alamıyorum, neden çalışan herhangi bir sorgu bulamıyorum, neden alamadım görünüyor. Ancak ALTER'im çalışmaya başlar başlamaz, diğer tüm sorgular bitmesini bekliyor. Dolayısıyla, etkinlik ALTER'in diğer tüm sorguları kilitlediğini, ancak ALTER'in kilidi almadığını gösterir. İyi anlamadığım bir şey olduğunu düşünüyorum!?

@ MatthieuVerrecchia: Richard'ın önerdiği testi denedin mi?
Erwin Brandstetter

1
Masamı yeni bir klonladım (pg_dump -> pg_sql ile). Yeni sütun, kilit sorununu onaylayan 50 ms'de doğru şekilde eklenmiştir. Bu arada, hala ALTER'in neden gerçekten standart db etkinliği ile kilitlenemediğini anlamıyorum.

1
@ErwinBrandstetter Önerilerinizi takip ettim ve bir VAKUM, sonra bir REINDEX denedim. REINDEX de engelliyordu, çünkü kilit de elde edemedi. Bazı araştırmalardan sonra, sorun düşündüğümüzden daha basitti .. Açık bir işlemle bir hafta kaldı <IDLE> kaldı Sorun çözüldü, teşekkürler her şey için bilgiler çok faydalıydı.
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.