通過手動創建統計信息優化sql查詢性能案例

来源:http://www.cnblogs.com/wy123/archive/2016/04/24/5427580.html
-Advertisement-
Play Games

來源於工作中的一個實際問題, 這裡是組合列數據不均勻導致查詢無法預估數據行數,從而導致無法選擇合理的執行計劃導致性能低下的情況 我這裡把問題簡單化,主要是為了說明問題 進行如下查詢,就是查詢那條所謂的特殊數據 發現執行計劃如下:走的是全表掃描,IO代價也不小, 這種情況下,明明只有一條數據,卻要走全 ...


來源於工作中的一個實際問題,

這裡是組合列數據不均勻導致查詢無法預估數據行數,從而導致無法選擇合理的執行計劃導致性能低下的情況

我這裡把問題簡單化,主要是為了說明問題

如下一張業務表,主要看兩個“狀態”欄位,BusinessStatus1 和 BusinessStatus2

create table BusinessTable
(
    Id int identity(1,1),
    Col2 varchar(50),
    Col3 varchar(50),
    Col4 varchar(50),
    BusinessStatus1 tinyint,
    BusinessStatus2 tinyint,
    CreateDate Datetime
)
GO

--向測試表中寫入數據:

begin tran
    declare @i int
    set @i=0
    while @i<500000
    begin
        insert into BusinessTable values (NEWID(),NEWID(),NEWID(),1,10,GETDATE()-RAND()*1000)
        insert into BusinessTable values (NEWID(),NEWID(),NEWID(),1,20,GETDATE()-RAND()*1000)
        insert into BusinessTable values (NEWID(),NEWID(),NEWID(),1,30,GETDATE()-RAND()*1000)
        
        insert into BusinessTable values (NEWID(),NEWID(),NEWID(),2,20,GETDATE()-RAND()*1000)
        insert into BusinessTable values (NEWID(),NEWID(),NEWID(),2,30,GETDATE()-RAND()*1000)
        insert into BusinessTable values (NEWID(),NEWID(),NEWID(),2,40,GETDATE()-RAND()*1000)

        insert into BusinessTable values (NEWID(),NEWID(),NEWID(),3,30,GETDATE()-RAND()*1000)
        insert into BusinessTable values (NEWID(),NEWID(),NEWID(),3,40,GETDATE()-RAND()*1000)
        insert into BusinessTable values (NEWID(),NEWID(),NEWID(),3,50,GETDATE()-RAND()*1000)


        set @i=@i+1
    end
commit

--插入一條特殊數據,也就是實際業務場景中:
insert into BusinessTable values (NEWID(),NEWID(),NEWID(),3,10,GETDATE()-RAND()*1000)

 

 

--測試數據的特點是:

--BusinessStatus1 的分佈位:1,2,3,
--BusinessStatus2 的分佈位:10,20,30,40,50

--目前數據的對應關係,

--但是註意插入的一條特殊數據:
--BusinessStatus1 和 BusinessStatus2 的組合為:BusinessStatus1=3 and BusinessStatus2=10,在451W條數據中是唯一的一個組合

--創建如下索引:
Create Clustered index idx_createDate on BusinessTable(CreateDate)

Create Index idx_status on BusinessTable(BusinessStatus1,BusinessStatus2)

 

 

進行如下查詢,就是查詢那條所謂的特殊數據

select * 
from BusinessTable 
where BusinessStatus1=3 and BusinessStatus2=10

發現執行計劃如下:走的是全表掃描,IO代價也不小,

這種情況下,明明只有一條數據,卻要走全表掃描

(實際業務中類似數據也不僅只有一條這麼巧,但是在千萬級的表中,符合類似條件的數據很少,

打個比方好理解一點,就像訂單表一樣,訂單是退訂狀態,且尚未退款,這種數據的分佈是少之又少吧

只是舉例,不要較真)

上面查詢的IO信息

 

再通過強制索引提示的情況下,發現同樣的查詢,IO有一個非常大的下降

 

分析上述sql為什麼不走索引?因為畢竟符合條件的數據只有一條,走全表掃描代價也過於大了,尤其是實際情況中,業務表更大,邏輯也沒有這麼直白

這個還要從索引統計信息說起,在符合索引中,索引統計信息只是統計前導列的,對於組合列的分佈,sqlserver是無法預估到的,這一點可以通過第一個查詢的執行計劃發現

sqlserver只是能夠預估到 BusinessStatus1 =3 的情況下的數據分佈,但是無法預估到 BusinessStatus1=3 and BusinessStatus2=10這個組合情況下的數據分佈情況

