qileilove

          blog已經(jīng)轉(zhuǎn)移至github,大家請(qǐng)?jiān)L問(wèn) http://qaseven.github.io/

          Oracle中SQL語(yǔ)句解析的步驟

           我們都知道在Oracle中每條SQL語(yǔ)句在執(zhí)行之前都需要經(jīng)過(guò)解析,這里面又分為軟解析和硬解析。那么這兩種解析有何不同之處呢?它們又分別是如何進(jìn)行解析呢?Oracle內(nèi)部解析的步驟又是如何進(jìn)行的呢?下面我們就這些話(huà)題進(jìn)行共同探討。
            在Oracle中存在兩種類(lèi)型的SQL語(yǔ)句,一類(lèi)為DDL語(yǔ)句,他們是從來(lái)不會(huì)共享使用的,也就是每次執(zhí)行都需要進(jìn)行硬解析。還有一類(lèi)就是DML語(yǔ)句,他們會(huì)根據(jù)情況選擇要么進(jìn)行硬解析,要么進(jìn)行軟解析。在Oracle 8i OCP教材的023中1-12有說(shuō)明SQL語(yǔ)句的解析步驟,當(dāng)一條SQL語(yǔ)句從客戶(hù)端進(jìn)程傳遞到服務(wù)器端進(jìn)程后,需要執(zhí)行如下步驟:
             在共享池中搜索 SQL 語(yǔ)句的現(xiàn)有副本
             驗(yàn)證 SQL 語(yǔ)句的語(yǔ)法是否準(zhǔn)確
             執(zhí)行數(shù)據(jù)字典查找來(lái)驗(yàn)證表和列的定義
             獲取對(duì)象的分析鎖以便在語(yǔ)句的分析過(guò)程中對(duì)象的定義不會(huì)改變
             檢查用戶(hù)訪問(wèn)引用方案對(duì)象的權(quán)限
             確定語(yǔ)句的最佳執(zhí)行計(jì)劃
             將語(yǔ)句和執(zhí)行計(jì)劃載入共享的 SQL 區(qū)
            這個(gè)先入為主的概念一直占據(jù)著我的腦海,我認(rèn)為硬解析就是上面幾個(gè)步驟。相對(duì)于硬解析,軟解析的步驟就是上面第一步找到現(xiàn)有SQL語(yǔ)句的副本后,只需要驗(yàn)證用戶(hù)是否有權(quán)限執(zhí)行就是了,這樣省略上面好幾個(gè)步驟,相對(duì)硬解析來(lái)說(shuō)性能開(kāi)銷(xiāo)就非常小了。即使是在論壇上和大家討論時(shí),我也一直堅(jiān)持這個(gè)看法。直到前一天看了Tom的《Effective Oracle By Design》中關(guān)于語(yǔ)句處理的章節(jié)后,我才知道這個(gè)自己一直堅(jiān)持的觀點(diǎn)事實(shí)上是錯(cuò)誤的。
            事實(shí)上,在Oracle中SQL語(yǔ)句的解析步驟如下:
            1、語(yǔ)法檢測(cè)。判斷一條SQL語(yǔ)句的語(yǔ)法是否符合SQL的規(guī)范,比如執(zhí)行:SQL> selet  *  from emp;我們就可以看出由于Select關(guān)鍵字少了一個(gè)“c”,這條語(yǔ)句就無(wú)法通過(guò)語(yǔ)法檢驗(yàn)的步驟了。
            2、語(yǔ)義檢查。語(yǔ)法正確的SQL語(yǔ)句在解析的第二個(gè)步驟就是判斷該SQL語(yǔ)句所訪問(wèn)的表及列是否準(zhǔn)確?用戶(hù)是否有權(quán)限訪問(wèn)或更改相應(yīng)的表或列?比如如下語(yǔ)句:
            SQL> select * from emp;
            select * from emp
            *
            ERROR at line 1:
            ORA-00942: table or view does not exist
            由于查詢(xún)用戶(hù)沒(méi)有可供訪問(wèn)的emp對(duì)象,因此該SQL語(yǔ)句無(wú)法通過(guò)語(yǔ)義檢查。
            3、檢查共享池中是否有相同的語(yǔ)句存在。假如執(zhí)行的SQL語(yǔ)句已經(jīng)在共享池中存在同樣的副本,那么該SQL語(yǔ)句將會(huì)被軟解析,也就是可以重用已解析過(guò)的語(yǔ)句的執(zhí)行計(jì)劃和優(yōu)化方案,可以忽略語(yǔ)句解析過(guò)程中最耗費(fèi)資源的步驟,這也是我們?yōu)槭裁匆恢睆?qiáng)調(diào)避免硬解析的原因。這個(gè)步驟又可以分為兩個(gè)步驟:
            (1、)驗(yàn)證SQL語(yǔ)句是否完全一致。在這個(gè)步驟中,Oracle將會(huì)對(duì)傳遞進(jìn)來(lái)的SQL語(yǔ)句使用HASH函數(shù)運(yùn)算得出HASH值,再與共享池中現(xiàn)有語(yǔ)句的HASH值進(jìn)行比較看是否一一對(duì)應(yīng)。現(xiàn)有數(shù)據(jù)庫(kù)中SQL語(yǔ)句的HASH值我們可以通過(guò)訪問(wèn)v$sql、v$sqlarea、v$sqltext等數(shù)據(jù)字典中的HASH_VALUE列查詢(xún)得出。如果SQL語(yǔ)句的HASH值一致,那么ORACLE事實(shí)上還需要對(duì)SQL語(yǔ)句的語(yǔ)義進(jìn)行再次檢測(cè),以決定是否一致。那么為什么Oracle需要再次對(duì)語(yǔ)句文本進(jìn)行檢測(cè)呢?不是SQL語(yǔ)句的HASH值已經(jīng)對(duì)應(yīng)上了?事實(shí)上就算是SQL語(yǔ)句的HASH值已經(jīng)對(duì)應(yīng)上了,并不能說(shuō)明這兩條SQL語(yǔ)句就已經(jīng)可以共享了。我們首先參考如下一個(gè)例子:
            假如用戶(hù)A有自己的一張表EMP,他要執(zhí)行查詢(xún)語(yǔ)句:select * from emp;用戶(hù)B也有一張EMP表,同樣要查詢(xún)select * from emp;這樣他們兩條語(yǔ)句在文本上是一模一樣的,他們的HASH值也會(huì)一樣,但是由于涉及到查詢(xún)的相關(guān)表不一樣,他們事實(shí)上是無(wú)法共享的。假如這時(shí)候用戶(hù)C又要查詢(xún)同樣一條語(yǔ)句,他查詢(xún)的表為scott下的公有同義詞,還有就是SCOTT也查詢(xún)同樣一張自己的表emp,情況會(huì)是如何呢?
          SQL> connect a/a
          Connected.
          SQL> create table emp ( x int );
          Table created.
          SQL> select * from emp;
          no rows selected
          SQL> connect b/b
          Connected.
          SQL> create table emp ( x int );
          Table created.
          SQL> select * from emp;
          no rows selected
          SQL> conn scott/tiger
          Connected.
          SQL> select * from emp;
          SQL> conn c/c
          Connected.
          SQL> select * from emp;
          SQL> conn/as sysdba
          Connected.
          SQL> select address,hash_value, executions, sql_text
          from v$sql
          where upper(sql_text) like 'SELECT * FROM EMP%'
          /
          ADDRESS  HASH_VALUE EXECUTIONS SQL_TEXT
          -------- ---------- ---------- ------------------------
          78B89E9C 3011704998          1 select * from emp
          78B89E9C 3011704998          1 select * from emp
          78B89E9C 3011704998          2 select * from emp
          ...
            我們可以看到這四個(gè)查詢(xún)的語(yǔ)句文本和HASH值都是一樣的,但是由于查詢(xún)的對(duì)象不同,只有后面兩個(gè)語(yǔ)句是可以共享的,不同情況的語(yǔ)句還是需要硬解析的。因此在檢查共享池共同SQL語(yǔ)句的時(shí)候,是需要根據(jù)具體情況而定的。
            我們可以進(jìn)一步查詢(xún)v$sql_shared_cursor以得知SQL為何不能共享的原因:
          SQL> select kglhdpar, address,
          auth_check_mismatch, translation_mismatch
          from v$sql_shared_cursor
          where kglhdpar in
          ( select address
          from v$sql
          where upper(sql_text) like 'SELECT * FROM EMP%' )
          /
          KGLHDPAR ADDRESS  A T
          -------- -------- - -
          78B89E9C 786C9D78 N N
          78B89E9C 786AC810 Y Y
          78B89E9C 786A11A4 Y Y
          ...
            TRANSLATION_MISMATCH表示SQL游標(biāo)涉及到的數(shù)據(jù)對(duì)象是不同的;AUTH_CHECK_MISMATCH表示對(duì)同樣一條SQL語(yǔ)句轉(zhuǎn)換是不匹配的。
            (2、)驗(yàn)證SQL語(yǔ)句執(zhí)行環(huán)境是否相同。比如同樣一條SQL語(yǔ)句,一個(gè)查詢(xún)會(huì)話(huà)加了/*+ first_rows */的HINT,另外一個(gè)用戶(hù)加/*+ all_rows */的HINT,他們就會(huì)產(chǎn)生不同的執(zhí)行計(jì)劃,盡管他們是查詢(xún)同樣的數(shù)據(jù)。我們下面就一個(gè)實(shí)例來(lái)說(shuō)明SQL執(zhí)行環(huán)境對(duì)解析的影響,我們通過(guò)將會(huì)話(huà)的workarea_size_policy變更來(lái)查看對(duì)同樣一條SQL語(yǔ)句執(zhí)行的影響:
          SQL> alter system flush shared_pool;
          System altered.
          SQL> show parameter workarea_size_policy
          NAME                                 TYPE        VALUE
          ------------------------------------ ----------- --------------
          workarea_size_policy                 string      AUTO
          SQL> select count(*) from t;
          COUNT(*)
          ----------
          5736
          SQL> alter session set workarea_size_policy=manual;
          Session altered.
          SQL> select count(*) from t;
          COUNT(*)
          ----------
          5736
          SQL> select sql_text, child_number, hash_value, address
          from v$sql
          where upper(sql_text) = 'SELECT COUNT(*) FROM T'
          /
          SQL_TEXT                       CHILD_NUMBER HASH_VALUE ADDRESS
          ------------------------------ ------------ ---------- --------
          select count(*) from t                    0 2199322426 78717328
          select count(*) from t                    1 2199322426 78717328
          ...
            可以看到由于不同會(huì)話(huà)workarea_size_policy設(shè)置得不同,即使是同樣一條SQL語(yǔ)句還是無(wú)法共享的。通過(guò)進(jìn)一步查詢(xún)v$sql_shared_cursor我們可以發(fā)現(xiàn)兩個(gè)會(huì)話(huà)的優(yōu)化器環(huán)境是不同的:
          SQL>selectoptimizer_mismatch
          fromv$sql_shared_cursor
          wherekglhdparin
          (selectaddress
          fromv$sql
          whereupper(sql_text)='SELECTCOUNT(*)FROMT');
          O
          -
          N
          Y
          ...
            通過(guò)如上三個(gè)步驟檢查以后,如果SQL語(yǔ)句是一致的,那么就會(huì)重用原有SQL語(yǔ)句的執(zhí)行計(jì)劃和優(yōu)化方案,也就是我們通常所說(shuō)的軟解析。如果SQL語(yǔ)句沒(méi)有找到同樣的副本,那么就需要進(jìn)行硬解析了。
            4、Oracle根據(jù)提交的SQL語(yǔ)句再查詢(xún)相應(yīng)的數(shù)據(jù)對(duì)象是否有統(tǒng)計(jì)信息。如果有統(tǒng)計(jì)信息的話(huà),那么CBO將會(huì)使用這些統(tǒng)計(jì)信息產(chǎn)生所有可能的執(zhí)行計(jì)劃(可能多達(dá)成千上萬(wàn)個(gè))和相應(yīng)的Cost,最終選擇Cost最低的那個(gè)執(zhí)行計(jì)劃。如果查詢(xún)的數(shù)據(jù)對(duì)象無(wú)統(tǒng)計(jì)信息,則按RBO的默認(rèn)規(guī)則選擇相應(yīng)的執(zhí)行計(jì)劃。這個(gè)步驟也是解析中最耗費(fèi)資源的,因此我們應(yīng)該極力避免硬解析的產(chǎn)生。至此,解析的步驟已經(jīng)全部完成,Oracle將會(huì)根據(jù)解析產(chǎn)生的執(zhí)行計(jì)劃執(zhí)行SQL語(yǔ)句和提取相應(yīng)的數(shù)據(jù)。

          posted on 2014-07-15 10:31 順其自然EVO 閱讀(222) 評(píng)論(0)  編輯  收藏


          只有注冊(cè)用戶(hù)登錄后才能發(fā)表評(píng)論。


          網(wǎng)站導(dǎo)航:
           
          <2014年7月>
          293012345
          6789101112
          13141516171819
          20212223242526
          272829303112
          3456789

          導(dǎo)航

          統(tǒng)計(jì)

          常用鏈接

          留言簿(55)

          隨筆分類(lèi)

          隨筆檔案

          文章分類(lèi)

          文章檔案

          搜索

          最新評(píng)論

          閱讀排行榜

          評(píng)論排行榜

          主站蜘蛛池模板: 罗源县| 汾西县| 铜山县| 阿城市| 和顺县| 嘉定区| 阳江市| 鄂州市| 故城县| 洱源县| 鱼台县| 沅陵县| 米易县| 海晏县| 务川| 北宁市| 蓬安县| 兴义市| 达孜县| 吉首市| 东安县| 柘城县| 应城市| 长子县| 将乐县| 安平县| 迭部县| 桐梓县| 镇平县| 全南县| 邯郸市| 湄潭县| 五常市| 鹤庆县| 漠河县| 台山市| 北辰区| 韶山市| 江达县| 且末县| 延吉市|