-
Notifications
You must be signed in to change notification settings - Fork 335
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
Return row counts for SQL ingestion (storage.sql.ingest()). #2059
Return row counts for SQL ingestion (storage.sql.ingest()). #2059
Conversation
Thanks for looking at this @smerritt! I think this would actually work fine, but interested in following up on this idea (from internal chat):
We already make some fairly strict assumptions around the SQL api being complete synchronous, in particular calling I don't think there's any real worry in adding At the very least, this removes any concept of |
I think we intentionally didn't add DB-wide counters because queries can be running concurrently (you can have multiple cursors) and so these counters felt like a footgun. Regarding the interface change to |
Flattening the counters into |
Fixup: f583865 |
f583865
to
a20dc3c
Compare
This is ready for review.
As far as the DB-wide counters, Kenton's right: they're a footgun. If you compute deltas around a chunk of purely synchronous code, you'll get correct numbers, but if any asynchrony creeps in between the queries across which you are computing deltas, your deltas can be too large. Summing row counts across queries is much less error-prone. I think it's better to take the interface change now, while it's still experimental, and just deal with a bit of jank in the D1 worker for a few weeks. |
D1 bills based on rows read and written, but sql.ingest() didn't return those. Now it does. This required changing the return type of sql.ingest(), but it's an experimental API so that should be okay. let sqlCode = "INSERT INTO tbl (col) VALUES (123); INSERT I"; let result = sql.ingest(sqlCode); Old: result == " INSERT I" New: result.remainder == " INSERT I" result.rowsRead == 0 result.rowsWritten == 1 This also gives us a convenient spot to stick additional information. For example, if we wanted to count how many SQL statements ingest() executed, we could easily add "result.statementsExecuted" without breaking any existing users. [1] This is a terrible understatement.
a20dc3c
to
479edba
Compare
479edba is a rebase on main. |
@smerritt ok, I'm happy with this. I can tweak the d1-worker stuff as necessary. Can I ask to add one more counter: |
Wrangler wants this so it can show users how many statements were executed. This matches how it used to work when Wrangler parsed the SQL locally.
This removes a bunch of boilerplate C++. It does not change the JS interface.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Code changes LGTM
D1 bills based on rows read and written, but sql.ingest() didn't return those. Now it does.
This required changing the return type of sql.ingest(), but it's an experimental API so that should be okay.
let sqlCode = "INSERT INTO tbl (col) VALUES (123); INSERT I";
let result = sql.ingest(sqlCode);
Old:
result == " INSERT I"
New:
result.remainder == " INSERT I"
result.meta.rowsRead == 0
result.meta.rowsWritten == 1
This "meta" attribute also gives us a convenient spot to stick additional information. For example, if we wanted to count how many SQL statements ingest() executed, we could easily add "result.meta.statementsExecuted" without breaking any existing users.
Implementation-wise, there might be an optimization opportunity around SqlStorage::IngestResult::getMeta(). Right now, it allocates a new Meta every time it's called, so if you do the obvious thing like so:
totalRead += result.meta.rowsRead
totalWritten += result.meta.rowsWritten
totalRedFish += result.meta.redFish // and so on
then that might end up allocating and discarding multiple Meta objects, and some caching could fix that. On the other hand, I'm not very familiar[1] with JSG internals, so maybe that's already happening somehow. I have no idea.
[1] This is a terrible understatement.