1. 程式人生 > >SQL Server 2014新特性——基數評估(白皮書閱讀筆記)

SQL Server 2014新特性——基數評估(白皮書閱讀筆記)

基數評估

目錄

說明

查詢優化器的目的是為了找出有效的執行計劃,根據cost運算,取出cost最小的計劃,作為執行計劃。其中影響cost最重要的一項就是基數評估(估計行數)。SQL Server 2014對基數評估做了修改。

基數評估準確的重要性

基數評估提供以下資訊:

1.響應行數評估(the distribution of data

2.不同值個數評估(distinct value count

3.重複值個數,作為上一級基數評估(duplicate count as input for parent operator estimation calculations

基數評估是通過計算統計資訊的出來的結果,而統計資訊通過優化器建立或者通過索引建立。

統計資訊分為:頭,密度向量,直方圖。

當統計資訊存在的時候基數評估器使用密度向量和直方圖來計算評估。

基數評估主要回答以下幾個問題:

1.一個或多個謂詞或過濾幾行

2.2個表之間的連線謂詞會過濾幾行

3.預計一個指定列集合中有多少不同值(distinct value

Sql server中有2種謂詞:1.過濾謂詞,2.連線謂詞

基數評估(CE):試圖回答wherejoinhaving這些謂詞的選擇性。也試圖回答groupdistinct的不同值(distinct value)。

CE

的計算從圖形執行計劃中是從右到左的,下一級的評估作為上一級計算評估的輸入。

每個執行計劃中的運算子都有評估值輸入,這個值決定了優化器使用什麼演算法的操作符,同時也決定了最終的執行計劃。所以如果評估出現偏差,會導致執行計劃選擇出現偏差,導致無法選出一個高效的執行計劃。

評估出現偏差會出現以下結果:

如果評估過小:

1.原本可以使用並行計劃更加有效的,現在使用序列計劃

2.不合適的join演算法

3.不合適的索引選擇,和索引訪問方法

如果評估過大:

1.原本使用序列計劃更加有效,現在使用並行計劃

2.不可合適的join演算法

3.不合適的索引選擇,和索引訪問方法

4.

過多的記憶體分配

5.記憶體浪費和沒必要的併發

模型假設

核心有以下假設:

Independence:假設,在沒有額外的相關資訊之外,資料在不同的列是沒有關聯的

Uniformity:在統計資訊的直方圖的step,資料分散式均勻分佈在step上的。

Containment 2個表連線,那麼高密度的一定被低密度的包含。

Inclusion:如果對一列對常數過濾,那麼認為這個常數資料一定存在在這個列中。

啟用新的基數評估

當資料庫的相容級別為120的時候,就是啟用了新的基數評估,預設使用新的基數評估。

但是可以通過查詢跟蹤標記來指定:

2312:在相容級別低於120的時候使用新的基數評估

9481:在相容級別在120下,使用老的基數評估

驗證基數評估的版本

可以從圖形執行計劃或者XML執行計劃中找到CardinalityEstimationModelVersion,如果為120就是新的基數評估,70就是老的基數評估。

在遷移到新的基數評估前要測試

新的基數評估雖然總體提示了效能,但是對個別查詢來說,會被影響,效能變差,所以要測試。

1.在類似生產環境下,測試大多數的負荷

2.可以先遷移到sql server 2014,但是使用不執行在120相容級別

3.也可以到120相容級別,但是在全域性範圍開9481跟蹤標記

4.新建資料庫推薦使用預設會使用120相容級別。

校驗基數評估

沒有什麼特別的就是通過實際值和評估值對個對比。

偏差問題

評估值偏差,是存在的,那麼多少算是偏差太大了?其實沒有一個固定的值,主要是看以下2點:

1.偏差是不是造成了資源過度使用

2.偏差是不是造成了特定查詢的效能問題

如果任意一個出現問題的話,那麼就能認為偏差太大了。

需要手動處理的變化

只有評估值變化的情況下,看效能是否下降超過預期,如果超過要進行手動干預。

如果評估值和老CE一樣,並且計劃沒有什麼變化,就不需要處理。

避免因為新的CE造成效能下降

1.能夠從新基數評估得到效能優化的查詢,就使用新基數評估,其他的進行重新調整。

2.有好處的查詢使用新的基數評估,其他的使用跟蹤標記9481

3.使用老的基數評估,特定的查詢可以指定跟蹤標記2312

4.直接除錯有問題的sql

5.使用老的基數評估

SQL Server 2014中的修改

增加多個謂詞的相關性的假設

在沒有多列統計資訊的情況下,SQL Server優化器會認為謂詞之間是不相關的。

老的基數評估:各個謂詞的選擇度相乘

新的基數評估:選擇度從低到高排序,然後使用以下公式:

修改超出統計資訊範圍的評估

如果超出統計資訊範圍,那麼老的基數評估就認為不存在,評估行數為1

新的基數評估會用,密度*總行數來當評估。

Join評估演算法修改

簡單Join

老的基數評估是以線性增長的方式一步一步對齊2個直方圖。(根本不知道是怎麼玩的)

新的基數評估,使用相對簡單的join評估演算法,只是用直方圖的最大最小邊界來對齊。(文章並沒有給出詳細的演算法很坑爹)。

新的基數評估是用這種原則,很容易發現評估值不夠準確。

Join條件

多個join條件,對於老的基數評估來說,是獨立的謂詞,是用選擇度相乘的方法來組合。

新的基數評估,是用2個不同值個數(distinct value count)中較小的一個,然後乘以2邊的平均頻率。(搞不懂

Join帶相等和不相等的謂詞

老的基數評估,是獨立的謂詞,是用選擇度相乘的方法來組合。

新的基數評估,認為大表小標多對1的關係。即大表中的一行,必定存在於表的一樣與之對應。這個演算法把大表的評估作為評估。(這個簡單

Join包含(Containment)假設的修改

如果是等值連線,那麼就會假設這個列表2邊都是存在的。如果存在join表上有非join謂詞,老的基數評估那麼會認為一些級別的相關,這種相關叫做簡單包含(Simple Containment)。

老的基數評估的JOIN評估,假設在使用join謂詞之前,任意存在的謂詞會縮小直方圖,而謂詞之間是不相關的。老CE用這樣的評估方式會讓評估值偏大。

USE [AdventureWorks2012];

GO

SELECT [od].[SalesOrderID], [od].[SalesOrderDetailID]

FROM    Sales.[SalesOrderDetail] AS [od]

INNER JOIN Production.[Product] AS [p]

ON [od].[ProductID] = [p].[ProductID]

WHERE   [p].[Color] = 'Red' AND

[od].[ModifiedDate] = '2008-06-29 00:00:00.000'

OPTION (QUERYTRACEON 9481); -- CardinalityEstimationModelVersion 70

新的基數評估是使用基本包含(Base Containment),新的基數評估,是直接從基表上面獲取選擇度,而不是經過謂詞過濾之後。

不同值計數評估的變化

對於新的基數評估和老的相比在多對多連線中,不同值計數評估相差很小。如果join條件會放大基數,老的基數評估可能會不準確。

新的基數評估根據join謂詞和非join謂詞選擇不同值。新的基數評估使用環境基數(ambient cardinality),環境基數是group by或者distinct列的最小不同值集合(The new CE uses “ambient cardinality”, which is the cardinality of the smallest set of joins that contains the GROUP BY or DISTINCT columns.)。

診斷輸出

使用新的xeventquery_optimizer_estimate_cardinality來輸出

CREATE EVENT SESSION [CardinalityEstimate] ON SERVER

ADD EVENT sqlserver.query_optimizer_estimate_cardinality

ADD TARGET package0.event_file( SET filename = N'S:\CE\CE_Data.xel' ,

                                  max_rollover_files =( 2 ) )

WITH ( MAX_MEMORY = 4096 KB ,

        EVENT_RETENTION_MODE = ALLOW_SINGLE_EVENT_LOSS ,

        MAX_DISPATCH_LATENCY = 30 SECONDS ,

        STARTUP_STATE = OFF );

GO

-- Start the session

ALTER EVENT SESSION [CardinalityEstimate] ON SERVER STATE=START;

--

-- Your workload to be analyzed executed here (or in another session)

--

-- Stop the session after the workload is executed

ALTER EVENT SESSION [CardinalityEstimate] ON SERVER STATE=STOP;

新基數評估的調優方法

修改資料庫相容級別

如果新的CE出現效能問題,可以通過修改相容級別回到以前的CE版本。

使用跟蹤標記

可以使用QUERYTRACEON來使用查詢級別選項,這個跟蹤標記會影響一個語句的CE級別。

基礎調優方法

統計資訊丟失

統計資訊丟失,但是沒有及時建立,應該檢視是否啟用了統計資訊自動建立選項。

統計資訊過期

統計資訊可能太老,導致查詢效能問題,考慮是否要手動跟新統計資訊。

統計資訊取樣率

表如果資料分佈不均衡,無法在直方圖上表現,看看統計資訊頭中的rows sampledrows的差距,可以考慮使用調整取樣率或者直接fullscan

過濾統計資訊(filtered statistics)

對於大的表存在資料不均衡,過濾統計資訊可以很好的解決這個問題。

注意點:過濾統計資訊的更新閥值是基於表的,而不是過濾謂詞。

在沒有recompile提示之下,過濾索引和過濾統計資訊不會被應用到引數化的欄位過濾。(In the absence of a RECOMPILE hint, filtered indexes and statistics will not be used in conjunction with parameterization that refers to the filter column.)。

多列統計資訊

自動建立統計資訊,只會建立單列的,多列統計資訊是手工建立的,建立多列統計資訊可以提高評估的準確性。提高查詢效能。

引數敏感性(Parameter Sensitivity

引數敏感性是因為資料分佈不均衡,引數化的執行計劃會以第一次執行的時候的引數來建立,如果資料不均衡,引數變化,會導致執行計劃不是很理想的狀況。可以加上OPTIMIZE FOR或者RECOPILE來解決。

表變數

SQL Server 2014上面表變數沒有相關的統計資訊的,如果要在表變數上存大量的資料建議使用臨時表。

多語句使用者定義表變數函式

和表變數差不多,多語句表變數函式也沒有統計資訊,只是用一個固定的基數100。考慮使用內聯表變數函式。

內聯表變數函式式沒有函式體的,直接return 一個表

而多語句表變數函式式有函式體的。

XML Reader表變數函式操作

使用nodes() XQUERY方法如果沒有XML索引,會導致很爛的評估,因為XML索引可以帶統計資訊。解決這個問題的方法是在XML列上加上XML索引。

資料型別轉化

如果謂詞資料型別,不對會導致資料型別轉化,這樣也會導致基數評估不準確,是因為列的統計資訊無法使用了。

Intra-column比較

Cardinality estimate issues can occur when performing comparisons between columns in the same table. If this is an issue, consider creating computed columns. The computed column can then be referenced in a filter predicate. You can automatically generate the computed column’s associated statistics (by activating automatic statistics creation at the database level) to improve overall estimates. If intra-table column comparison cardinality estimation is a frequent issue, consider normalization techniques (separate tables), derived tables, or common table expressions.

查詢提示

儘量避免使用查詢提示,查詢提示會覆蓋優化器的選擇,對於某些情況可能會導致更爛的效能。

分散式查詢

當通過連線伺服器查詢資料的時候,如果沒有許可權訪問統計資訊的話,會導致查詢效能很爛。

在使用前先確定訪問統計資訊需要多大的許可權。

遞迴CTE

謂詞複雜性

避免在謂詞列上使用函式或者表示式,這個沒啥好說,嚴重影響效能。

查詢複製性

複製的查詢也會讓評估帶來偏差,評估本來就是不準確的,來回怎麼倒騰就更加不準確了,應該簡化查詢。

參考: