最近收到一SQL Server數據庫服務器的告警郵件,告警內容具體如下所示:
DATE/TIME: 10/23/2018 4:30:26 PM
DESCRIPTION: The query processor ran out of internal resources and could not produce a query plan. This is a rare event and only expected for extremely complex queries or queries that reference a very large number of tables or partitions. Please simplify the query. If you believe you have received this message in error, contact Customer Support Services for more information.
COMMENT: (None)
JOB RUN: (None)
關於“8623 The query processor ran out of internal resources and could not produce a query plan”這個錯誤,這篇文章不分析錯誤產生的原因以及解決方案。這里僅僅介紹如何捕獲產生這個錯誤的SQL語句。因為出現這個錯誤,具體對應的SQL語句不會寫入到錯誤日志。不能定位到具體SQL語句,很難解決這錯誤。所以解決問題的前提是先定位SQL語句。我們可以通過擴展事件或服務器端跟蹤兩種方式來定位SQL語句。
擴展事件(Extended Events)捕獲
如下所示,腳本只需根據實際情況修改filename、metadatafile參數對應的值。就會創建擴展事件(Extented Events)overly_complex_queries
CREATE EVENT SESSION
overly_complex_queries
ON SERVER
ADD EVENT sqlserver.error_reported
(
ACTION (sqlserver.sql_text, sqlserver.tsql_stack, sqlserver.database_id, sqlserver.username)
WHERE ([severity] = 16
AND [error_number] = 8623)
)
ADD TARGET package0.asynchronous_file_target
(set filename = 'D:\DB_BACKUP\overly_complex_queries.xel' ,
metadatafile = 'D:\DB_BACKUP\overly_complex_queries.xem',
max_file_size = 10,
max_rollover_files = 5)
WITH (MAX_DISPATCH_LATENCY = 5SECONDS)
GO
-- Start the session
ALTER EVENT SESSION overly_complex_queries
ON SERVER STATE = START
GO
然后我們測試,使用網上一個腳本測試驗證,如下所示,執行這個腳本就會報“8623 The query processor ran out of internal resources and could not produce a query plan”錯誤,如下所示:
選中擴展事件(Extented Events)overly_complex_queries,單擊右鍵“Watch Live Data"就能查看是那個SQL語句出現這個錯誤(sql_text),當然,也可以通過選項“View Target Data”查看所有捕獲的數據。
注意:這個擴展事件只能運行在SQL Server 2012及后續版本,如果是SQL Server 2008的相關版本部署,就會報下面錯誤:
Msg 25706, Level 16, State 8, Line 1
The event attribute or predicate source, "error_number", could not be found.
Msg 15151, Level 16, State 1, Line 18
Cannot alter the event session 'overly_complex_queries', because it does not exist or you do not have permission.
服務器端跟蹤(Server Side Trace)捕獲
如上所示,剛好我們這台數據庫服務器的版本為SQL Server 2008 R2,我們只能采取Server Side Trace來捕獲這個錯誤的SQL語句。設置Server Side Trace腳本如下(相關參數需根據實際情況等設定):
-- 定義參數
declare @rc int
declare @TraceID int
declare @maxfilesize bigint
set @maxfilesize = 1024
-- 初始化跟蹤
exec @rc = sp_trace_create @TraceID output, 0, N'D:\SQLScript\trace_error_8623', @maxfilesize, NULL
--此處的D:\SQLScript\trace_error_8623是文件名(可自行修改),SQL會自動在后面加上.trc的擴展名
if (@rc != 0) goto error
-- 設置跟蹤事件
declare @on bit
set @on = 1
--trace_event_id=13 SQL:BatchStarting trace_event_id=22 ErrorLog
exec sp_trace_setevent @TraceID, 13, 1, @on
exec sp_trace_setevent @TraceID, 13, 3, @on
exec sp_trace_setevent @TraceID, 13, 6, @on
exec sp_trace_setevent @TraceID, 13, 7, @on
exec sp_trace_setevent @TraceID, 13, 8, @on
exec sp_trace_setevent @TraceID, 13, 11, @on
exec sp_trace_setevent @TraceID, 13, 12, @on
exec sp_trace_setevent @TraceID, 13, 14, @on
exec sp_trace_setevent @TraceID, 13, 15, @on
exec sp_trace_setevent @TraceID, 13, 35, @on
exec sp_trace_setevent @TraceID, 13, 63, @on
exec sp_trace_setevent @TraceID, 22, 1, @on
exec sp_trace_setevent @TraceID, 22, 3, @on
exec sp_trace_setevent @TraceID, 22, 6, @on
exec sp_trace_setevent @TraceID, 22, 7, @on
exec sp_trace_setevent @TraceID, 22, 8, @on
exec sp_trace_setevent @TraceID, 22, 12, @on
exec sp_trace_setevent @TraceID, 22, 11, @on
exec sp_trace_setevent @TraceID, 22, 14, @on
exec sp_trace_setevent @TraceID, 22, 14, @on
exec sp_trace_setevent @TraceID, 22, 35, @on
exec sp_trace_setevent @TraceID, 22, 63, @on
-- 啟動跟蹤
exec sp_trace_setstatus @TraceID, 1
-- 記錄下跟蹤ID,以備后面使用
select TraceID = @TraceID
goto finish
error:
select ErrorCode=@rc
finish:
GO
上面SQL會生成一個服務器端跟蹤事件,並返回對應的id,如下查看所示:
注意:上面捕獲SQL:BatchStarting事件(trace_event_id=13),是因為捕獲ErrorLog(trace_event_id=22)等事件時,都
無法捕獲到對應的SQL(對應的trace column沒有捕獲SQL語句,暫時還沒有找到一個好的解決方法)。這里也有個弊端,就是會捕獲大量無關的SQL語句。
測試過后,你可以使用SQL Profile工具打開D:\SQLScript\trace_error_8623.trc找到錯誤信息,對應的SQL語句(在這個時間點附近的SQL語句,一般為是錯誤信息后面的第一個SQL語句,需要做判斷),如下截圖所示:
也可以使用腳本查詢,如下所示,也是需要自己判斷定位SQL語句,一般都是“8623 The query processor ran out of internal resources and could not produce a query plan”出現后緊接着的SQL。
SELECT StartTime,EndTime,
TextData, ApplicationName,SPID,Duration,LoginName
FROM ::fn_trace_gettable(N'D:\SQLScript\trace_error_8623.trc',DEFAULT)
WHERE spid=64
ORDER BY StartTime
參考資料: