Akses Bersamaan SQLite

177

Apakah SQLite3 aman menangani akses bersamaan dengan beberapa proses membaca / menulis dari DB yang sama? Apakah ada pengecualian platform untuk itu?

anand
sumber
3
Saya lupa menyebutkan karunia hadiah : sebagian besar jawaban mengatakan itu tidak apa-apa: "SQLite cukup cepat", "SQLite menangani concurrency dengan baik" dll. Tetapi, imho, jangan jawab secara detail / jangan jelaskan dengan jelas apa yang terjadi jika dua operasi penulisan akan tiba pada waktu yang sama (teoretis kasus yang sangat langka). 1) Apakah akan memicu kesalahan dan mengganggu program? atau 2) Apakah operasi penulisan yang kedua menunggu sampai yang pertama selesai? atau 3) Apakah salah satu operasi penulisan akan dibuang (kehilangan data!)? 4) Sesuatu yang lain? Mengetahui keterbatasan penulisan bersama mungkin berguna dalam banyak situasi.
Basj
7
@Basj Singkatnya, 2) ia akan menunggu dan mencoba lagi beberapa kali (Dikonfigurasi), 1) memicu kesalahan, SQLITE_BUSY.3) Anda dapat mendaftarkan Panggilan Balik Untuk Menangani Kesalahan SQLITE_BUSY.
obgnaw

Jawaban:

112

Jika sebagian besar akses bersamaan dibaca (misalnya SELECT), SQLite dapat menanganinya dengan sangat baik. Tetapi jika Anda mulai menulis secara bersamaan, pertikaian kunci bisa menjadi masalah. Banyak yang kemudian akan bergantung pada seberapa cepat filesystem Anda, karena mesin SQLite itu sendiri sangat cepat dan memiliki banyak optimasi pintar untuk meminimalkan pertikaian. Terutama SQLite 3.

Untuk sebagian besar aplikasi desktop / laptop / tablet / telepon, SQLite cukup cepat karena tidak ada cukup konkurensi. (Firefox menggunakan SQLite secara ekstensif untuk bookmark, riwayat, dll.)

Untuk aplikasi server, seseorang beberapa waktu lalu mengatakan bahwa tampilan halaman kurang dari 100 ribu sehari dapat ditangani dengan sempurna oleh database SQLite dalam skenario tipikal (misalnya blog, forum), dan saya belum melihat bukti yang bertentangan. Bahkan, dengan disk dan prosesor modern, 95% situs web dan layanan web akan bekerja dengan baik dengan SQLite.

Jika Anda ingin akses baca / tulis yang sangat cepat, gunakan database SQLite di dalam memori . RAM beberapa kali lipat lebih cepat daripada disk.

Kijin
sumber
16
OP tidak bertanya tentang efisiensi dan kecepatan, tetapi tentang akses bersamaan. Server web tidak ada hubungannya dengan itu. Sama di dalam basis data memori.
Jarekczek
1
Anda benar sampai batas tertentu tetapi efisiensi / kecepatan berperan. Akses yang lebih cepat berarti waktu yang dihabiskan untuk menunggu kunci lebih rendah, sehingga mengurangi kelemahan kinerja konkurensi SQLite. Khususnya, jika Anda memiliki sedikit dan menulis cepat, DB tampaknya tidak akan memiliki masalah konkurensi sama sekali bagi pengguna.
Caboose
1
bagaimana Anda mengelola akses bersamaan ke dalam database sqlite di dalam memori?
P-Gn
42

Ya, SQLite menangani konkurensi dengan baik, tetapi itu bukan yang terbaik dari sudut kinerja. Dari apa yang saya tahu, tidak ada pengecualian untuk itu. Detailnya ada di situs SQLite: https://www.sqlite.org/lockingv3.html

Pernyataan ini menarik: "Modul pager memastikan perubahan terjadi sekaligus, bahwa semua perubahan terjadi atau tidak ada yang dilakukan, bahwa dua atau lebih proses tidak mencoba mengakses database dengan cara yang tidak kompatibel pada saat yang sama"

vcsjones
sumber
2
Berikut adalah beberapa komentar tentang masalah pada platform yang berbeda , yaitu sistem file NFS, dan Windows (walaupun mungkin hanya berkaitan dengan versi Windows yang lama ...)
Nate
1
Apakah mungkin memuat database SQLite3 ke dalam RAM untuk digunakan untuk semua pengguna dalam PHP? Saya kira tidak dengan itu menjadi prosedural
Anon343224user
1
@foxyfennec .. titik awal, meskipun SQLite mungkin bukan db optimal untuk kasus penggunaan ini. sqlite.org/inmemorydb.html
kingPuppy
37

