SqlServer性能優化


1、SQL執行的流程

SqlServer會對每一條執行的指令生成一個執行計划並對執行計划進行緩存plan cache,通常情況下執行同樣的SQL下次會直接查找plan進行執行跳過編譯的過程。新指令通常的執行流程為“收到執行指令——》plan cache中找不到(找到則跳過到編譯的流程)——》解釋(語法、句法)——》編譯——》生成執行計划並加入cache——》執行”。

SQL指令的執行方式如下:

(1)從緩存的執行計划執行

為了避免資源的浪費提高整體執行的效率SqlServer通常會查找plan cache執行,但執行計划的好壞最終決定了執行的效率緩存的plan並非最好的(這點在優化性能時需注意,某些情況下可能需要手工重建執行計划)。

(2)重編譯

有些時候,SqlServer為了確保返回正確的值,或者有性能上的顧慮,有意不重用緩存在內存里的執行計划,而現場編譯一份,這種行為,被稱為重編譯(recompile)。包括如下情況:

A、當指令或者批處理所涉及的任何一個對象(表格或者視圖)發生了架構(schema)變化

B、運行過sp_recompile

C、有些動作會清除內存里的所有執行計划,迫使大家都要做重編譯

D、當下面這些SET 開關值變化后,先前的那些執行計划都不能重用

E、當表格或者視圖上的統計信息發生變化后

 

2、執行計划

(1)作用

當我們的系統上線后數據庫的記錄不斷增加,之前寫的一些SQL語句或者一些ORM操作效率變得非常低。我們不得不考慮SQL優化,SQL優化大概是這樣一個流程:

A、定位執行效率低的SQL語句(定位)

B、分析為什么這段SQL執行的效率比較低(分析)

C、最后根據第二步分析的結構采取優化措施(解決)

執行計划可以告訴我們SQL的執行情況包括SQL如何使用索引、連接查詢的執行順序、查詢的數據行數等。

可通過如下語句查看緩存的執行計划

SELECT OBJECT_NAME(objid),sql,* FROM sys.[syscacheobjects] WHERE cacheobjtype='Compiled Plan'

 

(2)顯示執行計划的方式

A、SSMS界面進行選擇

B、使用快捷鍵Ctrl+l

C、通過SET開關控制

.SHOWPLAN_TEXT – 顯示了一個基本的基於文本的預估執行計划,而不必執行查詢。
.SHOWPLAN_ALL – 顯示帶有消耗預估值的基於文本的預估執行計划,而不必執行查詢。
.SHOWPLAN_XML – 顯示帶有消耗預估值的基於XML的預估執行計划,而不必執行查詢。等於在SQL Server Management Studio中的“Display Estimated Execution Plan…”選項。
.STATISTICS PROFILE – 執行查詢並顯示基於文本的實際執行計划。
 STATISTICS XML – 執行查詢並顯示基於XML的實際執行計划。等於在SQL Server Management Studio中的“Include Actual Execution Plan”選項。

D、使用SQL Server Profiler

E、通過執行計划緩存獲取

查看開銷大的執行計划:

按平均 CPU 時間檢索有關前五個查詢的信息

SELECT TOP 5 total_worker_time/execution_count AS [Avg CPU Time],  
Plan_handle, query_plan   
FROM sys.dm_exec_query_stats AS qs  
CROSS APPLY sys.dm_exec_query_plan(qs.plan_handle)  
ORDER BY total_worker_time/execution_count DESC;  
GO  

 

3、根據執行計划進行優化

 根據執行計划進行優化主要是去找到開銷比較大的塊進行分析並優化,關注點包括數據訪問的操作方式、讀取的數據量大小及是否采用臨時表等。數據訪問的方式無非是掃描、查找及兩者的結合。掃描就是讀取整個結構,可以訪問一個heap或者一個clustered索引或者一個non-clustered索引,而查找則不會讀取整個結構,它則是更高效地通過索引訪問一行,所以從這個角度來看,查找就只能應用在索引上面了。

(1)訪問操作

以下講解相關的概念,以表RecognisePhotoBox為例:

CREATE TABLE [dbo].[RecognisePhotoBox]
(
[BoxId] [bigint] NOT NULL IDENTITY(1, 1),
[VenderId] [int] NOT NULL,
[PhotoId] [varchar] (50) COLLATE Chinese_PRC_CI_AS NOT NULL,
[SkuCode] [int] NOT NULL
)
ALTER TABLE [dbo].[RecognisePhotoBox] ADD CONSTRAINT [PK_RECOGNISEPHOTOBOX] PRIMARY KEY CLUSTERED ([BoxId])
CREATE NONCLUSTERED INDEX [nci_RecognisePhotoBox_PhotoId_VenderId] ON [dbo].[RecognisePhotoBox] ([PhotoId], [VenderId])

A、表掃描

效率最低,大數據表盡量避免使用(臨時表也一樣需要建索引)

B、Clustered Index掃描

C、non-Clustered Index掃描

D、Clustered Index查找

 

E、non-Clustered Index查找

F、書簽查詢

如下SkuCode沒有在非聚集索引中,先會去non-Clustered Index查找一次,然后去Lookup前面查找結果對應的數據表記錄。

書簽查詢可通過Include索引(在索引中包括其它要查找的字段)等進行優化

CREATE NONCLUSTERED INDEX [nci_RecognisePhotoBox_PhotoId_VenderId] ON [dbo].[RecognisePhotoBox] ([PhotoId], [VenderId]) INCLUDE(SkuCode)

注意:執行計划里用來估計的信息來源於“數據庫統計信息”,如 estimated number of  rows

 

4、索引的重要性

 索引是對數據庫表中一列或多列的值進行排序的一種結構,使用索引可快速訪問數據庫表中的特定信息。索引分為聚集索引與非聚集索引,聚集索引表示表中存儲的數據按照索引的順序存儲,非聚集索引表示數據存儲在一個地方,索引存儲在另一個地方,索引帶有指針指向數據的存儲位置。

(1)索引優點

A、通過創建唯一性索引,可以保證數據庫表中每一行數據的唯一性。 
B、可以大大加快 數據的檢索速度,這也是創建索引的最主要的原因。 
C、可以加速表和表之間的連接,特別是在實現數據的參考完整性方面特別有意義。 
D、在使用分組和排序 子句進行數據檢索時,同樣可以顯著減少查詢中分組和排序的時間。 
E、通過使用索引,可以在查詢的過程中,使用優化隱藏器,提高系統的性能。

(2)索引缺點

A、創建索引和維護索引要耗費時間,這種時間隨着數據量的增加而增加。 
B、索引需要占物理空間,除了數據表占數據空間之外,每一個索引還要占一定的物理空間,如果要建立聚簇索引,那么需要的空間就會更大。 
C、當對表中的數據進行增加、刪除和修改的時候,索引也要動態的維護,這樣就降低了數據的維護速度。 

(3)查詢索引的層級結構及占用空間了解索引

--查詢索引信息
Select id.name,p.index_level,p.page_count,p.index_id, avg_record_size_in_bytes,max_record_size_in_bytes,min_record_size_in_bytes
from sys.dm_db_index_physical_stats(DB_ID('EXEU_TEST_MARK'),Object_id('RecognisePhotoBox'),null,null,'Detailed') as p
Inner Join sys.indexes as  id
On p.index_id = id.index_id
And p.object_id = id.object_id
And p.index_id > 1

其中Index_Level為0的表示索引的葉級,為1、2的表示索引的非葉級

 

5、復雜存儲過程的優化

(1)找到生成的執行計划

SELECT  OBJECT_NAME(dm_exec_query_plan.objectid),UseCounts, Cacheobjtype, Objtype, TEXT, query_plan
FROM sys.dm_exec_cached_plans
CROSS APPLY sys.dm_exec_sql_text(plan_handle)
CROSS APPLY sys.dm_exec_query_plan(plan_handle)
WHERE objtype='Proc' AND OBJECT_NAME(dm_exec_query_plan.objectid)='pr_createRecogniseCheckBill'

右擊query_plan的值另存為,文件的后綴填寫“.sqlplan”,保存先用記事本或其它編輯工具打開增加“XML聲明”

然后雙擊在SqlServer打開就可看到執行計划圖了

 

(2) 找到開銷大的查詢

此處大數據量的臨時表走了表掃描

需要給臨時表創建索引

CREATE INDEX tidx_1 ON #temp_boxNoStitch(PhotoId)
CREATE INDEX tidx_2 ON #temp_scaletable(PhotoId) INCLUDE(rowno,IsStitch)

 

6、大數據量優化的注意事項

(1)sp_executesql的效率非常低,用exec替換sp_executesql

(2)需在上下文多次使用的大數據關聯表結果,采用臨時表保存,並根據查詢條件對臨時表建索引

(3)建索引時需要去掉冗余度太高的字段當索引,可放到索引包含列include里

 

參考:

【MySQL】SQL執行計划分析

 https://blog.csdn.net/da_guo_li/article/details/79008016

SQL Server執行計划詳細介紹(一)

https://cloud.tencent.com/developer/news/254038

SQLSERVER編譯與重編譯

https://www.cnblogs.com/lyhabc/archive/2013/01/17/2865290.html

SQL查詢性能優化----解決書簽查找

https://www.2cto.com/database/201208/146201.html

數據庫索引的作用優點和缺點

https://blog.csdn.net/u013310119/article/details/52527632

對SQL Server索引包含列(Include)的一點認識

https://blog.csdn.net/zhengldg/article/details/9128723

如何獲得查詢的執行計划?(一)

http://bbs.51cto.com/thread-1317501-1.html

sys.dm_exec_query_plan (Transact-SQL)

https://docs.microsoft.com/zh-cn/sql/relational-databases/system-dynamic-management-views/sys-dm-exec-query-plan-transact-sql?view=sql-server-2017


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM