先查sys.dm_db_session_space_usage中internal_objects_alloc_page_count>100000的会话,再通过sys.dm_exec_requests关联SQL文本和wait_type(如SORT、PAGEIOLATCH_*),最后用sys.dm_exec_query_plan搜索执行计划中的Sort或Hash Match溢出节点。

TempDB 空间爆满不是关联本身的问题,而是执行计划里隐含的 Sort 或 Hash Match 操作溢出到磁盘导致的——尤其当内存估算严重偏低时。
怎么快速定位是哪个查询在吃掉 TempDB?
别靠猜,直接查运行中会话的内部对象分配量:
- 运行
SELECT session_id, internal_objects_alloc_page_count FROM sys.dm_db_session_space_usage WHERE internal_objects_alloc_page_count > 100000,重点关注internal_objects_alloc_page_count(单位是页,1页=8KB) - 把高占用的
session_id带入sys.dm_exec_requests查 SQL 文本和等待类型:wait_type IN ('SOS_SCHEDULER_YIELD', 'PAGEIOLATCH_XX', 'SORT')是典型信号 - 用
sys.dm_exec_query_plan提取执行计划 XML,搜索<RelOp.*PhysicalOp="Sort">或<RelOp.*PhysicalOp="Hash Match">节点,确认是否真有 spill(溢出)
为什么加了索引,关联还是走 Hash Match?
索引对 Hash Match 没有直接抑制作用;优化器选它,往往是因为统计信息过期或内存授予不足:
- 检查连接列的统计信息是否陈旧:
DBCC SHOW_STATISTICS('orders', 'IX_orders_user_id')中Rows和Rows Sampled差距过大,就该更新 - 看执行计划 XML 里的
GrantedMemoryKB和实际需要(比如EstimateRows× 行宽 × 2~3 倍)是否严重不匹配 - 即使有
user_id索引,若WHERE条件没下推(比如写在 JOIN 外层),优化器仍可能误判驱动表大小,强行选 Hash
临时缓解 + 长效控制怎么做?
紧急时不能只靠 DBCC SHRINKFILE,它在活动事务下基本无效;更关键的是控住源头:
- 立刻干预:用
KILL [session_id]终止已确认的长耗时关联查询(尤其wait_type = 'PAGEIOLATCH_IO'的) - 改写 SQL:把过滤条件尽量提前,例如用
JOIN (SELECT * FROM orders WHERE order_date >= '2025-01-01') o ON ...替代外层WHERE - 补索引要精准:对小表(
users)建覆盖索引,对大表(orders)确保连接列是索引最左列且统计信息新鲜 - 监控必须落地:定期跑
SELECT SUM(version_store_reserved_page_count) FROM sys.dm_db_file_space_usage,值持续上涨说明快照隔离或长事务在囤积版本记录
真正难处理的,是那些看似简单、但因统计偏差或内存估算失败而默默 spill 的关联——它们不会报错,只会悄悄拖慢整个实例,且很难被常规监控捕获。

















