问题:

我有一个脚本,该脚本具有从select语句插入的约4.5万个插入内容。当我尝试运行它时,我收到一条错误消息,指出我的内存不足。我如何才能运行此脚本?

上下文:


添加了一些新的数据字段,以使一个应用程序可以与另一个应用程序很好地玩
客户使用。
从客户端获取了一个完整的数据电子表格,该电子表格将当前数据项映射到这些新字段的值。
转换电子表格以插入语句。
如果我只运行某些语句,它将起作用,但整个脚本却不能。
不。没有错别字。

如果有其他方法,我应该加载此数据,请随时批评我,让我知道。

评论

关于SO的类似问题:(stackoverflow.com/questions/222442/…)不确定答案是否有帮助

#1 楼

SQL Server 2005的最大批处理大小为65,536 *网络数据包大小(NPS),其中NPS通常为4KB。达到256 MB。这意味着您的插入语句平均每个5.8 KB。看起来似乎不对,但是其中可能存在多余的空间或不寻常的东西。

我的第一个建议是在每个INSERT语句之后放置一个“ GO”语句。这会将您的45,000个INSERT语句单批分解为45,000个单独的批处理。这应该更容易消化。小心,如果其中一个插入失败,您可能很难找到罪魁祸首。您可能想通过交易来保护自己。如果您的编辑器具有良好的搜索和替换(可让您搜索并替换\ r \ n之类的返回字符)或宏工具,则可以快速添加这些语句。

第二条建议是使用向导直接从Excel导入数据。该向导会在后台为您构建一个小的SSIS程序包,然后运行该程序包。不会有这个问题。

评论


每个语句后都去?好吧,我想您是否正在使用其他确定的脚本生成它们。否则,我只会在每1000次INSERT之后插入一个。关于使事务原子化并最大程度地减少事务的大小,为什么不将所有行加载到临时表或表变量中,然后从那里一次加载到目标表?

–尼克·查马斯(Nick Chammas)
2012年4月19日在15:14

1000和1一样好,但更难以计数。老实说,他可能只在中间位置接近21,500条声明而放弃了一条GO声明。我喜欢GO修复程序,因为它不需要对当前脚本进行复杂的编辑,也不需要计算INSERT语句(它可能不会直接映射到行号)。

–达林海峡
2012年4月19日的16:00

当然,即使差一点地近似1000条语句也足够了。 :)

–尼克·查马斯(Nick Chammas)
2012年4月19日在16:13

添加GO是一个快速简便的修复程序。25mb脚本在不到9分钟的时间内运行就没有问题。希望将其作为脚本保存在我们的标准修补程序部署过程中,以确保它不出现问题。

–spaghetticowboy
2012年4月19日在17:58

#2 楼

BULK INSERTbcp似乎比45,000个插入语句更合适。

如果需要坚持使用插入语句,我会考虑以下几种选择:

A:使用事务并在每条语句中包装100或500或1000条语句最小化对日志和批处理的影响。例如:

BEGIN TRANSACTION;
INSERT dbo.table(a, ...) SELECT 1, ...
INSERT dbo.table(a, ...) SELECT 2, ...
...
INSERT dbo.table(a, ...) SELECT 500, ...
COMMIT TRANSACTION;
GO

BEGIN TRANSACTION;
INSERT dbo.table(a, ...) SELECT 1, ...
INSERT dbo.table(a, ...) SELECT 2, ...
...
INSERT dbo.table(a, ...) SELECT 500, ...
COMMIT TRANSACTION;
GO


B:代替单个插入语句,一次将UNION ALL用于100或500条语句,例如

INSERT dbo.table(a, ...)
SELECT 1, ...
UNION ALL SELECT 2, ...
...
UNION ALL SELECT 500, ...
GO

INSERT dbo.table(a, ...)
SELECT 501, ...
UNION ALL SELECT 502, ...
...
UNION ALL SELECT 1000, ...
GO


为了简洁起见,我省略了错误处理,但要点是,我永远不会尝试将单行的45,000条单独的语句发送到SQL Server。

评论


不幸的是,OP无法使用表值构造函数(2008或更高版本的功能)。他仍然必须将插入片段分为1000行,这是您可以与TVC一起分组的最大值。

–尼克·查马斯(Nick Chammas)
2012年4月19日在15:06

直到看到版本标签,这将是我的第一个建议。

–亚伦·伯特兰(Aaron Bertrand)
2012年4月19日在15:42

@NickChammas-这些值的性能随值子句BTW的数量非线性降低。我提交了一个连接项,其代表是在2008年的2008开发实例上以1000分钟的编译时间在2008年插入了1000行,其中包含10个VARCHAR(800)列,因为这样做不需要进行插入值的大量工作,而不仅仅是继续插入它们(参数化时执行起来快得多,没有值可看)。尽管2012年有了很大的改进,但非线性模式仍然存在,应在以后的版本中进行修复。

–马丁·史密斯
2012年4月21日在9:38

#3 楼

我不确定为什么会出现内存不足错误,但是有一个更简单的方法。

如果可以将电子表格中的数据导出为定界格式(例如csv),则可以使用SSMS中的数据导入向导为您插入数据:



评论


多数民众赞成在有用,但我没有访问客户端数据库。我必须在脚本中准备补丁和数据加载

–spaghetticowboy
2012-12-27 21:37

#4 楼

使用多个SqlBulkCopy,创建一个临时表。将新数据插入到临时表中,然后将临时表中的数据合并到现有表中。使用C#SqlBulkCopy.WriteToServer方法(DataTable)的示例。希望对您有帮助

#5 楼

是的,我们可以做到这一点,我尝试使用BCP(大容量复制程序)方法来避免内存不足的问题。

注:在SQL Server 2014上尝试过。

在BCP,首先我们需要将源数据库数据导出到bcp文件(在本地目录文件夹中),然后需要将该bcp文件导入到目标数据库。



下面是步步高升的步骤:

注意:

a)确保目标数据库中存在空表

b)确保临时表C文件夹中存在该文件夹



使用以下命令创建一个名为Export_Data.bat的bat文件:

bcp.exe [Source_DataBase_Name].[dbo].[TableName] OUT "C:\Temp\TableName.bcp" -S "Computer Name" -U "SQL Server UserName" -P "SQL Server Password" -n -q 


暂停

运行该bat文件,结果将在Temp文件夹中生成一个bcp文件。

然后创建另一个名为Import_Data的bat文件。 bat使用以下命令:

bcp.exe [Destination_DataBase_Name].[dbo].[TableName] IN "C:\Temp\TableName.bcp" -S "Computer Name" -U "SQL Server UserName" -P "SQL Server Password" -n -q 


暂停


然后我们就开始了!

评论


收到错误“输入,输出或格式选项需要有效的表名。”尝试导出数据时。

–森·雅各布
19年8月10日在19:19

能否将所有属性值都粘贴到您尝试过的命令中。请遵循以下示例:bcp.exe ExportDB.dbo.AddressCountry OUT“ C:\ Temp \ AddressCountry.bcp” -S“ IN-L20054” -U“ sa” -P“ sa” -n -q在那[ExportDB->源数据库,AddressCountry->源数据库中存在的表,IN-L20054->机器名称,“ sa”是数据库的用户名/密码]

–公里
19年8月10日在19:49



我现在没有。我最终在SSMS中使用了导入数据功能。然后使用MS OLE DB连接将目标DB(v14.0)连接到源DB(v.15.0),导入数百万行数据的速度非常快。谢谢!

–森·雅各布
19年8月16日在9:56