SQLite Eşzamanlı Erişim


177

SQLite3, aynı DB'den okuma / yazma işlemlerini birden çok işlemle eşzamanlı erişimi güvenli bir şekilde ele alıyor mu? Bunun için herhangi bir platform istisnası var mı?


3
Ödül goall'den bahsetmeyi unuttum : çoğu cevap iyi olduğunu söylüyor: "SQLite yeterince hızlı", "SQLite eşzamanlılığı iyi idare ediyor" vb, ama imho, ayrıntılı cevap vermeyin / iki yazma işlemi varsa ne olduğunu net bir şekilde açıklamayın aynı anda gelecekti (teorik çok nadir bir durum). 1) Bir hata tetikler ve programı keser mi? veya 2) İkinci yazma işlemi birincisi bitene kadar bekler mi? veya 3) Yazma işlemlerinden biri atılacak mı (veri kaybı!)? 4) Başka bir şey mi? Eşzamanlı yazmanın sınırlarını bilmek birçok durumda yararlı olabilir.
18'de Basj

7
@Basj Kısacası, 2) birkaç kez bekleyip tekrar dener (Yapılandırılabilir), 1) bir hata tetikler, SQLITE_BUSY.3) SQLITE_BUSY Hatalarını Ele Almak İçin Bir Geri Arama kaydedebilirsiniz.
18'de obgnaw

Yanıtlar:


112

Bu eşzamanlı erişimlerin çoğu okunursa (örn. SELECT), SQLite bunları çok iyi işleyebilir. Ancak aynı anda yazmaya başlarsanız, kilit çekişme sorun haline gelebilir. SQLite motorunun kendisi son derece hızlı olduğundan ve çekişmeyi en aza indirmek için birçok akıllı optimizasyona sahip olduğundan, birçok şey dosya sisteminizin ne kadar hızlı olduğuna bağlı olacaktır. Özellikle SQLite 3.

Çoğu masaüstü / dizüstü bilgisayar / tablet / telefon uygulaması için, yeterli eşzamanlılık olmadığı için SQLite yeterince hızlıdır. (Firefox, yer imleri, geçmiş vb. İçin SQLite'yi yaygın olarak kullanır)

Sunucu uygulamaları için, bir süre önce birisi, günde 100 bin sayfadan daha az bir şeyin tipik senaryolarda (örn. Bloglar, forumlar) bir SQLite veritabanı tarafından mükemmel bir şekilde ele alınabileceğini söyledi ve bunun aksine bir kanıt görmedim. Aslında, modern diskler ve işlemcilerle, web sitelerinin ve web hizmetlerinin% 95'i SQLite ile iyi çalışır.

Gerçekten hızlı okuma / yazma erişimi istiyorsanız, bir bellek içi SQLite veritabanı kullanın . RAM, diskten daha hızlı birkaç kat daha büyüktür.


16
OP verimlilik ve hız hakkında değil, eşzamanlı erişim hakkında sorular sorar. Web sunucularının bununla hiçbir ilgisi yoktur. Aynı bellek veritabanında.
Jarekczek

1
Bir dereceye kadar haklısınız, ancak verimlilik / hız bir rol oynuyor. Daha hızlı erişim, kilitleri beklemek için harcanan zamanın daha az olması, böylece SQLite'nin eşzamanlılık performansının dezavantajlarını azaltır. Özellikle, çok az ve hızlı yazmanız varsa, DB'nin bir kullanıcıyla herhangi bir eşzamanlılık sorunu olmayacak gibi görünecektir.
Caboose

1
bellek içi sqlite veritabanına eşzamanlı erişimi nasıl yönetirsiniz?
P-Gn

42

Evet, SQLite eşzamanlılığı iyi işler, ancak performans açısından en iyisi değildir. Söyleyebileceğimden, bunun istisnası yok. Ayrıntılar SQLite sitesinde bulunmaktadır: https://www.sqlite.org/lockingv3.html

Bu deyim ilgi çekicidir: "Çağrı modülü, değişikliklerin bir anda gerçekleşmesini, tüm değişikliklerin gerçekleşmesini veya hiçbirinin yapılmamasını, iki veya daha fazla işlemin veritabanına aynı anda uyumsuz yollarla erişmeye çalışmadığını garanti eder."


2
NFS dosya sistemleri ve Windows gibi farklı platformlardaki sorunlar hakkında bazı yorumlar (yalnızca Windows'un eski sürümleriyle ilgili olsa da ...)
Nate

1
PHP'deki tüm kullanıcılar için kullanılacak bir SQLite3 veritabanını RAM'e yüklemek mümkün müdür? Ben prosedürel olmak ile hayır tahmin
Anon343224user

1
@foxyfennec .. bir başlangıç ​​noktası olsa da SQLite bu kullanım durumu için en uygun db olmayabilir. sqlite.org/inmemorydb.html
kingPuppy

37

Evet öyle. Neden olduğunu anlayalım

SQLite işlemsel

SQLite'taki tek bir işlemdeki tüm değişiklikler ya tamamen gerçekleşir ya da hiç gerçekleşmez

Bu tür ACID desteği ve eşzamanlı okuma / yazma işlemleri 2 yolla sağlanır - günlük kaydı adı verilen ( eski yöntem olarak adlandıralım ) veya yazma öncesi günlük kaydı (" yeni yöntem " olarak adlandırılır)

Günlük Kaydı (Eski Yol)

Bu modda SQLite, DATABASE-LEVEL kilitleme kullanır . Bunu anlamak çok önemli.

Bu, bir şeyi okumak / yazmak gerektiğinde, ilk önce ENTIRE veritabanı dosyasında bir kilit elde ettiği anlamına gelir . Birden fazla okuyucu birlikte var olabilir ve paralel olarak bir şey okuyabilir

Yazma sırasında özel bir kilidin alındığından ve başka hiçbir işlemin aynı anda okuma / yazma yapmadığından ve yazmaların güvenli olduğundan emin olur.

Bu nedenle burada onlar SQLite uygular söylüyorsun serilestirilebilir işlemler

sorunlar

Her seferinde tüm bir veritabanını kilitlemesi gerektiğinden ve herkes yazma işleminin eşzamanlılıktan muzdarip olduğunu ve bu tür eşzamanlı yazma / okumaların oldukça düşük performans gösterdiğinden

Rollbacks / kesintileri

Bir şey veritabanı dosyasına yazılmadan önce SQLite öncelikle değiştirilecek parçayı geçici bir dosyaya kaydederdi. Veritabanı dosyasına yazmanın ortasında bir şey çökerse, bu geçici dosyayı alır ve değişiklikleri geri alır

İleri Yazma veya WAL (Yeni Yol)

Bu durumda, tüm yazma işlemleri geçici bir dosyaya eklenir ( önceden yazma günlüğü ) ve bu dosya periyodik olarak orijinal veritabanıyla birleştirilir. SQLite bir şey ararken öncelikle bu geçici dosyayı kontrol eder ve hiçbir şey bulunmazsa ana veritabanı dosyasıyla devam edin.

Sonuç olarak, okuyucular yazarlarla rekabet etmez ve performans Eski Yol'a kıyasla çok daha iyidir.

Uyarılar

SQlite büyük ölçüde altta yatan dosya sistemi kilitleme işlevine bağlıdır, bu yüzden dikkatli kullanılmalıdır, daha fazla ayrıntı burada

Ayrıca , özellikle günlüklü modda veritabanında kilitli bir hatayla karşılaşma olasılığınız olduğundan, uygulamanızın bu hata göz önünde bulundurularak tasarlanması gerekir


34

Kimse WAL (İleriye Günlüğe Yaz) modundan bahsetmemiş gibi görünüyor. İşlemlerin düzgün bir şekilde organize edildiğinden ve WAL modu açıkken, bir güncelleme devam ederken insanlar bir şeyler okurken veritabanını kilitli tutmaya gerek yoktur.

Tek sorun, bir noktada WAL'ın ana veritabanına yeniden dahil edilmesi gerektiğidir ve veritabanına son bağlantı kapatıldığında bunu yapar. Çok yoğun bir siteyle, tüm bağlantıların yakın olması birkaç saniye alabilir, ancak günde 100.000 sonuç bir sorun olmamalıdır.


İlginç, ama sadece tek bir makinede çalışıyor, veritabanına ağ üzerinden erişildiği yerlerde değil.
Bobík

Bir yazarın beklemesi için varsayılan zaman aşımının 5 saniye olduğunu ve bu database is lockedhatadan sonra yazar tarafından yükseltileceğini belirtmek gerekir
mirhossein

16

2019'da henüz yayınlanmamış ancak ayrı dallarda bulunan iki yeni eşzamanlı yazma seçeneği var.

"PRAGMA journal_mode = wal2"

Bu günlük kipinin normal "wal" kipine göre avantajı, yazarların diğeri kontrol işaretli iken bir wal dosyasına yazmaya devam edebilmeleridir.

CONCURRENT'I BAŞLAT - ayrıntılı dokümana bağlantı

BEGIN CONCURRENT geliştirmesi, veritabanı "wal" veya "wal2" modundaysa, sistem hala COMMIT komutlarını serileştirse de, birden çok yazarın aynı anda yazma işlemlerini işlemesine izin verir.

"BAŞLANGIÇ BAŞLAT" ile bir yazma işlemi açıldığında, aslında bir COMMIT yürütülene kadar veritabanının kilitlenmesi ertelenir. Bu, BEGIN CONCURRENT ile başlatılan herhangi bir sayıda işlemin aynı anda devam edebileceği anlamına gelir. Sistem, çakışan eşzamanlı işlemlerin yapılmasını önlemek için iyimser sayfa düzeyinde kilitleme kullanır.

Birlikte, başlangıç -eşzamanlı-wal2'de veya her biri ayrı bir kendi dalında bulunurlar .


1
Bu özelliklerin ne zaman piyasaya sürüleceğine dair bir fikrimiz var mı? Benim için gerçekten kullanışlı olabilirler.
Peter Moore

2
Fikrim yok. Dallardan kolayca inşa edebilirsiniz. .NET için düşük seviyeli arayüze sahip bir kütüphanem var ve WAL2 + eşzamanlı olarak başlıyor + FTS5: github.com/Spreads/Spreads.SQLite
VB

Oh, kesinlikle teşekkürler. Kararlılığı daha çok merak ediyorum. SQLite'ın yayınları söz konusu olduğunda oldukça iyi bir çentik ama üretim kodunda bir şube kullanmanın ne kadar riskli olacağını bilmiyorum.
Peter Moore

2
Bu konu genel olarak github.com/Expensify/Bedrock/issues/65 ve Bedrock konularına bakın . Üretimde kullanıyorlar ve o begin concurrentşeyleri itiyorlardı.
VB

13

SQLite, veritabanı düzeyinde bir okuyucu-yazar kilidine sahiptir . Birden fazla bağlantı (muhtemelen farklı işlemlerin sahip olduğu) aynı veritabanındaki verileri aynı anda okuyabilir, ancak veritabanına yalnızca bir tanesi yazabilir.

SQLite sınırsız sayıda eşzamanlı okuyucuyu destekler, ancak herhangi bir anda sadece bir yazara izin verir. Birçok durumda, bu bir sorun değildir. Yazar sırası yükseldi. Her uygulama veritabanını hızlı bir şekilde çalışır ve devam eder ve hiçbir kilit birkaç düzine milisaniyeden fazla sürmez. Ancak daha fazla eşzamanlılık gerektiren bazı uygulamalar vardır ve bu uygulamaların farklı bir çözüm araması gerekebilir. - SQLite @ SQLite.org İçin Uygun Kullanım Alanları

Okuyucu-yazar kilidi, bağımsız işlem işlemeyi mümkün kılar ve veritabanı düzeyinde özel ve paylaşılan kilitler kullanılarak uygulanır.

Bir bağlantı bir veritabanında yazma işlemi gerçekleştirmeden önce özel bir kilit alınmalıdır. Özel kilit elde edildikten sonra, kilit tekrar açılana kadar diğer bağlantılardan hem okuma hem de yazma işlemleri engellenir.

Eşzamanlı yazma olayları için uygulama ayrıntıları

SQLite, maksimum eşzamanlılık sağlamak için yazma işlemi sırasında veritabanını olabildiğince geç kilitlemeye yardımcı olan bir kilit tablosuna sahiptir.

İlk durum KİLİTLENMEDİ ve bu durumda bağlantı henüz veritabanına erişmedi. Bir işlem bir veritabanına bağlandığında ve hatta BEGIN ile bir işlem başlatıldığında, bağlantı hala KİLİT AÇIK durumundadır.

UNLOCKED durumundan sonra, bir sonraki durum SHARED durumudur. Veritabanından veri okuyabilmek (yazamayabilmek) için, bağlantının önce bir PAYLAŞILAN kilit alarak SHARED durumuna girmesi gerekir. Birden çok bağlantı aynı anda PAYLAŞILAN kilitleri elde edip koruyabilir, böylece birden çok bağlantı aynı veritabanındaki verileri aynı anda okuyabilir. Ancak, yalnızca bir PAYLAŞILAN kilit bile yayınlanmadığı sürece, hiçbir bağlantı veritabanına yazma işlemini başarıyla tamamlayamaz.

Bir bağlantı veritabanına yazmak istiyorsa, ilk olarak bir REZERV kilit almalıdır.

Aynı anda yalnızca tek bir REZERV kilit etkin olabilir, ancak birden fazla PAYLAŞILAN kilit tek bir REZERV kilit ile birlikte bulunabilir. REZERV EDİLEN, REZERVED bir kilit varken yeni PAYLAŞILAN kilitlerin edinilebileceğinden PENDING'den farklıdır. - SQLite Sürüm 3'te Dosya Kilitleme ve Eşzamanlılık @ SQLite.org

Bir bağlantı bir REZERV kilit aldığında, veritabanı değişiklik işlemlerini işlemeye başlayabilir, ancak bu değişiklikler gerçekte diske yazılmak yerine yalnızca arabellekte yapılabilir. Okuma içeriğinde yapılan değişiklikler bellek arabelleğine kaydedilir. Bir bağlantı bir değişiklik (veya işlem) göndermek istediğinde, SAKLIDIR kilidini ÖZEL bir kilide yükseltmek gerekir. Kilidi almak için önce kilidi bir BEKLEME kilidine kaldırmanız gerekir.

BEKLEME kilidi, kilidi tutan işlemin mümkün olan en kısa sürede veritabanına yazmak istediğini ve ÖZEL bir kilit alabilmesi için tüm mevcut SHARED kilitlerinin temizlenmesini beklediği anlamına gelir. Beklemede bir kilit etkinse, veritabanına yeni PAYLAŞILAN kilitlerin girilmesine izin verilmez, ancak mevcut PAYLAŞILAN kilitlerin devam etmesine izin verilir.

Veritabanı dosyasına yazmak için özel bir kilit gerekir. Dosyada yalnızca bir EXCLUSIVE kilidine izin verilir ve EXCLUSIVE kilidiyle başka hiçbir kilidin bir arada bulunmasına izin verilmez. Eşzamanlılığı en üst düzeye çıkarmak için SQLite, ÖZEL kilitlerin tutulduğu süreyi en aza indirmeye çalışır. - SQLite Sürüm 3'te Dosya Kilitleme ve Eşzamanlılık @ SQLite.org

SQLite'nin aynı DB'ye yazdığı birden çok işlemle eşzamanlı erişimi güvenli bir şekilde işlediğini söyleyebilirsiniz, çünkü bunu desteklemez! Yeniden yazma sınırlamasına ulaştığında SQLITE_BUSYya SQLITE_LOCKEDda ikinci yazar için alacaksınız .


Teşekkür ederim. 2 yazarlı kod örneği, nasıl çalıştığını anlamak için çok iyi olurdu.
Basj

1
@Basj kısacası, sqlite veritabanı dosyasında Okuma-Yazma Kilidi var. Aynı anda bir dosya yazmakla aynı. Ve WAL ile eşzamanlı yazma hala mümkün değildir, ancak WAL yazmayı hızlandırabilir ve okuma ve yazma eşzamanlı olabilir.
obgnaw

2
Kuyruğu kullanabilir ve Kuyruğu besleyen birden çok iş parçacığı ve Kuyruktaki SQL Deyimlerini kullanarak DB'ye yalnızca bir iş parçacığı yazabilir misiniz? Böyle bir şey bu
Gabriel

7

Bu iş parçacığı eski ama sqlite üzerinde yapılan testlerimin sonucunu paylaşmak için iyi olacağını düşünüyorum: I HARİKA kilit ve zaman aşımı ayarlanmış işlem içinde deyimleri SELECT ve UPDATE sql komutları yürütme 2 python programı (farklı işlemler aynı program) koştu Kilit almak için 10 saniye ve sonuç sinir bozucu oldu. Her örnek 10000 adım döngüsünde yaptı:

  • özel kilit ile db'ye bağlan
  • sayaç okumak için bir satır seçin
  • tarafından artırılan sayaca eşit yeni bir değer ile satır güncelleme 1
  • db ile yakın bağlantı

Sqlite işlem sırasında özel kilit vermiş olsa bile, gerçekten yürütülen döngülerin toplam sayısı 20 000'e eşit değil, daha azdı (tek bir sayaç üzerindeki toplam yineleme sayısı her iki işlem için sayıldı). Python programı neredeyse tek bir istisna atmadı (20 yürütme için seçim sırasında sadece bir kez). test anındaki sqlite revizyonu 3.6.20 ve python v3.3 CentOS 6.5 idi. Benim görüşüme göre, bu tür bir iş için daha güvenilir bir ürün bulmak ya da yazarı sqlite ile tek benzersiz işlem / iş parçacığıyla sınırlamak daha iyidir.


5
Burada tartışıldığı gibi python'da bir kilit almak için bazı sihirli kelimeler söylemeniz gerekir: stackoverflow.com/a/12848059/1048959 Bu, python sqlite belgelerinin with conyeterli olduğuna inanmanıza neden olmasına rağmen .
Dan Stahlke
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.