使用過濾統計信息解決基數預估錯誤

基數預估是SQL Server里一顆隱藏的寶石。一般而言,基數預估指的是,在查詢編譯期間,查詢優化器嘗試找出在執行計劃里從各個運算符平均返回的行數。這個估計用來驅動計劃本身生成并選擇正確的計劃運算符——例如像Nested Loop, Merge Join,還是Hash Join的物理連接。當這些估計錯誤時,查詢優化器就會選擇錯誤的計劃運算符,相信我——你的查詢就會非常非常非常慢!

查詢優化器使用稱為統計信息對象作為基數預估。每次當你創建一個索引,SQL Server在下面也會創建一個統計對象。這個對象描述了那個索引的數據分布。另外,在查詢執行時,SQL Server也能創建統計信息對象,在必須的時候(自動創建統計信息)。數據分布本身(復合索引鍵的第一列)被描述為所謂的直方圖(Histogram)

直方圖最痛苦之一就是最大只有200的步長。步長是對于你所給定列數據一部分的數據分布情況描述。你的表變得越大,你的直方圖就越不準確,因為你有最大200的步長(直方圖必須盡可能緊湊,它必須復核8kb的頁)。

在復合索引鍵里其他列,SQL Server在統計信息對象里用所謂的密度向量(Density Vector)來保存,它是復合索引鍵唯一值是如何的情況描述(彼此結合在一起)。例如在某列里有3個不同值,那列的密度向量是0.33333(1/3)。

從SQL Server 2008開始,SQL Server支持所謂的過濾統計信息(Filtered Statistics)(和過濾索引對應)。使用過濾統計信息,你可以為數據的子集創建統計信息對象。對于那個數據子集,你也會有直方圖和密度向量。如果在你的數據里有極端值,你可以對那個范圍的數據創建過濾統計信息對象,當那個范圍的數據被查詢時,就可以讓查詢優化器更好的估計返回的行數。因此使用過濾統計信息,你就提高了基數預估的準確性,SQL Server就會給更好的執行計劃性能。下面代碼顯示在SQL Server 2008及后續版本里如何創建過濾統計信息對象:?

1 CREATE STATISTICS Country_Austria ON Country(ID) 
2 WHERE Name = 'Austria' 
3 GO

?從上面代碼可以看到,你用WHERE子句限制表數據的子集,那會通過新的過濾統計信息對象來描述這些數據。但也只有的你的查詢也包含這個where條件,查詢優化器才可以只用這個新的統計信息對象,就像這樣:

1 SELECT SalesAmount FROM Country
2 INNER JOIN Orders ON Country.ID = Orders.ID
3 WHERE Name = 'Austria'
4 GO

如果在的查詢里并不包含同樣的WHERE子句,查詢優化期在執行計劃里訪問的索引的統計信息還是原來默認的。如果你對剛才的查詢啟用9204的跟蹤標記,你就可以看到在基數預估時,那個統計信息被查詢優化器使用:

 1 SELECT SalesAmount FROM Country
 2 INNER JOIN Orders ON Country.ID = Orders.ID
 3 WHERE Name = 'Austria'
 4 OPTION
 5 (
 6     RECOMPILE,-- Used to see the Statistics Output
 7     QUERYTRACEON 3604,-- Redirects the output to SSMS
 8     QUERYTRACEON 9204 -- Returns the Statistics that were used during Cardinality Estimation ("Stats loaded")
 9 )
10 GO

查詢本身也會編譯(因為RECOMPLIE查詢提示,即使查詢計劃已被緩存),因此在SSMS的消息窗,你就可以看到拿個統計信息被用做基數預估。

以過濾統計信息的簡單介紹為基礎,我想給你通過實例展示下,過濾統計信息是如何提高執行計劃質量的。?

 1 -- Create a new database
 2 CREATE DATABASE FilteredStatistics
 3 GO
 4  
 5 -- Use it
 6 USE FilteredStatistics
 7 GO
 8  
 9 -- Create a new table
10 CREATE TABLE Country
11 (
12 ID INT PRIMARY KEY, 
13 Name VARCHAR(100)
14 ) 
15 GO
16  
17 -- Create a new table
18 CREATE TABLE Orders
19 (
20 ID INT, 
21 SalesAmount DECIMAL(18, 2)
22 ) 
23 GO

?我們在表上建立相應的索引:

1 -- Create a Non-Clustered Index
2 CREATE NONCLUSTERED INDEX idx_Name ON Country(Name) 
3 GO
4  
5 -- Create a Clustered Index
6 CREATE CLUSTERED INDEX idx_ID_SalesAmount ON Orders(ID, SalesAmount) 
7 GO

最后往2個表里插入初始數據:?

 1 -- Insert a few records into the Lookup Table
 2 INSERT INTO Country VALUES(0, 'Austria') 
 3 INSERT INTO Country VALUES(1, 'UK')
 4 INSERT INTO Country VALUES(2, 'France') 
 5 GO
 6  
 7 -- Insert uneven distributed order data
 8 INSERT INTO Orders VALUES(0, 0)
 9  
10 DECLARE @i INT = 1 
11  
12 WHILE @i <= 1000
13 BEGIN 
14 INSERT INTO Orders VALUES (1, @i) 
15 SET @i += 1
16 END
17 GO

?為了保證所有的統計信息都已經是最新的,我用全掃描更新了統計信息:

1 -- Update the Statistics on both tables
2 UPDATE STATISTICS Country WITH FULLSCAN 
3 UPDATE STATISTICS Orders WITH FULLSCAN 
4 GO

點擊工具欄的顯示包含實際的執行計劃。我們來執行下列的查詢:

 1 SELECT SalesAmount FROM Country
 2 INNER JOIN Orders ON Country.ID = Orders.ID
 3 WHERE Name = 'UK'
 4 OPTION
 5 (
 6 RECOMPILE,-- Used to see the Statistics Output
 7     QUERYTRACEON 3604,-- Redirects the output to SSMS
 8     QUERYTRACEON 9204-- Returns the Statistics that were used during Cardinality Estimation ("Stats loaded")
 9 )
10 GO

從執行計劃里可以看到,基數預估出現了大問題。

SQL Server 估計行數是501,聚集索引查找運算符的實際行數是1000。SQL Server這里使用idx_ID_SalesAmount統計信息對象的密度向量來做那個估計:密度向量是0.5(在那列我們只有2個不同值),因此估計行數是501(1001 * 0.5)。

當你用Austria參數值執行同樣的查詢,SQL Server又一次估計行數是501,但是查詢本身值返回1行……當其他運算符使用這些估計做運算時,這個行為在執行計劃里會有巨大的副作用。例如,Sort和Hash運算符根據這些估計作為內存授予需要的大小。如果低估,你的查詢會涌向TempDb,如果高估,你就在浪費內存,當你有大量的并發查詢是,就會導致競爭問題(查詢內存的最大數量是有資源管理器限制的……)

你可以使用過濾統計信息來幫助這些特殊場景。這個會給SQL Server關于數據本身分布的更多信息,也會在基數預估里得到幫助。對于那個特殊場景,我創建2個不同的過濾統計信息,對于每個國家我都創建各自的過濾統計信息對象:?

1 -- Fix the problem by creating Filtered Statistics Objects
2 CREATE STATISTICS Country_UK ON Country(ID) 
3 WHERE Name = 'UK'
4  
5 CREATE STATISTICS Country_Austria ON Country(ID) 
6 WHERE Name = 'Austria' 
7 GO

?現在當你重新執行查詢時,最后你會看到基數預估是正確的:

?當你在你表上上創建了過濾統計信息時,你也要注意維護。從整個表本身——如果有20%的數據改變時,SQL Server會自動更新統計信息!!!?假設你有10000行的表,你在表的子集上創建了過濾統計信息,就定子集行數是500條。在這個情況下,當指定列有2000行改變時,SQL Server會更新過濾統計信息對象。因此你要更新過濾統計信息對象里4倍的數據,才會使統計信息失效然后它被更新(在過濾統計信息區間外,沒有數據發生改變)。這是很糟糕的情況,當你使用過濾統計信息時,要記住這個。

希望這篇文章給你過濾統計信息的很好概述,對于給出的查詢,你知道如何使用過濾統計信息幫助SQL Server提高基數預估。

感謝關注!

參考文章:

https://www.sqlpassion.at/archive/2013/10/29/fixing-cardinality-estimation-errors-with-filtered-statistics/

轉載于:https://www.cnblogs.com/woodytu/p/4618818.html

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/258661.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/258661.shtml
英文地址,請注明出處:http://en.pswp.cn/news/258661.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

faster-rcnn系列學習之準備數據

如下列舉了 將數據集做成VOC2007格式用于Faster-RCNN訓練的相關鏈接。 RCNN系列實驗的PASCAL VOC數據集格式設置 制作VOC2007數據集用于Faster-RCNN訓練 將數據集做成VOC2007格式用于Faster-RCNN訓練 這一篇比較詳細地介紹了如何制造voc2007的所有文件&#xff0c;內含相關軟件…

C# 委托鏈、多路廣播委托

委托鏈、多路廣播委托&#xff1a;也就是把多個委托鏈接在一起,我們把鏈接了多個方法的委托稱為委托鏈或多路廣播委托 例&#xff1a; 1 class HelloWorld2 {3 //定義委托類型4 delegate void DelegationChain();5 static void Main(string[] args)6 …

openssl 生成證書_使用證書和私鑰導出P12格式個人證書!

【OpenSSL】使用證書和私鑰導出P12格式個人證書1, 產生CA證書1.1, 生成ca的私鑰openssl genrsa -out cakey.pem 20481.2, 生成ca的自簽名證書請求openssl req -new -key cakey.pem -subj "/CNExample Root CA" -out cacsr.pem1.3, 自簽名ca的證書openssl x509 -req -…

PHP (20140505)

數據庫表與表之間的連接是用id聯系。 join on&#xff1b;轉載于:https://www.cnblogs.com/sunshine-c/p/3710283.html

py-faster-rcnn代碼roidb.py的解讀

roidb是比較復雜的數據結構&#xff0c;存放了數據集的roi信息。原始的roidb來自數據集&#xff0c;在trian.py的get_training_roidb(imdb)函數進行了水平翻轉擴充數量&#xff0c;然后prepare_roidb(imdb)【定義在roidb.py】為roidb添加了一些說明性的屬性。 在這里暫時記錄下…

python 概率分布_python實現概率分布

伯努利分布from scipy import statsimport numpy as npimport matplotlib.pyplot as pltxnp.arange(0,2,1)xarray([0, 1])# 求對應分布的概率&#xff1a;概率質量函數 (PMF)p0.5# 硬幣朝上的概率dfstats.bernoulli.pmf(x,p)dfarray([0.5, 0.5])#繪圖vlines用于繪制豎直線(vert…

CodeForces 7D Palindrome Degree 字符串hash

題目鏈接&#xff1a;點擊打開鏈接 #include<stdio.h> #include<iostream> #include<string.h> #include<set> #include<vector> #include<map> #include<math.h> #include<queue> #include<string> #include<stdlib…

程序清單8-9 回送所有命令行參數和所有環境字符串

1 /*2 3 Name : test.c4 Author : blank5 Version :6 Copyright : Your copyright notice7 Description : 程序清單8-9 回送所有命令行參數和所有環境字符串8 9 */ 10 11 #include "ourhdr.h" 12 13 int main(int argc, char *argv[]) 14…

SQL快速入門

關系化數據庫保存關系模式數據的容器關系模式是對業務對象實體&#xff0c;屬性以及關系的抽象&#xff0c;提煉需求的名詞是建立實體關系模型常用的方法。要了解E-R實體關系圖的繪制。常用關系數據庫Microsoft SQL Server&#xff1b;微軟公司產品&#xff0c;中等規模數據庫&…

Faster RCNN minibatch.py解讀

minibatch.py 的功能是&#xff1a; Compute minibatch blobs for training a Fast R-CNN network. 與roidb不同的是&#xff0c; minibatch中存儲的并不是完整的整張圖像圖像&#xff0c;而是從圖像經過轉換后得到的四維blob以及從圖像中截取的proposals&#xff0c;以及與之對…

oracle精簡版_使用Entity Framework Core訪問數據庫(Oracle篇)

前言哇。。看看時間 真的很久很久沒寫博客了 將近一年了。最近一直在忙各種家中事務和公司的新框架 終于抽出時間來更新一波了。本篇主要講一下關于Entity Framework Core訪問oracle數據庫的采坑。。強調一下&#xff0c;本篇文章發布之前 關于Entity Framework Core訪問oracl…

interrupt、interrupted 、isInterrupted 區別

interrupt&#xff1a;調用方法&#xff0c;是線程處于中斷狀態&#xff0c;但是這個方法只是讓線程設置為中斷狀態&#xff0c;并不會真正的停止線程。支持線程中斷的方法就是在堅持線程中斷狀態&#xff0c;一旦線程中斷狀態被設置為中斷&#xff0c;就會拋出異常。interrupt…

java String部分源碼解析

String類型的成員變量 /** String的屬性值 */ private final char value[];/** The offset is the first index of the storage that is used. *//**數組被使用的開始位置**/private final int offset;/** The count is the number of characters in the String. *//**String中…

python在材料模擬中的應用_基于Python的ABAQUS二次開發及在板料快速沖壓成形模擬中的應用...

2009doi:1013969/j1issn1100722012120091041013基于Python的ABAQUS二次開發及在板料快速沖壓成形模擬中的應用(北京航空航天大學飛行器制造工程系,北京100191)吳向東劉志剛萬敏王文平黃霖摘要:采用Python腳本語言對ABAQUS的前處理模塊進行二次開發,討論了Python腳本在ABAQUS二次…

Doxygen簡介

&#xff08;轉自&#xff1a;http://www.cnblogs.com/liuliunumberone/archive/2012/04/10/2441391.html&#xff09; 一&#xff0e;什么是Doxygen? Doxygen 是一個程序的文件產生工具&#xff0c;可將程序中的特定批注轉換成為說明文件。通常我們在寫程序時&#xff0c;或多…

javascript之閉包理解以及應用場景

1 function fn(){2 var a 0;3 return function (){4 return a;5 } 6 }如上所示&#xff0c;上面第一個return返回的就是一個閉包&#xff0c;那么本質上說閉包就是一個函數。那么返回這個函數有什么用呢&#xff1f;那是因為這個函數可以調用到它外部的a…

faster rcnn學習之rpn、fast rcnn數據準備說明

在上文《 faster-rcnn系列學習之準備數據》,我們已經介紹了imdb與roidb的一些情況&#xff0c;下面我們準備再繼續說一下rpn階段和fast rcnn階段的數據準備整個處理流程。 由于這兩個階段的數據準備有些重合&#xff0c;所以放在一起說明。 我們并行地從train_rpn與train_fas…

sql server規范

常見的字段類型選擇 1.字符類型建議采用varchar/nvarchar數據類型2.金額貨幣建議采用money數據類型3.科學計數建議采用numeric數據類型4.自增長標識建議采用bigint數據類型 (數據量一大&#xff0c;用int類型就裝不下&#xff0c;那以后改造就麻煩了)5.時間類型建議采用為dat…

關于標準庫中的ptr_fun/binary_function/bind1st/bind2nd

http://www.cnblogs.com/shootingstars/archive/2008/11/14/860042.html 以前使用bind1st以及bind2nd很少&#xff0c;后來發現這兩個函數還挺好玩的&#xff0c;于是關心上了。在C Primer對于bind函數的描述如下&#xff1a;“綁定器binder通過把二元函數對象的一個實參綁定到…

CSS偽類

一、首字母的顏色字體寫法 p:first-letter 二、文本的特殊樣式設置 first-line css偽類可與css類配合使用 偽元素只能用于塊級元素 轉載于:https://www.cnblogs.com/boyblog/p/4623374.html