SQL Server 統計信息更新時採樣百分比對數據預估準確性的影響

来源:http://www.cnblogs.com/wy123/archive/2016/09/15/5875237.html
-Advertisement-
Play Games

為什麼要寫統計信息 最近看到園子里有人寫統計信息,樓主也來湊熱鬧。 話說經常做資料庫的,尤其是做開發的或者優化的,統計信息造成的性能問題應該說是司空見慣。 當然解決辦法也並非一成不變,“一招鮮吃遍天”的做法已經行不通了(題外話:整個時代不都是這樣子嗎) 當然,還是那句話,既然寫了就不能太俗套,寫點不 ...


  

為什麼要寫統計信息

  最近看到園子里有人寫統計信息,樓主也來湊熱鬧。
  話說經常做資料庫的,尤其是做開發的或者優化的,統計信息造成的性能問題應該說是司空見慣。
  當然解決辦法也並非一成不變,“一招鮮吃遍天”的做法已經行不通了(題外話:整個時代不都是這樣子嗎)
  當然,還是那句話,既然寫了就不能太俗套,寫點不一樣的,本文通過分析一個類似實際案例來解讀統計信息的更新的相關問題。
  對於實際問題,不但要解決問題,更重要的是要從理論上深入分析,才能更好地駕馭資料庫。
 

統計信息基礎

首先說一個老掉牙的話題,統計信息的更新閾值:
1,表格從沒有數據變成有大於等於1條數據。
2,對於數據量小於500行的表格,當統計信息的第一個欄位數據累計變化量大於500以後。
3,對於數據量大於500行的表格,當統計信息的第一個欄位數據累計變化量大於500 + (20%×表格數據總量)以後。

觸發統計信息後,rowmodct歸0

 

關於統計信息“過期”的問題

下麵開始正文,網路上很多關於統計信息的文章,提到統計信息,很多都是統計信息過期的問題,然後跟新之後怎麼怎麼樣
尤其在觸發統計信息自動更新閾值的第三個區間:也就是說數據累計變化超過20%之後才能自動觸發統計信息的更新
這一點對於大表來說通常影響是比較大的,比如1000W的表,變化超過20%也+500也就是200W+500行之後才觸發統計信息更新,
這個閾值區間的自動觸發閾值,絕大多數情況是不能接受的,於是對於統計信息的診斷就變成了是否“過期”

 

 

判斷統計信息是否過期,然後通過更新統計信息來促使執行計劃更加準確地預估行數,這一點本無可厚非
但是,問題也就出在這裡了:那麼怎麼更新統計信息?一成不變的做法是否可行,這才是問題的重點。
當然肯定有人說,我就是按照預設方式更新的,更新完之後SQL也變得更加優化了什麼的
通過update statistics TableName StatisticName更新某一個索引的統計信息,
或者update statistics TableName更新全表的統計信息
這種情況下往往是小表上可以這麼做,當然對於大表或者小表沒有一個標準值,一切要結合事實來說明問題
 

下麵開始本文的主題:

抽象並簡化出業務中的一個實際案例,創建這麼一張表,類似於訂單和訂單明細表(主子表),
這裡你可以想象成是一個訂單表的子表,Id欄位是唯一的,有一個ParentID欄位,是非唯一的,
ParentID類似於主表的Id,測試數據按照一個主表Id對應50條子表明細的規律插入數據

CREATE TABLE [dbo].[TestStaitisticsSample](
    [Id] [int] IDENTITY(1,1) NOT NULL,
    [ParentId] [int] NULL,
    [OtherColumn] [varchar](50) NULL
) 


declare @i int=0
while(@i<100000000)
begin

    insert into [TestStaitisticsSample](ParentId,OtherColumn)values(@i,NEWID())
    /*
    中間插入50條,也即一個主表Id對應50條子表明細
    */
    insert into [TestStaitisticsSample](ParentId,OtherColumn)values(@i,NEWID())

    set @i=@i+1
end
go

create nonclustered index [idx_ParentId] ON [dbo].[TestStaitisticsSample]
(
    [ParentId] 
)
go

 

本來打算插入1億條的,中間我讓他執行我睡午覺去了,醒來之後發現SSMS掛掉了,掛掉了算了,數據也接近1億了,能說明問題就夠了
現在數據分佈的非常明確,就是一個ParentId有50條數據,這一點首先要澄清。

 

測試數據寫入,以及所創建完成之後來更新 idx_ParentId 索引上的統計信息,就按照預設的方式來更新,然後來觀察統計信息

 

預設方式更新統計信息(未指定採樣密度)

表裡現在是8000W多一點記錄,預設更新取樣時462239行,那麼這個統計信息靠譜嗎?

上面說了,造數據的時候,我一個ParentId對應的是50行記錄,這一點非常明確,他這裡給我統計出來的多少?

1,對於取樣的RANG_HI_Key值,比如51632,他給我預估了862.212行

2,對於AVG_RANG_ROW,比如45189到51632之間,他給我預估了6682.490行

這靠譜嗎,這個誤差是無法接受的,很多時候,對於大表,採用預設(未指定採樣密度)的情況下,預設的採樣密度並不足以準確地描述數據分佈情況

 

指定一個採樣密度的方式更新統計信息(20%採樣)

 

這一次用20%的採樣密度,可以看到取樣時15898626行

1,對於取樣的RANG_HI_Key值,比如216305,他給我預估了24.9295行

2,對於AVG_RANG_ROW,比如186302到216305之間,他給我預估了197.4439行

觀察比如上面預設的取樣密度,這一次不管是RANG_HI_Key還是AVG_RANG_ROW得預估,都有不一個非常高的下降,趨於接近於真實的數據分佈(50行)

