我花了一些时间专门为数据库和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并更改它的参数和连接,因为我打开并关闭不同事务的连接,我基本上是在不同的连接之间保持一个准备好的语句吗?
我很可能在这一点上思考问题,但我希望你能帮助我更好地理解这些事情是如何相互作用的,这样我就可以从中获益最多。
答案 0 :(得分:15)
有助于记住,连接池和准备(编译)语句只是具有限制的工具,没有方法可以同样适用于所有可能的情况。考虑到这一点,让我们记住何时可能想要使用连接池和预准备语句。
使用连接池的可能原因
当连接很昂贵时,连接池很有用,例如:
使用准备好的陈述的可能原因
准备好的语句只是为了通过减少解析时间来提高可重用查询的性能。
SQLite:什么是最佳选择?
答案取决于您的申请要求。就个人而言,我不确定SQLite连接池是否一定是一个不错的选择。如果您的应用程序是单线程的,那么最好使用与SQLite DB的单个永久连接,这可能比池化更快,并且允许您也使用预准备语句。这与SQL Server不同,在SQL Server中,连接池是一个非常合理的默认值。
如果性能很重要,那么您一定要对应用程序进行概要分析,以确定SQLite连接池是否对您的方案有益。
具体问题
大多数答案都与当前的System.Data.SQLite
提供商source相关。
如果我打开和关闭我的连接(这可能意味着也可能不意味着 因为线程池正在关闭连接然后多少 使用我是否真的从准备好的声明中获得了?
通常,您应该将来自池的连接视为新连接,即您不应期望从之前准备的语句中获得任何好处。除非你同时保留命令和连接,否则该声明将“重新准备”。
但是我不相信我会从保存单身中获益 事务中的对象,因为一旦我关闭了连接 现在是从第一个对象生成的预准备语句 丢失。这是真实的陈述吗?
这是一个真实的陈述。
如果我创建一个表示我将成为查询的SQLiteCommand 经常执行我需要将SQLiteCommand保留在内存中 准备好的声明保持活跃?
是的,你需要保留它。 SQLiteCommand
持有对准备好的陈述的引用。
如果我使用相同的SQLite语句创建一个新的SQLiteCommand 认识到新的SQLiteCommand与之前的相同 因此有一个可以使用的准备好的声明吗?
我认为它不受支持。
如果我在内存中保留一个SQLiteCommand并更改它的参数和 连接,因为我打开和关闭不同的连接 交易,我基本上保持准备好的声明 在不同的连接之间?
如果您更改了SQLiteCommand
的连接,则该语句将“重新准备”。
答案 1 :(得分:0)
我没有确切地知道核心问题是什么,但问题是如何在如此短的时间内在一个事务中插入批量插入语句。
这是我之前发现的一个可以帮助你的助手类:
你可以像这样使用它:
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();
如果您将其视为问题的解决方案,请试一试。