SQL Server / MySQL / Access - 加速以低效方式插入许多行

时间:2009-01-07 15:22:37

标签: mysql sql-server ms-access

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怎么样?

11 个答案:

答案 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:

  1. 您可以将恢复模式设置为“简单”,这样您的事务日志就会保持很小。不要忘记事后退缩。
  2. 禁用索引实际上是一个好主意。这适用于SQL 2005,而不适用于SQL Server 2000。

    修改[TABLE_NAME]上的索引[INDEX_NAME]

  3. 并启用

    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

您还可以在插入期间禁用目标表上的索引。