當然通過統計信息也可以看到,統計信息只記錄了BusinessStatus1的列的數據分佈情況,但是實際執行的過程中,無法預估BusinessStatus1=3 and BusinessStatus2=10的準確分佈

找到了問題的原因,就容易解決了,既然sqlserver無法預估到BusinessStatus1=3 and BusinessStatus2=10這個組合條件的數據分佈請,

那麼就創建一個過濾統計信息,讓sqlserver準確地知道這個條件下數據的分佈請,就容易做出相對準確的執行計划了

通過如下語句,創建一個該條件的統計信息

create statistics BusinessTableFilterStatistics 
on BusinessTable(BusinessStatus1,BusinessStatus2)
where BusinessStatus1=3 and BusinessStatus2=10


--創建完統計信息之後註意要做個更新
UPDATE STATISTICS BusinessTable BusinessTableFilterStatistics with fullscan

 

 

創建完統計信息之後,發現表上會增加一個剛剛創建的統計信息

 

現在再來看這個查詢的執行計劃情況,發現其按照預期的走了索引

 

同時觀察起IO情況,也有一個大幅度的下降

 

總結:

以上通過手動創建統計信息,來促使sqlserver在生成執行計劃的時候,準確地知道數據的分佈情況,做出較為優化的執行計劃,在某些特殊的情況下,可以作為優化的一個考慮方向

 

後記:

或許有人認為這個問題該歸結於parameter sniff的問題,其實這個問題跟parameter sniff還不太一樣(當然也有一點像)

通常情況下,所說的parameter sniff問題是單列數據分佈不均勻的情況下,因為執行計劃重用導致性能地下的一個現象,重點是執行計劃的不合理重用

這裡的問題在於,由於統計信息的數據計算方式,sqlserver 壓根無法預估到符合條件數據的準確分佈,從而無法做出合理的執行計劃的情況

當然這種情況也比較特殊,在強制索引提示以外,可以通過手動創建統計信息來達到優化的目的


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

-Advertisement-
Play Games
更多相關文章
  • 設置主佈局文件,為根佈局設置一個id,作為內容區 給ListView的條目設置點擊事件,setOnItemClickListener()方法,參數:上下文 當前的Fragment實現OnItemClickListener介面 實現onItemClick()方法 switch判斷一下當前菜單的索引位置 ...
  • redis-stat是一個用ruby寫成的監控redis的程式,基於info命令獲取信息,而不是通過monitor獲取信息 一、安裝ruby 由於國內網路原因,導致 rubygems.org 存放在 Amazon S3 上面的資源文件間歇性連接失敗。所以你會與遇到 gem install rack ...
  • Redis官網對 info 已經講解的比較清楚的,參考文檔 。可以看到,info的輸出結果是分幾塊的,有Servers、Clients、Memory等等,通過info後面接這些參數,可以指定輸出某一塊數據。 Redis 2.4.10,並沒有分塊輸出,而且也無法按上面說的加選項控制輸出某一塊,後來升級 ...
  • 1、複製概述1.1、複製解決的問題數據複製技術有以下一些特點:(1) 數據分佈(2) 負載平衡(load balancing)(3) 備份(4) 高可用性(high availability)和容錯1.2、複製如何工作從高層來看,複製分成三步:(1) master將改變記錄到二進位日誌(binary ...
  • 點擊查看Oracle函數大全線上版 SQL中的單記錄函數1.ASCII返回與指定的字元對應的十進位數;SQL> select ascii('A') A,ascii('a') a,ascii('0') zero,ascii(' ') space from dual; A A ZERO SPACE 65 ...
  • 要理解join語句,首先得明白笛卡爾乘積(即集合的乘運算),其定義如下: 笛卡爾(Descartes)乘積又叫直積。假設集合A={a,b},集合B={0,1,2},則兩個集合的笛卡爾積為{(a,0),(a,1),(a,2),(b,0),(b,1), (b,2)}。 在SQL的join聯結操作中,其實 ...
  • 條件有限,只在一臺機器上模擬部署一下,相關參數就不寫在配置文件里了,直接使用命令指定參數這裡我模擬三個伺服器分別為 serverA,serverB,serverC我是通過修改/etc/hosts 將他們d綁定到 127.0.0.1# cat /etc/hosts127.0.0.1 localhost ...
  • 從表中刪除某條記錄: delete from table_name where xx=xxxx; ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...