查看帶有參數的查詢的執行計劃
我有一個由應用程序(在本例中為 Microsoft Dynamics AX 2012)生成的範例查詢,它在性能方面無效(交叉連接、排序等)我想顯示它的執行計劃並嘗試通過索引或重寫來調整它它的某些部分。我不能只是將它複製/粘貼到 SSMS 中,因為有許多數據類型的參數。我什至不知道這些參數的值是什麼。
有沒有辦法快速辨識這個查詢的執行計劃?也許通過查詢一些DMV?我從監控軟體那裡得到了查詢文本,它一定已經完成了。
SELECT 2 AS f1, T3.RECID AS f2, T4.RECID AS f3, T4.GENERALJOURNALACCOUNTENTRY AS f4, T4.LEDGERDIMENSION AS f5, Sum(T6.TRANSACTIONCURRENCYAMOUNT) AS f6, T6.TRANSACTIONCURRENCY AS f7, T6.MONETARYAMOUNT AS f8, Sum(T7.ACCOUNTINGCURRENCYAMOUNT) AS f9, N'aaa' AS DATAAREAID, 1 AS RECVERSION, 5637144576 AS PARTITION, IDENTITY(bigint, 1, 1) AS RECID INTO [##ax_tmp_tim99_151_7623] FROM SUBLEDGERJOURNALENTRY T1 CROSS JOIN ACCOUNTINGDISTRIBUTION T2 CROSS JOIN TAXTRANS T3 CROSS JOIN SUBLEDGERJOURNALACCOUNTENTRY T4 CROSS JOIN ACCOUNTINGDISTRIBUTION T5 CROSS JOIN ACCOUNTINGDISTRIBUTION T6 CROSS JOIN SUBLEDGERJOURNALACCOUNTENTRYDISTRIBUTION T7 WHERE ( ( T1.PARTITION = @P1 ) AND ( ( ( ( T1.TRANSFERID = @P2 ) AND ( T1.LEDGER = @P3 ) ) AND ( T1.TYPE <> @P4 ) ) AND ( T1.TYPE <> @P5 ) ) ) AND ( ( T2.PARTITION = @P6 ) AND ( ( T2.ACCOUNTINGEVENT = T1.ACCOUNTINGEVENT ) AND ( ( ( T2.MONETARYAMOUNT <> @P7 ) AND ( T2.MONETARYAMOUNT <> @P8 ) ) AND ( T2.MONETARYAMOUNT <> @P9 ) ) ) ) AND ( ( ( T3.PARTITION = @P10 ) AND ( T3.DATAAREAID = @P11 ) ) AND ( T3.SOURCEDOCUMENTLINE = T2.SOURCEDOCUMENTLINE ) ) AND ( ( T4.PARTITION = @P12 ) AND ( ( ( ( T4.SUBLEDGERJOURNALENTRY = T1.RECID ) AND ( T4.POSTINGTYPE <> @P13 ) ) AND ( T4.POSTINGTYPE <> @P14 ) ) AND ( T4.POSTINGTYPE <> @P15 ) ) ) AND ( ( T5.PARTITION = @P16 ) AND ( T5.RECID = T2.PARENTDISTRIBUTION ) ) AND ( ( T6.PARTITION = @P17 ) AND ( ( ( T6.SOURCEDOCUMENTLINE = T5.SOURCEDOCUMENTLINE ) AND ( T6.PARENTDISTRIBUTION = T5.RECID ) ) AND ( ( ( T6.MONETARYAMOUNT = @P18 ) OR ( T6.MONETARYAMOUNT = @P19 ) ) OR ( T6.MONETARYAMOUNT = @P20 ) ) ) ) AND ( ( T7.PARTITION = @P21 ) AND ( ( ( T7.SUBLEDGERJOURNALACCOUNTENTRY = T4.RECID ) AND ( T7.ACCOUNTINGDISTRIBUTION = T6.RECID ) ) AND ( ( ( T7.ACCOUNTINGCURRENCYAMOUNT >= @P22 ) AND ( T6.TRANSACTIONCURRENCYAMOUNT >= @P23 ) ) OR ( ( T7.ACCOUNTINGCURRENCYAMOUNT < @P24 ) AND ( T6.TRANSACTIONCURRENCYAMOUNT < @P25 ) ) ) ) ) GROUP BY T3.RECID, T4.RECID, T4.GENERALJOURNALACCOUNTENTRY, T4.LEDGERDIMENSION, T6.TRANSACTIONCURRENCY, T6.MONETARYAMOUNT ORDER BY T3.RECID, T4.RECID, T4.GENERALJOURNALACCOUNTENTRY, T4.LEDGERDIMENSION, T6.TRANSACTIONCURRENCY, T6.MONETARYAMOUNT
你可以用這個
select st.text, qp.query_plan, qs.plan_handle, total_worker_time/execution_count AS [Avg CPU Time] FROM sys.dm_exec_query_stats AS qs cross apply sys.dm_exec_sql_text(qs.plan_handle) st cross apply sys.dm_exec_query_plan(qs.plan_handle) qp
如果您使用的是 sql server 2008 及更高版本,您還可以配置擴展事件以查看計劃等。
我相當廣泛地使用 Dynamics AX,如果您像這樣聲明所有 @p1..@Pn 參數,您可以相對容易地查看此查詢的估計執行計劃:
declare @P1 bigint, @p2 nvarchar(10), .... SELECT 2 AS f1, T3.RECID AS f2, T4.RECID AS f3, T4.GENERALJOURNALACCOUNTENTRY AS f4, T4.LEDGERDIMENSION AS f5, Sum(T6.TRANSACTIONCURRENCYAMOUNT) AS f6, T6.TRANSACTIONCURRENCY AS f7, T6.MONETARYAMOUNT AS f8, Sum(T7.ACCOUNTINGCURRENCYAMOUNT) AS f9, N'aaa' AS DATAAREAID, 1 AS RECVERSION, 5637144576 AS PARTITION, IDENTITY(bigint, 1, 1) AS RECID INTO [##ax_tmp_tim99_151_7623] FROM SUBLEDGERJOURNALENTRY T1 CROSS JOIN ACCOUNTINGDISTRIBUTION T2 CROSS JOIN TAXTRANS T3 CROSS JOIN SUBLEDGERJOURNALACCOUNTENTRY T4 CROSS JOIN ACCOUNTINGDISTRIBUTION T5 CROSS JOIN ACCOUNTINGDISTRIBUTION T6 CROSS JOIN SUBLEDGERJOURNALACCOUNTENTRYDISTRIBUTION T7 WHERE ( ( T1.PARTITION = @P1 ) AND ( ( ( ( T1.TRANSFERID = @P2 ) AND ( T1.LEDGER = @P3 ) ) AND ( T1.TYPE <> @P4 ) ) AND ( T1.TYPE <> @P5 ) ) ) AND ( ( T2.PARTITION = @P6 ) AND ( ( T2.ACCOUNTINGEVENT = T1.ACCOUNTINGEVENT ) AND ( ( ( T2.MONETARYAMOUNT <> @P7 ) AND ( T2.MONETARYAMOUNT <> @P8 ) ) AND ( T2.MONETARYAMOUNT <> @P9 ) ) ) ) AND ( ( ( T3.PARTITION = @P10 ) AND ( T3.DATAAREAID = @P11 ) ) AND ( T3.SOURCEDOCUMENTLINE = T2.SOURCEDOCUMENTLINE ) ) AND ( ( T4.PARTITION = @P12 ) AND ( ( ( ( T4.SUBLEDGERJOURNALENTRY = T1.RECID ) AND ( T4.POSTINGTYPE <> @P13 ) ) AND ( T4.POSTINGTYPE <> @P14 ) ) AND ( T4.POSTINGTYPE <> @P15 ) ) ) AND ( ( T5.PARTITION = @P16 ) AND ( T5.RECID = T2.PARENTDISTRIBUTION ) ) AND ( ( T6.PARTITION = @P17 ) AND ( ( ( T6.SOURCEDOCUMENTLINE = T5.SOURCEDOCUMENTLINE ) AND ( T6.PARENTDISTRIBUTION = T5.RECID ) ) AND ( ( ( T6.MONETARYAMOUNT = @P18 ) OR ( T6.MONETARYAMOUNT = @P19 ) ) OR ( T6.MONETARYAMOUNT = @P20 ) ) ) ) AND ( ( T7.PARTITION = @P21 ) AND ( ( ( T7.SUBLEDGERJOURNALACCOUNTENTRY = T4.RECID ) AND ( T7.ACCOUNTINGDISTRIBUTION = T6.RECID ) ) AND ( ( ( T7.ACCOUNTINGCURRENCYAMOUNT >= @P22 ) AND ( T6.TRANSACTIONCURRENCYAMOUNT >= @P23 ) ) OR ( ( T7.ACCOUNTINGCURRENCYAMOUNT < @P24 ) AND ( T6.TRANSACTIONCURRENCYAMOUNT < @P25 ) ) ) ) ) GROUP BY T3.RECID, T4.RECID, T4.GENERALJOURNALACCOUNTENTRY, T4.LEDGERDIMENSION, T6.TRANSACTIONCURRENCY, T6.MONETARYAMOUNT ORDER BY T3.RECID, T4.RECID, T4.GENERALJOURNALACCOUNTENTRY, T4.LEDGERDIMENSION, T6.TRANSACTIONCURRENCY, T6.MONETARYAMOUNT
@Aaron,這並不能有效地製作笛卡爾積,因為交叉連接受 where 子句的限制
AND ( ( T2.ACCOUNTINGEVENT = T1.ACCOUNTINGEVENT )
這使它變成了一個正常的內部連接。我完全不知道他們為什麼這樣做。
如果我能給您一個建議,請查看axinthefield PFE 部落格上記錄的DynamicsPerf工具。這將定期使用編譯值和執行計劃記錄您的查詢。我發現成本相當低,而且您從中獲得的資訊非常值得。
編輯:
如果您可以在測試環境中重現該問題(因為 AX 很容易進行參數嗅探),您可以使用內置的SQL 語句跟踪日誌來查找查詢的呼叫堆棧。如果您添加一個 forceliterals,則 AX 將生成一個沒有參數但有值的查詢。這將為您提供跟踪中的真實查詢,並可能有助於解決參數嗅探問題。
您還可以查看Trace Parser 工具,以使用實際參數值和查詢的程式碼跟踪來擷取跟踪。這也有很大幫助。
編輯2:
這在 dba 方面對您沒有多大幫助,但可以在與開發人員的討論中為您提供一些盔甲。
您在臨時表中看到的是在 AX 開發環境中聲明為“臨時類型 tempdb”的表。生成此查詢的查詢可能是某種構造,其集合基於
insert_recordset
使用查詢的此類臨時表編輯3:
對這個查詢進行更多思考,它正在建構一個包含大量分類帳事務的臨時表,如果這是一個巨大的數據集,您應該查看 tempdb 爭用。使用 Jimmy May 的這個查詢
SELECT [Drive], CASE WHEN num_of_reads = 0 THEN 0 ELSE (io_stall_read_ms/num_of_reads) END AS [Read Latency], CASE WHEN io_stall_write_ms = 0 THEN 0 ELSE (io_stall_write_ms/num_of_writes) END AS [Write Latency], CASE WHEN (num_of_reads = 0 AND num_of_writes = 0) THEN 0 ELSE (io_stall/(num_of_reads + num_of_writes)) END AS [Overall Latency], CASE WHEN num_of_reads = 0 THEN 0 ELSE (num_of_bytes_read/num_of_reads) END AS [Avg Bytes/Read], CASE WHEN io_stall_write_ms = 0 THEN 0 ELSE (num_of_bytes_written/num_of_writes) END AS [Avg Bytes/Write], CASE WHEN (num_of_reads = 0 AND num_of_writes = 0) THEN 0 ELSE ((num_of_bytes_read + num_of_bytes_written)/(num_of_reads + num_of_writes)) END AS [Avg Bytes/Transfer] FROM (SELECT LEFT(UPPER(mf.physical_name), 2) AS Drive, SUM(num_of_reads) AS num_of_reads, SUM(io_stall_read_ms) AS io_stall_read_ms, SUM(num_of_writes) AS num_of_writes, SUM(io_stall_write_ms) AS io_stall_write_ms, SUM(num_of_bytes_read) AS num_of_bytes_read, SUM(num_of_bytes_written) AS num_of_bytes_written, SUM(io_stall) AS io_stall FROM sys.dm_io_virtual_file_stats(NULL, NULL) AS vfs INNER JOIN sys.master_files AS mf WITH (NOLOCK) ON vfs.database_id = mf.database_id AND vfs.file_id = mf.file_id GROUP BY LEFT(UPPER(mf.physical_name), 2)) AS tab ORDER BY [Overall Latency] OPTION (RECOMPILE);
確保您的 tempdb 驅動器上的延遲不會太高,如果您只有一個,請增加 tempdb 文件的數量