SQL Server統計信息偏差影響表聯結方式案例淺析

来源:https://www.cnblogs.com/kerrycode/archive/2019/03/31/10632813.html
-Advertisement-
Play Games

我們知道資料庫中的統計信息的準確性是非常重要的。它會影響執行計劃。一直想寫一篇關於統計信息影響執行計劃的相關博客,但是都卡在如何構造一個合適的例子上,所以一直拖著沒有寫。巧合,最近在生產環境中遇到這麼一個案例,下麵對案例中的相關信息做了脫敏處理,有些中間步驟也省略了,只關註核心部分SQL。如下所示,... ...


 

我們知道資料庫中的統計信息的準確性是非常重要的。它會影響執行計劃。一直想寫一篇關於統計信息影響執行計劃的相關博客,但是都卡在如何構造一個合適的例子上,所以一直拖著沒有寫。巧合,最近在生產環境中遇到這麼一個案例,下麵對案例中的相關信息做了脫敏處理,有些中間步驟也省略了,只關註核心部分SQL。如下所示,同事反饋一個SQL語句執行很慢。

 

 

 
UPDATE  b
SET     b.[Status] = '已掃描,未簽收' ,
        b.[Time] = pr.CreatedDate
FROM    #Batch b
        JOIN WDPM.PdaRecords pr WITH ( NOLOCK ) ON b.Batch_No = pr.OrderNo
                                                              AND pr.FunctionName = '[WDPM].[usp_SaveOutOrder]'
WHERE   b.[Status] = '已打單,未掃描'
        AND pr.CreatedDate > b.[Time];

 

 

 

如下截圖所示,這個SQL語句基本上耗時271秒。一個臨時表與一個表做嵌套迴圈連接(Nested Loops)。 因為表WDPM.PdaRecords只有一個聚集索引,所以執行計劃中,這個表走聚集索引掃描。

 

 

 

 

clip_image001

 

 

註意:這裡表WDPM.PdaRecords本身缺少合適的索引,只有一個聚集索引。後面展開講述這個問題.這裡先圍繞統計信息的準確性對執行計劃的影響來展開講述。

 

clip_image002

 

 

物理表WDPM.PdaRecords的數據量為2505369(當然這個是一直在變化的。這個數值僅僅是實驗前的檢測記錄,一直有會話對其進行DML操作,所以數據會變化,所以這裡沒有列出統計信息截圖)。

 

clip_image003

 

我們看到Table Scan部分,預估行數(Estimated Number of Rows)為1, 實際行數為150。 這個偏差已經比較大了。

 

 

clip_image004

 

對於物理表WDPM.PdaRecords而言,基數估計的預估行數(Estimated Number of Rows)為921771, 但是由於嵌套迴圈連接,所以累加起來的實際行數(Actual Number of Rows)為: 921771*150  =138265650  。

 

clip_image005

 

clip_image006

 

 

我們知道嵌套迴圈(Nested Loops)演算法的時間複雜度為N*M N的預估值從1變成了150 ,這裡面的偏差就大了(因為每次聚集索引掃描的開銷也很大)。所以導致優化器在表的物理連接方式上選擇了嵌套迴圈(Nested Loops), 因為預估的代價是很小的。但是實際因為統計信息的誤差,導致這個代價放大了150倍。那麼如果我們更新臨時表的統計信息呢?然後執行這個SQL,會有什麼變化呢? 

 

如下所示,我們在執行SQL語句前,更新一下臨時表的統計信息。發現優化器在獲取了準確的統計信息後,在表的物理連接上選擇了Hash Join方式。而且SQL語句耗時變成了1秒多。為什麼呢? 因為優化器發現選擇Nested Loops的代價遠遠高於 Hash Join。所以它在獲取了準確的信息後,作出了最優選擇。之前之所以生成了一個錯誤的執行計劃,就是因為它得到的信息不准確,導致它作出了錯誤的抉擇。這個就好比你獲取了錯誤的信息,作出了錯誤的選擇,購買了一隻錯誤的股票,而巴菲特由於掌握了準確的行業信息,作出了正確的選擇。 購買了幾隻購票都大漲了。

 

 
UPDATE STATISTICS #Batch WITH FULLSCAN;
 
 
UPDATE  b
SET     b.[Status] = '已掃描,未簽收' ,
        b.[Time] = pr.CreatedDate
FROM    #Batch b
        JOIN WDPM.PdaRecords pr WITH ( NOLOCK ) ON b.Batch_No = pr.OrderNo
                                                              AND pr.FunctionName = '[WDPM].[usp_SaveOutOrder]'
WHERE   b.[Status] = '已打單,未掃描'
        AND pr.CreatedDate > b.[Time];

 

 

 

