PostgreSQL
 sql >> Baza danych >  >> RDS >> PostgreSQL

Jak zaktualizować PostgreSQL10 do PostgreSQL11 bez przestojów?

Historycznie najtrudniejszym zadaniem podczas pracy z PostgreSQL było zajmowanie się aktualizacjami. Najbardziej intuicyjnym sposobem aktualizacji, jaki można sobie wyobrazić, jest wygenerowanie repliki w nowej wersji i wykonanie w niej przełączenia awaryjnego aplikacji. W PostgreSQL nie było to po prostu możliwe w sposób natywny. Aby dokonać aktualizacji, trzeba było pomyśleć o innych sposobach aktualizacji, takich jak użycie pg_upgrade, zrzucanie i przywracanie lub korzystanie z narzędzi innych firm, takich jak Slony lub Bucardo, z których wszystkie mają swoje własne zastrzeżenia.

Dlaczego tak było? Ze względu na sposób, w jaki PostgreSQL implementuje replikację.

Wbudowana replikacja strumieniowa PostgreSQL jest tak zwana fizyczna:replikuje zmiany na poziomie bajt po bajcie, tworząc identyczną kopię bazy danych na innym serwerze. Ta metoda ma wiele ograniczeń, gdy myślisz o aktualizacji, ponieważ po prostu nie możesz stworzyć repliki w innej wersji serwera lub nawet w innej architekturze.

W tym miejscu PostgreSQL 10 zmienia zasady gry. W nowych wersjach 10 i 11 PostgreSQL implementuje wbudowaną replikację logiczną, która w przeciwieństwie do replikacji fizycznej, można replikować między różnymi głównymi wersjami PostgreSQL. To oczywiście otwiera nowe drzwi dla strategii ulepszania.

W tym blogu zobaczmy, jak możemy uaktualnić nasz PostgreSQL 10 do PostgreSQL 11 bez przestojów przy użyciu replikacji logicznej. Przede wszystkim przejdźmy przez wprowadzenie do replikacji logicznej.

Co to jest replikacja logiczna?

Replikacja logiczna to metoda replikacji obiektów danych i ich zmian w oparciu o ich tożsamość replikacji (zwykle klucz podstawowy). Opiera się na trybie publikowania i subskrybowania, w którym jeden lub więcej subskrybentów subskrybuje jedną lub więcej publikacji w węźle wydawcy.

Publikacja to zestaw zmian wygenerowany z tabeli lub grupy tabel (nazywany również zbiorem replikacji). Węzeł, w którym zdefiniowana jest publikacja, jest określany jako wydawca. Subskrypcja jest następną stroną replikacji logicznej. Węzeł, w którym zdefiniowana jest subskrypcja, określany jest mianem subskrybenta i określa on połączenie z inną bazą danych oraz zbiorem publikacji (jedną lub więcej), które chce subskrybować. Subskrybenci pobierają dane z publikacji, które subskrybują.

Replikacja logiczna ma architekturę podobną do fizycznej replikacji strumieniowej. Jest realizowany przez procesy „walsender” i „apply”. Proces walsendera rozpoczyna logiczne dekodowanie WAL i ładuje standardową wtyczkę dekodowania logicznego. Wtyczka przekształca zmiany odczytane z WAL na protokół replikacji logicznej i filtruje dane zgodnie ze specyfikacją publikacji. Dane są następnie w sposób ciągły przesyłane za pomocą protokołu replikacji strumieniowej do procesu roboczego aplikacji, który mapuje dane do lokalnych tabel i stosuje poszczególne zmiany w miarę ich odbierania, w prawidłowej kolejności transakcyjnej.

Diagram replikacji logicznej

Replikacja logiczna rozpoczyna się od wykonania migawki danych w bazie danych wydawcy i skopiowania jej do subskrybenta. Początkowe dane w istniejących subskrybowanych tabelach są zapisywane i kopiowane w równoległym wystąpieniu specjalnego rodzaju procesu stosowania. Ten proces utworzy własne tymczasowe gniazdo replikacji i skopiuje istniejące dane. Po skopiowaniu istniejących danych pracownik przechodzi w tryb synchronizacji, który zapewnia, że ​​tabela zostanie zsynchronizowana z głównym procesem wprowadzania, przesyłając strumieniowo wszelkie zmiany, które zaszły podczas początkowego kopiowania danych, przy użyciu standardowej replikacji logicznej. Po zakończeniu synchronizacji kontrola nad replikacją tabeli jest przekazywana z powrotem do głównego procesu wprowadzania, w którym replikacja jest kontynuowana normalnie. Zmiany w wydawcy są wysyłane do subskrybenta w czasie rzeczywistym.

Więcej informacji na temat replikacji logicznej można znaleźć w następujących blogach:

  • Przegląd replikacji logicznej w PostgreSQL
  • Replikacja strumieniowa PostgreSQL a replikacja logiczna

Jak zaktualizować PostgreSQL 10 do PostgreSQL 11 przy użyciu replikacji logicznej

Teraz, gdy wiemy, o co chodzi w tej nowej funkcji, możemy pomyśleć o tym, jak możemy jej użyć do rozwiązania problemu z uaktualnieniem.

Zamierzamy skonfigurować logiczną replikację między dwiema różnymi głównymi wersjami PostgreSQL (10 i 11) i oczywiście, gdy już to zadziała, to tylko kwestia wykonania przełączenia aplikacji do bazy danych w nowszej wersji.

Aby uruchomić replikację logiczną, wykonamy następujące kroki:

  • Skonfiguruj węzeł wydawcy
  • Skonfiguruj węzeł abonencki
  • Utwórz użytkownika subskrybenta
  • Utwórz publikację
  • Utwórz strukturę tabeli w subskrybencie
  • Utwórz subskrypcję
  • Sprawdź stan replikacji

Więc zacznijmy.

Po stronie wydawcy skonfigurujemy następujące parametry w pliku postgresql.conf:

  • listen_addresses:Na jakich adresach IP należy nasłuchiwać. Użyjemy „*” dla wszystkich.
  • wal_level:Określa, ile informacji jest zapisywanych w pliku WAL. Ustawimy to na logiczne.
  • max_replication_slots:Określa maksymalną liczbę gniazd replikacji obsługiwanych przez serwer. Musi być ustawiony na co najmniej liczbę subskrypcji, które mają się połączyć, plus pewną rezerwę na synchronizację tabeli.
  • max_wal_senders:Określa maksymalną liczbę jednoczesnych połączeń z serwerów w trybie gotowości lub podstawowych kopii zapasowych klientów przesyłania strumieniowego. Powinien być ustawiony na co najmniej taki sam jak max_replication_slots plus liczba fizycznych replik, które są połączone w tym samym czasie.

Pamiętaj, że niektóre z tych parametrów wymagały ponownego uruchomienia usługi PostgreSQL.

Plik pg_hba.conf również wymaga dostosowania, aby umożliwić replikację. Musimy zezwolić użytkownikowi replikacji na połączenie z bazą danych.

Na tej podstawie skonfigurujmy więc naszego wydawcę (w tym przypadku nasz serwer PostgreSQL 10) w następujący sposób:

  • postgresql.conf:
    listen_addresses = '*'
    wal_level = logical
    max_wal_senders = 8
    max_replication_slots = 4
  • pg_hba.conf:
    # TYPE  DATABASE        USER            ADDRESS                 METHOD
    host     all     rep     192.168.100.144/32     md5

Musimy zmienić użytkownika (w naszym przykładzie rep), który będzie używany do replikacji, oraz adres IP 192.168.100.144/32 na adres IP odpowiadający naszemu PostgreSQL 11.

Po stronie subskrybenta wymaga również ustawienia max_replication_slots. W takim przypadku należy ustawić co najmniej liczbę subskrypcji, które zostaną dodane do subskrybenta.

Inne parametry, które również należy tutaj ustawić, to:

  • max_logical_replication_workers:Określa maksymalną liczbę logicznych procesów roboczych replikacji. Obejmuje to zarówno pracowników zastosowania, jak i pracowników synchronizacji tabeli. Logiczne procesy robocze replikacji są pobierane z puli zdefiniowanej przez max_worker_processes. Musi być ustawiona na co najmniej liczbę subskrypcji, ponownie plus pewną rezerwę na synchronizację tabeli.
  • max_worker_processes:Ustawia maksymalną liczbę procesów w tle obsługiwanych przez system. Może zaistnieć potrzeba dostosowania, aby dostosować się do pracowników replikacji, co najmniej max_logical_replication_workers + 1. Ten parametr wymaga ponownego uruchomienia PostgreSQL.

