9 ms·
I benchmarked six Go SQLite drivers
- dave78 3y agoI hadn't heard of sqinn before. According to these benchmarks it beats Cgo-based solutions most of the time, which makes it a very interesting candidate. Anyone have real-world experience using it?
- KomoD 3y ago(Sqinn is made by the same guy that made these benchmarks in case you didn't realize)
- dave78 3y agoI did not notice that, thanks for pointing it out.
- cvilsmeier 3y agoYes, in fact the benchmark started out as a comparison between sqinn and mattn. (There was no modernc at that time.)
- cvilsmeier 3y agoSqinn author here. Yes, sqinn performs quite well compared to the 'standard' mattn driver. The only use case it clearly breaks down is when SELECTing very large (gigabytes) resultsets.
- microtherion 3y agoThat stood out to me as well. Any insights why sqinn and zombie underperform in this case, and is the problem inherent to their design?
- cvilsmeier 3y agoFor sqinn it's because of its design: Shuffling that much data over process boundaries takes time. For zombie, more pprof would be needed to explain the behaviour.
- ncruces 3y agoI would suspect some unnecessary copying. Nothing else explains a “lower level” binding (zombie) performing worse than modernc. My (WASM) binding also has a lower level API. But I worked hard to make database/sql work first class, so I wouldn't expect much improvement.
- iansinnott 3y agoThanks for creating the benchmarks, I hadn't heard of most of those libs. I seem to remember that modernc worked great until i added a FTS5 [1] table and things became very slow. This was a while ago now, so it may have changed or I may mave misattributed the slowness to the non-CGO implementation. I'd be curious to see how each performs with a fts index and some triggers. [1]: https://www.sqlite.org/fts5.html https://www.sqlite.org/fts5.html
- Traubenfuchs 3y agoWhat a curious state, there is just one jdbc (=java) driver for SQLite. Why are there 6 (or more!) for Go?
- cvilsmeier 3y agoMaybe because Go devs are more allergic to 'non-Go' solutions that Java devs are to 'non-Java' solutions? (Explain: Java's xerial driver is a DLL/SO wrapped in a Java library)
- lmz 3y agoAlso because there's a mismatch between goroutines and C threads as described here https://www.cockroachlabs.com/blog/the-cost-and-complexity-of-cgo/ https://www.cockroachlabs.com/blog/the-cost-and-complexity-o... while Java threads can map 1:1 to C threads.
- butlerm 3y agoPerhaps someone should define a new C compatible threading API to allow C libraries (including glibc or a wrapper around glibc) to work with something other than native pthreads. Such as goroutines or Java threads and so on.
- morelisp 3y agoMany general M:N threading solutions have been tried over the years. As far as I know current thinking is still that you need substantial cooperation from a language runtime to make it worthwhile. (And even then it's hard - Java's first attempt failed and they went 1:1 essentially between 1998-2022.)
- eatonphil 3y agoIf you search "topic:jdbc topic:sqlite" on GitHub [0] (and look closely, since most results are not relevant) you'll see there are more than one (e.g. [1]). xerial may be the defacto SQLite driver for Java. mattn/go-sqlite3 is the defacto SQLite driver for Go. But there are other options. [0] https://github.com/search?q=topic%3Ajdbc%20topic%3Asqlite&type=repositories https://github.com/search?q=topic%3Ajdbc%20topic%3Asqlite&ty... [1] https://github.com/gwenn/sqlite-jna https://github.com/gwenn/sqlite-jna
- eatonphil 3y agoI've done some variations of this as well recently. For inserts: https://github.com/eatonphil/databases-intuition/blob/main/README.md#sqlite-prepared-insert https://github.com/eatonphil/databases-intuition/blob/main/R.... And for selects: https://github.com/eatonphil/databases-intuition/blob/main/README.md#sqlite https://github.com/eatonphil/databases-intuition/blob/main/R.... Our workloads are a bit different and obviously our machines are a bit different. Mine only compares mattn/go-sqlite3 to my own fork of https://github.com/bvinc/go-sqlite-lite https://github.com/bvinc/go-sqlite-lite. go-sqlite-lite seemed like an easier-to-use version of crawshaw's package but it was abandoned so I forked it to bring it up to date. I agree, for best performance you shouldn't use mattn/go-sqlite3. It does some extra work in hotpaths. It is also higher level and easier to use though. So pick what's important to you.
- Groxx 3y ago"without cgo" benchmarks should probably have comparisons for stuff like indexing too, since that's no longer in the shared C library that every other library uses - I would generally expect them to be slower here. And interop with Go code for custom funcs, since sqlite makes that so easy, where I'd expect them to be faster in at least some cases (no repeated cgo overhead). "Complex" kinda covers this, since there are foreign keys involved, and it's also where e.g. Zombie shows an uncharacteristic slowdown compared to the other benchmarks. Seems like it's probably not a coincidence?
- acatton 3y agoIn my personal opinion and usage, the performance doesn't matter. Only one driver is written in pure go, and can be easily statically compiled and/or cross-compiled. > modernc, modernc.org/sqlite, a pure Go solution. This is a newer library, based on the SQLite C code re-written in Go. Unless I'm mistaken, this is not a re-write in Go. This is a transpilation of the the SQLite C library into go, using https://gitlab.com/cznic/ccgo https://gitlab.com/cznic/ccgo
- vbezhenar 3y agoSqlite developers go to very great lengths making sure their software works reliably. You can't just introduce some transpiler in-between and expect that it'll work. It's a different software and it should not even be called sqlite IMO. The only proper way to use sqlite is to use FFI.
- jchw 3y agoIf the transpiler is not breaking any defined behavior in C, there is no reason to believe it cannot be a perfectly reasonable solution. There is nothing inherently wrong with targeting another programming language when compiling code, it does not mean there is anything wrong or broken with the generated code or its semantics. It is a less battle-tested C compiler, sure, but it's a C compiler. IMO, you can't argue that something shouldn't be called sqlite because it contains a transpiled copy of sqlite. To me this isn't really substantially different from transpiling sqlite to JS using Emscripten.
- arp242 3y ago> You can't just introduce some transpiler in-between and expect that it'll work Obviously it "works" and they didn't "just" transpile it but spent quite a bit of effort on this. Whether it's free of bugs that are not present in SQLite is a different matter. And while it's not run against the SQLite proprietary tests, it does pass all of the TCL tests IIRC, which are quite comprehensive on their own, so there shouldn't be huge glaring bugs.
- shp0ngle 3y agoThey run the whole testsuite on the transpiled code. I think. But yeah it does give me a little shiver to think you are transpiling C code to go code, and the go-code is not really "pure go", but has a platform-dependent unsafe operations. Just look at the repo https://gitlab.com/cznic/sqlite/-/tree/master/lib?ref_type=heads https://gitlab.com/cznic/sqlite/-/tree/master/lib?ref_type=h...
- auspiv 3y agoSure showing time and N works. But it'd be a lot easier to interpret the data quickly if it was shown in terms of operations per second. Smaller bars do not usually mean improved performance.
- jen20 3y ago… what? Lots of graphs for performance (especially latency) use smaller bars to mean better numbers.
- effnorwood 3y ago[dead]
- cp9 3y agothe thing about the mattn driver is that it supports all the features that sqlite itself supports. you can compile in vtables, extra stat stuff, which FTS option you want, anything. and if you use zig as your cross compiler you don't even need separate toolchains for the different arch/OS combos, it all just works
- ncruces 3y agoIt doesn't support everything. No driver likely does. An example of one thing missing is the pointer passing interface which limits the ability to create complex extensions. If support was added, the way function creation and virtual tables where wrapped would make it hard to use. But even more trivial things like a decent interface to incremental blob IO have been left unaddressed. https://www.sqlite.org/bindptr.html https://www.sqlite.org/bindptr.html https://github.com/mattn/go-sqlite3/issues/239 https://github.com/mattn/go-sqlite3/issues/239
- matharmin 3y agoI'd recommend doing these benchmarks with WAL mode and synchronous = NORMAL as well. It makes quite a big difference in performance especially with many small transactions (e.g. the first example that inserts without explicit transactions).
- HackerThemAll 3y ago[flagged]
- rpsw 3y agoDid you run the Go benchmarks on the same laptop to compare?
- HackerThemAll 3y agoYes, I did. Never exceeded 40k trivial queries per second. That was my last day with Go lang. Did not analyze what amounted to such bad perf, I entirely lost interest with the language. Later I learnt the way of Go's date formatting and then I put it in the same drawer as INTERCAL or Brainf*ck.
- neonsunset 3y agoThere was a comment from https://news.ycombinator.com/user?id=HackerThemAll https://news.ycombinator.com/user?id=HackerThemAll with neutral rating that was likely taken down by a mod action despite not violating the rules. I am reposting it below shortly with minor stylistic changes for politeness. “Go's SQLite drivers exhibit surprisingly poor performance. In C# I was able to conduct 2 millions of point queries per second on my laptop. And it's not the fastest language in the world. Go is overrated. It's crudely trying to imitate what Pascal had in '80s using awkward syntax and tooling, but giving you extra CVEs for free.” Personally, I did not expect it to be this bad…and C# SQLite drivers aren’t even something new - most of them have been written eons ago and consist of fairly standard somewhat allocatey code. I wonder if it’s because of significant interop overhead in Go, or just fundamental language limitations and quality issues.
- zmj 3y agoFFI was high priority for C# in the early days, when most meaningful .NET software was running on Windows and doing interop with win32. The runtime was designed to ensure that scenario would be low-overhead, and that legacy lives on in modern .NET.
- neonsunset 3y agoFFI very much remains a priority today which can be seen with changes and migration to [LibraryImport], bespoke NativeAOT modes to produce native dynamically or statically linked libraries which expose C ABI functions with [UnmanagedCallersOnly] and now there is also a project to implement direct Swift library evolution ABI interop for improved support of iOS with MAUI as one of its main goals.
- justinclift 3y agoAs a data point, the gwenn/gosqlite one for GitHub returns field data correctly even when an individual fields' data type doesn't match the column definition. https://github.com/gwenn/gosqlite https://github.com/gwenn/gosqlite That's important when processing data from untrusted sources (user generated content, etc). No idea how it compares to the others performance wise though. :)
- tedunangst 3y ago> Mattn, although the de-facto standard, is not the best overall solution. What's wrong with it?
- cvilsmeier 3y agoNothing wrong with it, but there are other drivers that cross-compile better and are faster.
- ncruces 3y agoI'm the author or the WASM (+wazero) based github.com/ncruces/go-sqlite3. Happy to field questions. W.r.t. benchmark results. wazero's current compiler is somewhat naive, which may explain a large performance delta in CPU bound tests. A new compiler is in the works [1]. OTOH it seems interesting that in the (IO bound?) large test I'm doing better than modernc. I wonder why. I'll dig deeper into the results. [1]: https://github.com/tetratelabs/wazero/pull/1869 https://github.com/tetratelabs/wazero/pull/1869
- ncruces 3y agoTo follow up, I made a new release with performance fixes, and here are the new results: https://github.com/ncruces/go-sqlite-bench/blob/98553a08199b5a97ae2fd11848b96c2d3e575123/README.md#benchmarks-for-golang-sqlite-drivers https://github.com/ncruces/go-sqlite-bench/blob/98553a08199b...
- ncruces 3y agoThe performance difference was larger than I had expected. But this is good. To fix a recent crash [1] that was happening due to a particular case of reentrancy, which only showed up when I implemented virtual tables and queried other tables to implement one (e.g.: Go calls sqlite3_step to execute a query, which calls Go because it's a query on virtual table, which calls sqlite3_step to scan another table) I introduced a performance regression. The fix [2] was not to reuse some objects I was allocating once per connection. A mitigation for the regression was (very naive) caching [3]. TLDR: my caching is just not good enough. Simply caching more will go a long way (confirmed already by doubling cache size), but now that I have a good benchmark, I'll do better. I expect to cut numbers for CPU bound tests in half due to this mishap. So, thanks cvilsmeier! [1]: https://github.com/ncruces/go-sqlite3/commit/a9e32fd3f0b9f394355a1953d4892243f6e365ff https://github.com/ncruces/go-sqlite3/commit/a9e32fd3f0b9f39... [2]: https://github.com/ncruces/go-sqlite3/commit/d862f47d95d522fb7a63aacf1259714aff986d46 https://github.com/ncruces/go-sqlite3/commit/d862f47d95d522f... [3]: https://github.com/ncruces/go-sqlite3/commit/9c562f5d8bf7436e17cb1b761f160bfe98d70679 https://github.com/ncruces/go-sqlite3/commit/9c562f5d8bf7436...
- ncruces 3y ago