由于昂贵的查询导致事务日志磁盘已满

时间:2014-01-08 18:54:40

标签: sql-server sql-server-2012 transaction-log

我的查询有问题,看起来很简单,但在我的开发环境中,这会给我带来很多问题。

我要做的是通过新表中的新文章ID更改articleID。

+-----------------+
|     comments    |
+-----------------+
| cid | articleID |
+-----------------+
|  1  |     1     |
+-----------------+
|  2  |     1     |
+-----------------+
|  3  |     2     |
+-----------------+

+------------------------+
|      new_comments      | 
+------------------------+
| comment_id | articleID |
+------------------------+
|      1     |    10     |
+------------------------+
|      2     |    10     |
+------------------------+
|      3     |    32     |
+------------------------+ 

我希望表“评论”的结尾如下:

+-----------------+
|     comments    |
+-----------------+
| cid | articleID |
+-----------------+
|  1  |    10     |
+-----------------+
|  2  |    10     |
+-----------------+
|  3  |    32     |
+-----------------+

所以我执行这个查询:

UPDATE comments SET comments.articleID = new_comments.articleID_new
FROM comments INNER JOIN new_comments
ON comments.cid = new_comments.comment_id;

问题是我在磁盘上有20GB的可用空间,当我执行此查询时,事务日志开始增长并在查询完成之前使用所有可用空间。在6分钟内,磁盘的20GB可用空间就消失了。

我已将恢复模式更改为简单。但是,问题仍然存在,事务日志也在不断增长。

我可以看到数据库的事务日志使用我在stackoverflow中看到的下一个查询增长:

SELECT (size * 8.0)/1024.0 AS size_in_mb,
CASE
    WHEN max_size  = -1 THEN 9999999 -- Unlimited growth, so handle this how you want
    ELSE (max_size * 8.0)/1024.0
END AS max_size_in_mb
FROM MyDatabase.sys.database_files
WHERE data_space_id = 0;

有谁知道我有什么选择,或者我该怎么做才能阻止查询将这么多信息写入事务日志?

1 个答案:

答案 0 :(得分:0)

尝试这样的事情:

declare @batchSize int 10000;
while(1=1)
begin
UPDATE top(@batchSize) comments SET comments.articleID = new_comments.articleID_new
FROM comments INNER JOIN new_comments
ON comments.cid = new_comments.comment_id
where comments.articleID != new_comments.articleID_new;
if (@@rowcount < @batchSize)
   break
end

这将一次运行您的更新1000行,直到更新完成。与往常一样,首先在测试系统中运行它,但这应该可以解决问题。

现在,至于为什么要遇到这种情况,数据库需要能够在事务提交之前回滚事务。因此,如果您尝试在一个事务中修改过多数据,则会填满您的日志。因此,即使SQL在学术意义上是声明性的,我们有时也不会生活在学术界。 :)