Ya itu. Mari kita cari tahu alasannya

SQLite bersifat transaksional

Semua perubahan dalam satu transaksi dalam SQLite terjadi sepenuhnya atau tidak sama sekali

Dukungan ACID dan baca / tulis bersamaan disediakan dalam 2 cara - menggunakan apa yang disebut penjurnalan (sebut saja " cara lama ") atau pencatatan selanjutnya ( tuliskan " cara baru ")

Penjurnalan (Jalan Lama)

Dalam mode ini SQLite menggunakan penguncian DATABASE-LEVEL . Ini adalah poin penting untuk dipahami.

Itu berarti setiap kali perlu membaca / menulis sesuatu, pertama-tama ia akan mendapatkan kunci pada file database SELURUH . Banyak pembaca dapat hidup berdampingan dan membaca sesuatu secara paralel

Selama menulis itu memastikan kunci eksklusif diperoleh dan tidak ada proses lain membaca / menulis secara bersamaan dan karenanya menulis aman.

Inilah sebabnya mengapa di sini mereka mengatakan bahwa SQlite mengimplementasikan transaksi berseri

Masalah

Karena perlu mengunci seluruh basis data setiap kali dan semua orang menunggu proses penanganan penulisan konkurensi menderita dan penulisan / pembacaan bersamaan tersebut memiliki kinerja yang cukup rendah

Kembalikan / pemadaman

Sebelum menulis sesuatu ke file database, SQLite terlebih dahulu akan menyimpan potongan untuk diubah dalam file sementara. Jika sesuatu crash di tengah penulisan ke dalam file database itu akan mengambil file sementara ini dan mengembalikan perubahan darinya

Write-Ahead Logging atau WAL (Cara Baru)

Dalam hal ini semua penulisan ditambahkan ke file sementara ( write-ahead log ) dan file ini secara berkala digabungkan dengan database asli. Ketika SQLite sedang mencari sesuatu, pertama-tama ia akan memeriksa file sementara ini dan jika tidak ada yang ditemukan lanjutkan dengan file database utama.

Akibatnya, pembaca tidak bersaing dengan penulis dan kinerjanya jauh lebih baik dibandingkan dengan Cara Lama.

Peringatan

SQlite sangat tergantung pada fungsi penguncian sistem file yang mendasarinya sehingga harus digunakan dengan hati-hati, lebih detail di sini

Anda juga kemungkinan akan mengalami kesalahan terkunci di dalam basis data , terutama dalam mode penjurnalan sehingga aplikasi Anda harus dirancang dengan mengingat kesalahan ini.

Pesta
sumber
34

Sepertinya tidak ada yang menyebutkan mode WAL (Write Ahead Log). Pastikan transaksi diatur dengan benar dan dengan mode WAL diaktifkan, tidak perlu untuk menjaga basis data tetap terkunci sementara orang-orang membaca hal-hal sementara pembaruan sedang berlangsung.

Satu-satunya masalah adalah bahwa pada beberapa titik WAL perlu dimasukkan kembali ke dalam database utama, dan hal ini terjadi ketika koneksi terakhir ke database ditutup. Dengan situs yang sangat sibuk, Anda mungkin perlu beberapa detik untuk menutup semua koneksi, tetapi 100 ribu hit per hari seharusnya tidak menjadi masalah.

akc42
sumber
Menarik, tetapi hanya bekerja pada satu mesin, bukan pada scenarious di mana database diakses di jaringan.
Bobik
Layak disebutkan bahwa batas waktu default bagi seorang penulis untuk menunggu adalah 5 detik dan setelah database is lockedkesalahan itu akan dinaikkan oleh penulis
mirhossein
16

Pada tahun 2019, ada dua opsi penulisan konkuren baru yang belum dirilis tetapi tersedia di cabang terpisah.

"PRAGMA journal_mode = wal2"

Keuntungan dari mode jurnal ini daripada mode "wal" biasa adalah bahwa penulis dapat terus menulis ke satu file wal sementara yang lain diperiksa dengan cermat.

BEGIN CONCURRENT - tautan ke dokumen terperinci

Peningkatan BEGIN CONCURRENT memungkinkan banyak penulis untuk memproses transaksi penulisan secara simultan jika database berada dalam mode "wal" atau "wal2", meskipun sistem masih membuat serial perintah COMMIT.

Ketika transaksi menulis dibuka dengan "BEGIN CONCURRENT", sebenarnya mengunci basis data ditangguhkan sampai KOMIT dijalankan. Ini berarti bahwa sejumlah transaksi yang dimulai dengan BEGIN CONCURRENT dapat dilanjutkan secara bersamaan. Sistem ini menggunakan penguncian tingkat-halaman yang optimis untuk mencegah komitmen transaksi bersamaan yang bertentangan.

Bersama-sama mereka hadir dalam wal-concurrent-wal2 atau masing-masing dalam cabang yang terpisah .

VB
sumber
1
Apakah kita tahu ketika fitur-fitur itu akan masuk ke versi rilis? Mereka benar-benar berguna bagi saya.
Peter Moore
2
Tidak ada ide. Anda dapat membangun dengan mudah dari cabang. Untuk .NET saya memiliki perpustakaan dengan antarmuka tingkat rendah & WAL2 + mulai bersamaan + FTS5: github.com/Spreads/Spreads.SQLite
VB
Oh, tentu, terima kasih. Saya lebih bertanya-tanya tentang stabilitas. Kedudukan SQLite yang cukup tinggi dalam hal perilisannya, tetapi saya tidak tahu seberapa risikonya menggunakan cabang dalam kode produksi.
Peter Moore
2
Lihat utas ini github.com/Expensify/Bedrock/issues/65 dan Bedrock secara umum. Mereka menggunakannya dalam produksi dan mendorong begin concurrentbarang - barang itu.
VB
13

SQLite memiliki kunci pembaca-penulis pada tingkat basis data. Banyak koneksi (mungkin dimiliki oleh proses yang berbeda) dapat membaca data dari database yang sama pada saat yang sama, tetapi hanya satu yang dapat menulis ke database.

SQLite mendukung jumlah pembaca simultan yang tidak terbatas, tetapi hanya akan memungkinkan satu penulis setiap saat. Untuk banyak situasi, ini bukan masalah. Penulis mengantri. Setiap aplikasi melakukan pekerjaan databasenya dengan cepat dan bergerak, dan tidak ada kunci yang bertahan lebih dari beberapa lusin milidetik. Tetapi ada beberapa aplikasi yang membutuhkan konkurensi lebih banyak, dan aplikasi tersebut mungkin perlu mencari solusi yang berbeda. - Penggunaan Yang Tepat Untuk SQLite @ SQLite.org

Kunci pembaca-penulis memungkinkan pemrosesan transaksi independen dan diimplementasikan menggunakan kunci eksklusif dan bersama di tingkat basis data.

Kunci eksklusif harus diperoleh sebelum koneksi melakukan operasi penulisan pada database. Setelah kunci eksklusif diperoleh, operasi baca dan tulis dari koneksi lain diblokir hingga kunci dilepaskan lagi.

Detail implementasi untuk kasus penulisan bersamaan

SQLite memiliki tabel kunci yang membantu mengunci database selambat mungkin selama operasi penulisan untuk memastikan konkurensi maksimum.

Keadaan awal UNLOCKED, dan dalam kondisi ini, koneksi belum mengakses database. Ketika suatu proses terhubung ke database dan bahkan transaksi telah dimulai dengan BEGIN, koneksi masih dalam keadaan UNLOCKED.

Setelah negara UNLOCKED, negara berikutnya adalah negara SHARED. Agar dapat membaca (tidak menulis) data dari basis data, koneksi harus terlebih dahulu memasuki kondisi SHARED, dengan mendapatkan kunci SHARED. Beberapa koneksi dapat memperoleh dan memelihara kunci SHARED pada saat yang sama, sehingga beberapa koneksi dapat membaca data dari database yang sama pada saat yang sama. Tetapi selama hanya satu kunci SHARED yang tidak dirilis, tidak ada koneksi yang berhasil menyelesaikan penulisan ke database.

Jika koneksi ingin menulis ke database, pertama-tama harus mendapatkan kunci RESERVED.

Hanya satu kunci RESERVED yang dapat aktif pada satu waktu, meskipun beberapa kunci SHARED dapat hidup berdampingan dengan satu kunci RESERVED. RESERVED berbeda dari PENDING di mana kunci SHARED baru dapat diperoleh saat ada kunci RESERVED. - Penguncian File Dan Konkurensi Dalam SQLite Versi 3 @ SQLite.org

Setelah koneksi memperoleh kunci RESERVED, itu dapat mulai memproses operasi modifikasi database, meskipun modifikasi ini hanya dapat dilakukan dalam buffer, daripada benar-benar ditulis ke disk. Modifikasi yang dilakukan pada konten pembacaan disimpan dalam buffer memori. Ketika koneksi ingin mengirimkan modifikasi (atau transaksi), perlu untuk memperbarui kunci RESERVED ke kunci EKSKLUSIF. Untuk mendapatkan kunci, Anda harus terlebih dahulu mengangkat kunci ke kunci PENDING.

Kunci PENDING berarti bahwa proses menahan kunci ingin menulis ke database sesegera mungkin dan hanya menunggu semua kunci SHARED saat ini untuk menghapus sehingga bisa mendapatkan kunci EKSKLUSIF. Tidak ada kunci SHARED baru diizinkan terhadap database jika kunci PENDING aktif, meskipun kunci SHARED yang ada diizinkan untuk melanjutkan.

Kunci EKSKLUSIF diperlukan untuk menulis ke file database. Hanya satu kunci EKSKLUSIF yang diizinkan pada file dan tidak ada kunci lain dalam bentuk apa pun yang diizinkan untuk hidup berdampingan dengan kunci EKSKLUSIF. Untuk memaksimalkan konkurensi, SQLite berfungsi untuk meminimalkan jumlah waktu yang dimiliki kunci EKSKLUSIF. - Penguncian File Dan Konkurensi Dalam SQLite Versi 3 @ SQLite.org

Jadi Anda bisa mengatakan SQLite dengan aman menangani akses bersamaan dengan beberapa proses menulis ke DB yang sama hanya karena tidak mendukungnya! Anda akan mendapatkan SQLITE_BUSYatau SQLITE_LOCKEDuntuk penulis kedua saat mencapai batasan coba lagi.

obgnaw
sumber
Terima kasih. Contoh kode dengan 2 penulis akan sangat hebat untuk memahami cara kerjanya.
Basj
1
@ Basj singkatnya, sqlite memiliki Baca-Tulis Kunci pada file database. Ini sama seperti menulis file bersamaan. Dan dengan WAL, masih tidak dapat menulis bersamaan, tetapi WAL dapat mempercepat penulisan, dan membaca dan menulis dapat bersamaan. Dan WAL memperkenalkan kunci baru seperti WAL_READ_LOCK, WAL_WRITE_LOCK.
obgnaw
2
Bisakah Anda menggunakan Antrian dan memiliki beberapa utas memberi makan Antrian dan hanya satu utas menulis ke DB menggunakan Pernyataan SQL dalam Antrian. Sesuatu seperti ini
Gabriel
7

Utas ini sudah lama tetapi saya pikir akan lebih baik untuk berbagi hasil pengujian saya yang dilakukan di sqlite: saya menjalankan 2 contoh program python (proses yang berbeda dengan program yang sama) mengeksekusi pernyataan SELECT dan UPDATE perintah sql dalam transaksi dengan kunci EKSKLUSIF dan batas waktu disetel ke 10 detik untuk mendapatkan kunci, dan hasilnya membuat frustrasi. Setiap contoh dilakukan dalam 10.000 langkah loop:

  • terhubung ke db dengan kunci eksklusif
  • pilih satu baris untuk membaca penghitung
  • perbarui baris dengan nilai baru sama dengan penghitung yang bertambah 1
  • tutup koneksi ke db

Bahkan jika sqlite memberikan kunci eksklusif pada transaksi, jumlah total siklus yang benar-benar dieksekusi tidak sama dengan 20 000 tetapi lebih sedikit (jumlah total iterasi atas penghitung tunggal dihitung untuk kedua proses). Program python hampir tidak membuang satu pun pengecualian (hanya sekali selama pilih untuk 20 eksekusi). revisi sqlite pada saat pengujian adalah 3.6.20 dan python v3.3 CentOS 6.5. Menurut pendapat saya, lebih baik untuk menemukan produk yang lebih dapat diandalkan untuk jenis pekerjaan ini atau membatasi menulis ke sqlite untuk satu proses / utas unik.

asf las
sumber
5
Sepertinya Anda perlu mengucapkan beberapa kata ajaib untuk mendapatkan kunci dalam python, seperti yang dibahas di sini: stackoverflow.com/a/12848059/1048959 Ini terlepas dari kenyataan bahwa dokumentasi python sqlite membuat Anda percaya bahwa itu with consudah cukup.
Dan Stahlke