6

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

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

  1. 付款日期 datetime NOT NULL

  2. 编辑日期 datetime NULL

该表有大约 1 200 000 行。只有 ~1000 行的 edit_date 列 = 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

在此处输入图像描述

服务器需要几秒钟来完成它。但是如果我们运行查询 2

select top 1 *
from payments
where edit_date is not null
order by payment_date desc

在此处输入图像描述

执行结束时数据库“tempdb”的日志文件已满。备份数据库的事务日志以释放一些日志空间。

如果我们将 * 替换为某个特定的列,请参见查询 3

select top 1 payment_date
from payments
where edit_date is not null
order by payment_date desc

在此处输入图像描述

它也在几秒钟内完成。

魔法在哪里?

编辑 我更改了查询 1,使其在与第二个查询完全相同的行数上运行。它仍然会在一秒钟内返回,而查询 2 会填充 tempdb。

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

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

4

2 回答 2

5

tempdb发生这种情况是因为执行计划中的某些步骤可能会触发对特定数据的写入,sorts并且joins涉及大量数据。

由于您正在对具有大量列的表进行排序,因此 SQL 认为在没有关联数据的情况下在 temp db 中单独执行排序会很疯狂。如果这样做,则需要在基础表上进行大量低效的书签查找。

遵循以下规则:

  1. 尝试仅选择您需要的数据
  2. 适当调整 tempdb 的大小,如果您需要执行对大量行进行排序的疯狂查询,最好有一个适当大小的 tempdb
于 2012-08-09T04:08:19.613 回答
5

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

  • 任何需要比已分配给 SQL Server 更多内存的排序都将被迫在 tempdb 中完成其工作;
  • 如果排序需要的空间多于分配给 tempdb 的空间,则会发生上述错误之一;
  • DBCC CheckDB('any database') 将在 tempdb 中执行其工作——在较大的数据库上,这会占用相当多的空间;
  • DBCC DBREINDEX 或带有“在 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
    

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

短期修复

DBCC OPENTRAN -- or DBCC OPENTRAN('tempdb')
DBCC INPUTBUFFER(<number>)
KILL <number>

长期预防

-- 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

参考: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

于 2012-08-09T04:54:20.357 回答