导入数据,日志文件撑满磁盘,怎么办?

在SQLServer实例间迁移大量数据时,采用不同方法会导致显著差异。本文介绍了一种高效的方法,通过创建临时表并利用最小日志记录模式来快速迁移6000万条记录,同时避免了磁盘空间不足的问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

昨天在做变更时,遇到这样一个问题。
在同一个SQL Server实例上,要将一个库中的一个表的数据,全量导入到另一个数据库中,表结构完全一致的空表中。目的数据库的恢复模式是简单。
原定的实施计划是用导入导出向导做,但在向导执行时报错某一列的数据无效。

需要导入的数据有6000W行,要找到哪一行的数据有问题会非常耗时,于是就打算用

insert into destination_table select * from source_table with(nolock)

导入数据。


导入的过程中,执行


select count(1) from destination_table with(nolock)


随时查看导入的进度。
当运行了10分钟,插入了2000W行时,监控系统告警磁盘空间不足。检查磁盘空间发现,数据库日志文件所在的盘,可用空间只剩几十MB了。

只插入了1/3的数据, 日志文件增长20多GB,导致磁盘空间耗尽。服务器上暂时没有别的磁盘空间可用,于是就取消了insert的操作,让事务回滚,时不时执行


select count(1) from destination_table with(nolock)


看着行数不断减少,估计回滚完成的时间。回滚完成后,赶紧收缩了日志文件。在这种情况下,insert into的方式肯定是不行了,不仅日志空间不够,而且执行时间会比较长。
考虑到临时加磁盘空间时间上来不及,而分批导数据的话,又没有简便高效分批方案,于是改用最小日志记录的方式导数据。
执行以下的语句,先把数据导入到一个临时表destination_table_temp,再修改临时表的名字为destination_table,并创建索引等对象,使其结构与原来的destination_table完全一致。


select * into destination_table_temp from source_table with(nolock)


执行以上的语句,只用了几分钟,就导入了6000W条数据,而其日志文件只增长了不超过1GB。后续改表名,创建索引等就不再详述。


从这次导入数据的操作中,得到的经验如下:
  • 如果是简单的同构数据导入,尽量用SQL语句,简单明了,用导入导出向导会提高报错的概率,而且不好排查。
  • 在insert into 导入数据或者回滚的过程中,都可以执行select count(1) from xxx with(nock),查看导入或者回滚的进度。
  • 在select * into table_xxx from table_aaa的执行过程中,即便加了with(nolock),select count (*) from table_aaa 也会被阻塞,应该是架构锁的缘故。
  • 使用最小日志记录模式导入数据,速度非常快,产生的日志量非常少。不过select into table要在数据库的恢复模式是简单或大容量日志时,才能使用最小日志记录模式。
  • 正常日志记录模式导入数据时,大量的IO成本和等待时间其实都是消耗在写日志文件上,而写数据文件的成本相比之下少很多
  • 即便数据库的恢复模式是简单,一个大的事务也会造成日志文件的持续增长,而且事务结束后,日志文件不会自动收缩(除非打开了自动收缩的选项)。
参考资料:
https://technet.microsoft.com/en-us/library/ms191244(v=sql.105).aspx
https://technet.microsoft.com/en-us/library/ms188029(v=sql.105).aspx



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值