1. 程式人生 > >SQL Server 索引維護(1)—如何獲取索引使用情況

SQL Server 索引維護(1)—如何獲取索引使用情況

前言:

前面一文中,已經提到了三類常見的索引問題,那麼問題來了,當系統出現這些問題時,該如何應對?簡單而言,需要分析現有系統的行為,然後針對性地對索引進行處理:

  • 對於索引不足的情況:檢查缺少索引的情況,也需要檢查現有索引定義是否有問題。
  • 對於索引過多的情況:分析每一個索引的使用情況,判斷是否有存在的必要或者可合併、可修改的可能。
  • 對於索引不合理的情況:也要分析每個索引的定義,及其使用情況,確定索引是否有存在必要,如果有,是否能很好地支援查詢並且對現有系統的影響也不大。

從上面描述可知,我們的步驟是:


注:這個步驟並不是必須的,也不是固定的,視實際情況而定才是最佳方案。下面來介紹整個流程。

起因:

我們為什麼要維護索引?大家都知道——因為效能有問題了。為什麼效能有問題呢?索引不合理了唄!絕大部分系統和IT從業人員都很難在一開始就做好效能規劃。特別在國內這種趕專案進度,上線了再說的國情下,即使你知道這個功能有效能問題,但是修改會帶來嚴重的專案延期的前提下,所有人都不會允許你做改動的。所以大部分效能問題都在系統執行到一定程度或者資料量突發增長或持續增長時才出現。甚至很多領導層認為:系統能用是最重要的,效能問題可以推一下。在這一些背景下,對開發、設計人員過多地指責他們沒有做好前期工作是沒必要的,大家將心比心,多點理解,對後面優化工作也有幫助,畢竟別人不會那麼抵觸。

那麼在系統執行一段時間後出現效能問題或者運維壓力時,你就要介入進行效能優化。效能優化的第一步並不是盲足亂搞,而是找瓶頸,找到瓶頸才能做相應的處理,否則只能聽天由命,誤打誤撞的機率其實很小。下面我們假定系統的效能問題已經是索引引起的,那麼我們就從定位瓶頸著手。

收集系統行為:

我們知道,除非硬體BUG,否則一個靜止的系統不會出現效能問題。所以系統的效能問題本質上是因為系統的行為導致的。因此,我們首先需要收集系統行為來定位瓶頸。

系統行為各式各樣,又彼此關聯,我們很難輕易地定位所有問題。但是Windows、SQL Server作為成熟的軟體,在使用了十幾年之後,業界已經有了一套比較成熟和現成的方案,所以我們不妨根據這些方案來收集。大概流程如下:


由於本文不是專門討論如何偵測和處理系統性能問題的文章,所以非資料庫部分只簡略介紹。

首先,我們要做的是對基礎的檢測:伺服器及作業系統的檢查。伺服器和作業系統是軟體系統的支撐部分,並且一個軟體系統的實際執行離不開對它們的準確、高效運作。上圖中列出了“伺服器型號”的檢查,因為論壇上曾經有這麼個帖子,一個新伺服器安裝SQL Server之後,服務一啟動記憶體馬上佔滿,期間沒有任何操作。最後發現IBM x3650這款型號的伺服器對SQL Server存在問題,換了其他型號之後就消失了。另外,對伺服器特別是硬體的檢查也是必要的,剛接手系統時,老是說卡,用效能計數器檢測之後發現伺服器的個別盤IO問題很嚴重,檢查資料庫檔案存放路徑之後發現,雖然伺服器上有SSD盤,但是資料庫依舊執行在伺服器自帶的SAS盤上,後來把使用者庫、TempDB移到SSD之後,雖然沒有突飛猛漲的效能提升,但是再次檢查可以得知大部分盤的IO使用情況已經趨向正常。我們知道,伺服器對資料庫效能影響最大的不是記憶體大小,而是IO。由於資料庫不直接操作磁碟,而是把資料從磁碟載入到記憶體,所以磁碟的IO應該越快越好。簡單來說,在作業系統和硬體配置合理的前提下,資料庫檔案應該按照各自行為存放在儘可能快的硬碟中。由於本文的主題在索引上,所以這裡不多說。

對於作業系統配置,有幾個點需要注意:

  • 碟符劃分、RAID配置、命名規則等問題。
  • 網路配置、機器命名:本人維護的系統中,供應商在安裝好OS後馬上安裝SQL Server,送貨到機房之後,運維人員根據內部需要重新命名機器名,導致SQL Server某些功能無法識別administrator,比如複製功能。如有可能,建議先完成作業系統的配置再安裝SQL Server,若無法實現,可以用以下指令碼,修改SQL Server的配置,但本指令碼不能完全處理這類問題:
[sql] view plain copy  print?
  1. --檢查是否一致
  2. use master  
  3. go  
  4. select @@servername  
  5. select serverproperty('servername')  
  6. --如果不一致,執行下面的語句
  7. if  serverproperty('servername')  <>   @@servername   
  8.     begin
  9.    declare   @server   sysname   
  10.    set   @server   =  @@servername    
  11.    exec   sp_dropserver   @server  =   @server   
  12.    set   @server   =  cast(serverproperty('servername')  as   sysname)   
  13.    exec   sp_addserver   @server  =   @server   ,  @local   =   'LOCAL'
  14. end
  15. /***************************************  
  16. 說明:其實就是刪除舊的伺服器名servername,再新增新的伺服器名  
  17. sp_dropserver '舊的伺服器名'
  18. sp_addserver '新的伺服器名' , 'LOCAL'
  19. 3、重啟SQL SERVER  
  20. 4、再執行以下指令碼驗證一下。  
  21. ***************************************/  
  22. use master  
  23. go  
  24. select @@servername  
  25. select serverproperty('servername')  


下面進入重點部分,也就是對資料庫系統的偵測。收集系統行為資訊還有一個重要的原因就是了解系統讀寫行為,讀多還是寫多。讀寫比例直接影響表設計、資料型別特別是定長和變長的選擇,也影響索引填充因子的配置等。

但是本文集中在索引行為上,所以不打算花費太大篇幅在上面,後續再整理專題。從大範圍來說,伺服器行為可以通過分析應用程式的結構、效能計數器、伺服器端SQL Trace、儲存過程、函式、檢視讀寫次數及索引的使用情況來綜合分析,但是無論哪一種方式,要做充分的分析都是耗時、工作量大的體力和腦力活。

可是我們沒有必要總是全部收集,一個一個分析。我們可以使用“大膽假設,小心求證”的方式去應對。下面來點乾貨:

需要收集的資訊:

在實操之前,需要先了解我們的操作物件——本系列中的索引。簡單而言,就是要對錶上的索引進行資訊收集,索引的資訊很多,比如有多少資料頁、葉子節點包含了什麼資料、索引層級、鎖升級等等,但是大部分對處理常規問題而言並不必要,所以我們可以重點針對索引的某些明顯指標進行收集:

  • 索引的讀、寫次數。
  • 索引定義
  • 索引被使用的具體情況(本文的重點)
  • 索引碎片
  • 缺少索引(missingindex)的相關資訊

需要注意的是,你要收集的系統應該運行了足夠長的時間,比如數週甚至數月,除了讓快取能充分表現系統行為之外,也可以加大覆蓋系統行為的可能性,因為某些功能確實只在特定時間(如月結及其報表)才會發生,或者在異常時才會觸發,如果系統運行了幾個小時就開始收集資訊,那麼資訊的準確度可能不足以支撐系統分析。

網上有類似的文章,但是我覺得個人的方法也不錯,所以這裡我不打算根據網上的方法來介紹,而是介紹本人自己的方法,如有不妥或者漏洞,歡迎指出和分享你們的方法。

實操:

         對於索引問題,我要思考的是:現在的索引是否合理?如果合理,那麼效能問題可能是別的地方,當然,寫這篇文章證明是不合理的,那麼如何發現和定義呢?需要監控和分析。由於本人負責的系統是SQL 2008 R2,雖然已經支援擴充套件事件(Extent Events,xEvents),但是由於從SQL 2012開始才有圖形化介面,而且2008聽說還存在一定的bug,所以在這裡並沒有使用,個人還是挺看好這個功能,後續我會嘗試使用,也歡迎大家分享。

