SQLite z dwoma procesami Pythona uzyskującymi do niego dostęp: jeden odczyt, jeden zapis

22

Tworzę mały system z dwoma komponentami: jeden odpytuje dane z zasobu internetowego i tłumaczy je na dane SQL, aby zachować je lokalnie; drugi odczytuje dane sql z lokalnej instancji i podaje je za pośrednictwem json i spokojnego interfejsu API.

Pierwotnie planowałem zachować dane w Postgresql, ale ponieważ aplikacja będzie miała bardzo małą ilość danych do przechowywania i ruchu do obsługi, pomyślałem, że to przesada. Czy SQLite spełnia Twoje zadanie? Podoba mi się pomysł na małą powierzchnię i nie muszę utrzymywać kolejnego serwera SQL dla tego jednego zadania, ale martwię się o współbieżność.

Wydaje się, że z włączonym rejestrowaniem z wyprzedzeniem zapisu, jednoczesne odczytywanie i zapisywanie bazy danych SQLite może się zdarzyć bez blokowania któregokolwiek procesu z bazy danych.

Czy pojedyncza instancja SQLite może wytrzymać dostęp do dwóch równoległych procesów, jeśli tylko jeden czyta, a drugi pisze? Zacząłem pisać kod, ale zastanawiałem się, czy jest to niewłaściwe zastosowanie SQLite.

nocleg ze śniadaniem
źródło
3
@gnat Cool. Czy pojedyncza instancja SQLite może wytrzymać dostęp do dwóch równoległych procesów, jeśli tylko jeden czyta, a drugi pisze? Zacząłem pisać kod, ale zastanawiałem się, czy jest to niewłaściwe zastosowanie SQLite.
bb
Tylko jedna głowa do góry. W mojej poprzedniej firmie korzystaliśmy z SQL (zarówno MS, jak i Oracle Express) do przechowywania danych i zawsze uważaliśmy, że przy tak małej ilości przechowywanych danych nie potrzebujemy pełnego DB. Dlatego w jednym z wydań postanowiliśmy zrobić dokładnie to, co robisz. Zamień te produkty na SQLite. Mieliśmy dokładnie to samo, jeden program piszący, który położyłby dane na dysku i zaktualizował TOC oparty na SQL i proces czytnika (wiele wątków), który odczytałby TOC, aby ustalić, które dane pobrać. Nie wiem o SQLite w dzisiejszych czasach, ale ta niewielka współbieżność, na którą natrafiliśmy, okazała się być dużym utrudnieniem w ...
DXM,
... z tyłu. Nie pamiętam wszystkich szczegółów, ale myślę, że gdy jeden proces próbował uzyskać blokadę, a nie mógł, ponieważ inny czytał, śpi przez coś szalonego jak 20-30 sekund. W rezultacie stworzyliśmy dedykowany wątek, który był odpowiedzialny za dostęp do SQLite, a następnie mieliśmy zarówno nasze procesy, jak i wszystkie wątki, serializując ich żądania DB do tego jednego wątku. Z perspektywy czasu prawdopodobnie nie wybrałbym SQLite ponownie.
DXM,
1
@DXM dziękuję za ostrzeżenie, ale po przeprowadzeniu kilku testów nie spotkałem się z niczym podobnym. Wiem, że sqlite przeszedł gruntowny przegląd w wersji 3, która miała miejsce około 2004 roku, więc zastanawiam się, czy twoje negatywne doświadczenia sięga wcześniej.
bb
1
... sam, zamiast polegać na schematach blokowania SQLite. Nie wykonałem pracy sam, był to kolejny zespół, ale pozostawałem w ciągłej pętli, głównie po to, by przekazywać opinie i być ciekawym. Połączyłem się także z internetem, poczytałem trochę samodzielnie i znalazłem oryginalną stronę autora. Po przeczytaniu tego miałem wrażenie, że wynalazca SQLite po prostu nienawidził wątków i nie rozumiał, dlaczego ktokolwiek miałby ich używać, więc a) DB nie został zaprojektowany z myślą o nich i b) dodano blokady / ochronę / włamał się na później, ponieważ zbyt wiele osób o to poprosiło.
DXM,

Odpowiedzi:

25

Szukasz dokumentacji dotyczącej blokowania plików i współbieżności .

Procesy SQLite używają serii blokad do obsługi współbieżności; czytać, kilka procesów może uzyskać SHAREDblokadę.

Proces, który pisze, będzie musiał uzyskać RESERVEDblokadę i tylko wtedy, gdy faktycznie trzeba opróżnić zmiany na dysku, przechodzi do PENDINGstanu. Każdy proces odczytu będzie wtedy musiał odblokować plik, po czym proces zapisu będzie mógł przejść do EXCLUSIVEzapisywania do rzeczywistego pliku bazy danych.

Ponieważ proces zapisujący musi tylko zablokować plik bazy danych dla rzeczywistych zapisów (opróżnianie pamięci, zatwierdzanie), konfiguracja z jednym czytnikiem i tylko jednym zapisującym będzie działać całkiem dobrze. Spodziewałbym się, że będzie on działał równie dobrze, jeśli nie lepiej, jako konfiguracja z tylko jednym procesem wykonującym całe czytanie i pisanie.

SQLite jest mniej odpowiedni, gdy wiele procesów często pisze w tej samej bazie danych, ponieważ pisanie wymaga uzyskania wyłącznej PENDINGblokady w celu serializacji zmian.

Martijn Pieters
źródło
Dzięki za dokładną odpowiedź Martijn! Mam kilka skryptów do przetestowania i wydaje się, że dwa procesy z przyjemnością odczytują i zapisują jednocześnie jedną instancję sqlite. Robiłem równolegle żądania odczytu i zapisu odpalane co 1/100 sekundy i nadal nie otrzymałem zablokowanego wyjątku db. O dziwo, jedyny raz, kiedy dostałem komunikat o błędzie „Zablokowana baza danych”, był przy ręcznej próbie (z klientem wiersza poleceń sqlite3) usunięcia kilku wierszy, gdy żądania odczytu odpalały się z mojego skryptu w 1/100 sekundy. Zastanawiam się, czy pysql automatycznie ponawia próbę zapisu po takim błędzie.
bb
10

Chciałem tylko sprawdzić i poinformować wszystkich, że wdrożenie zakończyło się powodzeniem. Praca z SQLite była prawdziwą przyjemnością i dzięki temu, że pisaliśmy go tylko w jednym procesie, nigdy nie mieliśmy problemów z blokowaniem ... nawet przy bardzo szybkich jednoczesnych odczytach z drugiego procesu.

nocleg ze śniadaniem
źródło