TOP 第二章 之 繫結變數

2021-08-22 03:07:28 字數 3294 閱讀 5941

(此書中文名字還未敲定)

繫結變數

注意:你將會在下面的內容中看到一些執行計畫。第6章將會介紹如何獲取並解釋執行計畫。如果有什麼不清楚的話,可以考慮稍後返回本章。

2.5.1 優勢

繫結變數的優勢是可以在庫快取中共享游標,這樣就可以避免硬解析以及與之相關的額外開銷。下面內容是執行指令碼bind_variables.sql的結果,它展示了三個insert語句由於使用繫結變數而共享了庫快取中的同乙個游標的情形。

sql**, 略.
可是,也有一些情況下,即使使用繫結變數也會產生多個子游標。下面的例子就展示了這種情況。注意,insert語句與前面例子中的完全一樣。只有對應的varchar2變數的最大長度發生了變化(從32變成33了)。

sql**, 略.
之所以會建立新的子游標(子游標1),是因為相對於最初的3個insert語句來講,第4個insert語句的執行環境發生了變化。 這個不匹配可以通過查詢檢視 v$sql_shared_cursor 來得到確認,是繫結變數的原因。

sql**, 略.
這是由於資料庫引擎應用了繫結變數分級(graduation)。這個功能的目的是為了最小化子游標的數量,它是根據繫結變數的長短將繫結變數(各個大小不同)分為四個級別。在32個位元組以內被分在第乙個級別,33到128個位元組的被分在第二個級別,129到2000個位元組的被分在第三個級別,其餘的大於2000個位元組的被分在第四個級別。number型別的繫結變數被分在它的最大長度22個位元組上的級別上。從下面的例子可以看到,檢視v$sql_bind_metadata顯示了級別的最大長度。注意,即使在子游標1的變數長度只有33的時候,也是使用最大長度為128的級別。

sql**, 略.
系統不要求每次生成子游標的時候都生成乙個新的執行計畫。新的執行計畫是否與另乙個子游標使用的執行計畫一致,也依賴於繫結變數的值。這將在下面的內容中進行介紹。

2.5.2 劣勢

在where從句中使用繫結變數的缺點是會有一些至關重要的資訊對查詢優化器不可見。事實上,對查詢優化器來講,使用直接文字要比使用繫結變數來的更好。使用直接文字可以提高成本估算的準確性。當檢查乙個值是否在可用數值範圍以外(也就是,小於儲存在這個欄位的最小值,或者大於最大值)或者是否利用到直方圖(histogram)時,就更是這樣了。為了展示的需要,我們準備了乙個含有1000條記錄的表,它的字段id的值在1(最小值)到1000(最大值)之間。

sql**, 略.
如果乙個使用者查詢id小於990的所有記錄,查詢優化器知道(根據物件的統計資訊)有差不多99%的記錄被篩選。因此,它會選擇使用基於全表掃瞄的執行計畫。同時請注意,估算出的基數(執行計畫中rows欄位的資訊)與查詢語句實際返回的記錄數是否相符。

sql**, 略.
當另外乙個使用者查詢id小於10的所有記錄時,查詢優化器知道只有大約1%的記錄會被選中。因此,它會選擇使用基於索引掃瞄的執行計畫。在這個例子中,也請注意估算的準確與否。

sql**, 略.
只要是使用到繫結變數,查詢優化器都會忽略它們的具體值。從而,前面例子中的準確的估算就不太可能會出現。為了解決這個問題,oracle9i中引入了乙個被稱為繫結變數窺測(bind variable peeking)的功能。

警告:繫結變數窺測不支援隨oracle9i一起發布的jdbc 瘦驅動(jdbc thin driver)。這個限制在metalink的註解273635.1中有記載。
繫結變數窺測的概念是比較簡單的。在物理優化階段,查詢優化器會窺測繫結變數的值,將它作為文本來使用。這種方法的問題是它生成的執行計畫會依賴第一次生成執行計畫時所提供的值。下面這個基於指令碼bind_variable_peeking.sql的例子展示了這種情形。注意,第一次優化是使用值990來執行的。結果,查詢優化器就選擇了全表掃瞄。由於游標是共享的,因此是這個選擇影響了第二次使用10作為條件的查詢語句。

