Hier gibt es einige Missverständnisse:
Die Null-Bitmap ist nicht Teil des Heap-Tupel-Headers. Pro Dokumentation:
Es gibt einen Header mit fester Größe (der auf den meisten Computern 23 Byte belegt), gefolgt von einer optionalen Null-Bitmap ...
Ihre 32 nullbaren Spalten sind aus zwei Gründen nicht verdächtig:
Die Null-Bitmap wird pro Zeile hinzugefügt , und zwar nur, wenn mindestens ein tatsächlicher NULL
Wert in der Zeile vorhanden ist. Nullable Spalten haben keine direkte Auswirkung, nur tatsächliche NULL
Werte. Wenn die Null-Bitmap zugewiesen ist, wird sie immer vollständig zugewiesen (alles oder nichts). Die tatsächliche Größe der Null-Bitmap beträgt 1 Bit pro Spalte, aufgerundet auf das nächste Byte . Gemäß aktuellem Quellencode:
#define BITMAPLEN(NATTS) (((int)(NATTS) + 7) / 8)
Die Null-Bitmap wird nach dem Heap-Tupel-Header zugewiesen, gefolgt von einer optionalen OID und anschließend Zeilendaten. Der Beginn einer OID oder von Zeilendaten wird t_hoff
im Header durch angezeigt . Quellcode pro Kommentar :
Beachten Sie, dass t_hoff ein Vielfaches von MAXALIGN sein muss.
Nach dem Heap-Tupel-Header befindet sich ein freies Byte, das 23 Bytes belegt. Die Null-Bitmap für Zeilen mit bis zu 8 Spalten ist also effektiv ohne zusätzliche Kosten. Mit der 9. Spalte in der Tabelle werden t_hoff
weitere MAXALIGN
(normalerweise 8) Bytes erweitert, um weitere 64 Spalten bereitzustellen. Die nächste Grenze wäre also 72 Spalten.
So zeigen Sie Steuerinformationen eines PostgreSQL-Datenbankclusters (inkl. MAXALIGN
) An, Beispiel für eine typische Installation von Postgres 9.3 auf einem Debian-Computer:
sudo /usr/lib/postgresql/9.3/bin/pg_controldata /var/lib/postgresql/9.3/main
Ich habe die Anweisungen in der von Ihnen zitierten Antwort aktualisiert .
ALTER TABLE
Abgesehen davon sind 250 KB wirklich nicht so viel und würden auf jedem halbwegs anständigen Computer eine Frage von Sekunden sein (es sei denn, die Zeilen sind ungewöhnlich groß) , selbst wenn Ihre Anweisung ein Umschreiben einer ganzen Tabelle auslöst (was wahrscheinlich der Fall ist, wenn ein Datentyp geändert wird). . 10 Minuten oder mehr weisen auf ein völlig anderes Problem hin. Ihre Aussage wartet höchstwahrscheinlich darauf, eine Sperre für den Tisch zu bekommen.
Die wachsende Anzahl von Einträgen in pg_stat_activity
bedeutet offenere Transaktionen - zeigt an, dass gleichzeitig (höchstwahrscheinlich) gleichzeitig auf die Tabelle zugegriffen werden muss, bis der Vorgang abgeschlossen ist.
Ein paar Aufnahmen im Dunkeln
Suchen Sie nach einem möglichen Aufblähen des Tisches, versuchen Sie es mit einem sanften VACUUM mytable
oder aggressiveren Vorgang VACUUM FULL mytable
- bei dem möglicherweise dieselben Parallelitätsprobleme auftreten, da dieses Formular auch eine exklusive Sperre erhält. Sie könnten stattdessen pg_repack versuchen ...
Ich würde zunächst mögliche Probleme mit Indizes, Triggern, Fremdschlüsseln oder anderen Einschränkungen untersuchen, insbesondere solche, die die Spalte betreffen. Insbesondere könnte ein beschädigter Index beteiligt sein? Probieren Sie REINDEX TABLE mytable;
oder DROP
alle aus und fügen Sie sie anschließend ALTER TABLE
in derselben Transaktion erneut hinzu .
Versuchen Sie, den Befehl nachts oder immer dann auszuführen, wenn nicht viel Last vorhanden ist.
Eine Brute-Force-Methode wäre, den Zugriff auf den Server zu beenden und es dann erneut zu versuchen:
Ein Upgrade auf die aktuelle Version oder insbesondere auf die kommende Version 9.4 kann hilfreich sein, ohne dass Sie dies feststellen können . Es wurden verschiedene Verbesserungen für große Tabellen und für das Sperren von Details vorgenommen. Aber wenn in Ihrer Datenbank etwas kaputt ist, sollten Sie das wahrscheinlich zuerst herausfinden.
SET NOT NULL
nicht die Art ändern, es fügt nur eine Einschränkung - aber die Einschränkung muss geprüft gegen den Tisch, und das erfordert einen vollständigen Tabellenscan. 9.4 verbessert einige dieser Fälle, indem es schwächere Sperren verwendet, aber es ist immer noch ziemlich schwer.