When SQL Server has
poorly under-estimated the amount of rows that will be returned from an
operator in a query execution plan, less memory will be granted, finally the query execution will spill out to tempdb, and the query runs slow as more disk I/O will be incurred. You can fix those queries by adding missing indexes and update statistics with reasonable sampling size. The latest SQL Server 2017 CU3 added some improvements on tempdb spill diagnostics in DMV and Extended Events to let us find out which queries have tempdb spilling problem. Below query employs the new _spills columns in sys.dm_exec_query_stats DMV:
SELECT
DB_NAME(QP.[dbid]) AS [db_name],
OBJECT_NAME(QP.objectid, QP.[dbid]) AS [object_name],
SUBSTRING(ST.[text], (QS.statement_start_offset/2)+1,
((CASE QS.statement_end_offset
WHEN -1 THEN DATALENGTH(ST.[text])
ELSE QS.statement_end_offset
END - QS.statement_start_offset)/2) + 1) AS stmt_text,
QS.execution_count AS execution_count,
QS.total_spills / 128.0 AS total_spills_mb,
QS.last_spills / 128.0 AS last_spills_mb,
QS.min_spills / 128.0 AS min_spills_mb,
QS.max_spills / 128.0 AS max_spills_mb,
(QS.total_spills / QS.execution_count) / 128.0 AS avg_spills_mb
FROM sys.dm_exec_query_stats QS
CROSS APPLY sys.dm_exec_sql_text(QS.[sql_handle]) ST
CROSS APPLY sys.dm_exec_query_plan(QS.plan_handle) QP
WHERE QS.total_spills > 0
ORDER BY total_spills_mb DESC;