SQLite3 gestisce in modo sicuro l'accesso simultaneo da parte di più processi di lettura / scrittura dallo stesso DB? Ci sono delle eccezioni alla piattaforma?
SQLite3 gestisce in modo sicuro l'accesso simultaneo da parte di più processi di lettura / scrittura dallo stesso DB? Ci sono delle eccezioni alla piattaforma?
Risposte:
Se la maggior parte di questi accessi simultanei sono letti (ad es. SELECT), SQLite può gestirli molto bene. Ma se si inizia a scrivere contemporaneamente, la contesa tra i blocchi potrebbe diventare un problema. Molto dipenderà quindi da quanto è veloce il tuo filesystem, poiché lo stesso motore SQLite è estremamente veloce e ha molte ottimizzazioni intelligenti per ridurre al minimo la contesa. Soprattutto SQLite 3.
Per la maggior parte delle applicazioni desktop / laptop / tablet / telefono, SQLite è abbastanza veloce in quanto non c'è abbastanza concorrenza. (Firefox utilizza ampiamente SQLite per segnalibri, cronologia, ecc.)
Per le applicazioni server, qualcuno qualche tempo fa ha affermato che qualcosa di meno di 100.000 visualizzazioni di pagina al giorno potrebbero essere gestite perfettamente da un database SQLite in scenari tipici (ad esempio blog, forum) e non ho ancora visto alcuna prova del contrario. In effetti, con i moderni dischi e processori, il 95% dei siti Web e dei servizi Web funzionerebbe perfettamente con SQLite.
Se si desidera un accesso in lettura / scrittura molto veloce, utilizzare un database SQLite in memoria . La RAM è più veloce di molti ordini di grandezza rispetto al disco.
Sì, SQLite gestisce bene la concorrenza, ma non è la migliore dal punto di vista delle prestazioni. Da quello che posso dire, non ci sono eccezioni a questo. I dettagli sono sul sito di SQLite: https://www.sqlite.org/lockingv3.html
Questa affermazione è interessante: "Il modulo cercapersone garantisce che le modifiche avvengano tutte in una volta, che si verifichino tutte le modifiche o nessuna di esse, che due o più processi non provino ad accedere al database in modi incompatibili contemporaneamente"
Sì lo fa. Scopriamo perché
Tutte le modifiche all'interno di una singola transazione in SQLite si verificano completamente o per niente
Tale supporto ACID e le letture / scritture simultanee sono fornite in 2 modi - usando il cosiddetto journaling (chiamiamolo " vecchio modo ") o logging write-ahead (chiamiamolo " nuovo modo ")
In questa modalità SQLite utilizza il blocco DATABASE-LEVEL . Questo è il punto cruciale da capire.
Ciò significa che ogni volta che deve leggere / scrivere qualcosa acquisisce prima un blocco sul file di database INTERO . Più lettori possono coesistere e leggere qualcosa in parallelo
Durante la scrittura si assicura che venga acquisito un blocco esclusivo e che nessun altro processo sia in lettura / scrittura simultanea e che quindi le scritture siano sicure.
Ecco perché qui stanno dicendo strumenti SQlite transazioni serializzabili
Poiché deve bloccare un intero database ogni volta e tutti aspettano che un processo di gestione risulti compromesso dalla scrittura e tali scritture / letture simultanee hanno prestazioni piuttosto basse
Prima di scrivere qualcosa nel file di database, SQLite salverebbe innanzitutto il blocco da modificare in un file temporaneo. Se qualcosa si interrompe durante la scrittura nel file di database, questo file temporaneo viene prelevato e ripristinato le modifiche
In questo caso, tutte le scritture vengono aggiunte a un file temporaneo ( registro write-ahead ) e questo file viene periodicamente unito al database originale. Quando SQLite è alla ricerca di qualcosa, controlla prima questo file temporaneo e se non viene trovato nulla, procedi con il file di database principale.
Di conseguenza, i lettori non competono con gli scrittori e le prestazioni sono molto migliori rispetto al vecchio modo.
SQlite dipende fortemente dalla funzionalità di blocco del filesystem sottostante, quindi dovrebbe essere usato con cautela, maggiori dettagli qui
È anche probabile che si verifichi un errore di blocco del database , specialmente nella modalità journaling, quindi l'app deve essere progettata tenendo presente questo errore
Nessuno sembra aver menzionato la modalità WAL (Write Ahead Log). Assicurarsi che le transazioni siano organizzate correttamente e con la modalità WAL impostata, non è necessario mantenere bloccato il database mentre le persone leggono le cose mentre è in corso un aggiornamento.
L'unico problema è che a un certo punto il WAL deve essere nuovamente incorporato nel database principale e lo fa alla chiusura dell'ultima connessione al database. Con un sito molto affollato potresti trovare alcuni secondi per chiudere tutte le connessioni, ma 100K accessi al giorno non dovrebbero essere un problema.
database is locked
errore verrà generato dallo scrittore
Nel 2019, ci sono due nuove opzioni di scrittura simultanee non ancora rilasciate ma disponibili in rami separati.
Il vantaggio di questa modalità journal rispetto alla normale modalità "wal" è che gli scrittori possono continuare a scrivere su un file wal mentre l'altro è checkpoint.
INIZIA CONCORRENTE - link al documento dettagliato
Il miglioramento BEGIN CONCURRENT consente a più writer di elaborare le transazioni di scrittura contemporaneamente se il database è in modalità "wal" o "wal2", sebbene il sistema continui a serializzare i comandi COMMIT.
Quando viene aperta una transazione di scrittura con "BEGIN CONCURRENT", il blocco effettivo del database viene rinviato fino all'esecuzione di un COMMIT. Ciò significa che qualsiasi numero di transazioni avviate con BEGIN CONCURRENT può procedere contemporaneamente. Il sistema utilizza il blocco ottimistico a livello di pagina per impedire il commit di transazioni simultanee in conflitto.
Insieme sono presenti in begin-concorrente-wal2 o ciascuno in un proprio ramo separato .
begin concurrent
roba.
SQLite ha un blocco lettori-scrittore a livello di database. Connessioni multiple (possibilmente di proprietà di processi diversi) possono leggere i dati dallo stesso database contemporaneamente, ma solo uno può scrivere nel database.
SQLite supporta un numero illimitato di lettori simultanei, ma consentirà un solo writer in qualsiasi momento nel tempo. Per molte situazioni, questo non è un problema. Writer in coda. Ogni applicazione fa in modo che il suo database funzioni rapidamente e vada avanti e nessun blocco dura più di qualche decina di millisecondi. Ma ci sono alcune applicazioni che richiedono più concorrenza e quelle applicazioni potrebbero aver bisogno di cercare una soluzione diversa. - Usi appropriati per SQLite @ SQLite.org
Il blocco lettori-scrittore consente l'elaborazione di transazioni indipendenti ed è implementato utilizzando blocchi esclusivi e condivisi a livello di database.
È necessario ottenere un blocco esclusivo prima che una connessione esegua un'operazione di scrittura su un database. Dopo aver ottenuto il blocco esclusivo, entrambe le operazioni di lettura e scrittura da altre connessioni vengono bloccate fino al rilascio del blocco.
SQLite ha una tabella di blocco che aiuta a bloccare il database il più tardi possibile durante un'operazione di scrittura per garantire la massima concorrenza.
Lo stato iniziale è SBLOCCATO e in questo stato la connessione non ha ancora effettuato l'accesso al database. Quando un processo è collegato a un database e anche una transazione è stata avviata con INIZIA, la connessione è ancora nello stato SBLOCCATO.
Dopo lo stato SBLOCCATO, lo stato successivo è lo stato CONDIVISO. Per poter leggere (non scrivere) i dati dal database, la connessione deve prima entrare nello stato CONDIVISO, ottenendo un blocco CONDIVISO. Connessioni multiple possono ottenere e gestire blocchi SHARED contemporaneamente, quindi più connessioni possono leggere i dati dallo stesso database contemporaneamente. Fintanto che anche un solo blocco CONDIVISO rimane inedito, nessuna connessione può completare con successo una scrittura nel database.
Se una connessione desidera scrivere nel database, deve prima ottenere un blocco RISERVATO.
È possibile attivare solo un singolo blocco RISERVATO alla volta, sebbene più blocchi CONDIVISI possano coesistere con un singolo blocco RISERVATO. RISERVATO differisce da IN ATTESA in quanto è possibile acquisire nuovi blocchi CONDIVISI mentre è presente un blocco RISERVATO. - Blocco dei file e concorrenza in SQLite versione 3 @ SQLite.org
Una volta che una connessione ottiene un blocco RISERVATO, può iniziare a elaborare le operazioni di modifica del database, sebbene queste modifiche possano essere eseguite solo nel buffer, piuttosto che effettivamente scritte sul disco. Le modifiche apportate al contenuto della lettura vengono salvate nel buffer di memoria. Quando una connessione desidera inviare una modifica (o transazione), è necessario aggiornare il blocco RISERVATO a un blocco ESCLUSIVO. Per ottenere il blocco, è necessario innanzitutto sollevare il blocco su un blocco IN ATTESA.
Un blocco PENDING significa che il processo che tiene il blocco vuole scrivere nel database il più presto possibile e sta solo aspettando che tutti i blocchi SHARED attuali vengano cancellati in modo che possa ottenere un blocco ESCLUSIVO. Non sono consentiti nuovi blocchi condivisi sul database se è attivo un blocco PENDING, sebbene i blocchi condivisi esistenti possano continuare.
È necessario un blocco ESCLUSIVO per scrivere nel file di database. È consentito un solo blocco ESCLUSIVO sul file e nessun altro blocco di alcun tipo può coesistere con un blocco ESCLUSIVO. Al fine di massimizzare la concorrenza, SQLite lavora per ridurre al minimo il tempo di permanenza dei blocchi EXCLUSIVE. - Blocco dei file e concorrenza in SQLite versione 3 @ SQLite.org
Quindi potresti dire che SQLite gestisce in modo sicuro l'accesso simultaneo da più processi che scrivono sullo stesso DB semplicemente perché non lo supporta! Otterrai SQLITE_BUSY
o SQLITE_LOCKED
per il secondo autore quando raggiungerà la limitazione dei tentativi.
Questo thread è vecchio ma penso che sarebbe utile condividere il risultato dei miei test eseguiti su sqlite: ho eseguito 2 istanze di programma Python (diversi processi stesso programma) eseguendo istruzioni SELECT e UPDATE comandi sql all'interno della transazione con blocco ESCLUSIVO e timeout impostati su 10 secondi per ottenere un blocco e il risultato è stato frustrante. Ogni istanza ha fatto in 10000 step loop:
Anche se sqlite ha concesso il blocco esclusivo della transazione, il numero totale di cicli realmente eseguiti non era pari a 20.000 ma inferiore (il numero totale di iterazioni su un singolo contatore è stato conteggiato per entrambi i processi). Il programma Python non ha quasi generato alcuna eccezione (solo una volta durante la selezione per 20 esecuzioni). la revisione sqlite al momento del test era 3.6.20 e python v3.3 CentOS 6.5. Secondo me è meglio trovare un prodotto più affidabile per questo tipo di lavoro o limitare le scritture a sqlite a un singolo processo / thread unico.
with con
sia abbastanza.