<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    關(guān)于sql的執(zhí)行計(jì)劃(推薦詳細(xì))

    剛開始用SQL Server的時(shí)候,我沒有用顯示執(zhí)行計(jì)劃來對(duì)查詢進(jìn)行分析。我曾經(jīng)一直認(rèn)為我遞交的SQL查詢都是最優(yōu)的,而忽略了查詢性能究竟如何,從而對(duì)“執(zhí)行計(jì)劃”重視不夠。在我職業(yè)初期,我只要能獲取數(shù)據(jù)就很開心,而不去考慮數(shù)據(jù)是如何返回的,“執(zhí)行計(jì)劃”對(duì)我的查詢作了什么工作。我以為SQL Server會(huì)自己去處理查詢的性能問題的。作為一個(gè)剛進(jìn)入IT行業(yè)或者剛學(xué)到新技術(shù)的軟件工程師,在編寫代碼前不太可能有時(shí)間去學(xué)習(xí)其實(shí)必須掌握的知識(shí)。也許這是因?yàn)镮T行業(yè)競(jìng)爭(zhēng)太激烈的緣故。

    隨著時(shí)間的流逝,數(shù)據(jù)庫(kù)容量慢慢變大了。終于某天,客戶對(duì)應(yīng)用系統(tǒng)的查詢性能感到不滿意了。他面帶怒容來找我,抱怨由于查詢太慢,使得他需要花更多的時(shí)間來處理公務(wù)。最初,我建議客戶升級(jí)其系統(tǒng)資源,例如作為臨時(shí)解決方案,增加硬盤容量。雖然硬盤價(jià)格現(xiàn)在很便宜了,但是客戶還是要求我提供一個(gè)永久性的解決方案,檢查和好好調(diào)試查詢語句,來替代那種無休止地升級(jí)資源的臨時(shí)方案。因?yàn)榭蛻舻臐M意度對(duì)IT行業(yè)來說是十分重要的,因此我不得不考慮他的個(gè)人建議。我答應(yīng)他一定會(huì)檢查和調(diào)整我的代碼。


    如何入手呢?

    在剛進(jìn)入IT行業(yè)時(shí),我知道SQL Server的基礎(chǔ)只是。說實(shí)話,向客戶承諾檢查系統(tǒng)的時(shí)候,我還沒有一點(diǎn)入手的頭緒。不過我相信我可以通過GOOGL和BOL來獲取相應(yīng)的信息。

    我閱讀了一些關(guān)于SQL Server的書籍,BOL,以及在網(wǎng)上搜索的信息。于是我知道了“顯示執(zhí)行計(jì)劃”的概念。可以在查詢管理器中將該選項(xiàng)的開關(guān)設(shè)置為ON。“顯示執(zhí)行計(jì)劃”是一個(gè)圖形化工具,可以幫助開發(fā)者和DBA分析,優(yōu)化查詢,從而改善性能。

    “顯示執(zhí)行計(jì)劃”中不同的任務(wù)具有不同的圖標(biāo)。本文中我主要對(duì)“Table Scan”、“Index Scan”、“Index Seek”、“Cluster Index Scan”以及“Clustered Index Seek”感興趣。也許在以后,可以對(duì)別的任務(wù)進(jìn)行另外介紹。

    時(shí)間以F1方程式的速度開始流逝,我覺得該是我全面理解“Table Scan”、“Index Scan”、“Index Seek”、“Clustered Index Scan”、和“Clustered Index Seek”如何工作的時(shí)候了。

    我準(zhǔn)備開始分析并優(yōu)化我的查詢。在分析之前,我想到了一些問題。

    • MS-SQL Server什么時(shí)候使用"Table Scan"?
    • MS-SQL Server什么時(shí)候使用"Index Scan"?
    • MS-SQL Server什么時(shí)候使用"Index Seek"?
    • MS-SQL Server什么時(shí)候使用"Clustered Index Scan"?
    • MS-SQL Server什么時(shí)候使用"Clustered Index Seek"?

    ?

    我主要關(guān)注SQL Server是根據(jù)什么來使用“執(zhí)行計(jì)劃”分析查詢的。在經(jīng)過一段時(shí)間學(xué)習(xí)后,我了解了一些相關(guān)知識(shí)。這些知識(shí)應(yīng)該對(duì)開發(fā)和DBA新手有幫助。于是我決定寫這篇文章,共享我的知識(shí)以幫助別人來理解“執(zhí)行計(jì)劃”。

    如果你喜歡,可以慢慢讀完,也可以在SQL Server上,模擬我下面做的實(shí)驗(yàn)。


    開始入手

    為了解釋“顯示執(zhí)行計(jì)劃”中的“Table Scan”、“Index Scan”、“Index Seek”、“Clustered Index Scan”和“Clustered Index Seek”,先創(chuàng)建新表,并添加一些示例數(shù)據(jù)進(jìn)去。下面是創(chuàng)建新表的腳本:

    ?

    Create Table PerformanceIssue
    (
    ????PRID UniqueIdentifier NOT NULL,
    ????PRCode Int NOT NULL,
    ????PRDesc Varchar (100) NOT NULL
    )
    ON [PRIMARY]

    ?

    表創(chuàng)建后需要添加一些數(shù)據(jù)。使用下面的腳本添加100,000條記錄進(jìn)去。腳本執(zhí)行時(shí)間可能比較長(zhǎng),請(qǐng)耐心等待其執(zhí)行完畢。

    ?

    Declare @Loop Int
    Declare @PRID UniqueIdentifier
    Declare @ PRDesc Varchar (100)

    Set @Loop = 1
    Set @ PRDesc = ''

    WHILE @Loop <= 100000
    BEGIN
    ?? Set @PRID = NewID()
    ?? Set @PRDesc = ' PerformanceIssue - ' + Convert( Varchar(10),@Loop )
    ?? Insert Into PerformanceIssue Values (@PRID, @Loop, @PRDesc)
    ?? Set @Loop = @Loop + 1
    END

    ?

    腳本成功執(zhí)行后,數(shù)據(jù)就添加進(jìn)去了。

    用下面語句來看一下表的內(nèi)容:

    ?

    Select PRID, PRCode, PRDesc
    From PerformanceIssue
    GO

    ?

    由于記錄較長(zhǎng),因此這里就不列出查詢結(jié)果了。

    正如我前面講到,我想解釋何時(shí)會(huì)有“Table Scan”、“Index Scan”、“Index Seek”、“Clustered Index Scan”和“Clustered Index Seek”。上述哪個(gè)會(huì)改善性能呢?

    當(dāng)SQL Server返回?cái)?shù)據(jù)時(shí),我們想知道SQL Server采取何種掃描機(jī)制來協(xié)助獲取數(shù)據(jù)。首先看一下“Table Scan”。我們想了解什么時(shí)候“Table Scan”會(huì)產(chǎn)生。

    選擇“顯示執(zhí)行計(jì)劃”或者使用熱鍵“Alt + Q”來激活“顯示執(zhí)行計(jì)劃”,當(dāng)然也可以用快捷鍵“Ctrl+K”。

    看一下執(zhí)行下面查詢后的“執(zhí)行計(jì)劃”結(jié)果。

    ?

    Select PRID, PRCode, PRDesc
    From PerformanceIssue
    GO


    上面的“執(zhí)行計(jì)劃”中,SQL Server用到了“Table Scan”。我問自己為什么會(huì)有“Table Scan”,SQL Server是根據(jù)什么來使用該方法的。難道是因?yàn)槲蚁氆@取所有100,000條記錄嗎?于是我換了一個(gè)角度進(jìn)行思考,如果來避免查詢中出現(xiàn)“Table Scan”呢?此時(shí)我對(duì)SQL Server的掃描機(jī)制還不是很清楚,那么該如何優(yōu)化查詢呢?下面的SELECT查詢中僅選擇兩列:[PRID, PRCode]。

    ?

    Select PRID, PRCode
    From PerformanceIssue
    GO


    查詢執(zhí)行后,執(zhí)行計(jì)劃和第一個(gè)查詢一樣。于是將查詢改變?yōu)橹粰z索一個(gè)字段 [PRID]。

    ?

    Select PRID
    From PerformanceIssue

    GO


    查詢執(zhí)行后,執(zhí)行計(jì)劃仍然和第一個(gè)查詢的相同。對(duì)“Estimated row size”屬性不需要太大關(guān)注。意思我立刻決定只獲取一條記錄,看看執(zhí)行計(jì)劃會(huì)如何。查詢語句如下:

    ?

    Select PRID, PRCode, PRDesc
    From PerformanceIssue
    Where PRID = 'D386C151-5F74-4C2A-B527-86FEF9712955'
    -- PRID GUID value might be differ in your machine

    GO

    ?

    執(zhí)行完成后,執(zhí)行計(jì)劃顯示:

    查詢?nèi)匀皇褂昧恕癟able Scan”方法來顯示數(shù)據(jù)。

    那么,我需要想其它辦法來避免“Table Scan”。首先我想到應(yīng)該給表加上索引。于是我在PRID字段上創(chuàng)建非聚集索引。添加了索引后是否就能避免“Table Scan”?下面我們開始討論關(guān)于“Index Scan”和“Index Seek”的主題。


    Index Scan 和 Index Seek

    首先在PRID字段上創(chuàng)建非聚集索引。

    ?

    CREATE UNIQUE NONCLUSTERED INDEX UNC_PRID
    ON PerformanceIssue (PRID)
    GO

    ?

    本文假定讀者已經(jīng)知道非聚集索引如何工作的知識(shí)。了解非聚集索引更詳細(xì)的信息,請(qǐng)閱讀BOL相關(guān)主題,也可參看 http://www.sql-server-performance.com/gv_index_data_structures.asp。下面我們?cè)敿?xì)講述“Index Scan”是如何工作的。

    執(zhí)行下面語句并查看執(zhí)行計(jì)劃的結(jié)果。

    ?

    Select PRID, PRCode, PRDesc
    From PerformanceIssue
    GO


    奇怪了,“Table Scan”仍然用到了。為什么SQL Server沒有用到那個(gè)非聚集索引?于是繼續(xù)優(yōu)化查詢語句,選擇檢索兩個(gè)字段 [PRID, PRCode] 。

    ?

    Select PRID, PRCode From PerformanceIssue
    GO


    執(zhí)行結(jié)果是和上一個(gè)查詢結(jié)果一摸一樣。于是修改查詢?yōu)橹粰z索一個(gè)字段 [PRID] 。

    ?

    Select PRID
    From PerformanceIssue
    GO

    ?

    執(zhí)行計(jì)劃結(jié)果如下:

    “Index Scan”在查詢中被用到了,這很好。很自然,接下來的問題就是“Index Scan”什么時(shí)候會(huì)被用到。字段PRID上有一個(gè)索引,查詢語句中選中的字段為PRID。執(zhí)行查詢的時(shí)候,SQL Server掃描索引頁(yè),因此用到了“Index Scan”方法。前面的查詢中選擇了有索引的和沒有索引的字段,SQL Server無法使用“Index Scan”。當(dāng)查詢中只選擇有索引的字段時(shí),SQL Server就使用了“Index Scan”。我不清楚SQL Server底層到底是如何判斷的,不過通過這些試驗(yàn),我認(rèn)為當(dāng)查詢中只選擇有索引的字段時(shí),SQL Server就使用“Index Scan”方法

    下面看“Index Seek”方法何時(shí)產(chǎn)生。當(dāng)我看到“Seek”這個(gè)詞時(shí),第一反應(yīng)就是條件查詢這個(gè)主意。

    我嘗試三種不同的帶WHERE語法的查詢語句,以找出那種會(huì)用“Index Seek”。第一種語句如下:

    ?

    Select PRID, PRCode, PRDesc
    From PerformanceIssue
    Where PRCode = 8
    GO

    ?

    結(jié)果顯示,執(zhí)行計(jì)劃使用了“Table Scan”。

    第二種語句如下:

    ?

    Select PRID, PRCode, PRDesc
    From PerformanceIssue
    Where PRDesc = ' PerformanceIssue - 8'
    GO

    ?

    執(zhí)行計(jì)劃仍然使用“Table Scan”方法。

    第三種查詢語句如下:

    ?

    Select PRID, PRCode, PRDesc
    From PerformanceIssue
    Where PRID = 'D386C151-5F74-4C2A-B527-86FEF9712955'

    -- PRID GUID value might be differ in your machine
    GO



    查詢用到了“Index Seek”和“Bookmark Lookup”方法。用到“Index Seek”是因?yàn)閃HERE后面使用帶索引的字段PRID來進(jìn)行過濾。“Bookmark Lookup”方法被用到是因?yàn)椴樵冎羞x擇了沒有索引的字段。如果去掉這兩個(gè)沒有索引的字段,那么“Bookmark Lookup”方法就可以去掉。當(dāng)然如果只返回PRID字段,那么該查詢就沒什么意義了,因?yàn)閃HERE語句后面已經(jīng)給出PRID具體取值了。

    我認(rèn)為“Index Seek”在性能改善上比“Index Scan”和“Table Scan”要好,這主要表現(xiàn)在下面幾個(gè)方面:

    ?

    1. “Index Seek”不需要對(duì)表和索引頁(yè)進(jìn)行掃描;而“Table Scan”和“Index Scan”需要。
    2. “Index Seek”利用“WHERE”來過濾獲取的數(shù)據(jù),這樣比用“Index Scan”和“Table Scan”快很多。

    ?

    當(dāng)我完成這些測(cè)試后,我同事問我一個(gè)很有意思的問題:SQL Server什么時(shí)候使用“Clustered Index Scan”和“Clustered Index Seek”?下面對(duì)“Clustered Index Scan”和“Clustered Index Seek”進(jìn)行實(shí)驗(yàn)。

    我決定在PRCode上建一個(gè)聚集索引來測(cè)試“Clustered Index Scan”和“Clustered Index Seek”。


    Clustered Index Scan & Clustered Index Seek

    下面的腳本刪除PRID字段上的索引,并在PRCode字段上創(chuàng)建聚集索引。

    ?

    Drop Index PerformanceIssue.UNC_PRID
    GO
    CREATE UNIQUE CLUSTERED INDEX UC_PRCode
    ON PerformanceIssue( PRCode)
    GO
    -------------
    Clustered index has been created successfully.
    Index has been created.

    ?

    關(guān)于聚集索引的基礎(chǔ)知識(shí)請(qǐng)查閱聯(lián)機(jī)幫助的相關(guān)主題或者 http://www.sql-server-performance.com/gv_index_data_structures.asp。下面我們將重點(diǎn)放在“Clustered Index Scan”和“Clustered Index Seek”如何被使用上。

    執(zhí)行下面查詢語句:

    ?

    Select PRID, PRCode, PRDesc
    From PerformanceIssue
    GO

    ?

    查詢執(zhí)行后,可以看到執(zhí)行計(jì)劃中用到了“Clustered Index Scan”。

    下面用三種不同的WHERE方式來試驗(yàn)何時(shí)SQL Server會(huì)用到“Clustered Index Seek”。第一種形式如下:

    ?

    Select PRID, PRCode, PRDesc
    From PerformanceIssue
    Where PRDesc = ' PerformanceIssue - 8'
    GO

    ?

    查詢執(zhí)行后,可以看到執(zhí)行計(jì)劃中用到了“Clustered Index Scan”。

    第二種形式如下:

    ?

    Select PRID, PRCode, PRDesc
    From PerformanceIssue
    Where PRID = 'D386C151-5F74-4C2A-B527-86FEF9712955'

    -- PRID GUID value might be differ in your machine
    GO

    ?

    查詢執(zhí)行后,發(fā)現(xiàn)執(zhí)行計(jì)劃中用到的仍然是“Clustered Index Scan”。

    第三種形式:

    ?

    Select PRID, PRCode, PRDesc
    From PerformanceIssue
    Where PRCode = 8
    GO

    ?

    這次執(zhí)行計(jì)劃用到了“Clustered Index Seek”。

    當(dāng)在WHERE后用到PRCode字段的時(shí)候,“Clustered Index Seek”被用到。執(zhí)行計(jì)劃對(duì)聚集索引表檢索的時(shí)候,因?yàn)樵谶x取的字段中,包括沒有索引的字段,所以不用用到“Bookmark Lookup”方法。

    我個(gè)人認(rèn)為,從改善性能角度考慮,“Clustered Index Seek”比“Clustered Index Scan”和“Index Seek”要好。

    ?

    1. “Clustered Index Seek”不需要掃描整個(gè)聚集索引頁(yè)。
    2. 和“Index Scan”相比,對(duì)于檢索選擇的字段包含那些沒有索引的字段時(shí),“Clustered Index Seek”不會(huì)有“Bookmark Lookup”方法出現(xiàn)。

    ?

    通過這些試驗(yàn),我對(duì)執(zhí)行計(jì)劃的應(yīng)用積累了實(shí)際經(jīng)驗(yàn)。我知道哪種掃描機(jī)制可以提高性能,從而是的客戶滿意。

    ?

    posted on 2008-04-08 23:38 金家寶 閱讀(20340) 評(píng)論(8)  編輯  收藏 所屬分類: MS-SQL

    評(píng)論

    # re: 關(guān)于sql的執(zhí)行計(jì)劃(推薦詳細(xì))[未登錄] 2012-10-16 16:51 candy

    “因?yàn)樵谶x取的字段中,包括沒有索引的字段,所以不用用到“Bookmark Lookup”方法” 這句話是錯(cuò)的

    因?yàn)樵谟芯奂饕谋碇懈鶕?jù)聚集索引檢索數(shù)據(jù),索引中已經(jīng)包含了該條數(shù)據(jù)的全部?jī)?nèi)容,所以才不需要Bookmark Lookup  回復(fù)  更多評(píng)論   

    # re: 關(guān)于sql的執(zhí)行計(jì)劃(推薦詳細(xì)) 2013-01-22 17:05 張俊

    好東東  回復(fù)  更多評(píng)論   

    # re: 關(guān)于sql的執(zhí)行計(jì)劃(推薦詳細(xì))[未登錄] 2013-05-15 18:08 Frank

    很少看到寫得這么細(xì)致的文章,掌聲鼓勵(lì)!  回復(fù)  更多評(píng)論   

    # re: 關(guān)于sql的執(zhí)行計(jì)劃(推薦詳細(xì)) 2013-07-22 15:36 很郁悶

    什么是BOL?是BLOG嗎?  回復(fù)  更多評(píng)論   

    # re: 關(guān)于sql的執(zhí)行計(jì)劃(推薦詳細(xì)) 2014-04-03 16:28 niaomingjian

    @candy
    有道理  回復(fù)  更多評(píng)論   

    # re: 關(guān)于sql的執(zhí)行計(jì)劃(推薦詳細(xì)) 2015-03-21 14:22 王振

    @niaomingjian
    說的很好  回復(fù)  更多評(píng)論   

    # re: 關(guān)于sql的執(zhí)行計(jì)劃(推薦詳細(xì))[未登錄] 2015-04-13 17:39 lee

    2.“Index Seek”利用“WHERE”來過濾獲取的數(shù)據(jù),這樣比用“Index Scan”和“Table Scan”快很多。 個(gè)人覺得這句話表達(dá)意思不對(duì),不建立索引的時(shí)候,也可以用WHERE來過濾獲取數(shù)據(jù)。  回復(fù)  更多評(píng)論   

    # re: 關(guān)于sql的執(zhí)行計(jì)劃(推薦詳細(xì))[未登錄] 2015-06-18 15:17 A

    內(nèi)容(請(qǐng)不要發(fā)表任何與政治相關(guān)的內(nèi)容)   回復(fù)  更多評(píng)論   

    主站蜘蛛池模板: 99精品视频免费| 亚洲成AV人片在| 一二三四免费观看在线视频中文版| 人碰人碰人成人免费视频| 亚洲日本久久一区二区va| 亚洲AV日韩精品久久久久| 少妇亚洲免费精品| 成人在线免费观看| 久久精品国产免费观看三人同眠| 中文在线观看永久免费| 香蕉视频在线观看免费| 亚洲色大18成人网站WWW在线播放| 久久精品亚洲精品国产色婷| 综合久久久久久中文字幕亚洲国产国产综合一区首 | 内射无码专区久久亚洲| 欧美三级在线电影免费| 在线日本高清免费不卡| a级男女仿爱免费视频| 一个人看的www免费在线视频| 亚洲aⅴ无码专区在线观看春色| 在线aⅴ亚洲中文字幕| 亚洲一区二区三区在线观看蜜桃| 久久夜色精品国产噜噜亚洲AV| 亚洲精品国产品国语在线| 狠狠色婷婷狠狠狠亚洲综合 | 亚洲欧洲国产综合AV无码久久| 亚洲成人午夜电影| 亚洲综合激情六月婷婷在线观看| 亚洲AV无码不卡在线播放| 亚洲精品无码永久在线观看你懂的 | 亚洲中文字幕无码专区| 亚洲国产精品自产在线播放| 免费人成视频在线观看不卡| 免费人成年轻人电影| 亚洲成a人片在线观看老师| 亚洲国产成人久久精品99| 免费a级毛片在线观看| 国产一区二区免费在线| 免费a级毛片永久免费| www.91亚洲| 国产精品亚洲美女久久久|