但是這個誤差還是比較大的,如果繼續提高採樣密度,看看有什麼變化?

 

指定一個採樣密度的方式更新統計信息(70%採樣) 

 

這一次用70%的採樣密度,可以看到取樣是55962290行

1,對於取樣的RANG_HI_Key值,比如1978668,他給我預估了71.15906行

2,對於AVG_RANG_ROW,比如1124024到1978668之間,他給我預估了61.89334行

可以說,對於絕大多數值得預估(AVG_RANG_ROW),都愈發接近於真實值

   

 

指定一個採樣密度的方式更新統計信息(100%採樣)

 

這個就不做過多解釋了,基本上跟真實值是一樣的,只是AVG_RANG_ROW有一點非常非常小的誤差。

 

 取樣密度高低與統計信息準確性的關係

 

  至於為什麼預設取樣密度和較低取樣密度情況下,誤差很大的情況我簡單解釋一下,也非常容易理解,
  因為“子表”中存儲主表ID的ParentId值允許重覆,在存在重覆值的情況下,如果採樣密度不夠,極有可能造成“以偏概全”的情況
  比如對10W行數據取樣1W行,原本10W行數劇中有2000個不重覆的ParentId值,
  如果是10%的取樣,在1W行取樣數據中,因為密度不夠大,只找到了20個不重覆的ParentId值,
  那麼就會認為每一行ParentId對應500行數據,這根實際的分佈的每個ParentId有一個非常大的誤差範圍
  如果提高採樣密度,那麼這個誤差就會越來越小。
  

  因此在觀察統計信息是否過期,決定更新統計信息的時候,一定要註意取樣的密度,
  就是說表中有多少行數據,統計信息更新的時候取了多少採樣行,密度有多高。
  當然,肯定有人質疑,那你說採樣密度越高,也就是取樣行數越高越準確,那麼我就100%取樣。
  這樣行不行?
  還要分情況看,對於幾百萬或者十幾萬的小表來說,當然沒有問題,這也是為什麼資料庫越小,表數據越少越容易掩蓋問題的原因。
  對於大表,上億的,甚至是十幾億的,你按照100%採樣試一試?
  

  舉個實際例子:

  我這裡對一個稍微大一點的表做個全表統計信息的更新,測試環境,伺服器沒負載,存儲是比普通的機械硬碟要強很多的SAN存儲
  採用full scan,也就是100%採樣的更新操作,看一下,僅僅這一樣表的update statistic操作就花費了51分鐘
  試想一下,對一個數百GB甚至數TB的庫來說,你敢這麼搞一下。

  

 

  扯一句,這個中秋節過的,折騰了大半天,話說做測試過程中電腦有開始有點卡,

  做完測試之後停掉SQLServer服務,瞬間記憶體釋放了7個G,可見這些個操作還是比較耗記憶體的

  

  

 

總結:

  本文通過對於某些場景下,在對較大的表的索引統計信息更新時,採樣密度的分析,闡述了不同採樣密度下,對統計信息預估的準確性的影響。

  當然對於小表,一些都好說。

  隨著單表數據量的增加,統計信息的更新策略也要做相應的調整,

  不光要看統計信息是否“過期”,更重要的是註意統計信息更新時究竟取樣了全表的多少行數據做統計。

  對於大表,採用FULL SCAN或者100%採樣往往是不可行的,這時候就需要做出權衡,做到既能準確地預估,又能夠以合理的代價執行。

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 一、登錄 打開終端,輸入/usr/local/mysql/bin/mysql -u root -p 初次進入mysql,密碼為空。當出現mysql>提示符時,表示你已經進入mysql中。鍵入exit退出mysql。 二、更改Mysqlroot用戶密碼 更改mysql root 用戶密碼,在終端輸入/ ...
  • oracle使用java source調用外部程式 需求 Oracle調用第三方外部程式。Oracle使用sqluldr2快速導出大批量數據,然後用winrar壓縮後發送郵件。 原碼 java source create or replace and compile java source name... ...
  • Spark Streaming Spark Streaming 是Spark為了用戶實現流式計算的模型。 數據源包括Kafka,Flume,HDFS等。 DStream 離散化流(discretized stream), Spark Streaming 使用DStream作為抽象表示。是隨時間推移而 ...
  • 地址:http://www.sqlite.org/download.html組織形式可以看到source code是Amalgamation。真正的源碼在這裡什麼是Amalgamation下載源碼以後,打開時候這樣子的src文件夾里就是所有的代碼,大概有一百多個。那麼為啥還要有一個Amalga... ...
  • 在MongoDB(版本 3.2.9)中,數據的分發是指將collection的數據拆分成塊(chunk),分佈到不同的分片(shard)上,數據分發主要有2種方式:基於數據塊(chunk)數量的均衡分發和基於片鍵範圍(range)的定向分發。MongoDB內置均衡器(balancer),用於拆分塊和 ...
  • 索引是一種特殊的文件(InnoDB數據表上的索引是表空間的一個組成部分),它們包含著對數據表裡所有記錄的引用指針。註:[1]索引不是萬能的!索引可以加快數據檢索操作,但會使數據修改操作變慢。每修改數據記錄,索引就必須刷新一次。為了在某種程式上彌補這一缺陷,許 多SQL命令都有一個DELAY_KEY_ ...
  • 轉載於:http://blog.csdn.net/wudongxu/article/details/8623610 SQL標准定義了4類隔離級別,包括了一些具體規則,用來限定事務內外的哪些改變是可見的,哪些是不可見的。低級別的隔離級一般支持更高的併發處理,並擁有更低的系統開銷。 Read Uncom ...
  • 作者對序列化的描述淺顯易懂!(https://www.douban.com/note/313096752/) ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...