为什么我得到"数据库'tempdb的日志文件'已满"

hor*_*rgh 5 sql sql-server sql-server-2000 sql-execution-plan

让我们有一个支付表,其中35列包含主键(autoinc bigint)和3个非聚集的非唯一indeces(每个在一个int列上).

在表的列中,我们有两个日期时间字段:

  1. 付款日期 datetime NOT NULL

  2. EDIT_DATE datetime NULL

该表有大约1 200 000行.只有~1000行有edit_date column = null.9000行的edit_date不为null且不等于payment_date其他行有edit_date = payment_date

当我们运行以下查询1时:

select top 1 *
from payments
where edit_date is not null and (payment_date=edit_date or payment_date<>edit_date)
order by payment_date desc
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

服务器需要几秒钟才能完成.但是如果我们运行查询2:

select top 1 *
from payments
where edit_date is not null
order by payment_date desc
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

执行结束于数据库'tempdb'的日志文件已满.备份数据库的事务日志以释放一些日志空间.

如果我们用某些列替换*,请参阅查询3

select top 1 payment_date
from payments
where edit_date is not null
order by payment_date desc
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

它也会在几秒钟内完成.

魔术在哪里?

编辑 我已经更改了查询1,以便它在与第二个查询完全相同的行数上运行.并且它仍然在一秒钟内返回,而查询2填充tempdb.

答案 我按照建议添加了一个索引,为两个日期字段做了这个 - 一切都按预期开始快速运行.虽然,问题是 - 为什么在这种情况下,sql server在类似的查询上表现不同(查询1与查询2); 我想了解服务器优化的逻辑.我同意如果两个查询都使用了类似的tempdb,但他们没有....

最后我将答案标记为第一个,在那里我看到了问题的必然症状,第一个,以及关于如何避免这种情况的想法(即凹痕)

Sam*_*ron 5

发生这种情况是因为执行计划中的某些步骤可能会触发tempdb特定的写入sortsjoins涉及大量数据.

由于您正在使用列加载列对表进行排序,因此SQL决定在没有关联数据的情况下在temp db中单独执行排序会很疯狂.如果它这样做,它将需要在底层表上执行gazzilion低效的书签查找.

遵循以下规则:

  1. 尝试仅选择所需的数据
  2. 适当地调整tempdb的大小,如果你需要做一个对gazzilion行进行排序的疯狂查询,你最好有一个适当大小的tempdb


NG.*_*NG. 5

通常,当磁盘空间不足或为数据库增长设置了不合理的低最大大小时,tempdb 会填满。许多人认为 tempdb 仅用于 #temp 表。事实上,您可以轻松地填充 tempdb,而无需创建单个临时表。其他一些可能导致 tempdb 填满的场景:

  • 任何需要比分配给 SQL Server 还多的内存的排序都将被迫在 tempdb 中完成它的工作;
  • 如果排序需要的空间多于分配给 tempdb 的空间,则会发生上述错误之一;
  • DBCC CheckDB('any database') 将在 tempdb 中执行它的工作——在较大的数据库上,这会消耗相当多的空间;
  • DBCC DBREINDEX 或带有“Sort in tempdb”选项集的类似 DBCC 命令也可能会填满 tempdb;
  • 涉及联合、排序依据/分组依据、笛卡尔连接、外部连接、游标、临时表、表变量和散列的大型结果集通常需要 tempdb 的帮助;
  • 任何未提交且未回滚的事务都可能使 tempdb 中的对象处于孤立状态;
  • 使用带有“创建临时存储过程”选项的 ODBC DSN 可以在连接的生命周期内将对象留在那里。

    使用 tempdb 去

        SELECT name 
            FROM tempdb..sysobjects 
    
        SELECT OBJECT_NAME(id), rowcnt 
            FROM tempdb..sysindexes 
            WHERE OBJECT_NAME(id) LIKE '#%' 
            ORDER BY rowcnt DESC
    
    Run Code Online (Sandbox Code Playgroud)

较高的行数值可能表示消耗空间的最大临时表。

短期修复

DBCC OPENTRAN -- or DBCC OPENTRAN('tempdb')
DBCC INPUTBUFFER(<number>)
KILL <number>
Run Code Online (Sandbox Code Playgroud)

长期预防

-- SQL Server 7.0, should show 'trunc. log on chkpt.' 
-- or 'recovery=SIMPLE' as part of status column: 

EXEC sp_helpdb 'tempdb' 

-- SQL Server 2000, should yield 'SIMPLE': 

SELECT DATABASEPROPERTYEX('tempdb', 'recovery')
ALTER DATABASE tempdb SET RECOVERY SIMPLE
Run Code Online (Sandbox Code Playgroud)

参考:https : //web.archive.org/web/20080509095429/http : //sqlserver2000.databases.aspfaq.com : 80/why-is-tempdb-full-and-how-can-i-prevent-this- from-happening.html
其他参考资料:http : //social.msdn.microsoft.com/Forums/is/transactsql/thread/af493428-2062-4445-88e4-07ac65fedb76