日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 运维知识 > 数据库 >内容正文

数据库

SQL Server 查询性能优化——创建索引原则(一)

發(fā)布時(shí)間:2023/12/2 数据库 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 SQL Server 查询性能优化——创建索引原则(一) 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

?

???? 索引是什么?索引是提高查詢性能的一個(gè)重要工具,索引就是把查詢語(yǔ)句所需要的少量數(shù)據(jù)添加到索引分頁(yè)中,這樣訪問(wèn)數(shù)據(jù)時(shí)只要訪問(wèn)少數(shù)索引的分頁(yè)就可以。但是索引對(duì)于提高查詢性能也不是萬(wàn)能的,也不是建立越多的索引就越好。索引建少了,用WHERE子句找數(shù)據(jù)效率低,不利于查找數(shù)據(jù)。索引建多了,不利于新增、修改和刪除等操作,因?yàn)樽鲞@些操作時(shí),SQL?SERVER除了要更新數(shù)據(jù)表本身,還要連帶地立即更新所有的相關(guān)索引,而且過(guò)多的索引也會(huì)浪費(fèi)硬盤空間。因此要建得恰到好處,這就需要經(jīng)驗(yàn)了。

?

一:索引的基本目的

???? 索引的基本目的是在大量數(shù)據(jù)中找尋少量數(shù)據(jù)。你可以想像一下,若一本書有700頁(yè),就像數(shù)據(jù)表有700個(gè)數(shù)據(jù)頁(yè),而索引卻有600個(gè)索引頁(yè),你會(huì)想用索引來(lái)查詢書籍的內(nèi)容嗎?

???? 索引字段的值重復(fù)性越低越好,假設(shè)書籍中如“的”“了”這些在文章中重復(fù)性極高的字,每頁(yè)都有一大堆,你會(huì)先翻索引頁(yè)某個(gè)位置有“的”,翻回該頁(yè)讀取了“的”之后,再索引看下一個(gè)“的”,結(jié)果是在先前同一頁(yè)的不同位置,又翻回書籍原頁(yè)查看下一個(gè)“的”。

???? 那么怎么理解索引是從大量數(shù)據(jù)中尋找少量數(shù)據(jù)呢?下面我們舉個(gè)例子來(lái)說(shuō)明。

???? 如果一個(gè)數(shù)據(jù)表的記錄平均長(zhǎng)度為400字節(jié),則100萬(wàn)條記錄需要5萬(wàn)個(gè)數(shù)據(jù)頁(yè),其計(jì)算公式如下:

  1000000/8060/400=50000

  如果該數(shù)據(jù)表建立聚集索引,鍵值為4個(gè)字節(jié)長(zhǎng)度,而ID的數(shù)據(jù)長(zhǎng)度為13個(gè)字節(jié),因此索引結(jié)構(gòu)每條記錄為20個(gè)字節(jié)。

  4(聚集索引鍵值)+13ID鍵值)+3(管理信息)=20

  以ID字段所建立的索引,100%填充率,則總分頁(yè)數(shù)約為2482頁(yè),其計(jì)算方式如下:

  1000000/(8060/20)

  即使是使用80%的填充率來(lái)計(jì)算也只有3106頁(yè)。其計(jì)算方式如下:

  1000000/((8060*0.8)/20)

  從上面可以看出如果是第一種情況,則索引頁(yè)只占到總數(shù)據(jù)頁(yè)的5%:

  2482/50000=0.04964?

  即使考慮取每頁(yè)只填充80%的索引數(shù)據(jù),第二種情況,索引頁(yè)也只是占總數(shù)據(jù)頁(yè)的6%:

  3106/50000=0.06212?

  再說(shuō)如果查詢條件中的字段建立索引,則由于索引鍵值數(shù)據(jù)都是以B-Tree有順序的擺放,所以可采用二分查找找數(shù)據(jù)。也就是2N次方大于記錄數(shù),就可以找到該條數(shù)據(jù)。而220次方大于100萬(wàn),因此最多找尋20次就可以找到該條記錄。由于比較次數(shù)少,數(shù)據(jù)結(jié)構(gòu)也小,節(jié)省訪問(wèn)硬盤與內(nèi)在的資源,索引將大幅提升找尋數(shù)據(jù)的效率。SQL?SERVER為提高訪問(wèn)與查找對(duì)比的效率,用來(lái)作索引的數(shù)據(jù)域鍵值愈小愈好,也就是要讓分頁(yè)盡量存更多的鍵值記錄。