clip_image007

 

 

clip_image008

 

當然,瞭解到這裡,還遠遠沒有結束。我們發現表WDPM.PdaRecords 只有一個聚集索引,而且聚集索引位於Iden自增欄位上,從另外一個角度來看,這個表其實是缺少合適的索引的。那麼我們可以創建一個索引。

 

CREATE INDEX IX_PdaRecords_N1 ON wdpm.PdaRecords(OrderNo,FunctionName)

 

 

創建索引後,即使不更新臨時表#Batch的統計信息,我們發現執行計劃也會走嵌套迴圈(Nested Loops),而不會走Hash Join了。這個又是什麼原因呢?

 

clip_image009

 

此處截圖,是第二次執行SQL,臨時表的數據變化了(生成臨時表的數據的SQL有好幾個,每次執行獲取的數據都會有部分變化)

 

clip_image010

 

因為有了合適的索引,趨近準確的統計信息,以及謂詞下推(predicate push down),基數(Cardinality)的預估行數(Esitmted Row Size)為35.0545 與實際行數(Actual Number of Rows)為666, 這樣即使迴圈次數為140.  總的訪問記錄數為140*666=93240 , 這個是遠遠小於之前錯誤執行計劃的138265650 。所以即使臨時表的#Batch的統計信息有誤,但是優化器還是生成了一個不錯的執行計劃。這樣SQL的執行時間也就縮短到了1秒內.

 

 

clip_image011

 

這個案例僅僅是為了展示:統計信息的準確與否,會導致優化器生成的執行計劃選擇不同的表連接方式, 例如從嵌套迴圈(Nested Loops)變成Hash Join。 僅僅是為了說明統計信息準確的重要性。


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

-Advertisement-
Play Games
更多相關文章
  • 基本信息記錄我在使用win10過程中遇到的一些問題我所使用的兩個win10系統Win10 企業版 1607(家裡電腦)Win10 專業版 1806(公司電腦)win10 開啟Sets請問您在開始-設置-系統-多任務中是否看到Sets的相關設置。如果沒有請您嘗試將時區和地區設置成美國後查看有沒有相關設... ...
  • 我們在前面的章節中已經詳細介紹了堆在進程中的地址空間是如何分佈的,對於程式來說,堆空間只是程式向操作系統申請划出來的一大塊地址空間。而程式在通過 malloc申請 記憶體空間時的大小卻是不一定的,從數個字到數個GB都是有可能的。於是我們必須將堆空間管理起來,將它分塊地按照用戶需求出售給最終的程式,並且 ...
  • 記憶體映射mmap是Linux內核的一個重要機制,它和虛擬記憶體管理以及文件IO都有直接的關係,這篇細說一下mmap的一些要點。 修改(2015 11 12):Linux的虛擬記憶體管理是基於mmap來實現的。vm_area_struct是在mmap的時候創建的,vm_area_strcut代表了一段連續 ...
  • 一. 菜單欄 “虛擬機” ——》 “設置 ” 使用linux.so鏡像文件 此文件在vmware workstation 的安裝目錄。並且打開CD/DVD的連接。 二.終端執行如下命令 mount /dev/cdrom /mnt/cdrom 掛載 cd /mnt/cdrom cp VMwareXXX ...
  • 普通文件IO總結 FILE結構體 打開文件fopen函數 文件指針名=fopen(文件名,使用文件方式) eg: 打開方式有: fopen若過出錯則,返回一個NULL可以用作錯誤異常處理的判斷條件; fclose函數 用於關閉當前文件 fclose(FILE*);返回值為0表示正確,非零錯誤。 文件 ...
  • Samba 服務 yum install samba mv smb.conf smb.conf.bak cat smb.conf.bak | grep -v "#" | grep -v ";" | grep -v "^$" > smb.conf 與系統用戶映射關係 初次創建用戶samba資料庫 pd ...
  • 環境:MacOS 10.13.6 虛擬機:VirtualBox6.0(VirtualBox-6.0.4-128413-OSX.dmg) Linux:Centos7(CentOS-7-x86_64-Minimal-1810.iso) 一:虛擬機安裝 這個。。。。真沒啥好說的。。。略過 二:虛擬機創建C ...
  • 概述 資料庫相對於其它存儲軟體一個核心的特征是它支持事務,所謂事務的ACID就是原子性,一致性,隔離性和持久性。其中原子性,一致性,持久性更多是關註單個事務本身,比如,原子性要求事務中的操作要麼都提交,要麼都不提交;一致性要求事務的操作必須滿足定義的約束,包括觸發器,外鍵約束等;持久性則要求如果事務 ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...