Dlatego musimy skonfigurować naszego subskrybenta (w tym przypadku nasz serwer PostgreSQL 11) w następujący sposób:

  • postgresql.conf:
    listen_addresses = '*'
    max_replication_slots = 4
    max_logical_replication_workers = 4
    max_worker_processes = 8

Ponieważ ten PostgreSQL 11 będzie wkrótce naszym nowym masterem, powinniśmy rozważyć dodanie parametrów wal_level i archive_mode w tym kroku, aby uniknąć ponownego ponownego uruchomienia usługi później.

wal_level = logical
archive_mode = on

Te parametry będą przydatne, jeśli chcemy dodać nowe urządzenie podrzędne replikacji lub korzystać z kopii zapasowych PITR.

W wydawcy musimy utworzyć użytkownika, z którym połączy się nasz subskrybent:

world=# CREATE ROLE rep WITH LOGIN PASSWORD '*****' REPLICATION; 
CREATE ROLE

Rola używana do połączenia replikacji musi mieć atrybut REPLICATION. Dostęp dla roli musi być skonfigurowany w pg_hba.conf i musi mieć atrybut LOGIN.

Aby móc skopiować dane początkowe, rola używana do połączenia replikacji musi mieć uprawnienie SELECT do opublikowanej tabeli.

world=# GRANT SELECT ON ALL TABLES IN SCHEMA public to rep;
GRANT

Utworzymy publikację pub1 w węźle wydawcy dla wszystkich tabel:

world=# CREATE PUBLICATION pub1 FOR ALL TABLES;
CREATE PUBLICATION

Użytkownik, który utworzy publikację, musi mieć uprawnienie CREATE w bazie danych, ale aby utworzyć publikację, która automatycznie publikuje wszystkie tabele, użytkownik musi być superużytkownikiem.

W celu potwierdzenia utworzonej publikacji skorzystamy z katalogu pg_publication. Ten katalog zawiera informacje o wszystkich publikacjach utworzonych w bazie danych.

world=# SELECT * FROM pg_publication;
-[ RECORD 1 ]+------
pubname      | pub1
pubowner     | 16384
puballtables | t
pubinsert    | t
pubupdate    | t
pubdelete    | t

Opisy kolumn:

  • nazwawydawcy:nazwa publikacji.
  • wydawca:właściciel publikacji.
  • puballtables:Jeśli tak, ta publikacja automatycznie uwzględnia wszystkie tabele w bazie danych, w tym te, które zostaną utworzone w przyszłości.
  • pubinsert:Jeśli prawda, operacje INSERT są replikowane dla tabel w publikacji.
  • pubupdate:Jeśli prawda, operacje UPDATE są replikowane dla tabel w publikacji.
  • pubdelete:Jeśli prawda, operacje DELETE są replikowane dla tabel w publikacji.

Ponieważ schemat nie jest replikowany, musimy wykonać kopię zapasową w PostgreSQL 10 i przywrócić ją w naszym PostgreSQL 11. Kopia zapasowa zostanie wykonana tylko dla schematu, ponieważ informacje zostaną zreplikowane podczas początkowego transferu.

W PostgreSQL 10:

$ pg_dumpall -s > schema.sql

W PostgreSQL 11:

$ psql -d postgres -f schema.sql

Gdy mamy już nasz schemat w PostgreSQL 11, tworzymy subskrypcję, zastępując wartości host, dbname, user i password tymi, które odpowiadają naszemu środowisku.

PostgreSQL 11:

world=# CREATE SUBSCRIPTION sub1 CONNECTION 'host=192.168.100.143 dbname=world user=rep password=*****' PUBLICATION pub1;
NOTICE:  created replication slot "sub1" on publisher
CREATE SUBSCRIPTION

Powyższe spowoduje rozpoczęcie procesu replikacji, który zsynchronizuje początkową zawartość tabel w publikacji, a następnie rozpocznie replikację przyrostowych zmian w tych tabelach.

Użytkownik tworzący subskrypcję musi być superużytkownikiem. Proces ubiegania się o subskrypcję zostanie uruchomiony w lokalnej bazie danych z uprawnieniami superużytkownika.

Do weryfikacji utworzonej subskrypcji możemy posłużyć się wówczas katalogiem pg_stat_subscription. Ten widok będzie zawierał jeden wiersz na subskrypcję dla głównego pracownika (z pustym numerem PID, jeśli pracownik nie jest uruchomiony) oraz dodatkowe wiersze dla pracowników obsługujących początkową kopię danych subskrybowanych tabel.