?

?注:

  如果未使用?UNIQUE?屬性創(chuàng)建聚集索引,數(shù)據(jù)庫(kù)引擎將向表自動(dòng)添加一個(gè)?4?字節(jié)的?uniqueifier?列。必要時(shí),數(shù)據(jù)庫(kù)引擎將向行自動(dòng)添加一個(gè)?uniqueifier?值以使每個(gè)鍵唯一。此列和列值供內(nèi)部使用,用戶不能查看或訪問(wèn)。

?

?

二:什么是索引

  在?SQL?Server?中,索引是按?B?樹結(jié)構(gòu)進(jìn)行組織的。如下圖。

?????????   

?

  您也可以把索引理解為一種特殊的目錄。微軟的SQL?SERVER提供了兩種索引:聚集索引(clustered?index,也稱聚類索引、簇集索引)和非聚集索引(nonclustered?index,也稱非聚類索引、非簇集索引)。下面,舉例來(lái)說(shuō)明一下聚集索引和非聚集索引的區(qū)別:

  其實(shí),新華字典的正文本身就是一個(gè)聚集索引。比如,我們要查按”字,就會(huì)很自然地翻開字典的前幾頁(yè),因?yàn)?/span>按”的拼音是“an”,而按照拼音排序的新華字典是以英文字母“a”開頭并以“z”結(jié)尾的,那么按”字就自然地排在字典的前部。如果您翻完了所有以“a”開頭的部分仍然找不到這個(gè)字,那么就說(shuō)明新華字典中沒(méi)有這個(gè)字;同樣的,如果查招”字,那也會(huì)將新華字典翻到最后部分,因?yàn)?span style="font-family:'Times New Roman';">“招”的拼音是“zhao。也就是說(shuō),新華字典的正文部分本身就是一個(gè)目錄,您不需要再去查其他目錄來(lái)找到您需要找的內(nèi)容。我們把這種正文內(nèi)容本身就是一種按照一定規(guī)則排列的目錄稱為聚集索引

  如果您碰到一個(gè)不認(rèn)識(shí)的字,不知道它的發(fā)音,這時(shí)候,您就不能按照剛才的方法找到您要查的字,而需要去根據(jù)偏旁部首查到您要找的字,然后根據(jù)這個(gè)字后的頁(yè)碼直接翻到某頁(yè)來(lái)找到您要找的字。但您結(jié)合部首目錄檢字表而查到的字的排序并不是真正的正文的排序方法,比如您查字,我們可以看到在查部首之后的檢字表中的頁(yè)碼是672頁(yè),檢字表中的上面是字,但頁(yè)碼卻是63?頁(yè),的下面是字,頁(yè)面是390頁(yè)。很顯然,這些字并不是真正的分別位于字的上下方,現(xiàn)在您看到的連續(xù)的馳、張、弩三字實(shí)際上就是他們?cè)诜蔷奂饕械呐判?#xff0c;是字典正文中的字在非聚集索引中的映射。我們可以通過(guò)這種方式來(lái)找到您所需要的字,但它需要兩個(gè)過(guò)程,先找到目錄中的結(jié)果,然后?再翻到您所需要的頁(yè)碼。我們把這種目錄純粹是目錄,正文純粹是正文的排序方式稱為非聚集索引

?

通過(guò)以上例子,我們可以理解到什么是聚集索引非聚集索引。進(jìn)一步引申一下

?

聚集索引

  聚集索引指的是數(shù)據(jù)表本身就是索引的一部分,就是指數(shù)據(jù)表本身就是聚集索引的子葉層,整個(gè)數(shù)據(jù)表的擺放順序是按照你選定的鍵值由小到大排序,SQL?SERVER??2000?之后的版本可指定數(shù)據(jù)由大到小排序。

  整個(gè)數(shù)據(jù)表按照鍵值字段由小到大排序,再搭配由鍵值字段加上指針的上層索引結(jié)構(gòu),也就是根節(jié)點(diǎn)和非子葉層級(jí),形成整個(gè)聚集索引。因?yàn)閿?shù)據(jù)表內(nèi)實(shí)際擺放數(shù)據(jù)的方式只能遵循一種順序,所以一個(gè)數(shù)據(jù)表只能有一個(gè)聚集索引。在指定聚集索引時(shí),數(shù)據(jù)域本身并不需要唯一,或指定為唯一的聚集索引,SQL?SERVER內(nèi)部會(huì)自動(dòng)為重復(fù)的鍵值建立4個(gè)字節(jié)的唯一標(biāo)識(shí)。

  如果你的數(shù)據(jù)表有一列常常用來(lái)排序,另一列常常用來(lái)?范圍查詢,還有一列重復(fù)性非常高,則該用哪一列來(lái)做聚集索引。正確答案是依據(jù)哪個(gè)查詢最重要,最常被用戶執(zhí)行。例如:你的老板一小時(shí)內(nèi)多次執(zhí)行某個(gè)查詢當(dāng)然比一個(gè)月執(zhí)行一兩次的查詢來(lái)得重要。

  表(堆)創(chuàng)建聚集索引或刪除和重新創(chuàng)建現(xiàn)有聚集索引時(shí),要求數(shù)據(jù)庫(kù)具有額外的可用工作區(qū)來(lái)容納數(shù)據(jù)排序結(jié)果和原始表或現(xiàn)有聚集索引數(shù)據(jù)的臨時(shí)副本。

  當(dāng)堆或聚集表具有多個(gè)分區(qū)時(shí),每個(gè)分區(qū)都有一個(gè)堆或?B?樹結(jié)構(gòu),其中包含該指定分區(qū)的行組。例如,如果一個(gè)聚集表有?4?個(gè)分區(qū),那么將有?4?個(gè)?B?樹,每個(gè)分區(qū)一個(gè)。

?

  聚集索引(?Clustered?Index

  ·????????聚集索引的葉節(jié)點(diǎn)就是實(shí)際的數(shù)據(jù)頁(yè)

  ·????????在數(shù)據(jù)頁(yè)中數(shù)據(jù)按照索引順序存儲(chǔ)

  ·????????行的物理位置和行在索引中的位置是相同的

  ·????????每個(gè)表只能有一個(gè)聚集索引

  ·????????聚集索引的平均大小大約為表大小的?5%左右

?

  要使用索引來(lái)更有效地排序查詢數(shù)據(jù),最直接的方式就是在你要排序的字段上建立聚集索引。在建立聚集索引之后,SQL?SERVER會(huì)重新組織數(shù)據(jù)頁(yè),讓其中的數(shù)據(jù)行按照聚集索引中鍵值的順序存儲(chǔ)。SQL?SERVER不需要在硬盤上的數(shù)據(jù)一定要實(shí)際按照聚集索引排序,但在建立聚集索引時(shí),會(huì)嘗試在邏輯上排序數(shù)據(jù)的同時(shí),也會(huì)在物理上讓數(shù)據(jù)盡可能地排序。在索引子葉層級(jí)中的每個(gè)數(shù)據(jù)頁(yè)都有一個(gè)指針指向索引分頁(yè)的前一頁(yè)與后一頁(yè),形成雙向鏈接串行,在內(nèi)部的系統(tǒng)數(shù)據(jù)表包含了各索引子葉層第一個(gè)分頁(yè)的地址,為了保證數(shù)據(jù)在邏輯上是依照聚集索引的順序存放的,SQL?SERVER?只需要由第一個(gè)分頁(yè)開始,并依照其連接串行一個(gè)接著一個(gè)依序?qū)ふ覕?shù)據(jù)即可。如下圖。

?

????????

?

注:聚集表是有聚集索引的表。

?

?

非聚集索引

