Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Help with node-sqlite3 performance #458

Open
daniellockyer opened this issue Jan 5, 2024 · 3 comments
Open

Help with node-sqlite3 performance #458

daniellockyer opened this issue Jan 5, 2024 · 3 comments

Comments

@daniellockyer
Copy link

daniellockyer commented Jan 5, 2024

Hey all! 👋🏻 I currently maintain node-sqlite3, the most popular set of bindings for sqlite3 with over 800k downloads per week. The Node-API team converted node-sqlite3 from NAN to Node-API in v5, which was released in 2020 (thanks!).

Using Node-API makes the code really nice to understand (especially given I'm not a day-in-day-out C++ dev) and distribute prebuilt binaries for.

The biggest difference between node-sqlite3 and others in the ecosystem is API design (async + callbacks in node-sqlite3 vs sync elsewhere) and performance. I don't doubt async involves overhead, but that's the style that this package is aimed at. If you look at this benchmark, node-sqlite3 is far behind in terms of performance.

I'd like to understand if our use of Node-API could be improved to increase performance, or best practices. The move to Node-API refactored quite a bit of code but we also kept some older concepts around from the NAN implementation.

To try and determine the blockers on performance, I captured this flamegraph from our (somewhat naive) benchmarks:

CleanShot 2024-01-05 at 10 01 51@2x

30% of time is spent in napi_set_named_property, as part of https://github.com/TryGhost/node-sqlite3/blob/ba4ba07f792304c1554f6c5bd70dcb399d0a82d3/src/statement.cc#L790-L823. This code turns the rows from SQLite into an object, so we can push it to an array to return to the user. This would clearly be on the hotpath for a DB fetching benchmark but I can't find any way to improve the performance. I ended up reading nodejs/node#45905, which sounds similar.

17% of the time is spent in napi_create_string_utf8, which seems to have a lot of GC traces beneath it. Similar with napi_create_object. Is this just a red herring because the benchmark creates a lot of new Objects in short succession?

If anyone has any advice for debugging or refactoring, or time to have a poke around, help would be greatly appreciated 🙏🏻

@mhdawson
Copy link
Member

mhdawson commented Jan 8, 2024

I'm not sure if the new API added in https://github.com/nodejs/node/pull/51042/files might help? NAPI_EXPERIMENTAL would need to be enabled.

Will also try to remember to make sure we discuss in the next Node-API team meeting to see if anybody has any suggestions.

@mhdawson mhdawson added this to the Milestone 11 milestone Jan 12, 2024
@mhdawson
Copy link
Member

We discussed a bit in the meeting today, we do think the existing changes in 51042 may help and @legendecas may experiment to see if using it in sqlite speeds things up. It was also mentioned that nodejs/node#45905 is possibly related in terms of issues.

gabrielschulhof added a commit to gabrielschulhof/node-sqlite3 that referenced this issue Mar 24, 2024
Field names do not change from row to row, so let's create JS strings
only during the process of calling back into JS with the first row, not
with each row. We save the JS strings we created while calling back
with the first row, and re-use them when creating objects for
subsequent rows.

Re: nodejs/abi-stable-node#458
gabrielschulhof added a commit to gabrielschulhof/node-sqlite3 that referenced this issue Mar 25, 2024
Field names do not change from row to row, so let's create JS strings
only during the process of calling back into JS with the first row, not
with each row. We save the JS strings we created while calling back
with the first row, and re-use them when creating objects for
subsequent rows.

Re: nodejs/abi-stable-node#458
@gabrielschulhof
Copy link
Collaborator

@daniellockyer I filed TryGhost/node-sqlite3#1772. It's not a spectacular improvement, but I guess every bit helps.

@mhdawson mhdawson removed this from the Milestone 11 milestone Aug 9, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants