問(wèn)題
在我的T-SQL代碼中,我經(jīng)常使用基于集合的運(yùn)算。我被告知這些運(yùn)算的類型正是SQL Server設(shè)計(jì)所處理的,并且它應(yīng)該比串行處理要快些。我知道游標(biāo)的存在但是我不確定如何使用它們。您能提供一些游標(biāo)的例子嗎?您能否給一些關(guān)于何時(shí)使用游標(biāo)的指導(dǎo)?我假定微軟由于某種原因創(chuàng)建了它們,所以它們必須有以高效方式使用的地方。
專家解答
在某些圈子中,游標(biāo)從未被使用過(guò),在其他圈子中,它們是一種最后手段,而在其它組中它們經(jīng)常被使用。在每個(gè)組中,它們由于不同原因而使用游標(biāo)。無(wú)論你對(duì)游標(biāo)使用原因有什么樣的立場(chǎng),可能它們?cè)谝粋€(gè)特定環(huán)境中具有用武之地而在另一個(gè)環(huán)境中卻沒(méi)有用處。所以它歸結(jié)于你對(duì)這個(gè)技術(shù)的理解,然后歸結(jié)于隨及而來(lái)對(duì)問(wèn)題的理解導(dǎo)致做出一個(gè)決定,這個(gè)決定就是基于游標(biāo)的過(guò)程是否恰當(dāng)。讓我們先來(lái)做以下幾件事情:
l 看一個(gè)游標(biāo)實(shí)例
l 分解游標(biāo)的組成部分
l 分析使用游標(biāo)的優(yōu)缺點(diǎn)
游標(biāo)實(shí)例
以下是一個(gè)游標(biāo)實(shí)例,講述了備份在串行狀態(tài)下如何執(zhí)行。
| 以下為引用的內(nèi)容: DECLARE@nameVARCHAR(50)--databasename DECLARE@pathVARCHAR(256)--pathforbackupfiles DECLARE@fileNameVARCHAR(256)--filenameforbackup DECLARE@fileDateVARCHAR(20)--usedforfilename SET@path='C:Backup' SELECT@fileDate=CONVERT(VARCHAR(20),GETDATE(),112) DECLAREdb_cursorCURSORFOR SELECTname FROMmaster.dbo.sysdatabases WHEREnameNOTIN('master','model','msdb','tempdb') OPENdb_cursor FETCHNEXTFROMdb_cursorINTO@name WHILE@@FETCH_STATUS=0 BEGIN SET@fileName=@path @name '_' @fileDate '.BAK' BACKUPDATABASE@nameTODISK=@fileName FETCHNEXTFROMdb_cursorINTO@name END CLOSEdb_cursor DEALLOCATEdb_cursor |
游標(biāo)組成
根據(jù)以上的實(shí)例,游標(biāo)包括這些組成部分:
l DECLARE語(yǔ)句 – 聲明在代碼塊中使用的變量
l SETSELECT語(yǔ)句 – 把這些變量初始化為某個(gè)具體的值
l DECLARE CURSOR語(yǔ)句 – 在游標(biāo)中填充將要求取的值。
注意 – DECLARE CURSOR FOR語(yǔ)句和SELECT語(yǔ)句中具有相同數(shù)量的變量。變量數(shù)目可能是一個(gè)或者很多個(gè)并且有相關(guān)聯(lián)的列。
l OPEN語(yǔ)句 – 打開游標(biāo),開始進(jìn)行數(shù)據(jù)處理
l FETCH NEXT語(yǔ)句 – 從游標(biāo)中把具體的值分配給變量
注意: 這個(gè)邏輯用于WHILE語(yǔ)句之前的初始對(duì)象,接著作為WHILE語(yǔ)句的一部分在這個(gè)過(guò)程的每個(gè)循環(huán)中再次執(zhí)行。
l WHILE語(yǔ)句 – 作為開始的條件,繼續(xù)處理數(shù)據(jù)
l BEGIN...END語(yǔ)句 – 代碼塊的開始和結(jié)束
注意:按照不同的數(shù)據(jù)處理,可以使用不同的BEGIN...END語(yǔ)句
l 數(shù)據(jù)處理 – 在這個(gè)例子中,邏輯是用來(lái)把一個(gè)數(shù)據(jù)庫(kù)備份到具體的路徑和文件名,但是這可以只與任何DML或者管理邏輯有關(guān)。
l CLOSE語(yǔ)句 – 釋放當(dāng)前的數(shù)據(jù)和相關(guān)聯(lián)的鎖,但是允許游標(biāo)重新打開。
l DEALLOCATE語(yǔ)句 – 破壞游標(biāo)
游標(biāo)分析
以下分析旨在更深入了解基于游標(biāo)的邏輯是否有利:
l 聯(lián)機(jī)事務(wù)處理(OLTP)- 在大多數(shù)的聯(lián)機(jī)事務(wù)處理環(huán)境中,基于集合的邏輯適合簡(jiǎn)短的事務(wù)。我們的團(tuán)隊(duì)已經(jīng)遇到第三方應(yīng)用,這個(gè)應(yīng)用在它所有的過(guò)程中使用游標(biāo),這將導(dǎo)致一些問(wèn)題,但這是一個(gè)很罕見的現(xiàn)象。通常情況下,基于集合的邏輯足夠靈活而且游標(biāo)很少被用到。
l 報(bào)表 – 基于報(bào)表的設(shè)計(jì)和潛在設(shè)計(jì),通常情況下游標(biāo)是不需要的。盡管如此,我們的團(tuán)隊(duì)遇到報(bào)表要求,而參照完整性沒(méi)有存在于潛在的數(shù)據(jù)庫(kù)中,同時(shí)需要使用游標(biāo)來(lái)正確計(jì)算報(bào)表值。當(dāng)需要下游過(guò)程的合計(jì)數(shù)據(jù)時(shí),我們面臨相同的狀況,一個(gè)基于游標(biāo)的方法可以用一種可接受的方式快速形成和執(zhí)行來(lái)滿足要求。
l 串行化過(guò)程 – 如果你需要以串行化方式完成一個(gè)過(guò)程,那么游標(biāo)是一個(gè)可行的選項(xiàng)。
l 管理員任務(wù) – 很多管理員任務(wù)需要在串行狀態(tài)下執(zhí)行,這與基于游標(biāo)的邏輯很相符,但是基于其他系統(tǒng)的對(duì)象存在來(lái)滿足這種需要。在某些情況下,游標(biāo)用來(lái)完成這一進(jìn)程。
l 大型數(shù)據(jù)集 – 在大型數(shù)據(jù)集的情況下,你可能會(huì)遇到以下任何一種情況:
基于游標(biāo)的邏輯可能沒(méi)有足夠大的規(guī)模滿足需求。
在服務(wù)器上具有大型數(shù)據(jù)集的運(yùn)算而內(nèi)存又很小,數(shù)據(jù)可能會(huì)被分頁(yè)或獨(dú)占SQL Server,這將是很費(fèi)時(shí)間的,可能會(huì)導(dǎo)致爭(zhēng)奪和內(nèi)存的問(wèn)題。
有些固有的工具把數(shù)據(jù)存儲(chǔ)到一個(gè)隱藏的文件中,所以在內(nèi)存中處理數(shù)據(jù)可能會(huì)也可能不會(huì)是實(shí)際的情況。
如果數(shù)據(jù)能夠在一個(gè)中間數(shù)據(jù)庫(kù)中處理,那么對(duì)生產(chǎn)環(huán)境的影響只有在最后數(shù)據(jù)被處理時(shí),所以服務(wù)器上所有的資源可用于ETL過(guò)程,然后引入最后的數(shù)據(jù)。
SSIS支持批處理數(shù)據(jù),這將解決把大量數(shù)據(jù)分解成更多可管理的大小和比用按行方法執(zhí)行效果更好的總體需求。
根據(jù)游標(biāo)或者SSIS邏輯如何編碼,它可能基于檢查點(diǎn)或者在游標(biāo)的每一行做標(biāo)記來(lái)在失敗時(shí)重新啟動(dòng)。盡管如此,用可能并非事實(shí)的基于集合的方法直到獲得數(shù)據(jù)的整個(gè)集合是完整的。同樣地,解決行的問(wèn)題會(huì)更加困難。
游標(biāo)的替代
下面列出了可以替代能夠滿足相同需求的基于游標(biāo)的邏輯:
l 基于集合的邏輯
l SSIS或者數(shù)據(jù)轉(zhuǎn)換服務(wù)
l WHILE循環(huán)
l COALSCE
l sp_MSforeachdb
l sp_MSforeachtable
l CASE表達(dá)
l 用GO命令重復(fù)一批數(shù)據(jù)
新聞熱點(diǎn)
疑難解答
圖片精選