SQL語句為什麼不會共享(上)
SQL語句是一種描述性的語言。Oracle接受一個SQL之後,要進行一系列的解析parse操作,最終生成真正操作的步驟——執行計劃。Oracle對一個SQL進行第一次硬解析(hard parse)之後,就將執行計劃快取在SGA的library cache中。
進行執行計劃快取的目的就是進行執行計劃共享,這樣期望在下次輸入相同SQL的時候能夠共享該計劃,減少由於硬解析帶來的Library Cache Lock和Library Cache Pin。但是實際中,真正實現SQL語句執行計劃共享是一件很複雜的事情,要滿足很多現實條件。本系列將從SQL語句遊標共享的角度,討論幾種SQL遊標不能共享的場景。
1、 環境準備
首先,我們準備一個簡單的實驗環境。
SQL> select * from v$version;
BANNER
----------------------------------------------------------------
Oracle Database 10g Enterprise Edition Release 10.2.0.1.0 - Prod
PL/SQL Release 10.2.0.1.0 - Production
CORE 10.2.0.1.0 Production
TNS for 32-bit Windows: Version 10.2.0.1.0 - Production
NLSRTL Version 10.2.0.1.0 – Production
我們選擇Oracle 10gR2的環境。同時,在sys的使用者schema下,存在一個資料表t。我們本系列中的大部分實驗都是圍繞這個資料表進行的。
2、父子游標的cursor sharing
為了增加本系列的可理解性。在本部分中稍稍介紹Oracle父子游標機制和共享機制。
ü 當Oracle接受到一個全新的SQL時,要進行硬解析hard parse,形成執行計劃。執行計劃對應的shared cursor本質上就是SGA上的一個地址區域。儲存執行計劃是以父遊標parent cursor和子游標child cursor兩部分進行儲存;
ü 父遊標parent cursor對應的就是SQL語句字面相同的SQL與之對應。對每一個父遊標而言,Oracle都會分配一個系統唯一的sql_id與之對應。新SQL進行shared pool尋找可共享的shared cursor的時候,首先定位到的就是父遊標parent cursor;
ü 子游標child cursor是繫結在父遊標上形成多對一關係的執行計劃。由於最佳化器模式等原因,一個父遊標會對應多個子遊標。每個子游標中攜帶的才是真正的執行計劃;
ü 在Oracle內部檢視上,v$sqlarea檢視表示的是父遊標資訊,v$sql檢視中表示的是子游標資訊;
3、 SQL字面值差異
兩個SQL如果語義相同,是否可以實現遊標共享嗎?首先,我們執行兩個SQL語句。
SQL> select /*+ demo_1 */count(*) from t;
COUNT(*)
----------
18015
SQL> select /*+ demo_1 */count(*) from T;
COUNT(*)
----------
18015
兩個SQL語句的差異只是在大小寫拼寫上。我們觀察父子游標情況。
SQL> select sql_text, sql_id, OPTIMIZER_MODE, hash_value, plan_hash_value, address from v$sqlarea where sql_text like 'select /*+ demo_1 */%';
SQL_TEXT SQL_ID OPTIMIZER_MODE HASH_VALUE PLAN_HASH_VALUE ADDRESS
----------------------------------- ------------- -------------- ---------- --------------- --------
select /*+ demo_1 */count(*) from t 1vp29y1g9zjs2 ALL_ROWS 1587529474 2966233522 6967139C
select /*+ demo_1 */count(*) from T 2kjp0bmmn7jsg ALL_ROWS 3879978767 2966233522 69670434
從結果看,Oracle為兩個略微差異的SQL語句生成了不同的父遊標。在v$sqlarea中,有兩行記錄與之對應。但是,我們注意到兩個父遊標對應的plan_hash_value值相同,說明雖然兩個遊標沒有實現共享,但是遊標生成的執行計劃內容上是相同的。
結論:在Oracle中,要實現遊標共享的前提條件,就是輸入SQL的字面值100%相同,不允許有任何包括大小寫的差異。
4、 SQL指定物件相同(1)
SQL字面相同,那麼SQL語句一定可能共享嗎?我們說,不同使用者schema下對應相同的名稱。這樣就可能出現相同的SQL語句透過不同的使用者發出,對應不同物件的情況。下面我們進行試驗。
SQL> col owner for a10;
SQL> col object_name for a20;
SQL> select owner, object_name, object_id from dba_objects where object_name='T';
OWNER OBJECT_NAME OBJECT_ID
---------- -------------------- ----------
SYS T 54216
SCOTT T 54136
sys使用者和scott使用者下,存在兩個相同名稱T的物件。但是本質上肯定是兩個物件。
//當前使用者為sys
SQL> show user;
User is "SYS"
SQL> select /*+ demo_2 */ count(*) from t;
COUNT(*)
----------
18015
//切換到scott使用者
SQL> conn scott/tiger@orcl;
Connected to Oracle Database 10g Enterprise Edition Release 10.2.0.1.0
Connected as scott
SQL> select /*+ demo_2 */ count(*) from t;
COUNT(*)
----------
0
兩個SQL字面完全一樣,此時作為相同的SQL語句,在Oracle library cache中是如何呢?
SQL> select sql_text, sql_id, OPTIMIZER_MODE, hash_value, plan_hash_value, address, executions,version_count from v$sqlarea where sql_text like 'select /*+ demo_2 */%';
SQL_TEXT SQL_ID OPTIMIZER_MODE HASH_VALUE PLAN_HASH_VALUE ADDRESS EXECUTIONS VERSION_COUNT
----------------------------------- ------------- -------------- ---------- --------------- -------- ---------- -------------
select /*+ demo_2 */ count(*) from 6d100h31dw99u ALL_ROWS 3269338426 2966233522 69654C70 2 2
t
我們在父遊標中只看到了一個父遊標資訊,同時executions為2表示該SQL被執行過兩次,同實際相同。而version_count為2說明兩次執行,雖然可以共享父遊標,但是在子游標層面上,變為兩個子游標,進而是兩個執行計劃。
SQL> select sql_id, PARSING_SCHEMA_NAME, child_number from v$sql where sql_id='6d100h31dw99u';
SQL_ID PARSING_SCHEMA_NAME CHILD_NUMBER
------------- ------------------------------ ------------
6d100h31dw99u SYS 0
6d100h31dw99u SCOTT 1
結論:兩個schema下發出的SQL,如果環境相同,SQL字面值相同,在shared pool中共享父遊標,對應不同的子游標。執行計劃不能共享。
此時,如果我們進一步想,如果兩個SQL字面值相同,而且對應相同的物件,會怎麼樣呢?
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/17203031/viewspace-703624/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 為什麼 SQL 語句使用了索引,但卻還是慢查詢?SQL索引
- 為什麼說共享WiFi專案是如今風口,會不會已經太晚了!WiFi
- Java中如何解析SQL語句、格式化SQL語句、生成SQL語句?JavaSQL
- SQL語句SQL
- 必知必會——SQL語句基本語法整理SQL
- 執行一條sql語句都經歷了什麼?SQL
- 執行一條 SQL 語句,期間發生了什麼?SQL
- 為什麼說會不會SQL,決定著你的工資?方向不對,努力也白費!SQL
- 程式語言中為什麼使用分號作為語句結束符?
- 【SQL】9 SQL INSERT INTO 語句SQL
- 【SQL】10 SQL UPDATE 語句SQL
- 【SQL】11 SQL DELETE 語句SQLdelete
- SQL SELECT 語句SQL
- sql常用語句SQL
- 網站為什麼會打不開網站
- [20240409]為什麼一條sql語句在例項2執行要慢的分析.txtSQL
- [20210407]分析sql語句的共享記憶體段3.txtSQL記憶體
- [20220328]查詢游標為什麼不共享指令碼.txt指令碼
- SAP:什麼熱 什麼不熱 為什麼你會關心?(轉)
- win10為什麼連不上共享印表機 wind10無法連線共享印表機的方法Win10
- java switch語句是什麼?Java
- Java 可以採用什麼語句跳出迴圈語句Java
- 這就是為什麼你學不會DDD
- Python 的切片為什麼不會索引越界?Python索引
- 1.3. SQL 語句SQL
- Oracle基本SQL語句OracleSQL
- Sql語句小整理SQL
- SQL語句優化SQL優化
- SQL語句IN的用法SQL
- SQL 語句學習SQL
- [20220420]完善查詢游標為什麼不共享指令碼.txt指令碼
- MySQL 修改int型別為bigint SQL語句拼接MySql型別
- Hibernate/JPA如何保證不生成多餘的SQL語句?SQL
- [20220109]開發不應該這樣寫SQL語句.txtSQL
- Python中break語句和continue語句有什麼區別?Python
- Oracle SQL精妙SQL語句講解OracleSQL
- 怎樣在sqlite3上執行SQL語句SQLite
- 為什麼螞蟻永遠不會堵車?
- GreatSQL 中為什麼 Update 不會被鎖等待SQL