Działa tu wiele czynników:
- Opóźnienie sieci i opóźnienia w obie strony
- Narzuty na instrukcje w PostgreSQL
- Przełączniki kontekstowe i opóźnienia harmonogramu
COMMIT
koszty, jeśli dla osób wykonujących jedno zatwierdzenie na wstawkę (nie jesteś)COPY
-specyficzne optymalizacje dla ładowania zbiorczego
Opóźnienie sieci
Jeśli serwer jest zdalny, możesz „płacić” stałą „cenę” za wyciąg, powiedzmy 50 ms (1/20 sekundy). Lub znacznie więcej w przypadku niektórych baz danych hostowanych w chmurze. Ponieważ następna wstawka nie może się rozpocząć, dopóki ostatnia nie zakończy się pomyślnie, oznacza to, że Twoje maksimum szybkość wstawiania wynosi 1000/w obie strony-opóźnienie-w-ms wierszy na sekundę. Przy opóźnieniu 50 ms („czas pingowania”) to 20 wierszy na sekundę. Nawet na serwerze lokalnym to opóźnienie jest niezerowe. Podczas gdy COPY
po prostu wypełnia okna wysyłania i odbierania TCP i przesyła wiersze tak szybko, jak DB może je zapisać, a sieć może je przesłać. Opóźnienie nie ma na niego dużego wpływu i może wstawiać tysiące wierszy na sekundę w tym samym łączu sieciowym.
Koszty instrukcji w PostgreSQL
Istnieją również koszty parsowania, planowania i wykonywania instrukcji w PostgreSQL. Musi brać blokady, otwierać pliki relacji, wyszukiwać indeksy itp. COPY
spróbuje zrobić to wszystko raz, na początku, a potem skoncentruj się na jak najszybszym załadowaniu wierszy.
Koszty przełączania zadań/kontekstu
Istnieją dodatkowe koszty czasu, ponieważ system operacyjny musi przełączać się między postgresem w oczekiwaniu na wiersz, podczas gdy aplikacja przygotowuje go i wysyła, a następnie, gdy aplikacja czeka na odpowiedź postgresa, podczas gdy postgres przetwarza wiersz. Za każdym razem, gdy przełączasz się z jednego na drugie, tracisz trochę czasu. Więcej czasu jest potencjalnie marnowane na zawieszanie i wznawianie różnych niskopoziomowych stanów jądra, gdy procesy wchodzą i wychodzą ze stanów oczekiwania.
Brakuje optymalizacji COPY
Co więcej, COPY
ma pewne optymalizacje, których może używać dla niektórych rodzajów obciążeń. Jeśli nie ma wygenerowanego klucza, a wartości domyślne są na przykład stałymi, może je wstępnie obliczyć i całkowicie ominąć executor, szybko ładując dane do tabeli na niższym poziomie, co całkowicie pomija część normalnej pracy PostgreSQL. Jeśli CREATE TABLE
lub TRUNCATE
w tej samej transakcji, którą COPY
, może wykonać jeszcze więcej sztuczek, aby przyspieszyć ładowanie, omijając normalne księgowanie transakcji potrzebne w bazie danych z wieloma klientami.
Mimo to COPY
w PostgreSQL wciąż może zrobić o wiele więcej, aby przyspieszyć rzeczy, rzeczy, których jeszcze nie wie, jak to zrobić. Może automatycznie pominąć aktualizacje indeksu, a następnie odbudować indeksy, jeśli zmieniasz więcej niż określoną część tabeli. Może wykonywać aktualizacje indeksu w partiach. Dużo więcej.
Koszty zobowiązań
Ostatnią rzeczą do rozważenia jest poniesienie kosztów. Prawdopodobnie nie stanowi to dla ciebie problemu, ponieważ psycopg2
domyślnie otwiera transakcję i nie zobowiązuje się, dopóki tego nie powiesz. Chyba że kazałeś mu korzystać z automatycznego zatwierdzania. Ale dla wielu sterowników DB automatyczne zatwierdzanie jest ustawieniem domyślnym. W takich przypadkach wykonałbyś jedno zatwierdzenie na każde INSERT
. Oznacza to opróżnianie jednego dysku, w którym serwer upewnia się, że zapisuje wszystkie dane z pamięci na dysk i każe dyskom zapisywać własne pamięci podręczne do trwałej pamięci masowej. Może to zająć długo czas i bardzo się różni w zależności od sprzętu. Mój laptop NVMe BTRFS z dyskiem SSD może wykonać tylko 200 fsyncs na sekundę, w porównaniu do 300 000 niezsynchronizowanych zapisów na sekundę. Więc załaduje tylko 200 wierszy na sekundę! Niektóre serwery mogą wykonać tylko 50 fsyncs/sekundę. Niektórzy mogą zrobić 20.000. Więc jeśli musisz regularnie zatwierdzać, spróbuj załadować i zatwierdzić partiami, wstawiaj w wielu wierszach itp. Ponieważ COPY
tylko jedno zatwierdzenie na końcu, koszty zatwierdzeń są znikome. Ale oznacza to również COPY
nie można odzyskać błędów w trakcie przechodzenia przez dane; cofa cały ładunek zbiorczy.