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

时间:2012-05-22 14:11:45

标签: c# sqlite prepared-statement connection-pooling

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

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

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

现在为了改进我的查询和插入,我读到了有关使用预准备语句的内容。 In SQLite, do prepared statements really improve performance?http://petesbloggerama.blogspot.com/2007/02/sqlite-adonet-prepared-statements.html似乎都表明,当执行多次执行的查询时,准备好的语句是可行的。我还读过一个预准备语句特定于连接,一旦连接关闭,准备好的语句就会丢失。

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

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

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

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

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

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

2 个答案:

答案 0 :(得分:15)

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

使用连接池的可能原因

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

  • 建立连接(与SQL Server或Oracle DB的网络连接)需要重要时间,并且“缓存”打开的连接有助于提高系统性能。
  • 应用程序中的限制和共享(来自服务多个并发请求的Web应用程序的连接)或应用程序之间的连接,因此必须尽快释放它们以让其他客户端继续。< / LI>

使用准备好的陈述的可能原因

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

SQLite:什么是最佳选择?

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

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

具体问题

大多数答案都与当前的System.Data.SQLite提供商source相关。

  

如果我打开和关闭我的连接(这可能意味着也可能不意味着   因为线程池正在关闭连接然后多少   使用我是否真的从准备好的声明中获得了?

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

  

但是我不相信我会从保存单身中获益   事务中的对象,因为一旦我关闭了连接   现在是从第一个对象生成的预准备语句   丢失。这是真实的陈述吗?

这是一个真实的陈述。

  

如果我创建一个表示我将成为查询的SQLiteCommand   经常执行我需要将SQLiteCommand保留在内存中   准备好的声明保持活跃?

是的,你需要保留它。 SQLiteCommand持有对准备好的陈述的引用。

  

如果我使用相同的SQLite语句创建一个新的SQLiteCommand   认识到新的SQLiteCommand与之前的相同   因此有一个可以使用的准备好的声明吗?

我认为它不受支持。

  

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

如果您更改了SQLiteCommand的连接,则该语句将“重新准备”。

答案 1 :(得分:0)

我没有确切地知道核心问题是什么,但问题是如何在如此短的时间内在一个事务中插入批量插入语句。

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

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();

如果您将其视为问题的解决方案,请试一试。