標籤:SQL SERVER/MSSQL SERVER/數據庫/DBA/內存池/緩衝區算法
瞭解執行計劃對數據庫性能分析很重要,其中涉及到了語句性能分析與存儲,這也是寫這篇文章的目的,在瞭解執行計劃以前先要了解一些基礎知識,因此文章前面會講一些概念,學起來會比較枯燥,可是這些基礎知識很是重要。sql
目錄數據庫
SQL Server 有一個用於存儲執行計劃和數據緩衝區的內存池。池內分配給執行計劃或數據緩衝區的百分比隨系統狀態動態波動。內存池中用於存儲執行計劃的部分稱爲過程緩存。緩存
SQL Server 執行計劃包含下列主要組件:數據結構
執行計劃的主體是一個重入的只讀數據結構,可由任意數量的用戶使用。這稱爲查詢計劃。查詢計劃中不存儲用戶上下文。內存中查詢計劃副本永遠不超過兩個:一個副本用於全部的串行執行,另外一個用於全部的並行執行。並行副本覆蓋全部的並行執行,與並行執行的並行度無關。架構
每一個正在執行查詢的用戶都有一個包含其執行專用數據(如參數值)的數據結構。此數據結構稱爲執行上下文。執行上下文數據結構能夠從新使用。若是用戶執行查詢而其中的一個結構未使用,將會用新用戶的上下文從新初始化該結構。併發
SQL Server 有一個高效的算法,可查找用於任何特定 SQL 語句的現有執行計劃。在 SQL Server 中執行任何 SQL 語句時,關係引擎將首先查看過程緩存中是否有用於同一 SQL 語句的現有執行計劃。SQL Server 將從新使用找到的任何現有計劃,從而節省從新編譯 SQL 語句的開銷。若是沒有現有執行計劃,SQL Server 將爲查詢生成新的執行計劃。性能
什麼狀況下會刪除執行計劃測試
在沒有人工手動清除緩存的狀況下,若是出現內存不足的狀況下SQL Server會自動清除一部分沒被利用到的緩存計劃。spa
全部緩存的最大大小取決於max server memory的大小。
怎樣判斷須要刪除的執行計劃
果存在內存不足的狀況,數據庫引擎將使用基於開銷的方法來肯定從過程緩存中刪除哪些執行計劃。怎樣肯定一個執行計劃的開銷呢,對於一個第一次執行的執行計劃SQL Server將它的開銷值設爲0,被屢次執行過的執行計劃SQL Server將它的開銷值設置爲原始編譯開銷,因此數據庫引擎會重複檢查每一個執行計劃的狀態並將刪除當前開銷爲零的執行計劃。若是存在內存不足的狀況,當前開銷爲零的執行計劃不會自動被刪除,而只有在數據庫引擎檢查該執行計劃並發現其當前開銷爲零時,纔會刪除該計劃。當檢查執行計劃時,若是當前沒有查詢使用該計劃,則數據庫引擎將下降當前開銷以將其推向零。
數據庫引擎會重複檢查執行計劃,直至刪除了足夠多的執行計劃,以知足內存需求爲止。若是存在內存不足的狀況,執行計劃可屢次對其開銷進行增長或下降。若是內存不足的狀況已經消失,數據庫引擎將再也不下降未使用執行計劃的當前開銷,而且全部執行計劃都將保留在過程緩存中,即便其開銷爲零也是如此。
根據數據庫新狀態的不一樣,數據庫中的某些更改可能致使執行計劃效率下降或無效。SQL Server 將檢測到使執行計劃無效的更改,並將計劃標記爲無效。此後,必須爲執行查詢的下一個鏈接從新編譯新的計劃。致使計劃無效的狀況包括:
--1.緩存的每個對象返回一行,包括緩存計劃的類型、緩存引用的對象、緩存計劃佔用的空間、被使用次數、以及建立時間等 SELECT * FROM sys.syscacheobjects; --2.緩存的每一個查詢計劃返回一行,包括執行計劃被使用的次數、執行計劃的大小、內存地址、執行計劃的類型、語句等 SELECT * FROM sys.dm_exec_cached_plans; GO ---3.返回由指定的 sql_handle 標識的 SQL 批處理的文本 /*其中sql_handle來自: sys.dm_exec_query_stats sys.dm_exec_requests sys.dm_exec_cursors sys.dm_exec_xml_handles sys.dm_exec_query_memory_grants sys.dm_exec_connections plan_handle來自:sys.dm_exec_cached_plans */ SELECT * FROM sys.dm_exec_sql_text(sql_handle | plan_handle); GO --4.以 XML 格式返回計劃句柄指定的批查詢的顯示計劃,主要接受來自sys.dm_exec_cached_plans的plan_handle句柄 SELECT * FROM sys.dm_exec_query_plan(plan_handle); GO --5.每一個計劃屬性返回一行,主要接受來自sys.dm_exec_cached_plans的plan_handle句柄 SELECT * FROM sys.dm_exec_plan_attributes(plan_handle); GO --6.針對每一個 Transact-SQL 執行計劃、公共語言運行時 (CLR) 執行計劃和與計劃關聯的遊標返回一行,,主要接受來自sys.dm_exec_cached_plans的plan_handle句柄 SELECT * FROM sys.dm_exec_cached_plan_dependent_objects(plan_handle); --7.返回緩存查詢計劃的聚合性能統計信息。緩存計劃中的每一個查詢語句在該視圖中對應一行,而且行的生存期與計劃自己相關聯。在從緩存刪除計劃時,也將從該視圖中刪除對應行。*/ --該系統視圖針對每個緩存中的執行計劃統計其執行時間、物理、邏輯操做等信息 SELECT * FROM sys.dm_exec_query_stats
--清空緩存中的執行計劃 DBCC FREEPROCCACHE; -- ( plan_handle | sql_handle | pool_name ) GO -- 清空制定數據庫的執行計劃 DBCC FLUSHPROCINDB(<dbid>); GO ---清空緩存中的數據 DBCC DROPCLEANBUFFERS; ---清空特定緩存存儲區中的執行計劃 DBCC FREESYSTEMCACHE(<cachestore>) -- 'ALL', pool_name, 'Object Plans', 'SQL Plans', 'Bound Trees' GO
---清空制定數據庫執行計劃 DECLARE @DBID INT SET @DBID=DB_ID() DBCC FLUSHPROCINDB(@DBID); GO ---建立測試數據庫 CREATE TABLE TPlan (ID INT PRIMARY KEY IDENTITY(1,1), Name NVARCHAR(20) NOT NULL, Istate INT NOT NULL, Idate DATETIME DEFAULT(GETDATE()) ) GO ---建立索引 CREATE INDEX IX_TPlan_NAME ON TPlan (Name ) GO INSERT INTO TPlan(Name,Istate) VALUES('1',1),('2',2),('3',3) GO SELECT NAME FROM TPlan GO SELECT Cacheobjtype,objtype,dbid,objid,usecounts,pagesused,sql FROM sys.syscacheobjects WHERE DBID=DB_ID()
使用Profiler監控
使用SQL:StmtRecompile監控,若是是監控存儲過程則使用:SP:Recompile
修改索引
在索引中添加字段
DROP INDEX [IX_TPlan_NAME] ON [dbo].[TPlan] WITH ( ONLINE = OFF ) GO USE [Study] GO CREATE NONCLUSTERED INDEX [IX_TPlan_NAME] ON [dbo].[TPlan] ( [Name] ASC ) INCLUDE ( [Istate]) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, FILLFACTOR = 90) ON [PRIMARY] GO
再執行查詢
SELECT NAME FROM TPlan
增長查詢非相關字段
ALTER TABLE [dbo].[TPlan] ADD Number INT
刪除查詢有關的索引也一樣會致使執行計劃重編譯,這裏就不截圖貼出來了。
查看執行計劃
SELECT Cacheobjtype,objtype,dbid,objid,usecounts,pagesused,sql FROM sys.syscacheobjects WHERE DBID=DB_ID()
執行計劃中顯示了該執行計劃被調用了兩次,在隨機叢書中寫的是會從新編譯新的執行計劃,若是是這樣的話那這裏的值應該是1纔對。
猜想:SQL Server在架構更改的時候經過檢測執行計劃已經對原先的執行計劃進行了編譯,因此在新的查詢中仍是使用了第一次查詢的執行計劃。
若是有誰知道結果麻煩告知。
備註: 做者:pursuer.chen 博客:http://www.cnblogs.com/chenmh 本站點全部隨筆都是原創,歡迎你們轉載;但轉載時必須註明文章來源,且在文章開頭明顯處給明連接,不然保留追究責任的權利。 《歡迎交流討論》 |