在SQL server的性能優化過程中的常見技巧

在sql server 的性能優化過程中,tsql的語句優化是很重要的一環。當您使用各種手段找出系統最需要優化的語句后,應該如何對該語句進行優化呢?下面列出一些tsql 語句優化的常見技巧。 1. 語句的執行計劃分析 首先要對該語句的執行計劃(execution plan)進

在sql server 的性能優化過程中,tsql的語句優化是很重要的一環。當您使用各種手段找出系統最需要優化的語句后,應該如何對該語句進行優化呢?下面列出一些tsql 語句優化的常見技巧。

1. 語句的執行計劃分析

首先要對該語句的執行計劃(execution plan)進行分析,找出語句運行慢的原因。比如說,

在檢查執行計劃是否包含table scan /index scan等昂貴的操作?

對table, worktable是否進行了大量的邏輯讀?

是否使用了不合適的join類型?

并發(串行)執行計劃是否不合適 等等

舉一個的例子,

Table ‘myTable’. Scan count 1, logical reads 15877, physical reads 0, read-ahead reads 0.

SQL Server Execution Times:

CPU time = 47 ms, elapsed time = 174 ms.

Rows Executes StmtText

—— ——— ———————————————————————————————-

10 1 select EmpNo, Code, MAX(DueDate) from myTable where EmpNo = ‘21250’ group by EmpNo,Code

10 1 |–Stream Aggregate(GROUP BY:([myTable].[Code]) DEFINE:([Expr1002]=MAX([CERTIFICAT

10 1 |–Sort(ORDER BY:([myTable].[Code] ASC))

10 1 |–Table Scan(OBJECT:([SSS].[dbo].[myTable]), WHERE:([myTable]

大家看上圖,logical reads15877,很大的一個值。 執行計劃里面有table Scan,那么明顯就是一個缺少index導致表被全掃描的例子。加一個索引就會好了。

再看另外一個例子:

表 ‘myTableStatus’。掃描計數 0,邏輯讀取 4 次,物理讀取 0 次,預讀 0 次,lob 邏輯讀取 0 次,lob 物理讀取 0 次,lob 預讀 0 次

表 ‘myTable’。掃描計數 8,邏輯讀取 1408666 次,物理讀取 0 次,預讀 0 次,lob 邏輯讀取 0 次,lob 物理讀取 0 次,lob 預讀 0 次

表 ‘myTableType’。掃描計數 0,邏輯讀取 2 次,物理讀取 0 次,預讀 0 次,lob 邏輯讀取 0 次,lob 物理讀取 0 次,lob 預讀 0 次。

表 ‘Transactions’。掃描計數 0,邏輯讀取 2 次,物理讀取 0 次,預讀 0 次,lob 邏輯讀取 0 次,lob 物理讀取 0 次,lob 預讀 0 次。

Rows Executes StmtText

——————– ——————– ———————————————————————————–

2 1 SELECT * FROM vwmyTableItems WHERE 1=1 AND “myTableTypeId” = 1 AND “BranchId” = 1

2 1 |–Sort(DISTINCT ORDER BY:([j].[myTableID] DESC, [j].[UUID] ASC, [j].[ParentID] A

2 1 |–Compute Scalar(DEFINE:([Expr1009]=[Log_DB].[dbo].[FormatDate]([Log_DB].[d

2 1 |–Nested Loops(Inner Join)

1 1 |–Clustered Index Seek(OBJECT:([Log_DB].[dbo].[Transactions].[PK_

2 1 |–Nested Loops(Inner Join)

1 1 |–Clustered Index Seek(OBJECT:([Log_DB].[dbo].[myTableType].

2 1 |–Nested Loops(Inner Join, OUTER REFERENCES:([j].[myTableSta

0 0 |–Compute Scalar(DEFINE:([Expr1011]=(((substring(replic

2 1 | |–Nested Loops(Inner Join, OUTER REFERENCES:([PtnI

468971 1 | |–Index Seek(OBJECT:([Log_DB].[dbo].[myTable]

2 468971 | |–Clustered Index Seek(OBJECT:([Log_DB].[dbo]

2 2 |–Clustered Index Seek(OBJECT:([Log_DB].[dbo].[myTableS

從上面計劃看,問題是表myTable邏輯讀取 1408666 次,非常巨大。另外Nested Loop的cluster index seek 執行了468971 次. 這樣的執行計劃導致CPU 很高。 如何減少邏輯讀和減少Nested Loop里面的執行次數是關鍵。 對這類執行計劃,可以考慮改寫語句,或者嘗試不同的join type。比如,使用option(hash join) 來改變join類型,看看性能是否改善。

2. 語句的常見優化手段

分析完畢執行計劃,你知道了語句為什么慢。接下來語句的優化常見方法是如下。

表/索引 的統計信息是否最新?運行update statistics with FULLSCAN更新統計信息再看看。

對有table scan或者index scan的地方,仔細檢查是否缺少索引?運行Database tuning wizard對該語句分析下,或者手工加上索引看看。也可以查詢sys.dm_db_missing_index_details來看看系統是否大量缺少index。

join的類型是否合適,使用join hint試試試用不同的join類型。

使用index hint 試下不同的index

index是否合適,索引字段的順序是否最佳?

WHERE 語句的寫法是否不夠有效率?比如說,它是否包含了OR, ,等符號?

語句里面是否使用了自定義函數UDF?UDF常導致table scan。

語句是否導致頻繁recompile? 看看是不是temp table導致的。

語句是否返回了大量的結果集合? 返回幾萬十幾萬筆資料是有些多哦。可以使用TOP N限制結果集。

是否使用了低效率的游標?盡量使用fast_forward readonly 類型的游標比較好。

如果語句開銷很大,那么該語句是否有必要?能否減少它的執行次數?

3.簡化和重寫語句

在系統的整體性能優化里面, TSQL優化優先級并不是最高的。 下面按照對系統性能影響的重要程度依次列出優化的幾個層面:

Application

Database Design

Microsoft SQL Server

Operating System

Hardware

也就是說,程序的優化效果最明顯,接下來是的設計優化,再接下來才是TSQL的優化。硬件的優化是最后考慮比較好。一味增加內存和CPU未必能夠解決性能問題。

在程序的優化里面,如果能夠改寫數據庫訪問邏輯,改寫TSQL語句, 或者簡化TSQL語句,有時候你能夠獲得驚人的性能回報。

? 版權聲明
THE END
喜歡就支持一下吧
點贊6 分享