SQL Server中SCAN 和SEEK的区别
SQL Server中SCAN 和SEEK的區(qū)別
SQL SERVER使用掃描(scan)和查找(seek)這兩種算法從數(shù)據(jù)表和索引中讀取數(shù)據(jù)。這兩種算法構(gòu)成了查詢的基礎(chǔ),幾乎無(wú)處不在。Scan會(huì)掃描并且返回整個(gè)表或整個(gè)索引。 而seek則更有效率,根據(jù)謂詞(predicate),只返索引內(nèi)的一個(gè)或多個(gè)范圍內(nèi)的數(shù)據(jù)。下面將以如下的查詢語(yǔ)句作為例子來(lái)分析scan和seek:
select OrderDate from Orders where OrderKey = 2Scan
使用Scan的方式,SQL Server 會(huì)去讀取Orders表中的每一行數(shù)據(jù),讀取的時(shí)候評(píng)估是否滿足謂詞 “where order=2”。如果滿足(數(shù)據(jù)行符合條件),則返回該行。這個(gè)例子里,我們將這個(gè)謂詞稱作“residual predicate”。為了得到最優(yōu)的性能,SQL會(huì)盡可能地在掃描中使用“residual predicate”。但如果residual predicate的開銷過(guò)于昂貴,SQL Server可能會(huì)使用單獨(dú)的“filter iterator”. “residual predicate”以where關(guān)鍵字的形式出現(xiàn)在文本格式的plan中。對(duì)XML格式的plan,則是<predicate>標(biāo)記的形式。
下面這個(gè)掃描的文本格式的plan的結(jié)果:
? |–Table Scan(OBJECT:([ORDERS]), WHERE:([ORDERKEY]=(2)))
下圖說(shuō)明了掃描的方式:
無(wú)論數(shù)據(jù)行是否滿足條件,掃描的讀取方式都會(huì)訪問(wèn)表中的每一個(gè)數(shù)據(jù),所以scan的成本和表的數(shù)據(jù)總量是成比例的。 因此,如果表很小或者表內(nèi)的大多數(shù)數(shù)據(jù)多滿足謂詞,scan是一種有效率的讀取方式。然而如果表很大或者絕大多數(shù)的數(shù)據(jù)并不滿足謂詞, 那么這種方式會(huì)讓我們?cè)L問(wèn)到太多不需要的數(shù)據(jù)頁(yè)面,并執(zhí)行更多的額外的IO操作。
Seek
繼續(xù)以上面的查詢?yōu)槔?#xff0c;如果在orderkey列上有一個(gè)索引,那么seek可能會(huì)是一個(gè)好的選擇。使用seek的訪問(wèn)方式,SQL Server會(huì)使用索引直接導(dǎo)向到滿足謂詞條件的數(shù)據(jù)行。 這個(gè)例子里,我們將這個(gè)謂詞稱為“seek predicate”。 大多數(shù)情況下,SQL Server不必將“seek predicate”重新評(píng)估為“residual predicate”。 索引會(huì)保證“seek”只返回符合條件的數(shù)據(jù)行。“seek predicate”以seek關(guān)鍵字的形式出現(xiàn)在文本格式的plan中。 對(duì)于xml 格式的plan,則以<seekpredicates>標(biāo)記出現(xiàn)。
下面是使用seek的文本格式的plan的結(jié)果:
|–Index Seek(OBJECT:([ORDERS].[OKEY_IDX]), SEEK:([ORDERKEY]=(2)) ORDERED FORWARD)
使用seek時(shí),SQL Server只會(huì)直接訪問(wèn)到滿足條件的數(shù)據(jù)行和數(shù)據(jù)頁(yè),因此它的成本只跟滿足條件的數(shù)據(jù)行的及其相應(yīng)的數(shù)據(jù)頁(yè)面數(shù)量成比例,?和基表的數(shù)據(jù)量完全沒(méi)有關(guān)系。因此,如果對(duì)于一個(gè)選擇性很高(通過(guò)這個(gè)謂詞,可以篩選掉表中的大部分?jǐn)?shù)據(jù))的謂詞條件,seek是非常高效的。
下面的表格列出了seek和scan這兩種查找方式和堆表,聚簇索引和非聚簇索引的各種組合:
| ? ? ? ? | Scan | Seek |
| Heap | Table Scan | ? |
| Clustered Index | Clustered Index Scan | Clustered Index Seek |
| Non-Clustered Index | Index Scan | Index Seek |
?
?
index seek與index scan
低效 Index Scan(索引掃描):就全掃描索引(包括根頁(yè),中間頁(yè)和葉級(jí)頁(yè)):?
高效
Index Seek(索引查找):通過(guò)索引向前和向后搜索 :
?
?解釋解釋index?seek和index?scan:?索引是一顆B樹, index?seek是查找從B樹的根節(jié)點(diǎn)開始,一級(jí)一級(jí)找到目標(biāo)行。 index?scan則是從左到右,把整個(gè)B樹遍歷一遍。 假設(shè)唯一的目標(biāo)行位于索引樹最右的葉節(jié)點(diǎn)上(假設(shè)是非聚集索引,樹深度2,葉節(jié)點(diǎn)占用k頁(yè)物理存儲(chǔ))。 index?seek引起的IO是4,而index?scan引起的IO是K,性能差別巨大。
seek:從B樹根到葉節(jié)點(diǎn)的過(guò)程 掃描:當(dāng)SEEK完成后,在葉節(jié)點(diǎn)執(zhí)行范圍或全部掃描(按查詢的選擇性會(huì)有不同
關(guān)于索引,可以仔細(xì)讀讀聯(lián)機(jī)文檔關(guān)于物理數(shù)據(jù)庫(kù)體系結(jié)構(gòu)部分 ???? 查詢條件中不要包含運(yùn)算
這些運(yùn)算包括字符串連接(如:select * from Users where UserName + ‘pig’ = ‘張三pig’),通配符在前面的Like運(yùn)算(如:select * from tb1 where col4 like ‘�’),使用其他用戶自定義函數(shù)、系統(tǒng)內(nèi)置函數(shù)、標(biāo)量函數(shù)等等(如:select * from UserLog where datepart(dd, LogTime) = 3)。
???????? SQLServer在處理以上語(yǔ)句時(shí),一樣沒(méi)辦法估算開銷。最終結(jié)果當(dāng)然是clustered index?scan或者table?scan了。
??? 查詢條件中不要包含同一張表內(nèi)不同列之間的運(yùn)算所謂的“運(yùn)算”包括加減乘除或通過(guò)一些function(如:select * from tb where col1 – col2 = 1997),也包括比較運(yùn)算(如:select * from tb where col1 > col2)。這種情況下,SQLServer一樣沒(méi)辦法估算開銷。不論col1、col2上都有索引還是創(chuàng)建了col1、col2上的覆蓋索引還是創(chuàng)建了col1 include col2的索引。
但是這種查詢有解決辦法,可以在表上多創(chuàng)建一個(gè)計(jì)算字段,其值設(shè)置為你的“運(yùn)算”結(jié)果,再在該字段上創(chuàng)建一個(gè)索引,就Ok了。
(結(jié)果集/總行數(shù))被稱為選擇性,比值越大,選擇性就越高。
你得到了它,本文的重點(diǎn)就是選擇性。
統(tǒng)計(jì)信息,說(shuō)白了,就是表中某個(gè)字段取某個(gè)值時(shí)有多少行結(jié)果集。統(tǒng)計(jì)信息可以說(shuō)是一種選擇性的度量,SQLServer就是根據(jù)它來(lái)估算不同查詢計(jì)劃的優(yōu)劣。若表中總行數(shù)為1w,采樣行數(shù)為1w。provider_no值為21的只有1行,而值為500的行則有4824行。
?
我們知道,SQLServer會(huì)緩存查詢計(jì)劃,假如有這么一個(gè)存儲(chǔ)過(guò)程:
create proc myproc
(
??? @pno int
)
as
select * from charge where provider_no = @pno
第一次我們傳進(jìn)來(lái)一個(gè)21,OK,它會(huì)緩存該存儲(chǔ)過(guò)程的執(zhí)行計(jì)劃為nonclustered index?seek那個(gè)。后來(lái)我們又傳進(jìn)來(lái)一個(gè)500,完蛋了,服務(wù)器發(fā)現(xiàn)它有一個(gè)myproc的緩存,so,又通過(guò)nonclustered index?seek執(zhí)行,接著你的同伙看到你的查詢花費(fèi)了巨量的IO,于是,你被鄙視了。
這說(shuō)明了啥?說(shuō)明如果你的查詢選擇性變動(dòng)劇烈,你應(yīng)該告訴SQLServer不要緩存查詢計(jì)劃,每次都應(yīng)該重新評(píng)估、編譯。實(shí)現(xiàn)方法很簡(jiǎn)單,查詢的尾巴上加一個(gè)option(recompile)好了。而且SQL2k5還有一個(gè)nb的 feature,可以每次只重新編譯存儲(chǔ)過(guò)程的一部分(當(dāng)然,你也可以選擇重新編譯整個(gè)存儲(chǔ)過(guò)程,這取決于你的需求。詳見聯(lián)機(jī)文檔。)
?
轉(zhuǎn)載于:https://www.cnblogs.com/gered/p/8780177.html
總結(jié)
以上是生活随笔為你收集整理的SQL Server中SCAN 和SEEK的区别的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 为什么做梦老是梦到以前的老房子
- 下一篇: Mysql ---Sqlserver数据