我需要显著提高SQLite的编写速度(或者建议SQLite之外的其他解决方案)。
- 方案:**
- 我有71列,每列有365 * 24 * 60个值。(365 =天)
- 我使用"insert intos"来测试db_performance
- 为了缩短测试时间,我进行了90天的测试,而不是365天(因此结果时间跨度将为x4)
- 设置:**我尝试过各种普拉格马
- 同步关断
- 锁定模式独占
- 使用不同的值缓存和页面大小(虽然我读取的值较低可能会提高性能,但对我来说,较高的值做得很好)
- 日志模式关闭
- 更改超时值
- 方法:**
- #A1收集所有"insert intos",每个都执行非查询,最后执行一个大型事务
- #A2与上述相同,但具有ParallelForEach和ExecuteNonqueryAsync
- #A3收集一天内的所有"插入信息",每个信息执行一个事务
- 表格结构:**
- #T1包含所有列的一个表
- #T2每列一个表
- 结果:**我跑了90天(所以不会花太长时间),主要问题是写作速度。
我测量了5个相位,分别是:
- #P1设置表格和标题(~8 - 9ms)
- #P2准备数据(对于执行非查询的每个"插入"命令)(~15000 - 18000ms!)
- #P3执行事务(约200 - 500 ms)
- #P4读取一整列(约80 - 200 ms)
- #P5删除一整列(约1 - 9 ms)
我尝试了前面提到的所有不同的方法和途径,但都无法改进#P2。有什么想法可以解决这个问题吗?或者有什么更好的解决方案,比如无服务器数据库(领域?)吗?
下面是#A1 #P2 #T2的代码,它是目前为止效果最好的...
using (var transaction = sqLiteConnection.BeginTransaction())
{
using (var command = sqLiteConnection.CreateCommand())
{
foreach (var vcommand in values_list)
{
command.CommandText = vcommand;
command.ExecuteNonQuery();
}
}
transaction.Commit();
}
(values list是一个字符串[],其中包含71 * 90个insert intos或Marks版本1中的巨型命令。)
编辑/更新:我尝试了Mark Benningfield的方法,对一个表中所有列的所有值进行一次巨大的"插入",可以将总体速度提高到~8500ms(#P2~7500ms)。
最终更新:好吧,我做了一堆测试,并将总结结果:
为了便于比较,所有数据库都有相同的值,一个值为[129600,71]的二维双精度数组。它们都没有预准备插入语句,因此包括了将值转换为所需格式的生成时间(阶段2)。
SQLite处理一个大型事务需要约14秒(之前的~8s没有生成insert-into-command live)。SQL_CE是此场景的最佳选择。这主要是因为不使用字符串操作("INSERT INTO"),但是使用数据表和行+bulkInsert.Realm是有趣的,特别是对于移动用户-非常直观。但是你不能添加动态对象atm(所以你需要一个静态对象)Influx是另一个很好的时间序列数据库,但是它非常具体,不是嵌入式的,并且有一个糟糕的C#实现(它可能通过控制台执行得更好)。
4条答案
按热度按时间gk7wooem1#
您是否尝试过将数据写入文本文件,然后使用import命令(请参阅导入CSV文件)?与INSERT命令不同,这些例程通常忽略触发器并使用直接表访问。
rks48beu2#
让你的插入命令看起来像这样(通过你需要的方式构造它):
然后执行 single insert命令,对已知数据进行批量更新。
gstyhher3#
好吧,我做了一堆测试,并将总结结果:
为了便于比较,所有数据库都有相同的值,一个值为[129600,71]的二维双精度数组。它们都没有预准备插入语句,因此包括了将值转换为所需格式的生成时间(阶段2)。
SQLite处理一个大型事务需要约14秒(之前的~ 8 s没有生成insert-into-command live)。SQL_CE是此场景的最佳选择。这主要是因为不使用字符串操作(“INSERT INTO”),但是使用数据表和行+ bulkInsert. Realm是有趣的,特别是对于移动的用户-非常直观。但是你不能添加动态对象atm(所以你需要一个静态对象)Influx是另一个很好的时间序列数据库,但是它非常具体,不是嵌入式的,并且有一个糟糕的C#实现(它可能通过控制台执行得更好)。
gr8qqesn4#
执行批量插入的最快和推荐的方法是使用带参数的预准备语句。这样,语句(命令)只被解析和准备一次,而不必为每行重新解析。SQLite也不必从命令文本解析参数值,而是直接提供和使用它们。对于每行,您只需切换参数。
所以我们不应该这样做:
你应该这样做:
这样会执行得更好。语句仅在第一次执行时解析。所有后续执行都将使用已准备好的语句。它还可以保护您免受SQL注入攻击:文本参数不会被插入到实际的SQL语句字符串中,这将允许对语句进行操作。相反,它们将作为值直接传递给SQLite。因此,您不仅可以提高性能,还可以防止最常见的数据库攻击场景之一。
一般规则:永远不要将值直接放入SQL语句中。请始终使用参数。
注:还有其他创建和参数的方法。这只是一个示例。例如,还可以使用命名参数: