共計(jì) 4820 個(gè)字符,預(yù)計(jì)需要花費(fèi) 13 分鐘才能閱讀完成。
本篇內(nèi)容介紹了“Oracle Cursor 的相關(guān)知識(shí)點(diǎn)有哪些”的有關(guān)知識(shí),在實(shí)際案例的操作過(guò)程中,不少人都會(huì)遇到這樣的困境,接下來(lái)就讓丸趣 TV 小編帶領(lǐng)大家學(xué)習(xí)一下如何處理這些情況吧!希望大家仔細(xì)閱讀,能夠?qū)W有所成!
游標(biāo)是一個(gè)基本對(duì)象,它是 SQL 語(yǔ)句或 PL/SQL 編程式構(gòu)造的一種完整可執(zhí)行表示,可以被任何授權(quán)會(huì)話使用和重用。游標(biāo)必須被創(chuàng)建,定位(通過(guò)搜索來(lái)查找),消毀(回收),失效與重載。如果游標(biāo)的任何部分不在共享池中,并且出于任何原因需要,則必須重新加載該游標(biāo),這會(huì)降低性能。
開發(fā)人員通常對(duì)游標(biāo)有很好的理解因?yàn)樗麄冃枰獙iT創(chuàng)建,打開,執(zhí)行,獲取與關(guān)閉游標(biāo)。DBA 通常將游標(biāo)作為與 SQL 相關(guān)的簡(jiǎn)單內(nèi)存塊來(lái)看待。然而,這種過(guò)于簡(jiǎn)單的關(guān)點(diǎn)限制了我們?yōu)榕c游標(biāo)相關(guān)的性能問(wèn)題創(chuàng)建解決方案的能力。因此,如果花時(shí)間更好地理解游標(biāo),將會(huì)注意到性能解決方案選項(xiàng)將顯著增加。
父游標(biāo)與子游標(biāo)
游標(biāo)這個(gè)術(shù)語(yǔ)本身是一個(gè)抽象概念,用來(lái)引用共享的信息 (位于共享 SQL 區(qū)),私有信息(位于會(huì)話的 PGA) 與用來(lái)定位各種游標(biāo)組件的 library cache chain 節(jié)點(diǎn)(當(dāng)引用 library cache 時(shí)就叫作 handle)。不幸地是這種多用途的定義也增加了混淆。當(dāng)一個(gè)游標(biāo)被關(guān)閉時(shí),Oracle 不會(huì)簡(jiǎn)單的回收這三個(gè)游標(biāo)組件。而是 Oracle 可能會(huì)按需來(lái)回收游標(biāo)組件。
一個(gè)游標(biāo)第一次執(zhí)行時(shí),會(huì)存在一個(gè)父游標(biāo)與子游標(biāo)。后續(xù)的會(huì)話,即使相同的會(huì)話執(zhí)行相同的 SQL 語(yǔ)句(哈希值相同),可能會(huì)使用不同的子游標(biāo)。雖然 SQL 語(yǔ)句在文本上完全相同,但是創(chuàng)建子游標(biāo)是為了捕獲特定的特征,比如優(yōu)化模式的差異(例如 first_rows),這會(huì)導(dǎo)致不同的執(zhí)行計(jì)劃或不同的會(huì)話級(jí)參數(shù)(cursor_sharing=similar)。下面的例子簡(jiǎn)單的顯示了相同會(huì)話執(zhí)行相同 SQL 語(yǔ)句兩次,只是在兩次執(zhí)行之間執(zhí)行了 alter session 命令,這足以強(qiáng)制創(chuàng)建一個(gè)額外的子游標(biāo)。trace 命令用來(lái)證明創(chuàng)建了兩個(gè)子游標(biāo)。
SQL oradebug setmypid
Statement processed.
SQL alter session set optimizer_mode = all_rows;
Session altered.
SQL select * from dual;
SQL alter session set optimizer_mode = first_rows;
Session altered.
SQL select * from dual;
SQL alter session set events immediate trace name library_cache level 10
Session altered.
SQL oradebug tracefile_name
/u01/app/oracle/diag/rdbms/jy/jy1/trace/jy1_ora_6675.trc
下面的內(nèi)容是上面的 trace 命令所創(chuàng)建的跟蹤文件中的一部分內(nèi)容。我們通過(guò)搜索 select * from dual 來(lái)定位我們關(guān)心的內(nèi)容并檢查 SQL 語(yǔ)句。此時(shí),我們感興趣的是,這條 SQL 語(yǔ)句僅由一個(gè)會(huì)話執(zhí)行,但它創(chuàng)建了兩個(gè)子游標(biāo)。
Bucket: #=108289 Mutex=0xc5eeae00(3298534883328, 1118, 0, 6)
LibraryHandle: Address=0xcf2e9a48 Hash=382da701 LockMode=0 PinMode=0 LoadLockMode=0 Status=VALD
ObjectName: Name=select * from dual
FullHashValue=0d54fc02b2ad4044a2cb0974382da701 Namespace=SQL AREA(00) Type=CURSOR(00) ContainerId=1 ContainerUid=1 Identifier=942515969 OwnerIdn=0
Statistics: InvalidationCount=0 ExecutionCount=2 LoadCount=3 ActiveLocks=0 TotalLockCount=2 TotalPinCount=1
Counters: BrokenCount=1 RevocablePointer=1 KeepDependency=2 Version=0 BucketInUse=1 HandleInUse=1 HandleReferenceCount=0
Concurrency: DependencyMutex=0xcf2e9af8(0, 2, 0, 0) Mutex=0xcf2e9b98(768, 37, 0, 6)
Flags=RON/PIN/TIM/PN0/DBN/[10012841] Flags2=[0000]
WaitersLists:
Lock=0xcf2e9ad8[0xcf2e9ad8,0xcf2e9ad8]
Pin=0xcf2e9ab8[0xcf2e9ab8,0xcf2e9ab8]
LoadLock=0xcf2e9b30[0xcf2e9b30,0xcf2e9b30]
Timestamp: Current=04-17-2019 09:33:16
HandleReference: Address=0xcf2e9c20 Handle=(nil) Flags=[00]
ReferenceList:
Reference: Address=0x84497a08 Handle=0x818e2850 Flags=ROD[21]
Reference: Address=0x84c9e3d0 Handle=0xb28b76a0 Flags=ROD[21]
LibraryObject: Address=0xbd5972a8 HeapMask=0000-0001-0001-0000 Flags=EXS[0000] Flags2=[0000] PublicFlags=[0000]
DataBlocks:
Block: #= 0 name=KGLH0^382da701 pins=0 Change=NONE
Heap=0x83043cc0 Pointer=0xbd597378 Extent=0xbd597200 Flags=I/-/P/A/-/-/-
FreedLocation=0 Alloc=3.390625 Size=3.976562 LoadTime=4111958371
ChildTable: size= 16
Child: id= 0 Table=0xbd598128 Reference=0xbd597bf8 Handle=0xb38e2928
Child: id= 1 Table=0xbd598128 Reference=0xbd597f48 Handle=0xbdfc20a8
NamespaceDump:
Parent Cursor: sql_id=a5ks9fhw2v9s1 parent=0xbd597378 maxchild=2 plk=n ppn=n prsfcnt=0 obscnt=0
CursorDiagnosticsNodes:
ChildNode: ChildNumber=0 ID=3 reason=Optimizer mismatch(10) size=3x4 optimizer_mode_hinted_cursor=0 optimizer_mode_cursor=1 optimizer_mode_current=2
庫(kù)緩存對(duì)象之間的關(guān)系不僅為執(zhí)行目的而必須維護(hù),而且當(dāng)其中一個(gè)組件發(fā)生更改時(shí)也必須維護(hù)。假設(shè)一個(gè)表被 2000 個(gè) SQL 語(yǔ)句,100 個(gè)函數(shù)與 20 個(gè)包所引用。現(xiàn)在假設(shè)表的一列被重命名。Oracle 將會(huì)使所有相關(guān)的 SQL 語(yǔ)句與程序結(jié)構(gòu)失效。這可能導(dǎo)致在請(qǐng)求 latching 與 locking 時(shí)出現(xiàn)級(jí)聯(lián)效應(yīng)。多個(gè)相關(guān)會(huì)話、失效、重新編譯和計(jì)時(shí)的組合導(dǎo)致整個(gè) Oracle 實(shí)例被鎖定。很明顯 Oracle 已經(jīng)知道了這種問(wèn)題的嚴(yán)重性并且積極的減小出現(xiàn)這種情況的可能性。但每個(gè) DBA 要了解 library cache 之間的關(guān)系是非常復(fù)雜的并且有時(shí)可能導(dǎo)致出現(xiàn)問(wèn)題。
Cursor Building
當(dāng)在 library cache 中搜索并沒有找到游標(biāo)時(shí)就會(huì)創(chuàng)建游標(biāo)。這就是硬解析。很明顯這是一個(gè)相對(duì)昂貴的操作它需要請(qǐng)求內(nèi)存管理(分配與可能回收),使用 latching 來(lái)確保序列化,使用 locking 來(lái)阻止不合適的更改,執(zhí)行內(nèi)核代碼需要消耗 CPU 資源,和可能需要 IO 操作來(lái)將數(shù)據(jù)字典信息插入 row cache 中。
游標(biāo)是使用共享池中的數(shù)據(jù)來(lái)創(chuàng)建的,如果數(shù)據(jù)當(dāng)前不在共享池中,Oracle 將創(chuàng)建它自己的 SQL 語(yǔ)句來(lái)從數(shù)據(jù)字典表中檢索數(shù)據(jù)。Oracle 動(dòng)態(tài)創(chuàng)建的 SQL 會(huì)命名為遞歸 SQL 并運(yùn)行它。為了創(chuàng)建一個(gè)游標(biāo) Oracle 需要的數(shù)據(jù)是優(yōu)化器統(tǒng)計(jì)信息,會(huì)話信息,安全信息,對(duì)象信息與對(duì)象關(guān)聯(lián)信息。
游標(biāo)是由稱為堆的共享池內(nèi)存塊創(chuàng)建的。傳統(tǒng)上,不同的 SQL 語(yǔ)句需要不同大小的內(nèi)存塊。常見的 SQL 語(yǔ)句通常請(qǐng)求 4KB 大小的內(nèi)存塊。與 free exten 管理一樣,請(qǐng)求不一致大小的內(nèi)存塊會(huì)導(dǎo)致分配,性能與效率問(wèn)題。從 Oracle 10gr2 開始,Oracle 將所有的內(nèi)存塊定義為 4KB。當(dāng)合適的內(nèi)存塊不能快速地找到時(shí),Oracle 最終可能會(huì)放棄并 posts 一個(gè) 4031 錯(cuò)誤“out of shared poll memory”并停止 SQL 語(yǔ)句的處理。
Cursor Searching Introduction
與 buffer cache 中的每個(gè) buffer 一樣,每個(gè)父游標(biāo)與子游標(biāo)必須被定位并且搜索必須要快速。這將請(qǐng)求內(nèi)存,一個(gè)搜索結(jié)構(gòu),序列化,內(nèi)核代碼與大量 CPU 資源。
因?yàn)橛螛?biāo)與程序結(jié)構(gòu)存放在 library cache 中,有一個(gè)結(jié)構(gòu)來(lái)定位對(duì)象。Oracle 選擇使用哈希算法與相關(guān)哈希類似結(jié)構(gòu)。解析操作的一部分是判斷一個(gè)游標(biāo)當(dāng)前是否存放在 library cache 中了。如果確實(shí)在 library cache 中找到了這個(gè)游標(biāo),進(jìn)行了一些解析操作,因此它確實(shí)是一個(gè)軟解析。然而如果在 library cache 中沒有找到這個(gè)游標(biāo),整個(gè)游標(biāo)需要被創(chuàng)建,因此它就是硬解析。游標(biāo)創(chuàng)建與硬解析是相當(dāng)昂貴的操作。
Cursor Pinning and Locking
固定游標(biāo)類似于固定 buffer。它被用來(lái)確保當(dāng)游標(biāo)被引用時(shí)不會(huì)被回收 (有時(shí)也叫破壞)。游標(biāo)顯然不是關(guān)系結(jié)構(gòu),但是 SQL 與關(guān)系結(jié)構(gòu)(例如 employee 表) 相關(guān),關(guān)系結(jié)構(gòu)用于構(gòu)建游標(biāo)(例如 sys.col$),因此使用了鎖——也就是說(shuō),使用了隊(duì)列。游標(biāo)隊(duì)列也叫作 CU 隊(duì)列并且就像其它隊(duì)列一樣通過(guò) Oracle 的等待接口可以檢測(cè)。
當(dāng)創(chuàng)建與執(zhí)行游標(biāo)時(shí)就要固定游標(biāo)。這是很容易理解的,當(dāng)你創(chuàng)建一個(gè)游標(biāo)時(shí),它是一種內(nèi)存結(jié)構(gòu),你不想其它的進(jìn)程回收相關(guān)的內(nèi)存。正常情況下,游標(biāo)在創(chuàng)建與執(zhí)行完成后不會(huì)出現(xiàn)固定的情況。這意味著在你執(zhí)行一個(gè)游標(biāo)后且等待 2 分鐘后你想再次執(zhí)行相同的游標(biāo),這時(shí)游標(biāo)可能已經(jīng)被回收了。如果出現(xiàn)這種情況,在 library cache 中找不到需要的游標(biāo),將會(huì)執(zhí)行硬解析,它將完全重新創(chuàng)建游標(biāo)。
在創(chuàng)建與執(zhí)行游標(biāo)時(shí)也可能會(huì)出現(xiàn)鎖定的情況。但它不同于固定游禁。固定的關(guān)注點(diǎn)在于內(nèi)存回收。而鎖是確保與游標(biāo)相關(guān)的表在創(chuàng)建與執(zhí)行游標(biāo)時(shí)不被修改。顯然,這可能會(huì)造成一些相當(dāng)奇怪的情況,而 Oracle 不會(huì)允許這種情況發(fā)生。
“Oracle Cursor 的相關(guān)知識(shí)點(diǎn)有哪些”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關(guān)的知識(shí)可以關(guān)注丸趣 TV 網(wǎng)站,丸趣 TV 小編將為大家輸出更多高質(zhì)量的實(shí)用文章!