?  非聚集索引是完全獨(dú)立于數(shù)據(jù)表之外的結(jié)構(gòu),所以不會(huì)影響數(shù)據(jù)行的順序,其子葉層包含索引行。每個(gè)索引行包含非聚集鍵值、行定位符和任意包含列或非鍵列。行定位符中存入的數(shù)據(jù)有兩種類型:書簽(BOOKMARK)或聚集索引的鍵值。如果數(shù)據(jù)表上建立了聚集索引,則行定位符中存入的數(shù)據(jù)就是聚集索引的鍵值。如果數(shù)據(jù)表沒(méi)有建立聚集索引,則行定位符中存入的數(shù)據(jù)就是書簽,即指向數(shù)據(jù)表中記錄具體位置的ROWID,也就是文檔編號(hào)、分頁(yè)編號(hào)與頁(yè)內(nèi)記錄編號(hào)(稱之為SOLT編號(hào))所組合成的值。通過(guò)該ROWID?在數(shù)據(jù)表內(nèi)獲取數(shù)據(jù)就稱為書簽查找?BOOKMARK?LOOKUP。所以,一般通過(guò)非聚集索引查找到符合的鍵值后,還會(huì)搭配書簽查找。

  當(dāng)非聚集索引從結(jié)構(gòu)中找到符合的記錄時(shí),雖然在子葉層該鍵值是由小到大排序,因此可能在一個(gè)分頁(yè)上就有全部符合查詢條件的鍵值,但因?yàn)閿?shù)據(jù)表中數(shù)據(jù)行的擺放是沒(méi)有按順序的(或是說(shuō)沒(méi)有按照該非聚集索引的鍵值順序擺放),所以真正符合記錄的數(shù)據(jù)是散布在文檔各處的,而SQL?SERVER每次讀取數(shù)據(jù)都是以數(shù)據(jù)頁(yè)為單位,因此,找到一條記錄所在位置后,要先將存放該條記錄的分頁(yè)讀到內(nèi)存中,再?gòu)脑擁?yè)讀出記錄。

  因?yàn)?span style="font-size:16px;">BOOKMARK?LOOKUP是進(jìn)行隨機(jī)的I/O操作,當(dāng)符合查詢的記錄很多時(shí),通過(guò)非聚集索引訪問(wèn)將導(dǎo)致數(shù)據(jù)頁(yè)讀取非常頻繁,就算兩條記錄在同一個(gè)分頁(yè),該分頁(yè)也會(huì)被重復(fù)讀兩次,因此或符合的記錄有N條,就需要讀取數(shù)據(jù)表內(nèi)的分頁(yè)N頁(yè),雖然大部分的讀取操作都是針對(duì)內(nèi)存中的高速緩存,但記錄數(shù)過(guò)多時(shí)一樣沒(méi)有效率,還不如數(shù)據(jù)表掃描,全部掃描一遍,把符合條件數(shù)據(jù)找出來(lái)。

  雖然?SQL?2005?以后的版本中已經(jīng)不在提 BOOKMARK?LOOKUP(但實(shí)際上卻是換湯不換藥),我們的很多搜索都是使用如下的搜索過(guò)程:先在非聚集中找,然后再在聚集索引中找。如下圖。

????????

?

?

  非聚集索引?(?Unclustered?Index??

  ·????????非聚集索引的頁(yè),不是數(shù)據(jù),而是指向數(shù)據(jù)頁(yè)的頁(yè)。

  ·????????若未指定索引類型,則默認(rèn)為非聚集索引

  ·????????葉節(jié)點(diǎn)頁(yè)的次序和表的物理存儲(chǔ)次序不同

  ·????????每個(gè)表最多可以有?249個(gè)非聚集索引(一般認(rèn)為每個(gè)表不應(yīng)該超過(guò)10個(gè)索引)

  ·????????在非聚集索引創(chuàng)建之前創(chuàng)建聚集索引(否則會(huì)引發(fā)索引重建)

?

  聚集索引與非聚集索引使用的情況:

?動(dòng)作描述

使用聚集索引?

?使用非聚集索引

?外鍵列

?應(yīng)

?應(yīng)

?主鍵列

?應(yīng)

?應(yīng)

?列經(jīng)常被分組排序(order?by)

?應(yīng)

?應(yīng)

?返回某范圍內(nèi)的數(shù)據(jù)

?應(yīng)

?不應(yīng)

?小數(shù)目的不同值

?應(yīng)

?不應(yīng)

?大數(shù)目的不同值

?不應(yīng)

?應(yīng)

?頻繁更新的列

?不應(yīng)?

?應(yīng)

?頻繁修改索引列

?不應(yīng)

?應(yīng)

?一個(gè)或極少不同值

?不應(yīng)

?不應(yīng)

?

  今天就普及一下索引的一些基本知識(shí),明天來(lái)說(shuō)明怎么選擇要?jiǎng)?chuàng)建索引的列,條件是什么,方法是什么。

轉(zhuǎn)載于:https://www.cnblogs.com/chillsrc/archive/2012/09/19/2694313.html

總結(jié)

以上是生活随笔為你收集整理的SQL Server 查询性能优化——创建索引原则(一)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。