當然,如同在下面的例子中那樣,如果第乙個執行計畫替換成使用值10來執行,查詢優化器就會選擇乙個基於索引掃瞄的執行計畫-然後,就會再一次發生這兩條查詢語句上。注意,為了避免共享前面例子中的游標,這些語句是使用小寫字母來寫的。

有必要強調,只要游標還儲存在庫快取中並且可以被共享,就可以被重用。不管與它相關的執行計畫的效率如何,這種事情都會發生。

為了解決這個問題,oracle11g中引入了乙個稱為擴充套件的游標共享(extended cursor sharing,也稱為適應性游標共享,adaptive cursor sharing)的新功能。它的目的是在重用乙個已經存在的但是會導致執行效率低下的游標時能夠自動進行識別。通過檢視前面例子中使用的sql語句在v$sql中的內容,可用來幫助我們理解這個特性是如何工作的。要到oracle11g中v$sql檢視中才有下面這些字段:

在下面的例子中,游標是可共享的並且是繫結變數敏感的,但是沒有使用擴充套件的游標共享:

sql**, 略.
當游標對這個繫結變數賦不同的值執行多次以後,有趣的事情發生了。在使用值10和990執行了幾次以後,檢視v$sql提供的資訊發生了變化。注意,0號游標不再可共享,並且產生了兩個新的使用了擴充套件的游標共享的子游標。

檢視與這個游標關聯的執行計畫,你可能會發現,其中乙個新的子游標會使用基於全表掃瞄的執行計畫,而同時另乙個會使用基於索引掃瞄的執行計畫:

sql**, 略.
有以下幾個新的動態效能檢視可用來進一步分析生成這兩個游標的原因:v$sql_cs_statistics、 v$sql_cs_selectivity和v$sql_cs_histogram。第乙個檢視說明是否使用了窺測(peeking)以及對應於每個游標的相關執行統計資訊。根據下面的輸出,基本可以確認,對於同乙個執行語句,游標1處理的記錄數高於游標2處理的記錄數。因此,查詢優化器在一種情況下選擇了全表掃瞄,而在另一種情況下卻選擇了索引掃瞄。

sql**, 略.
檢視v$sql_cs_selectivity顯示與每個游標的每個選擇條件相關的選擇性範圍。事實上,資料庫引擎不會為每乙個繫結變數值建立乙個新的游標。而是將具有同樣選擇性的並有可能導致生成同乙個執行計畫的繫結變數值組合在一起(以生成乙個新的游標)。

sql**, 略.
總的來講,為了提高執查詢優化器生成高效的執行計畫的可能性,最好不要使用繫結變數。繫結變數有時候可能有用。遺憾的是,生成的執行計畫是否高效只能看運氣如何。唯一的例外是,oracle資料庫11g中的新的擴充套件的游標共享會自動識別這個問題。

2.5.3 最佳實踐

使用任何特性都需要權衡利弊得失。有些情況下,這是比較容易決定的。例如,在不涉及到where從句(如普通的插入語句)的時候,就沒理由不使用繫結變數。另一方面,在柱狀圖資訊對查詢優化器有很大影響的情況下,最好不要使用繫結變數。否則,可能會在進行繫結變數窺視的時候遇到較大負面風險。不過,還有以下兩個關鍵案例可供參考:

–eof–

google+

c 第二章 變數

c 基本算術型別 char 8位 wchar t 16位 short 16位 int 16位 long 32位 float 6位有效數字 double 10位有效數字 long double 10位有效數字 1.8位的塊為乙個位元組,32位為乙個字 2.unsigned無符號型別,表示大於等於0的數...

第二章 shell變數

檢視所有全域性和區域性變數 delare和set 檢視所有全域性變數 env 定義環境變數 使用者變數在家目錄下的 bash profile和 bashrc中設定 全域性變數在 etc profile和 etc bashrc及 etc profile.d 下的指令碼檔案 登入shell待用流程 et...

C primer之第二章

閱讀至2.5.2時,發現乙個不知道的知識點 如果某個型別的別名指代的是復合型別或是常量,那麼它用到宣告語句裡面就會產生意想不到的後果,例如下面的宣告語句用到了型別pstring,它實際上是型別char 的別名 typedef char pstring 1 const pstring cstr 0 c...