39

我一直在花一些时间阅读数据库和 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 并在我打开和关闭不同事务的连接时更改它的参数和连接,我是否实质上在不同的连接之间保持了准备好的语句?

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

4

2 回答 2

18

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

使用连接池的可能原因

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

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

使用准备好的语句的可能原因

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

SQLite:最好的选择是什么?

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

如果性能很重要,您绝对应该分析应用程序以查看 SQLite 连接池是否对您的方案有益。

具体问题

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

如果我正在打开和关闭我的连接(这可能意味着也可能不意味着由于线程池而关闭了连接),那么我真的从准备好的语句中得到了多少用处?

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

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

这是一个真实的陈述。

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

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

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

我不认为它被支持。

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

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

于 2012-11-22T02:30:18.290 回答
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();

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

于 2012-06-18T13:36:29.523 回答