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