SQL Server索引的具體使用標(biāo)準(zhǔn)描述
以下的文章主要向大家講述的是SQL Server索引的具體使用標(biāo)準(zhǔn)(Index Usage Criteria),我們大家都知道在實(shí)際操作中我們?yōu)榱擞行У貨Q定應(yīng)該創(chuàng)建哪些合適的SQL Server索引,你必須決定這些索引實(shí)際中是否被SQL Server使用過(guò)。
如果一個(gè)索引不能被有效使用,在修改數(shù)據(jù)時(shí),那只會(huì)浪費(fèi)空間和增加不必要的負(fù)擔(dān)。
需要記住的主要標(biāo)準(zhǔn)是:如果至少是索引的第一列沒有被包含在一個(gè)有效的搜索參數(shù)(search argument SARG)或join子句中,那么SQL Server 就不會(huì)使用索引進(jìn)行更有效地書簽查找(bookmark lookup)。
為創(chuàng)建復(fù)合索引,選擇列的順序時(shí)牢記住這一點(diǎn),想想下面的在store表中的索引:
- Create index nc1_stores on stores (city, state, zip)
下面的每一個(gè)查詢將會(huì)用到索引,因?yàn)樗鼈儼薙QL Server索引的第一列city,其為一個(gè)SARG:
- Sql代碼
- select stor_name from stores
- where city = 'Frederick'
- and state = 'MD'
- and zip = '21702'
- select stor_name from stores
- where city = 'Frederick'
- and state = 'MD'
- and zip = '21702'
- Sql代碼
- select stor_name from stores
- where city = 'Frederick'
- and state = 'MD'
- select stor_name from stores
- where city = 'Frederick'
- and state = 'MD'
- Sql代碼
- select stor_name from stores
- where city = 'Frederick'
- and zip = '21702'
- select stor_name from stores
- where city = 'Frederick'
- and zip = '21702'
然而,下面的查詢不會(huì)用到索引而進(jìn)行書簽查找,因?yàn)樗鼈儧]指定city列為一個(gè)SARG:
- Sql代碼
- select stor_name from stores
- where state = 'MD'
- and zip = '21702'
- select stor_name from stores
- where state = 'MD'
- and zip = '21702'
- Sql代碼
- select stor_name from stores
- where zip = '21702'
- select stor_name from stores
- where zip = '21702'
對(duì)于前面提到的最后兩個(gè)查詢,如果你顯示執(zhí)行計(jì)劃(execution plan)信息,你可能發(fā)現(xiàn),查詢實(shí)際上使用了nc1_store索引來(lái)檢索了結(jié)果集(resultset)。如果再仔細(xì)看,你會(huì)發(fā)現(xiàn)查詢沒有使用索引最有效地方式——它使用了索引掃描(index scan),而不是索引查找(index seek)。
有關(guān)查詢存取方法(query aceess method)的更多信息,可參見第35章“Understanding Query Optimization”,在該章中將講述索引查找。
在索引查找(Index seek)中,SQL Server 沿著索引樹(index tree)從根級(jí)(root level)向下進(jìn)行SQL Server索引鍵值匹配搜索,直到搜索到指定的行,然后使用存儲(chǔ)在索引鍵值中的書簽值(bookmark value)直接從數(shù)據(jù)頁(yè)中檢索匹配的數(shù)據(jù)行(這個(gè)書簽值可以是行標(biāo)識(shí)符(RID),或者聚集索引的鍵值)。
對(duì)一個(gè)索引掃描(Index scan),SQL Server搜索索引樹中所有葉級(jí)(leaf level)中的行來(lái)進(jìn)行可能匹配的查找。如果發(fā)現(xiàn)滿足匹配的行,然后利用書簽檢索數(shù)據(jù)行。
盡管兩者都使用了索引,從I/O代價(jià)角度來(lái)講,索引掃描比索引查找的代價(jià)要高,但比表掃描(Table scan)要略微要小些。
然而,本章學(xué)習(xí)設(shè)計(jì)索引的目的是為了使用索引查找,所以當(dāng)我談到使用索引時(shí),指的是索引查找。
為了得到可能列的書簽查詢,你可能想到的一個(gè)容易的方法是在表中所有列上都創(chuàng)建索引,這樣任何類型的查詢都可以使用索引了。這種策略可能在某些支持ad hoc queries(隨意的查詢)的只讀的DSS(決策支持系統(tǒng))環(huán)境下是合適的,但是這樣也存在問(wèn)題,因?yàn)槿匀粫?huì)造成有許多索引不被使用。
正如你在本章的Index selection節(jié)看到的,不會(huì)僅僅因?yàn)樵谀沉袆?chuàng)建了索引,優(yōu)化器就總會(huì)使用該列的SQL Server索引,例如,當(dāng)該列的選擇性不夠時(shí)(not selective enough),就不會(huì)使用該列的索引。另外,在一張大表(large table)上創(chuàng)建太多索引會(huì)占據(jù)數(shù)據(jù)庫(kù)中的大量空間,增加了備份的要求時(shí)間。
前面也提到過(guò),在一個(gè)OLTP(在線聯(lián)機(jī)處理)系統(tǒng)上,太多的索引會(huì)給數(shù)據(jù)的插入、修改、刪除操作帶來(lái)大量的額外負(fù)擔(dān),造成性能上的不利影響。
引用
建議:(每張表4-5個(gè)索引)
我曾經(jīng)常犯的一個(gè)設(shè)計(jì)錯(cuò)誤是在OLTP環(huán)境下定義了太多的索引。許多情況下,有些索引是冗余的或者是優(yōu)化器在處理查詢時(shí)就根本沒有考慮。結(jié)果,這些索引導(dǎo)致空間的浪費(fèi)和增加了修改數(shù)據(jù)時(shí)的不必要負(fù)擔(dān)。
在這一點(diǎn)上有一個(gè)案例,有個(gè)客戶在一個(gè)表上創(chuàng)建了8個(gè)索引,其中4個(gè)SQL Server索引都是在同一列上,該列的鍵值唯一(unique key),在索引中該列都是第一個(gè)索引列。對(duì)表的查詢和修改操作,該列都包含在where 子句中。
結(jié)果只有4個(gè)的其中1個(gè)索引曾被用到過(guò)。
希望在本章結(jié)束后,你將會(huì)理解為什么所有這些SQL Server索引不是必須的,并且能重新認(rèn)識(shí)和決定在哪些列上創(chuàng)建索引將會(huì)收益,而哪些列上應(yīng)避免創(chuàng)建索引。
【編輯推薦】
- SQL Server創(chuàng)建表所要用到的代碼
- 創(chuàng)建SQL Server數(shù)據(jù)庫(kù)更是實(shí)在
- 優(yōu)化SQL Server數(shù)據(jù)庫(kù)的經(jīng)驗(yàn)大盤點(diǎn)
- SQL Server 2005商業(yè)智能功能淺析
- 實(shí)現(xiàn)SQL Server數(shù)據(jù)備份可用觸發(fā)器