2012-05-22 32 views
29

我一直花一些时间阅读数据库和SQLite的不同最佳实践。在阅读时,我发现自己做了很多事情,我不应该这样做,当试图解决这些问题时,在思考使用SQLite和ADO实现的一些细节时,我变得很困惑。SQLite/C#连接池和准备好的语句混淆

我的困惑主要来自准备好的语句和连接池。

在阅读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

我不太熟悉SQLite,但关于为什么一个人应该尽快关闭连接,你自己来接近自己回答:底层的物理连接没有关闭,你只需将连接返回到池。其含义是它可以被其他线程使用。很明显,如果你坚持连接但不实际使用它,那将限制最大可能的利用率。 (同样清楚的是:如果您处于单线程环境中,连接池并没有太多意义,尽管伤害不大。) –

回答

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

给它一个尝试,如果你把它看成是解决您的问题。

+0

您发布的链接似乎已被破坏。 (Chrome声称它是无止境的重定向循环) –

+0

当然,您可以在循环中使用插入行并调用flush后缀来提交事务,再次使用辅助链接:[SQLiteBulkInsertHelper.cs](https://docs.google.com/open?id = 0B5-wcgU-Ku-eMDNlY1R3SzByV00) –

+0

好的,谢谢你在评论中发布的链接看起来很好我已经在你的文章中修复了它。 –

15

它有助于记住连接池和准备(编译)语句只是有其限制的工具,没有办法可以同样适用于所有可能的情况。记住这一点,让我们记住何时可能想要使用连接池和准备好的语句。当连接是昂贵的,例如

可能愿意使用连接池

连接池是有用的:

  • 这需要显著时间建立连接(网络连接到SQL服务器或Oracle数据库),为了提高系统性能,“缓存”打开的连接是有益的。
  • 连接是在应用程序(来自服务于多个并发请求的Web应用程序的连接)内或应用程序之间的有限和共享,因此必须尽快释放它们以让其他客户端继续。

可能原因使用预准备语句

准备语句只是旨在改善通过削减解析时可重复使用的查询的性能。

SQLite:什么是最佳选择?

答案取决于您的应用需求。就个人而言,我不确定SQLite连接池是否是一个不错的选择。如果你的应用程序是单线程的,最好使用一个到SQLite数据库的永久连接,这可能比池化速度快得多,并且也允许你使用准备好的语句。这与SQL Server的不同之处在于连接池是一个非常合理的默认设置。

如果性能很重要,您应该确定应用程序的配置文件,以查看SQLite连接池是否有利于您的场景。

具体问题

大部分的答案都与当前System.Data.SQLite提供商source

如果我打开和关闭我的连接(这可能会或可能并不意味着 连接被关闭以进行线程池),然后多少 使用我真的从一份声明中得到些什么?

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

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

这是一个真实的陈述。

如果我创建一个代表查询,我会 执行很多时候我需要保持这种SQLiteCommand在内存中 准备好的声明中保持活跃一个SQLiteCommand?

是的,你需要保留它。 SQLiteCommand持有对准备好的声明的参考。

如果我创建一个具有相同的SQLite语句的新SQLiteCommand是 认识到,新SQLiteCommand是一样的前面和 因而具有可以使用一份声明中?

我不认为这是支持。

如果我记得一个SQLiteCommand并改变它的参数和 连接,我打开和关闭不同的 交易的连接我在本质上保持一份声明中不同的连接之间活着 ?

如果更改SQLiteCommand的连接,语句将被“重新准备”。

+0

使用预准备语句(特别是插入和更新)的一个非常重要的附加原因是为了防止SQL注入攻击。在所有情况下,准备好的语句正确地转义了要存储在数据库中的值。 –