Live data from Hacker News

How bloom filters made SQLite 10x faster

avi.im

51–60 of 127 posts

Re: How bloom filters made SQLite 10x faster

#51

What happens if the table is one with a big number of deletes? The Bloom filter false positive rate will keep increasing as time goes on. One way to address this is to recalculate it every n deletes, but this sounds similar to AUTOVACUUM issues in PostgreSQL and might result in unexpected drops in performance

The article says "at the start of the join operation the bits will be set in the bloom filter".

So maybe this is built for every query? Would be needed anyway if there is a where clause for the joined table.

Re: How bloom filters made SQLite 10x faster

#53
post #38

Thanks to its simplicity for development and hosting SQLite has become our first choice for new Apps. We use a number of different ways to workaround its single concurrent writer limitation [1]. Whilst we're currently using Litestream for replication, we're currently evaluating switching to SQLite's native rsync [2]. [1] https://servicestack.net/posts/scalable-sqlite [2] https://www.sqlite.org/rsync.html

Litestream replicates continuously. sqlite3_rsync takes a snapshot. How do you plan to use the latter?

Re: How bloom filters made SQLite 10x faster

#54
post #15

Earlier quoted context omitted.

I think people overstate this. Yes, the sqlite concurrency model is a bad choice if you have a high degree of concurrent writes. However for many applications that simply isn't true. When it comes to websites i think people significantly overestimate the amount of concurrent writes.

Depending on the amount of write throughput you need and whether you care about latency, "concurrent writes" aren't necessarily a problem either. You can just shove them into a queue and then have a single thread pull stuff out of the queue and push it into SQLite. That still scales, up to a point.

No, because your readers are still blocked by writers and still randomly fail if you forgot to set busy_timeout, which is something at least one person didn't they had to do until they read this comment.

Re: How bloom filters made SQLite 10x faster

#55
post #38

Thanks to its simplicity for development and hosting SQLite has become our first choice for new Apps. We use a number of different ways to workaround its single concurrent writer limitation [1]. Whilst we're currently using Litestream for replication, we're currently evaluating switching to SQLite's native rsync [2]. [1] https://servicestack.net/posts/scalable-sqlite [2] https://www.sqlite.org/rsync.html

Dumb question, but how do you use SQLite on kubernetes? Indeed SQLite doesn't work over NFS (and I guess other remote file shares) so how do you share access to it to other pods?

Re: How bloom filters made SQLite 10x faster

#56
post #55
post #38

Thanks to its simplicity for development and hosting SQLite has become our first choice for new Apps. We use a number of different ways to workaround its single concurrent writer limitation [1]. Whilst we're currently using Litestream for replication, we're currently evaluating switching to SQLite's native rsync [2]. [1] https://servicestack.net/posts/scalable-sqlite [2] https://www.sqlite.org/rsync.html

Dumb question, but how do you use SQLite on kubernetes? Indeed SQLite doesn't work over NFS (and I guess other remote file shares) so how do you share access to it to other pods?

Without an additional layer you will have to be happy with a single vertically scaled instance of your application. If you want to resort to horizontal scaling, you can look into something like LiteFS

Re: How bloom filters made SQLite 10x faster

#57
post #7

SQLite is getting better and better. I am using it in production for a bunch of websites and never got a problem.

It should be fine for read-only data. If you want to write, be aware that only one process can write at a time, and if you forget to set busy_timeout at the start of the connection, it defaults to zero milliseconds and you'll get an error if another process has locked the database for writing while you try to read or write it. Client-server databases tend to handle concurrent writers better.

I thought WAL mode solves this. Am I misunderstanding the docs, or this SQLite running without a write ahead log?

There are advantages and disadvantages to using WAL instead of a rollback journal. Advantages include:

    WAL is significantly faster in most scenarios.
    WAL provides more concurrency as readers do not block writers and a writer does not block readers. Reading and writing can proceed concurrently.
    Disk I/O operations tends to be more sequential using WAL.
    WAL uses many fewer fsync() operations and is thus less vulnerable to problems on systems where the fsync() system call is broken.*

Re: How bloom filters made SQLite 10x faster

#58
post #21

Earlier quoted context omitted.

No, it's indeed a very real problem. I ran into with a very small service.

You want to configure it so it has a timeout. Take turns. That’s how locks work. The only difference between SQLite and Postgres write locking is the granularity.

sqlite also polls for lock availability

Re: How bloom filters made SQLite 10x faster

#59
post #17

Earlier quoted context omitted.

Maybe not such a great fit for sqlite: > One of the challenges with binary fuse filters, is that they are immutable once populated, so data cannot be added incrementally, and they consume a significant amount of memory during the populate process

Same restriction with cuckoo filters. Are there any better than bloom filters without this restriction?

I think you may be confusing the strict immutability of binary fuse with the "degraded" (aka need-to-resize-a-hash-table-once-"full") of https://en.wikipedia.org/wiki/Cuckoo_filter under high hash table load.

In any event, to address your question, most of the time people truncate to some round number of bytes (8, 16, 32, 64 bits, really) because this is very cheap, but it’s actually barely more expensive to truncate to any smaller than 64 number of bits with masks & shifts. Doing so with a back-to-back array of such truncated b-bit numbers (https://github.com/c-blake/adix/blob/master/adix/sequint.nim) structured as a regular hash table (such as robin hood linear probing (https://github.com/c-blake/adix/blob/master/adix/bltab.nim) where a hit or miss will likely only induce a nearly guaranteed single cache line miss up to ~90..95+% utilization) lets you make a filter with many fewer CPU cache misses (~10X fewer, but everything always depends on where you land in the parameter space) than a Bloom filter at a small 2..4X cost in more space.

There are some example numbers and a “calculus analysis” at the bottom of https://github.com/c-blake/adix/blob/master/tests/bl.nim, but it’s all only a few hundred lines of Nim and you could re-do a test in your favorite ProgLang. This table does eventually "fill up" like Cuckoo or any fixed malloc'd arena at which point people usually double/whatever to make more space resulting in a linear amortized cost growing up from zero. I would just call this a b-bit hash existence filter or maybe b-filter or bit-level filter if you want to get brief.

FWIW, I believe this was even understood by the aboriginal paper by Bloom in his 1970 CACM article (https://cacm.acm.org/research/space-time-trade-offs-in-hash-...) based upon his footnote2, though I think he was referring less to a CPU cache and more to "loading a whole word of memory at a time" like the 36-bit word IBM mainframes of the day, though these are similar mathematically (just think of a 64B cache-line as a 512-bit aligned word). Somehow it got lost in the teaching of Bloom filters.

To speculate on that "somehow", once you have a new dimension (accuracy in space-time-accuracy here), it is easy/natural to only consider "projections", but such oversimplifications can lead one astray. E.g., most people I know optimize for space only to indirectly optimize for time, but most discussion on this topic is about space-accuracy.

Re: How bloom filters made SQLite 10x faster

#60
post #36

Earlier quoted context omitted.

I was more thinking about solving NP hard problems. Modern CPUs are fast, if the benefit is worth it against the downstream task, just do it.

Most instances of most NP hard problems are fast and easy to solve in practice. Eg you have to go to quite a bit of effort to construct a knapsack problem that's hard to solve.

What complexity class will be the problem of construct only hards to solve knapsack (or others) problems?
Post reply on HN