[英]MS SQL Server, multiple insert
假设我写了查询:
INSERT INTO DestinationTable
(ColumnA, ColumnB, ColumnC, etc.)
SELECT FROM SourceTable
(ColumnA, ColumnB, ColumnC, etc.)
我的源表有2200万行。
SQL服务器填满我的硬盘驱动器,并出错。
为什么SQL服务器无法处理我的查询?
我应该使用游标并一次插入一行吗?
PS - 它是SQL Express 2005,但我可以尝试完整版。
更新:我还想提一下,当我在管理工作室查看时,我的源表只占用大约1GB的存储空间。 然而,我的25GB可用磁盘空间不知何故被填满了吗? 我也在使用2个不同的数据库Source.mdf - > Destination.mdf,我不知道这是否有任何区别。
批量更新......
INSERT INTO DestinationTable
(ColumnA, ColumnB, ColumnC, etc.)
SELECT TOP 100000 ColumnA, ColumnB, ColumnC, etc.
FROM SourceTable
WHERE NOT EXISTS (SELECT *
FROM DestinationTable
WHERE DestinationTable.KeyCols = SourceTable.KeyCols)
WHILE @@ROWCOUNT <> 0
INSERT INTO DestinationTable
(ColumnA, ColumnB, ColumnC, etc.)
SELECT TOP 100000 ColumnA, ColumnB, ColumnC, etc.
FROM SourceTable
WHERE NOT EXISTS (SELECT *
FROM DestinationTable
WHERE DestinationTable.KeyCols = SourceTable.KeyCols)
如果您需要在一个txn等中处理检查点,日志文件管理,则有各种变体
您可以将数据批量复制到本机格式的文件(编辑从Csv更改为本机),然后将其重新导入到新表中。
您可以尝试将数据库恢复模型设置为“简单”而不是“完整”(默认值)。 这是在Management Studio中的数据库属性的“选项”页面上完成的。 这应该会降低您的事务日志大小。 完成插入后,您始终可以将恢复模型设置回“完全”。
我强烈建议您在执行此类繁重的批量数据操作时将数据库恢复模型设置为BULK_LOGGED。
默认情况下 - 数据库设置为SIMPLE或FULL恢复模型。
完全记录所有事务的完整恢复模型旨在用于正常使用。
大容量日志恢复模型旨在临时在大型批量操作期间使用 - 假设它是受批量日志恢复模型影响的批量操作之一(有关更多信息,请参阅msdn中最小可记录的操作) .microsoft.com / EN-US /库/ ms191244.aspx)。
BULK_LOGGED恢复模型最少记录事务
你可以使用下面的代码片段来完成它
--Determine the recovery model currently used for the database
SELECT name AS [Database Name],
recovery_model_desc AS [Recovery Model]
FROM sys.databases
WHERE name=<database_name> ;
--Remember this recovery model so that you can switch back to the same later
--set the database recovery model to BULK_LOGGED
ALTER DATABASE <database_name> SET RECOVERY BULK_LOGGED;
--Run your heavy data insert tasks
INSERT INTO DestinationTable
(ColumnA, ColumnB, ColumnC, etc.)
SELECT FROM SourceTable
(ColumnA, ColumnB, ColumnC, etc.)
/*Again set the database recovery model to FULL or SIMPLE
(the result which we had got from first query)*/
ALTER DATABASE <database_name> SET RECOVERY FULL;
--OR
ALTER DATABASE <database_name> SET RECOVERY SIMPLE;
*注意 - 请在批量操作过程中保持耐心* [:P]
我以前做了很多次。 请告诉我这是否对您有所帮助。
有关在恢复模型之间切换的详细信息,请参阅以下MSDN文章 - 在msdn.microsoft.com/en-us/library/ms190203.aspx上从完整或批量记录恢复模型切换的注意事项
您正在以支持事务的方式插入数据。 无法通过您正在使用的方法禁用此功能,但是您可以通过其他方法在事务范围之外执行此操作。 参见下文:
http://support.microsoft.com/kb/59462
关键的方法是:
DBOPTION'SELECT INTO'为真
INSERT INTO ... SELECT(2200万行)的问题在于它都作为一个事务运行。 因此,即使数据库处于简单恢复模式,您也可能会填满事务日志驱动器。
一次插入一行是一个可怕的想法,它将需要永远。
使用BCP导出数据,导入是BULK INSERT可能是最快的方法。 但它需要学习如何使用BCP实用程序。
如果您决定在T-SQL中执行此操作,则必须将其分解为批处理。 INSERT ... SELECT TOP(n)...上一个答案中的WHERE NOT EXISTS方法有效,但WHERE子句的执行时间可能会相加。 为了使它更高效,更复杂,我有时使用ROW_NUMBER()OVER(ORDER BY pk)和WHERE rn%(n)= 0来填充每n行的pk值的临时表。然后你可以使用一个带INSERT INTO ... SELECT ... WHERE pk> @a和pk <= @b的循环,带有适当的代码来更新temp表中每次迭代的变量。 只需确保在第一次或最后一次迭代中不会遗漏任何行。
您可能希望在Integration Services中执行此操作,Integration Services也可以执行批量插入。 有一篇关于在30分钟左右内加载数TB数据的微软白皮书。 他们将源数据导出(BCP?)到多个文件中,并创建了多个与目标结构相同的表。 然后将每个文件插入一个单独的空表中,它们都可以作为最小化日志运行。 所有这些导入都作为单独的并行进程运行。 最后使用表分区命令将每个导入表合并到目标表中。
在30分钟内加载1TB: https : //technet.microsoft.com/en-us/library/dd537533(v = sql.100).aspx
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.