SQLite Begin Concurrent
sqlite.org
sqlite.org
https://sqlite.org/hctree/doc/hctree/doc/hctree/index.html
Discussion: https://news.ycombinator.com/item?id=34434025
On the bright side, the interface is simple enough, and maybe they could just swap out the implementation underneath for something more sophisticated later.
[1] Or on HDD, you really end up with lots of seeks for reading as well as writing. But that's probably unfair to consider: if you're using HDD, probably wanting more concurrency isn't your biggest opportunity to improve.
Currently, the lock granularity is the entire database. This makes it smaller.
The reason this isn't transactions by default is correctness concerns for programs.
It's optimistic concurrency. If there's a conflict, the client gets SQLITE_BUSY_SNAPSHOT and has to roll back and try again. There's no guarantee the second try will succeed either. They might need to back off (as in, sleep between attempts) and/or entirely stop using "BEGIN CONCURRENT" after n tries.
edit:
originally also wrote above: In fact, without some way of ensuring transactions write to pages in a consistent order, I don't think there's any guarantee any transaction will make progress. It could degenerate to livelock.
...but I think I was wrong about this part. I think SQLITE_BUSY_SNAPSHOT means another transaction actually committed touching these pages; so progress was made in the system as a whole.
Ah.
However, unless they do some very careful accounting, this sounds equivalent to snapshot isolation which has anomalies not found with serializable isolation, though the chance of this happening is reduced by using page level locking.
Otherwise you can’t properly abort the txn because a “select x where y” that was previously empty, no longer is.
The issues you describe only arise with concurrent inserts/updates into the same table. Essentially, what we would get if this got merged into the main branch is table level locking.
Moreover, high performance applications that want to saturate disk writing rates can usually afford to organize their architecture around making massively parallel modifications interference-free (for example, support for the nonconsecutive key assignments the article suggests has vast ramifications).
Edit: maybe it's still being actively developed?
In fact, one should always assume that a transaction might fail, since other databases aren't immune to conflicts and deadlocks, either. The only difference with SQLite is that it is very clear and explicit about what it is doing.
This capability has existed for years.
It’s just not in -main.
https://www.sqlite.org/src/timeline?r=begin-concurrent
What’s of more interest is the ‘bedrock’ branch that includes both WAL2 + BEGIN CONCURRENT
I really hope browsers/apps/etc don't enable this... but I'm sure many will. A fully sequential database is trivially safe in a way that is absurdly difficult to replicate with concurrency in the mix, and people consistently come to rely on that safety and not realize it.
---
I get the desire, and honestly putting it in sqlite is probably the right choice. With enough care, this seems like a very reasonable set of tradeoffs, and there will almost certainly be good, impactful uses of it. I'm just lamenting the inevitable human decisions this will lead to if it hits the standard feature set, because obviously concurrent is better and faster.
Like maybe by requiring completely different keywords for concurrent vs non-concurrent?
Putting a loaded gun within reach of millions of people is less safe than not doing that.
Now I can at least say "wait, there is concurrency in SQLite if we need it. No problem".
- SQLite is typically used on same-host without any networking…
- Meaning that latency is much, much lower…
- Meaning that you will have much fewer overlapping transactions at any given point in time…
- Which results in less memory usage and…
- An SQLite instance will remain “low-latency” in wall-clock time even under pressure…
- And you have more leeway for ping-ponging (the N+1 problem) which can reduce query complexity, amount of indices, etc
In short, the performance you can squeeze out of a SQLite system is is unexpectedly high, as long as you can fit app+db on the same machine. Instead, I believe you’d choose a single-master networked db often for other (legitimate, but typcially not perf) reasons.
As a meager indie dev, this is a very appealing trade off. I’m not a db expert, and looking at the total complexity and churn in the field, I really don’t want to become one. SQLite has like three knobs. And as a bonus, I can run the same system on client machines.
In my experience, the CPU utilization of process workers preparing data into SQL statements is generally the chokepoint in most/script programs instead of SQlite write speeds themselves. Of course, this is dependent on numerous factors such as the existence of indices, compexity of write operation, etc., but--as a rule--SQlite is much more efficient if I dedicate one process to handle all writes and optimize that process for speed (i.e. batch writes, etc.).
I generally think in terms of SQLite -> Firebird (maybe) -> PostgreSQL -> CockroachDB (or others). Just depends.
That increases complexity on the application side though.
Just as one example, imagine a mobile app that does a bulk data download, and needs to persist it all to the local database in a single transaction for consistency purposes. This transaction can take a couple of seconds, or maybe a minute of you're working with millions of rows.
Now without concurrency, your database is locked for the entire transaction, and this may block any user actions.
With WAL, you can at least continue doing reads during this transaction.
With BEGIN CONCURRENT, the user may be able to continue most actions, as long as it doesn't touch the same set of data.
Now there are other ways of solving this problem: use smaller transactions and different mechanisms to ensure consistency. Or use separate databases if you can structure your data that way. But BEGIN CONCURRENT can be a nice solution without having to restructure the data completely.
Now these data volumes may be extreme, but even with "background" transaction taking in the order of a second can have an impact on how responsive the app feels to the user.