world=# SELECT * FROM pg_stat_subscription;
-[ RECORD 1 ]---------+------------------------------
subid                 | 16428
subname               | sub1
pid                   | 1111
relid                 |
received_lsn          | 0/172AF90
last_msg_send_time    | 2018-12-05 22:11:45.195963+00
last_msg_receipt_time | 2018-12-05 22:11:45.196065+00
latest_end_lsn        | 0/172AF90
latest_end_time       | 2018-12-05 22:11:45.195963+00

Opisy kolumn:

  • subid:OID subskrypcji.
  • subname:Nazwa subskrypcji.
  • pid:identyfikator procesu procesu roboczego subskrypcji.
  • relid:OID relacji, którą synchronizuje pracownik; null dla głównego pracownika aplikacji.
  • received_lsn:Ostatnia odebrana lokalizacja dziennika zapisu z wyprzedzeniem, początkowa wartość tego pola to 0.
  • last_msg_send_time:Czas wysłania ostatniej wiadomości otrzymanej od oryginalnego nadawcy WAL.
  • last_msg_receipt_time:Czas otrzymania ostatniej wiadomości od nadawcy WAL.
  • latest_end_lsn:Ostatnia lokalizacja dziennika zapisu z wyprzedzeniem zgłoszona do pierwotnego nadawcy WAL.
  • latest_end_time:Czas ostatniej lokalizacji dziennika zapisu z wyprzedzeniem zgłoszony do pierwotnego nadawcy WAL.

Aby zweryfikować stan replikacji w masterze, możemy użyć pg_stat_replication:

world=# SELECT * FROM pg_stat_replication;
-[ RECORD 1 ]----+------------------------------
pid              | 1178
usesysid         | 16427
usename          | rep
application_name | sub1
client_addr      | 192.168.100.144
client_hostname  |
client_port      | 58270
backend_start    | 2018-12-05 22:11:45.097539+00
backend_xmin     |
state            | streaming
sent_lsn         | 0/172AF90
write_lsn        | 0/172AF90
flush_lsn        | 0/172AF90
replay_lsn       | 0/172AF90
write_lag        |
flush_lag        |
replay_lag       |
sync_priority    | 0
sync_state       | async

Opisy kolumn:

  • pid:identyfikator procesu procesu nadawcy WAL.
  • usesysid:OID użytkownika zalogowanego w tym procesie nadawcy WAL.
  • nazwa użytkownika:nazwa użytkownika zalogowanego w tym procesie nadawcy WAL.
  • nazwa_aplikacji:nazwa aplikacji, która jest połączona z tym nadawcą WAL.
  • client_addr:adres IP klienta połączonego z tym nadawcą WAL. Jeśli to pole ma wartość NULL, oznacza to, że klient jest połączony przez gniazdo Unix na serwerze.
  • nazwa_hosta_klienta:nazwa hosta podłączonego klienta zgłoszona przez odwrotne wyszukiwanie DNS klienta_addr. To pole nie będzie puste tylko dla połączeń IP i tylko wtedy, gdy log_hostname jest włączony.
  • client_port:numer portu TCP, którego klient używa do komunikacji z tym nadawcą WAL, lub -1, jeśli używane jest gniazdo Unix.
  • backend_start:Czas rozpoczęcia tego procesu.
  • backend_xmin:horyzont xmin tego trybu gotowości zgłaszany przez hot_standby_feedback.
  • stan:Bieżący stan nadawcy WAL. Możliwe wartości to:uruchamianie, przechwytywanie, przesyłanie strumieniowe, tworzenie kopii zapasowych i zatrzymywanie.
  • sent_lsn:Ostatnia lokalizacja dziennika zapisu z wyprzedzeniem wysłana w tym połączeniu.
  • write_lsn:ostatnia lokalizacja dziennika zapisu z wyprzedzeniem zapisana na dysku przez ten serwer w trybie gotowości.
  • flush_lsn:Ostatnia lokalizacja dziennika zapisu z wyprzedzeniem opróżniona na dysk przez ten serwer rezerwowy.
  • replay_lsn:Ostatnia lokalizacja dziennika zapisu z wyprzedzeniem odtworzona w bazie danych na tym serwerze rezerwowym.
  • write_lag:Czas, jaki upłynął od lokalnego opróżnienia ostatniego WAL-a do otrzymania powiadomienia, że ​​ten serwer rezerwowy go zapisał (ale jeszcze go nie opróżnił ani nie zastosował).
  • flush_lag:Czas, jaki upłynął od lokalnego opróżnienia ostatniego WAL-a do otrzymania powiadomienia, że ​​ten serwer rezerwowy go zapisał i opróżnił (ale jeszcze go nie zastosował).
  • replay_lag:Czas, jaki upłynął od lokalnego opróżnienia ostatniego WAL-a do otrzymania powiadomienia, że ​​ten serwer rezerwowy zapisał, opróżnił i zastosował go.
  • sync_priority:Priorytet tego serwera rezerwowego przy wybieraniu go jako synchronicznego trybu gotowości w replikacji synchronicznej opartej na priorytetach.
  • sync_state:Synchroniczny stan tego serwera w trybie gotowości. Możliwe wartości to async, potencjał, synchronizacja, kworum.

Aby zweryfikować, kiedy początkowy transfer się zakończył, możemy zobaczyć log PostgreSQL subskrybenta:

2018-12-05 22:11:45.096 UTC [1111] LOG:  logical replication apply worker for subscription "sub1" has started
2018-12-05 22:11:45.103 UTC [1112] LOG:  logical replication table synchronization worker for subscription "sub1", table "city" has started
2018-12-05 22:11:45.114 UTC [1113] LOG:  logical replication table synchronization worker for subscription "sub1", table "country" has started
2018-12-05 22:11:45.156 UTC [1112] LOG:  logical replication table synchronization worker for subscription "sub1", table "city" has finished
2018-12-05 22:11:45.162 UTC [1114] LOG:  logical replication table synchronization worker for subscription "sub1", table "countrylanguage" has started
2018-12-05 22:11:45.168 UTC [1113] LOG:  logical replication table synchronization worker for subscription "sub1", table "country" has finished
2018-12-05 22:11:45.206 UTC [1114] LOG:  logical replication table synchronization worker for subscription "sub1", table "countrylanguage" has finished

Lub sprawdzenie zmiennej srsubstate w katalogu pg_subscription_rel. Ten katalog zawiera stan dla każdej replikowanej relacji w każdej subskrypcji.

world=# SELECT * FROM pg_subscription_rel;
-[ RECORD 1 ]---------
srsubid    | 16428
srrelid    | 16387
srsubstate | r
srsublsn   | 0/172AF20
-[ RECORD 2 ]---------
srsubid    | 16428
srrelid    | 16393
srsubstate | r
srsublsn   | 0/172AF58
-[ RECORD 3 ]---------
srsubid    | 16428
srrelid    | 16400
srsubstate | r
srsublsn   | 0/172AF90

Opisy kolumn:

  • srsubid:Odniesienie do subskrypcji.
  • srrelid:Odniesienie do relacji.
  • srsubstate:kod stanu:i =inicjowanie, d =kopiowanie danych, s =synchronizacja, r =gotowość (normalna replikacja).
  • srsublsn:Zakończ LSN dla stanów s i r.

Możemy wstawić kilka rekordów testowych do naszego PostgreSQL 10 i sprawdzić, czy mamy je w naszym PostgreSQL 11:

PostgreSQL 10:

world=# INSERT INTO city (id,name,countrycode,district,population) VALUES (5001,'city1','USA','District1',10000);
INSERT 0 1
world=# INSERT INTO city (id,name,countrycode,district,population) VALUES (5002,'city2','ITA','District2',20000);
INSERT 0 1
world=# INSERT INTO city (id,name,countrycode,district,population) VALUES (5003,'city3','CHN','District3',30000);
INSERT 0 1

PostgreSQL 11:

world=# SELECT * FROM city WHERE id>5000;
  id  | name  | countrycode | district  | population
------+-------+-------------+-----------+------------
 5001 | city1 | USA         | District1 |      10000
 5002 | city2 | ITA         | District2 |      20000
 5003 | city3 | CHN         | District3 |      30000
(3 rows)

W tym momencie mamy wszystko gotowe, aby skierować naszą aplikację do naszego PostgreSQL 11.

W tym celu przede wszystkim musimy potwierdzić, że nie mamy opóźnienia replikacji.

Na urządzeniu głównym:

world=# SELECT  application_name,  pg_wal_lsn_diff(pg_current_wal_lsn(), replay_lsn) lag FROM pg_stat_replication;
-[ RECORD 1 ]----+-----
application_name | sub1
lag              | 0

A teraz musimy tylko zmienić nasz punkt końcowy z naszej aplikacji lub load balancera (jeśli taki mamy) na nowy serwer PostgreSQL 11.

Jeśli mamy load balancer, taki jak HAProxy, możemy go skonfigurować używając PostgreSQL 10 jako aktywnego i PostgreSQL 11 jako kopii zapasowej, w ten sposób:

Widok stanu HAProxy

Tak więc, jeśli po prostu zamkniesz master w PostgreSQL 10, serwer kopii zapasowej, w tym przypadku w PostgreSQL 11, zacznie odbierać ruch w sposób przejrzysty dla użytkownika/aplikacji.

Pod koniec migracji możemy usunąć subskrypcję w naszym nowym masterze w PostgreSQL 11:

world=# DROP SUBSCRIPTION sub1;
NOTICE:  dropped replication slot "sub1" on publisher
DROP SUBSCRIPTION

I sprawdź, czy został poprawnie usunięty:

world=# SELECT * FROM pg_subscription_rel;
(0 rows)
world=# SELECT * FROM pg_stat_subscription;
(0 rows)
Pobierz oficjalny dokument już dziś Zarządzanie i automatyzacja PostgreSQL za pomocą ClusterControlDowiedz się, co musisz wiedzieć, aby wdrażać, monitorować, zarządzać i skalować PostgreSQLPobierz oficjalny dokument

Ograniczenia

Przed użyciem replikacji logicznej pamiętaj o następujących ograniczeniach:

  • Schemat bazy danych i polecenia DDL nie są replikowane. Początkowy schemat można skopiować za pomocą pg_dump --schema-only.
  • Dane sekwencji nie są replikowane. Dane w kolumnach serii lub tożsamości poparte sekwencjami będą replikowane jako część tabeli, ale sama sekwencja nadal będzie pokazywać wartość początkową subskrybenta.
  • Obsługiwana jest replikacja poleceń TRUNCATE, ale należy zachować ostrożność podczas obcinania grup tabel połączonych kluczami obcymi. Podczas replikacji akcji obcinania subskrybent obcina tę samą grupę tabel, która została obcięta u wydawcy, jawnie określonej lub niejawnie zebranej za pomocą funkcji CASCADE, z pominięciem tabel, które nie są częścią subskrypcji. Będzie to działać poprawnie, jeśli wszystkie tabele, których dotyczy problem, są częścią tej samej subskrypcji. Ale jeśli niektóre tabele subskrybenta, które mają zostać obcięte, mają łącza klucza obcego do tabel, które nie są częścią tej samej (lub żadnej) subskrypcji, wówczas zastosowanie akcji obcinania na subskrybenta nie powiedzie się.
  • Duże obiekty nie są replikowane. Nie ma na to obejścia, poza przechowywaniem danych w normalnych tabelach.
  • Replikacja jest możliwa tylko z tabel podstawowych do tabel podstawowych. Oznacza to, że tabele po stronie publikacji i po stronie subskrypcji muszą być tabelami normalnymi, a nie widokami, widokami zmaterializowanymi, tabelami głównymi partycji lub tabelami obcymi. W przypadku partycji można replikować hierarchię partycji jeden do jednego, ale obecnie nie można replikować do innej konfiguracji partycjonowanej.

Wniosek

Utrzymywanie aktualnego serwera PostgreSQL poprzez regularne uaktualnianie było koniecznym, ale trudnym zadaniem aż do wersji PostgreSQL 10.

W tym blogu przedstawiliśmy krótkie wprowadzenie do replikacji logicznej, funkcji PostgreSQL wprowadzonej natywnie w wersji 10, i pokazaliśmy, jak może ona pomóc w realizacji tego wyzwania przy strategii zerowego czasu przestoju.


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Funkcja Postgres zwraca tabelę nie zwraca danych w kolumnach

  2. org.postgresql.util.PSQLException:indeks kolumny jest poza zakresem:3, liczba kolumn:2

  3. Indeks na sygnaturze czasowej:funkcje w wyrażeniu indeksu muszą być oznaczone jako IMMUTABLE

  4. Jak zaimportować zrzut Heroku PG na komputer lokalny?

  5. Zablokuj na SELECT, aby inny proces nie otrzymał starych danych