既然xEvents不可用,那麼還是來點傳統方式吧——計劃快取(Plan cache)和DMO(DMVs 和DMFs,動態管理物件)。需要注意的是計劃快取儲存的是預估執行計劃,有些程式的實際行為是不同的。所以預估執行計劃只能作為入門。

在確定工具之後,接下來就要思考如何使用。前面提到的指標中,除了“索引被使用的具體情況”之外,其他都能用各種DMO獲取。但是基於連貫性原因,我邊描述操作邊簡要介紹各種DMO。

通常來說,一個系統有大量的物件(儲存過程、動態SQL、函式、檢視等),除非問題非常特殊,一眼就能定位,否則我會按照下面原則來檢查:

1、  從SSMS中的報表獲取LongRunning 。

2、  用語句獲取LongRunning物件。(1、2兩個我將單獨起文介紹)

3、  通過與開發人員的溝通獲取可能的效能瓶頸。

4、  對大表和索引很多的表進行優先分析。

5、  當然還有其他,不過這些多多少少跟運氣有關,說不定誤打正著碰對了瓶頸。

在本次Troubleshooting中,我按上面順序進行操作,最後發現第四個原則的效果明顯,所以我重點討論第四個原則。

查詢索引定義:

         在這次維護索引中,我選擇了對大表進行優先分析,當然對於很多系統來說,這些表一點都不大,不過別在意細節。首先我從最大的表開始,逐個分析每個表的索引。找表的行數太容易了,這裡就不說了。當我找到最大表時,我們可以很輕易地從SSMS中找到表上有多少索引,然後呢?

在SQL 2000時代,很多sp_xxxx系統儲存過程都能獲取一定的資訊,比如sp_helpindex 表名這種方式可以獲取表上索引的定義,但是這個系統儲存過程並不支援SQL 2005及後續版本出現的新功能,如包含索引的描述,所以你只能看到索引名、定義在INCLUDE關鍵字前的那些列(假設它們是包含索引),對於包含索引中的包含列,卻沒有顯示。這種方式有一個風險,很多人通過這個儲存過程看到某些索引的前面幾列完全相同,就直接刪除其中重複索引,其實這些索引是包含索引,對某些程式的支援有作用,這種魯莽行為可能導致系統性能突然猛降,所以要“大膽假設、小心求證!!!”。

我們可以使用DMO來實現這種需要,注意替換表名:

[sql] view plain copy  print?
  1. DECLARE @tblnvarchar(265)  
  2. SELECT @tbl = '表名'
  3. SELECT o.name,i.index_id, i.name, i.type_desc,  
  4.        substring(ikey.cols, 3, len(ikey.cols))AS key_cols,  
  5.        substring(inc.cols, 3, len(inc.cols)) ASincluded_cols,  
  6.        stats_date(o.object_id, i.index_id) ASstats_date,  
  7.        i.filter_definition  
  8. FROM   sys.objects o  
  9. JOIN   sys.indexes i ON i.object_id = o.object_id  
  10. CROSS  APPLY (SELECT', ' + c.name +  
  11.                      CASE ic.is_descending_key  
  12.                           WHEN 1 THEN' DESC'
  13.                           ELSE''
  14.                      END
  15.               FROM   sys.index_columns ic  
  16.               JOIN   sys.columns c ON ic.object_id = c.object_id  
  17.                                   ANDic.column_id = c.column_id  
  18.               WHERE  ic.object_id = i.object_id  
  19.                 AND  ic.index_id = i.index_id  
  20.                 AND  ic.is_included_column = 0  
  21.               ORDERBY ic.key_ordinal  
  22.               FOR XML PATH('')) AS ikey(cols)  
  23. OUTER  APPLY (SELECT', ' + c.name
  24.               FROM   sys.index_columns ic  
  25.               JOIN   sys.columns c ON ic.object_id = c.object_id  
  26.                                   ANDic.column_id = c.column_id  
  27.               WHERE  ic.object_id = i.object_id  
  28.                 AND  ic.index_id = i.index_id  
  29.                 AND  ic.is_included_column = 1  
  30.               ORDERBY ic.index_column_id  
  31.               FOR XML PATH('')) AS inc(cols)  
  32. WHERE  o.name = @tbl  
  33.   AND i.type IN (1, 2)  
  34. ORDERBY o.name, i.index_id  

結果如下:


可以比較直觀地看到索引定義及其統計資訊更新時間(這個極其重要,但是不是本文的重點,所以也不詳細描述)。獲取索引定義是為了分析設計是否合理、是否可修改,如果不知道你要操作的物件是什麼樣子的,也就不可能有下面的步驟。

每個表上索引的使用情況:

當你知道有多少個索引,索引是怎樣的時候,就可以開始收集索引使用情況,這裡分兩步,但是可以同時進行:

1.獲取索引的讀寫情況:

2.獲取索引的被使用資訊,這裡的被使用是指:從伺服器啟動開始(這個很重要,因為你讀的是快取),這個索引在系統中被什麼物件(動態SQL、儲存過程、函式等,包含了物件的文字資訊)使用過,使用了多少次,對應的計劃快取是怎樣的。

對於第一步,我們可以用簡單的DMV來得到:

[sql] view plain copy  print?
  1. SELECT  OBJECT_NAME(ddius.[object_id]) AS [TableName] ,  
  2.         i.nameAS [IndexName

    相關推薦

    SQL Server 索引維護1—如何獲取索引使用情況

    前言: 在前面一文中,已經提到了三類常見的索引問題,那麼問題來了,當系統出現這些問題時,該如何應對?簡單而言,需要分析現有系統的行為,然後針對性地對索引進行處理: 對於索引不足的情況:檢查缺少索引的情況,也需要檢查現有索引定義是否有問題。對於索引過多的情況:分析每一個索引的使用情況,判

    SQL Server On Linux1——CentOS 7 安裝SQL Server2019

    前言 SQL Server 2019已經正式公佈,雖然只是preview版,但是不影響我們追求新的技術。接下來的一個系列,隨著本人的研究,儘量讓這個系列成為“教程”,真正的入門到精通。 環境準備   不廢話,先把研究環境搭建起來。由於某些原因(晚點再說),本系列

    Sql Server資料庫開發1資料庫設計

    1.瞭解E-R圖 E-R圖是一種廣泛使用的設計工具,主要用來表示事物、事物的資料和期間的關係資訊。 E-R圖中資訊的三種形式: 1)實體:就是一種物件,若干個具有共同特徵的實體被稱為實體集,實體一般使用名詞。 2)屬性:用來表現實體特徵的一個數據,屬性一般使用

    探索SQL Server元資料索引元資料

    背景 在第一篇中我介紹瞭如何訪問元資料,元資料為什麼在資料庫裡面,以及如何使用元資料。介紹瞭如何查出各種資料庫物件的在資料庫裡面的名字。第二篇,我選擇了觸發器的主題,因為它是一個能提供很好例子的資料庫物件,並且在這個物件中能夠提出問題和解決問題。 本篇我將會介紹元資料中的索引,不僅僅是因為它們本身很重要,更

    mysql索引學習1常見索引索引失效

    介紹 1.什麼是索引? 一般的應用系統,讀寫比例在10:1左右,而且插入操作和一般的更新操作很少出現效能問題,在生產環境中,

    SQL Server On Linux4——Linux 初步配置1

    接上文:SQL Server On Linux(3)——SQL Server 2019 For Linux 下載並部署示例資料庫 本文聊一下Linux,因為這個系列是Linux上的SQL Server,所以我們有必要初步瞭解一下這個基石,地基不穩那麼上面搭建的東西也必然搖搖晃

    SQL Server資料庫開發1.資料庫設計

    一、E-R圖   實體:可以用我們已知的“物件”去理解,若干個具有共同特性的的實體稱為”實體集”。符號:矩形。   屬性:它是一個數據,它的表現為某個實體的一個特徵,實體包含其作為“成員資料”。符號:橢圓形。   關係:實體有大有小,某些實體的存在是建立在另

    JDBC1——獲取數據庫連接

    name puts 數據庫驅動 靜態代碼塊 use root driver pri gui 主要講通過 DriverManager 連接 DriverManager 是驅動的管理類. 1). 可以通過重載的 getConnection() 方法獲取數據庫連接. 較為方便

    SQL Server進階T-SQL查詢和編程的背景

    .com src 編程 server 分享 bubuko 進階 分享圖片 img SQL Server進階(一)T-SQL查詢和編程的背景

    SQL Server進階表表達式

    ins upd 逗號 csdn 引用 ssd 優點 暫存 可讀性 概述   SQL Server支持四種類型的表表達式:派生表,公用表表達式,視圖和內聯表值函數。 派生表 派生表是一個查詢結果生成的表,類似於臨時表。 派生表可以簡化查詢,避免使用臨時表。相比手動生成

    SQL Server進階集合運算

    nbsp 分享圖片 src 函數 server -c 計算 lec 括號 概述 為什麽使用集合運算:   在集合運算中比聯接查詢和EXISTS/NOT EXISTS更方便。 並集運算(UNION) 並集:兩個集合的並集是一個包含集合A和B中所有元素的集合。

    SQL Server進階查詢

    解決方案 查詢 小結 練習 數據 分組 函數 sql 方案 開窗函數 透視數據 逆透視數據 分組集 小結 練習 解決方案SQL Server進階(八)查詢

    SQL Server On Linux3——SQL Server 2019 For Linux 下載並部署示例資料庫

      接上文SQL Server On Linux(2)——SQL Server 2019 For Linux安裝過程細節研究 正所謂工欲善其事必先利其器,讀者可能也跟作者一樣很迫切希望瞭解和嘗試SQL Server On Linux及SQL 2019的各種新特性,不過為了走得

    SQL Server On Linux2——SQL Server 2019 For Linux安裝過程細節研究

      接上文SQL Server On Linux(1)——CentOS 7 安裝SQL Server2019 在安裝過程中,作者發現了一些資訊,這些資訊引起了作者的興趣,那麼下面作者把自己研究的結果分享出來,如果讀者對此有深入研究過,歡迎指正。 為什麼要研究這些東西?說白了就

    微信開發學習總結——素材管理1獲取臨時素材和新增永久素材

    這裡需要說一下圖片,語音,視訊的回覆訊息構造,這三種訊息構造時的都需要一個mediaId,而這個mediaId是通過素材管理介面上傳多媒體檔案得到的,為了構造圖片,語音,視訊的這幾種回覆訊息,我事先準備好了測試素材,如下圖所示: 客服介面圖文推送上傳圖片 在傳送圖文訊息時,我們需要新

    Oracle的索引分裂和索引維護

    索引不是建好了就行了?難道還需要維護?帶著這個問題,開啟本篇部落格。 我們知道索引的資料結構是B樹,每次更新資料都會對索引進行更新,所以如果是一張訂單表,看起來這張表會一直在增長,並且訂單表會經受一定的高併發考驗(比如各種大促活動,秒殺活動)。對於開發人員來說,好像只對表操作就可以了,不

    SQL Server全文搜尋轉載

    看這篇文章之前請先看一下下面我摘抄的全文搜尋的MSDN資料,基本上MSDN上關於全文搜尋的資料的我都copy下來了並且非常認真地閱讀和試驗了一次,並且補充了一些SQL語句,這篇文章本人抽取了一些本人自認為是重點的出來並且加入了一些自己的內容,補充MSDN上沒有的和整理了網上關於全文搜尋的資料至於全文搜尋的效能

    SQL Server視訊總結

    引言:SQL Server視訊的第四章是針對表(tabel)的管理,所以這章的重要性不言而喻,話不多說,我們開始總結 第四章 資料表管理 一、.欄位的資料型別 -數字資料型別 1.整數資料型別 (bigint、-int、smallin

    SQL Server視訊總結

    引言:相對第四章的比較細化、針對物件較單一的知識點,第五章的內容對於資料庫來說,則較為巨集觀:索引、檢視和架構。 第五章 操作架構、索引和檢視 一、建立檢視 方法1: CREATE VIEW view_name(view_column_name) AS

    python程式1獲取一個網頁的所有中文字元

    所有的中文字元都是在html的各種標籤之中,因此我們需要拿到html的整個檔案。為此我們匯入requests庫,再者,我們需要去除標籤將全部內容進行文字化,此處是中英文都有的文字,為此我們引入beautifulsoup,因為get_text方法使得我們可以獲取所