SQLite/C#连接池和准备语句混淆

Lux*_*782 32 c# sqlite connection-pooling prepared-statement

我花了一些时间专门为数据库和SQLite阅读不同的最佳实践.在阅读时我发现我做了很多我不应该做的事情,在尝试修复这些问题时,我在考虑使用SQLite及其ADO实现的一些更精细的细节时感到困惑.

我的困惑源于准备好的陈述和连接池.

在阅读http://msdn.microsoft.com/en-us/library/ms971481.aspx时,我发现只应为事务打开连接.交易完成后,应关闭连接.我没有牢牢掌握为什么会这样,但我一直在假设作者知道的比我更好.我明白当连接关闭时并不意味着它实际上已经存在已经关闭.它只是意味着它已被放回池中.

现在,为了改进我的查询和插入,我阅读了有关使用预准备语句 在SQLite中,准备好的语句真的能提高性能吗?http://petesbloggerama.blogspot.com/2007/02/sqlite-adonet-prepared-statements.html似乎都表明,当执行多次执行的查询时,准备好的语句是可行的.我还读过,预准备语句特定于连接,并且一旦连接关闭,预准备语句就会丢失.

我的困惑是这个.如果我打开和关闭我的连接(可能或不可能意味着由于线程池而关闭连接)那么我从准备好的声明中获得了多少用处?我可以理解,如果我有1000个对象,我需要在单个事务中保存,准备好的语句可以帮助很多.但是我不相信我会看到在事务中保存单个对象会带来好处,因为一旦我关闭了连接,从第一个对象生成的预准备语句现在就会丢失.这是真实的陈述吗?

我相信准备好的语句与我的SQLiteCommand对象的范围有关,这进一步加剧了我的困惑.

如果我创建一个表示我将经常执行的查询的SQLiteCommand,我是否需要将SQLiteCommand保留在内存中以使预准备语句保持活动状态?

如果我用相同的SQLite语句创建一个新的SQLiteCommand,它是否认识到新的SQLiteCommand与前一个相同,因此有一个可以使用的预准备语句?

如果我在内存中保留一个SQLiteCommand并更改它的参数和连接,因为我打开并关闭不同事务的连接,我基本上在不同的连接之间保持一个准备好的语句?

我很可能在这一点上思考问题,但我希望你能帮助我更好地理解这些事情是如何相互作用的,这样我才能从中获益最多.

Ser*_*lov 15

有助于记住,连接池和准备(编译)语句都只是具有限制的工具,没有方法可以同样适用于所有可能的情况.考虑到这一点,让我们记住何时可能想要使用连接池和预处理语句.

使用连接池的可能原因

当连接很昂贵时,连接池很有用,例如:

  • 建立连接(与SQL Server或Oracle DB的网络连接)需要很长时间,并且有助于"缓存"打开的连接以尝试提高系统性能.
  • 连接受限并在应用程序(来自服务多个并发请求的Web应用程序的连接)或应用程序之间共享,因此必须尽快释放它们以让其他客户端继续.

使用准备陈述的可能原因

准备好的语句只是为了通过减少解析时间来提高可重用查询的性能.

SQLite:什么是最佳选择?

答案取决于您的应用要求.就个人而言,我不确定SQLite连接池是否一定是一个不错的选择.如果您的应用程序是单线程的,那么最好使用与SQLite DB的单个永久连接,这可能比池化更快,并且允许您也使用预准备语句.这与SQL Server不同,在SQL Server中,连接池是一个非常合理的默认值.

如果性能很重要,那么您应该对应用程序进行概要分析,以查看SQLite连接池是否对您的方案有益.

具体问题

大多数答案都与当前的System.Data.SQLite提供者来源有关.

如果我打开和关闭我的连接(可能或不可能意味着由于线程池而关闭连接)那么我从准备好的声明中获得了多少用处?

通常,您应该将来自池的连接视为新的,即您不应期望从之前准备的语句中获得任何好处.除非您同时保留命令和连接,否则该语句将"重新准备".

但是我不相信我会看到在事务中保存单个对象会带来好处,因为一旦我关闭了连接,从第一个对象生成的预准备语句现在就会丢失.这是真实的陈述吗?

这是一个真实的陈述.

如果我创建一个表示我将经常执行的查询的SQLiteCommand,我是否需要将SQLiteCommand保留在内存中以使预准备语句保持活动状态?

是的,你需要保留它.SQLiteCommand提到准备好的陈述.

如果我用相同的SQLite语句创建一个新的SQLiteCommand,它是否认识到新的SQLiteCommand与前一个相同,因此有一个可以使用的预准备语句?

我认为它不受支持.

如果我在内存中保留一个SQLiteCommand并更改它的参数和连接,因为我打开并关闭不同事务的连接,我基本上在不同的连接之间保持一个准备好的语句?

如果更改了SQLiteCommand连接,则语句将"重新准备".

  • 使用预准备语句(尤其是插入和更新)的一个非常重要的附加原因是防止 SQL 注入攻击。在所有情况下,准备好的语句都会正确转义要存储在数据库中的值。 (2认同)

小智 1

我没有准确地理解核心问题是什么,但如果问题是如何在这么短的时间内在一个事务中插入批量插入语句。

这是我之前发现的一个可以帮助您的帮助器类:

SQLiteBulkInsertHelper.cs

你可以这样使用它:

SQLiteBulkInsertHelper ContactBlk = new SQLiteBulkInsertHelper("<SQLiteConnection>","<Table Name>");
ContactBlk.AllowBulkInsert = true;
ContactBlk.AddParameter("<Column Name>", /*Column Data Type*/System.Data.DbType.Int64);
ContactBlk.AddParameter("<Column Name>", /*Column Data Type*/System.Data.DbType.String);
ContactBlk.Insert(new object[] {<First Column Value>,<Second Column Value>});
ContactBlk.Flush();
Run Code Online (Sandbox Code Playgroud)

如果您认为它可以解决您的问题,请尝试一下。