Jest tu kilka nieporozumień:
Zerowy bitmapy jest nie część nagłówka sterty krotki. Według dokumentacji:
Istnieje nagłówek o stałym rozmiarze (zajmujący 23 bajty na większości komputerów), a następnie opcjonalna pusta mapa bitowa ...
Twoje 32 zerowalne kolumny są niepomyślne z dwóch powodów:
Bitmapa o wartości zerowej jest dodawana do wiersza i tylko wtedy, gdy w wierszu znajduje się co najmniej jedna rzeczywista NULL
wartość . Kolumny dopuszczające wartości zerowe nie mają bezpośredniego wpływu, a jedynie rzeczywiste NULL
wartości. Jeśli przydzielona jest pusta mapa bitowa, zawsze jest ona przydzielana całkowicie (wszystko lub nic). Rzeczywisty rozmiar pustej mapy bitowej wynosi 1 bit na kolumnę, w zaokrągleniu do następnego bajtu . Według aktualnego kodu sosu:
#define BITMAPLEN(NATTS) (((int)(NATTS) + 7) / 8)
Pusta mapa bitowa jest przydzielana za nagłówkiem krotki sterty, po której następuje opcjonalny identyfikator OID, a następnie dane wiersza. Początek OID lub danych wiersza jest oznaczony t_hoff
w nagłówku. Kod źródłowy komentarza :
Zauważ, że t_hoff musi być wielokrotnością MAXALIGN.
Po nagłówku krotki kupy znajduje się jeden wolny bajt, który zajmuje 23 bajty. Tak więc zerowa bitmapa dla wierszy do 8 kolumn faktycznie nie wiąże się z żadnymi dodatkowymi kosztami. Z dziewiątą kolumną w tabeli t_hoff
przesuwa się kolejny MAXALIGN
(zwykle 8) bajtów, aby zapewnić kolejne 64 kolumny. Tak więc następna granica będzie mieć 72 kolumny.
Aby wyświetlić informacje kontrolne klastra bazy danych PostgreSQL (włącznie MAXALIGN
), przykład typowej instalacji Postgres 9.3 na maszynie Debiana:
sudo /usr/lib/postgresql/9.3/bin/pg_controldata /var/lib/postgresql/9.3/main
Zaktualizowałem instrukcje w powiązanej cytowanej odpowiedzi .
To wszystko, nawet jeśli twoja ALTER TABLE
instrukcja uruchamia przepisywanie całej tabeli (co prawdopodobnie robi, zmieniając typ danych), 250K to naprawdę niewiele, i byłoby to kwestią sekund na każdej przyzwoitej maszynie (chyba że rzędy są niezwykle duże) . 10 minut lub więcej wskazuje zupełnie inny problem. Najprawdopodobniej twoje oświadczenie czeka na blokadę stołu.
Rosnąca liczba wpisów pg_stat_activity
oznacza więcej otwartych transakcji - oznacza równoczesny dostęp do tabeli (najprawdopodobniej), który musi czekać na zakończenie operacji.
Kilka ujęć w ciemności
Sprawdź ewentualne wzdęcia przy stole, spróbuj łagodnego VACUUM mytable
lub bardziej agresywnego VACUUM FULL mytable
- który może napotkać te same problemy z współbieżnością, ponieważ ta forma zyskuje również wyłączną blokadę. Zamiast tego możesz spróbować pg_repack ...
Zacznę od sprawdzenia możliwych problemów z indeksami, wyzwalaczami, kluczem obcym lub innymi ograniczeniami, szczególnie tymi dotyczącymi kolumny. Może to dotyczyć szczególnie uszkodzonego indeksu? Wypróbuj je wszystkie REINDEX TABLE mytable;
lub DROP
dodaj je ponownie ALTER TABLE
w tej samej transakcji .
Spróbuj uruchomić polecenie w nocy lub zawsze, gdy nie ma dużego obciążenia.
Metoda brute-force polega na zatrzymaniu dostępu do serwera, a następnie spróbuj ponownie:
Bez możliwości przypisania go, pomocne może być uaktualnienie do bieżącej wersji lub nadchodzącej wersji 9.4 . Wprowadzono kilka ulepszeń dla dużych tabel i szczegółów blokowania. Ale jeśli coś jest zepsute w twoim DB, prawdopodobnie powinieneś to najpierw zrozumieć.
SET NOT NULL
nie zmienia typu, po prostu dodaje ograniczenie - ale ograniczenie musi być sprawdzone względem tabeli, a to wymaga pełnego skanowania tabeli. 9.4 poprawia niektóre z tych przypadków, przyjmując słabsze blokady, ale wciąż jest dość ciężki.