-
Notifications
You must be signed in to change notification settings - Fork 97
Implement SqliteCommand.Prepare #235
Comments
It used to be implemented in early days of the project, but there was one big problem: calling |
Why not using finalizers for this? Given that SQLite does not support stored procedures, prepared statements functionality is the only opportunity and performance cost is quite substantial. |
@buybackoff Oh I wasn't pushing back on implementing the feature in some other way, I was just giving some history. |
@bricelam so will you add this back some day? |
Moving to the backlog as we do want to keep this around to consider implementing in the future |
@bricelam regarding your comment on disposal and memory looks above... Isn't the idea of preparing of a prepared command (almost) always imply, by definition, some external resource being allocated which later has to be freed? In the case of a remote database server like PostgreSQL, resources on the server are allocated when a command is prepared (that's what makes the speedup possible), in sqlite it's in unmanaged memory in the same process, but it's always going to be there... Also, I understand historically in .NET DbCommands aren't always disposed. But why is that important in a discussion of EFCore using prepared statements? As long as you take care to always dispose your commands inside EFCore you should be fine, should you? |
Yes, unmanaged memory is allocated, but in the current implementation it isn't done until you call execute. We consider the memory to be owned by the
Our team maintains this principle; we still consider the fact that |
@bricelam I understand what you're saying, but at the end of the day isn't this a purely EFCore-internal issue, i.e. that only touches upon how EFCore manages its DbCommands? If you implemented command preparation, you'd just have to make sure that you guys dispose of command everywhere, without caring whether the rest of the .NET world does so or not, no? |
No, this particular issue is about adding a general, ADO.NET-friendly way of using prepared statements in |
My bad, I confused this with dotnet/efcore#5459. FYI I had a similar problem with un-prepared commands in Npgsql with EF6. At some point Npgsql required you to dispose of a command, otherwise some internal resource was leaked. This caused an issue with EF6 which, as you say, does not dispose of commands. The solution I ended up adopting was to release said resource when a command's connection was closed. You may be able to do something similar with Sqlite's prepared statements, limiting any potential leakage to a connection's open lifetime (of course Dispose could still be used on a command for earlier deallocation). |
Related issue is byte[] allocation for UTF8 in MarshalEx. Without prepared statements, any SQL command always allocates. This could be mitigated using a buffer pool, or the string marshalling logic could be changed to first call Encoding.GetNumberOfBytes and then to call GetBytes overload that writes directly to a pointer. In my tests that was one of the main garbage generators. (There is also string concatenation in param prefix check). I do not write strings columns now, but this could affect all cases with strings as well, not just SQL statements. |
@roji Awesome! That was our general thinking of how we'd implement this issue. It's good to hear it's been validated. I especially like the idea of freeing the memory sooner if the command does get disposed. |
@buybackoff Can you create a new issue on string marshaling? Those sound like options worth exploring. We're also hoping for dotnet/corefx#7804. |
Was going to do so, just received an email from this thread and replied. Even when Core has it (any ETA? RC42 maybe... :) ), .NET 4.5/6 will have to deal with it anyway. |
I'm just trying to implement the proposed solution of @roji. If I prepare the statements before the execution, I have a problem with such a statement: |
A few thoughts:
|
Re-opening. We had to back this out due to a memory leak. We need to investigate and fix it before merging again. |
I am trying to reimplement Prepare and were able to harden it further. But I still see flaky test failures in EntityFramework.
which seems for me only possible if The current version can be found at Should I send a pull request for this?
|
Yes, feel free to send a PR; we can close mine. |
I got to the bottom of the issue we were seeing. If a connection got finalized before its readers, the connection was left open. Updating to use |
Prepare method is not implemented and the prepared statement is not reused (as in System.Data.SQLite), but is disposed on every execution. Currently there is no way to reuse a command like in this example.
In the simplest insert case, it takes almost 20% (of which UTF8 marshalling is 2.4 pp):
I haven't found any discussion in issues about that. It is not hard to implement, but I am not sure if it is already on your TODO list and what design you have in your minds?
The text was updated successfully, but these errors were encountered: