SETUP
我必须在SQL Server 2000/2005,MySQL或Access中插入几百万行。不幸的是,我没有一种简单的方法来使用批量插入或BCP或普通人类会采用的任何其他方式。插入将发生在一个特定的数据库上,但该代码需要与数据库无关 - 因此我无法进行批量复制,SELECT INTO或BCP。但是,我可以在插入之前和之后运行特定的查询,具体取决于我要导入的数据库。
例如
If IsSqlServer() Then
DisableTransactionLogging();
ElseIf IsMySQL() Then
DisableMySQLIndices();
End If
... do inserts ...
If IsSqlServer() Then
EnableTransactionLogging();
ElseIf IsMySQL() Then
EnableMySQLIndices();
End If
问题
我可以对SQL Server做些什么有趣的事情来加速这些插入吗?
例如,我是否可以发出命令告诉SQL Server,“嘿,不要在事务日志中记录这些事务。”
或许我可以说,“嘿,我有一百万行进来,所以在我完成之前不要更新你的索引。”
ALTER INDEX [IX_TableIndex] ON Table DISABLE
... inserts
ALTER INDEX [IX_TableIndex] ON Table REBUILD
(注意:上面的索引禁用仅适用于2005年,而不适用于2000.如果您知道在2000年执行此操作的方法,则可获得奖励积分。)
MySQL和Access怎么样?
答案 0 :(得分:4)
在这里杀死性能的最重要的事情是(听起来像)你正在对数据库执行一百万个不同的INSERT。每个INSERT都被视为一个操作。如果您可以将其作为单个操作执行,那么您几乎肯定会获得巨大的性能提升。
MySQL和SQL Server都支持“选择”没有表名的常量表达式,因此这应该作为一个语句工作:
INSERT INTO MyTable(ID, name)
SELECT 1, 'Fred'
UNION ALL SELECT 2, 'Wilma'
UNION ALL SELECT 3, 'Barney'
UNION ALL SELECT 4, 'Betty'
我不清楚Access是否支持,没有Access可用。但是,据我所知,Access确实支持SELECT中的常量,你可以强制将上述内容强制转换为ANSI SQL-92(所有3个引擎都应该支持它;它与你的'DB不可知'一样接近' ll get)只需添加
FROM OneRowTable
到每个SELECT的末尾,其中'OneRowTable'是一个只有一行虚拟数据的表。
这应该允许您在远远少于一百万个INSERT语句中插入一百万行数据 - 而索引重组等内容将只执行一次,而不是一百万次。在此之后,您可能不太需要其他优化。
答案 1 :(得分:2)
这是常规流程还是一次性事件?
过去,我只编写了当前索引,删除它们,插入行,然后重新添加索引。
SQL Management Studio可以通过右键单击菜单编写索引...
答案 2 :(得分:1)
对于SQL Server:
禁用索引实际上是一个好主意。这适用于SQL 2005,而不适用于SQL Server 2000。
修改[TABLE_NAME]上的索引[INDEX_NAME]
并启用
alter index [INDEX_NAME] on [TABLE_NAME] rebuild
然后只需逐个插入行。你必须要有耐心,但至少它会更快。
答案 3 :(得分:1)
如果它是一次性的事情(或者它经常发生以证明自动化的理由),还考虑删除/禁用所有索引,然后在插入完成时再次添加/重新启用它们
答案 4 :(得分:0)
将恢复模式设置为简单的问题在于,它会影响同时输入数据的任何其他用户,从而导致无法恢复的更改。
Samre禁用索引的事情,这会禁用所有人,并可能使数据库运行速度慢于slug。
建议您批量运行导入。
答案 5 :(得分:0)
如果这不是需要非常快速阅读的内容,您可以在MySQL的表格中执行"Insert Delayed"。这允许您的代码继续运行,而无需等待插入实际发生。这确实有一些限制,但如果你主要关注的是让程序快速完成,这可能会有所帮助。请注意,有一长串的情况可能无法按预期发挥作用。检查the docs。
我不知道此功能是否适用于Access或MS SQL。
答案 6 :(得分:0)
您是否考虑过使用工厂模式?我猜你正在为此编写代码,所以如果使用工厂模式,你可以编写一个工厂,它返回一个具体的“IDataInserter”类型类来完成工作。
这仍然允许您与数据无关并为每种类型的数据库获取最快的方法。
答案 7 :(得分:0)
SQL Server 2000/2005,MySQL和Access都可以直接从tab / cr文本文件加载它们只有不同的命令来执行它。如果你有case语句来确定你导入的数据库只是想出他们导入文本文件的偏好。
答案 8 :(得分:0)
您可以使用DTS(2000)或SSIS(2005)构建一个包来执行此操作吗? DTS和SSIS都可以从同一来源拉出并输出到不同的潜在目的地。如果可以,请去SSIS。这里有很多优秀,快速的技术以及嵌入IsSQLServer,IsMySQL等逻辑的功能。
答案 9 :(得分:0)
值得考虑breaking your inserts into smaller batches;具有大量查询的单个事务将会很慢。
答案 10 :(得分:-1)
您可以考虑在批量插入期间使用SQL的批量记录恢复模型。
http://msdn.microsoft.com/en-us/library/ms190422(SQL.90).aspx
http://msdn.microsoft.com/en-us/library/ms190203(SQL.90).aspx
您还可以在插入期间禁用目标表上的索引。