Skip to content

Custom allocator degrades performance of concurrent reads for complex queries #356

Description

@jearbear

I'm porting an application from Postgres which has some non trivial queries that take ~20ms to execute. These queries are run concurrently using Task.async_stream. When using Postgres, this doesn't really affect the runtime of the individual queries so it yields a nice performance benefit. When I used SQLite (via ecto_sqlite3), I noticed that when run concurrently, they would seem to effectively run serially, like each query will just take longer so the total runtime doesn't improve.

The effect is minimal for simple queries, but much more noticeable for the more involved queries in my app. Which is unfortunate because chains of slow queries are the ones I'm more likely to attempt to speed up via concurrency 😅.

I believe this is happening due to the custom allocators used here: https://github.com/elixir-sqlite/exqlite/blob/main/c_src/sqlite3_nif.c#L1428-L1439. When I disable them, throughput starts scaling nicely with the number of workers as expected. (As an aside, after I set SQLITE_DEFAULT_MEMSTATUS=0 which yielded another ~x2 speed up)

My thinking is that these queries are complex enough that they result in a lot of allocations and the custom allocator is becoming a serialization bottleneck.

Would you be open to a PR that provides a flag to disable the custom allocator? If I'm understanding the motivations for its introduction, I'm personally fine trading off visibility into memory usage for the performance benefits.

If you're not quite convinced this could be the problem, I'm happy to work on building a minimal repro tomorrow. Thanks!

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions