官术网_书友最值得收藏!

5.2 解析過程

上面我們簡單描述了一下SQL語句的解析步驟,下面將通過圖5-2具體說明整個解析及游標查找過程。

圖5-2 SQL解析及游標查找

首先我們來說明幾個概念。前面講到了SQL解析,它的生成結果保存在庫高速緩存中。保存的對象我們稱為庫緩存對象(Library Cache Object)。所有的庫緩存對象都是以一種名為庫緩存對象句柄(Library Cache Object Handles)的結構保存的。具體形式上,庫緩存對象句柄是以哈希表的形式存儲在庫緩存中的。整個庫緩存可以看成是由一組哈希桶(Hash Bucket)組成的。

當用戶提交一條SQL語句后,優化器會根據目標SQL的文本計算一個哈希值,然后去庫緩存中找匹配的Hash Bucket,如圖5-2所示的步驟①。這里需要強調一點,不同SQL文本可能計算的哈希值相同。此外,相同SQL文本也可能代表的是不同的語句(后面會看到這樣的示例)。

在找到對應的Hash Bucket后,在這個桶的后面是一個Library Cache Object Handles的鏈表。鏈表中的每一個Library Cache Object Handle都對應著一個SQL文本解析后的內存結構(游標)。每一個Library Cache Object Handle對應的內存結構都可分為一個Parent Cursor和若干個Child Cursor,在Parent Cursor中保存有指向Child Cursor的指針結構。在Parent Cursor中保存著SQL文本,在Child Cursor中保存著SQL解析樹和執行計劃,如圖5-2中所示的步驟②。

針對每個Parent Cursor,會有多個Child Cursor。每個Child Cursor都對應一套SQL執行計劃。下面就需要遍歷這個Child Cursor的鏈表,找到適合的Child Cursor了。如果找不到,會生成一個新的Child Cursor,并掛在Parent Cursor的下面,如圖5-2所示的步驟③。

下面我們分別看看不同的解析類型,對應于上面的結構是如何進行的。

1.硬解析

根據上面所述,如果根據SQL文本計算的哈希值(sql_id)無法在庫高速緩存中找到,則開啟一個硬解析的過程。在這一過程中,首先需要在共享池中獲取一個栓鎖(Latch),然后在共享池的可用Chunk鏈表(也就是Bucket)中找到一個可用的Chunk,然后釋放Latch。在獲得了Chunk后,這塊Latch就可以認為是進入Library Cache了,從而開始硬解析的過程。在經過一系列的步驟后,優化器創建一個最優的執行計劃。數據庫會將產生的執行計劃、SQL文本等裝載進Library Chache中的若干個Heap。對應于上面的結構,會生成一個Parent Cursor,下面掛著一個Child Cursor。

2.軟解析

如果在Bucket中找到了某一SQL語句,則說明該SQL語句以前運行過,于是進行軟解析。軟解析是相對于硬解析而言的。如果解析過程中,可以從硬解析中去掉一個或多個步驟,則這樣的解析就是軟解析。它又可以細分為三種類型:

·類型-hard parse:某個Session發出的SQL語句與Library Cache里其他Session發出的SQL語句一致。這時,該解析過程中可以去掉硬解析中某些步驟,但仍要進行數據字典檢查、名稱轉換和權限檢查。對應于上面的結構,就是找到一個對應的Parent Cursor,后續操作生成一個Child Cursor,并掛在其他Child Cursor的后面。

·類型-soft parse:某個Session發出的SQL語句與Library Cache里同一個session之前發出的SQL語句一致。這時,該解析過程中只需要進行權限檢查,因為可能通過Grant改變了該Session用戶的權限。對應于上面的結構來說,就是在Parent Cursor下掛的Child Cursor找到你所需要的解析結果。這種情況可以省略很多解析動作,直接返回結構即可。

·類型-soft soft parse:當設置了初始化參數session_cached_cursors,且某個Session對相同的Cursor進行第三次訪問時,將在該Session的PGA里創建一個標記,并且該游標即使已經被關閉也不會從Library Cache中交換出去。這樣,該Session以后再執行相同的SQL語句時,將跳過硬解析的所有步驟。這種情況是最高效的解析方式,但是會消耗很大的內存。對應于上面的結構來說,就是根本不需要再訪問共享池,直接在會話自有的內存區域中就可以找到解析結果。這是效率最高的一種方式。

3.解析優化

從上面過程的說明可見,數據庫硬解析的過程就是生成游標的過程;軟解析的過程就是找到以前生成的游標的過程;軟軟解析就是直接在客戶端就找到緩存在本地游標的過程。從性能的角度講,需要盡可能地避免發生硬解析。這也是為什么數據庫要將共享游標保存在庫緩存中的原因。因為這樣,屬于這個實例的每一個進程都可以重用它們。

有兩個原因可以解釋為什么硬解析的開銷較高。第一個原因是硬解析過程很長,涉及大量復雜操作,這些都非常依賴CPU操作。第二個原因是要分配內存來將父游標與子游標保存在庫緩存中。由于庫緩存是在所有會話之間共享的,庫緩存中的內存分配必須串行執行。在實際操作中,在分配父游標和子游標所需的內存之前,必須取得一個保護共享池的閂鎖。

雖然軟解析的影響已經遠比硬解析要小,但還是需要盡量避免軟解析,因為它也會導致某種串行處理。事實上,為了所有共享的父游標,也必須取得一個保護庫緩存的閂鎖。總的來講,需要盡可能避免硬解析和軟解析,因為它們都會抑制應用程序的可擴展性。

下面通過一個示例說明生成游標的過程,大家也可以從操作中看到如何通過數據字典查看語句緩存的游標情況。

主站蜘蛛池模板: 西充县| 蓬溪县| 海宁市| 宁安市| 张家川| 河曲县| 手游| 威宁| 班玛县| 玛纳斯县| 大足县| 湖北省| 钟祥市| 怀安县| 霍邱县| 泰州市| 临海市| 崇文区| 茶陵县| 黑龙江省| 静海县| 汉阴县| 册亨县| 天长市| 沁水县| 博乐市| 平邑县| 手游| 宜川县| 漳平市| 新源县| 鸡西市| 浏阳市| 玛沁县| 马公市| 霍邱县| 什邡市| 黔西县| 合阳县| 东城区| 洛浦县|