oracle學(xué)習(xí)筆記2:SQL執(zhí)行

數(shù)據(jù)庫原理理解
oracle 體系結(jié)構(gòu)

共享池是oracle緩存程序數(shù)據(jù)的地方
庫高速緩存:執(zhí)行過的每一句SQL語句捆交,都存有解析后的內(nèi)容
解析包括語句的語法进萄,檢驗(yàn)提及的對(duì)象缤骨,以及確認(rèn)對(duì)象的用戶權(quán)限上鞠。
數(shù)據(jù)字典高速緩存區(qū):oracle使用的系統(tǒng)參數(shù)
使用最近最少使用算法(Least Recently Used, LRU),用來管理共享池中的對(duì)象。
寫SQL語句時(shí)顶岸,一定要考慮如果高效的使用共享池腔彰。

共享池
SQL> select sql_text,sql_id,child_number,hash_value,executions from v$sql where upper(sql_text) like '%EMPLOYEES%';
 
SQL_TEXT                                                                         SQL_ID        CHILD_NUMBER HASH_VALUE EXECUTIONS
-------------------------------------------------------------------------------- ------------- ------------ ---------- ----------
 select * from employees where department_id=60                                  3advtjun8csb4            0 2827379044          3
 select /* a comment */ * from employees where department_id=60                  fs9k1uvtkk817            0 4079558695          1
 SELECT * FROM EMPLOYEES WHERE DEPARTMENT_ID=60                                  86sbrvcmd3mv5            0  651284325          1

三條語句,返回相同的結(jié)果辖佣,但oracle認(rèn)為他們是不同的霹抛,因?yàn)閛racle首先將字符串轉(zhuǎn)換為散列值。這個(gè)散列值就是放在庫高速緩存中的關(guān)鍵字卷谈。

在解析中綁定變量

SQL> variable v_dept number
SQL> exec :v_dept := 10
SQL> select * from employees where department_id = :v_dept;
SQL> exec :v_dept := 60
SQL> select * from employees where department_id = :v_dept;

鎖存器是oracle為了讀取存放在庫高速緩存或者其它內(nèi)存結(jié)構(gòu)中的信息時(shí)必須獲得的一種鎖杯拐。鎖存器可以保護(hù)庫高速速緩存或其它內(nèi)存結(jié)構(gòu)中的信息被兩個(gè)同時(shí)進(jìn)行的會(huì)話修改,或一個(gè)會(huì)話正要讀取的信息被另一個(gè)會(huì)話修改而導(dǎo)致的損壞世蔗。

互拆鎖:是一個(gè)序列化組件端逼,用來阻止多個(gè)線程同時(shí)訪問一個(gè)共享結(jié)構(gòu)。優(yōu)點(diǎn)是占用內(nèi)存少污淋,可以快速獲取或釋放裳食。
語法解析仍然要使用鎖存器。

oracle獲取鎖存器的頻率越多芙沥,越可能觸發(fā)爭(zhēng)奪诲祸。越需要等待較長的時(shí)間浊吏。因此正確編寫代碼,較少使用鎖存器救氯,也就是硬解析找田,是非常重要的。

Paste_Image.png

測(cè)試物理讀和邏輯讀
E:\plustrce.sql

set echo on

drop role plustrace;
create role plustrace;

grant select on v_$sesstat to plustrace;
grant select on v_$statname to plustrace;
grant select on v_$mystat to plustrace;
grant plustrace to dba with admin option;

set echo off
SQL> conn sys/0524 as sysdba;
SQL> @'E:\plustrce.sql'
SQL>grant plustrace to scott;
SQL> grant all on employees to scott;
SQL> conn scott/scott
SQL> alter system flush buffer_cache;
SQL> alter system flush shared_pool;
SQL> set autotrace traceonly statistics;
SQL> select * from employees where department_id=60;
SQL> set autotrace off;
SQL> alter system flush buffer_cache;
SQL> alter system flush shared_pool;
SQL> set autotrace traceonly statistics;
SQL> select * from employees where department_id=60;
SQL> set autotrace off;

應(yīng)開發(fā)出更多重用共享池和緩沖區(qū)緩存中信息的代碼着憨。

查詢轉(zhuǎn)換

發(fā)生在查詢執(zhí)行完語法和權(quán)限檢查之后墩衙,優(yōu)化器為了決定最終的執(zhí)行計(jì)劃而為不同的計(jì)劃計(jì)算成本預(yù)估之前。轉(zhuǎn)換和優(yōu)化是兩個(gè)不同的任務(wù)甲抖。

  • 視圖合并
    --對(duì)于大多數(shù)select-project-join(SPJ)類型查詢會(huì)自動(dòng)應(yīng)用簡(jiǎn)單視圖合并
    select *
    from orders o, (select sales_rep_id from orders) o_view
    where o.sales_rep_id = o_view.sales_rep_id(+)
    and o.order_total > 10000;
    
    --不使用提示
    select *
    from orders o, (select /*+ NO_MERGE */ sales_rep_id from orders) o_view
    where o.sales_rep_id = o_view.sales_rep_id(+)
    and o.order_total > 10000;
    
    --不使用提示
    --當(dāng)查詢包含聚合計(jì)算如group by, distinct或外關(guān)聯(lián)時(shí)漆改,就會(huì)使用復(fù)雜的視圖合并,從而消除包含聚合計(jì)算的視圖准谚,使用更少的資源生成結(jié)果集挫剑。
    select e1.last_name,e1.salary,v.avg_salary
    from employees e1,
    (select  department_id,avg(salary) avg_salary from employees e2 group by department_id) v
    where e1.department_id=v.department_id and e1.salary>v.avg_salary;
    
    --使用merge提示
    select /*+ MERGE(v) */ e1.last_name,e1.salary,v.avg_salary
    from employees e1,
    (select  department_id,avg(salary) avg_salary from employees e2 group by department_id) v
    where e1.department_id=v.department_id and e1.salary>v.avg_salary;
    
    --關(guān)閉_complex_view_merging
    alter session set "_complex_view_merging"=FALSE;
    
    
    explain plan for 
    select /*+ MERGE(v) */ e1.last_name,e1.salary,v.avg_salary
    from employees e1,
    (select  department_id,avg(salary) avg_salary from employees e2 group by department_id) v
    where e1.department_id=v.department_id and e1.salary>v.avg_salary;
    select * from table(dbms_xplan.display);
    --如果_complex_view_merging=False,即使用了MERGE,也不會(huì)進(jìn)行視圖合并
  • 子查詢解嵌套
    --不相關(guān)子查詢的解嵌套轉(zhuǎn)換

    select *
      from employees
     where employee_id in (select manager_id from departments);

    explain plan for 
    select *
      from employees
     where employee_id in (select manager_id from departments);

    select * from table(dbms_xplan.display);

    --使用NO_UNNEST提示
    --不進(jìn)行查詢轉(zhuǎn)換將會(huì)選用filter運(yùn)算而不是nested loops連接 filter效率更低
    select *
      from employees
     where employee_id in (select /*+ NO_UNNEST */ manager_id from departments);

    explain plan for
    select *
      from employees
     where employee_id in (select /*+ NO_UNNEST */ manager_id from departments);
     
     select * from table(dbms_xplan.display);
    --相關(guān)子查詢的解嵌套轉(zhuǎn)換
    select outer.employee_id,
           outer.last_name,
           outer.salary,
           outer.department_id
      from employees outer 
      where outer.salary >
                 (select avg(inner.salary)
                    from employees
                   inner where inner.department_id = outer.department_id);
                   

    explain plan for
    select outer.employee_id,
           outer.last_name,
           outer.salary,
           outer.department_id
      from employees outer 
      where outer.salary >
                 (select avg(inner.salary)
                    from employees
                   inner where inner.department_id = outer.department_id);

    select * from table(dbms_xplan.display);
    --相關(guān)列變成了聯(lián)結(jié)條件而子查詢的剩余部分用來生成內(nèi)嵌視圖
  • 聯(lián)結(jié)消除
    --主外鍵表消除
    select e.*
      from employees e, departments d
     where e.department_id = d.department_id;

    explain plan for
      select e.*
        from employees e, departments d
       where e.department_id = d.department_id;

    select * from table(dbms_xplan.display);

departments表的聯(lián)結(jié)是如何完全消除的柱衔,之所以能夠消除樊破,是因?yàn)閐epartments表中沒有任何一列出現(xiàn)在查詢列表中。并且由于主-外鍵約束唆铐,使得對(duì)于employees表中的每一行哲戚,在departments表中最多有一行匹配的記錄。

/*
外聯(lián)結(jié)表消除 外聯(lián)表確保employees表中的每一行在結(jié)果集中至少出現(xiàn)一次艾岂,在jobs.job_id列上的唯一健約束顺少,確保了對(duì)于employees表中的
每一行,在jobs表中最多有一行與之相匹配王浴。這兩個(gè)屬性保證了employees表中的每一行在結(jié)果集中出現(xiàn)并且僅出現(xiàn)一次祈纯。
*/
  select e.first_name, e.last_name, e.job_id
    from employees e, jobs j
   where e.job_id = j.job_id(+);
  
  explain plan for
    select e.first_name, e.last_name, e.job_id
      from employees e, jobs j
     where e.job_id = j.job_id(+);
  
  select * from table(dbms_xplan.display);

Note:
如果在查詢的任何地方使用了聯(lián)結(jié)鍵,則不支持聯(lián)結(jié)消除叼耙。
如果主外鍵約束包含多個(gè)列,則不支持聯(lián)結(jié)消除粒没。

  • 排序消除
--order by消除
select count(*)
  from (select d.department_name
          from departments d
         where d.manager_id = 7
         order by d.department_name);

explain plan for
  select count(*)
    from (select d.department_name
            from departments d
           where d.manager_id = 7
           order by d.department_name);

select * from table(dbms_xplan.display);

--使用no_query_transformation提示筛婉,讓優(yōu)華器不要對(duì)查詢進(jìn)行移除排序的轉(zhuǎn)換
select /*+ no_query_transformation */
 count(*)
  from (select d.department_name
          from departments d
         where d.manager_id = 7
         order by d.department_name);

explain plan for
  select /*+ no_query_transformation */
   count(*)
    from (select d.department_name
            from departments d
           where d.manager_id = 7
           order by d.department_name);

select * from table(dbms_xplan.display);
  • 謂詞推進(jìn)
--謂詞推進(jìn)
select e1.last_name, e1.salary, v.avg_salary
  from employees e1,
       (select department_id, avg(salary) avg_salary
          from employees e2
         group by department_id) v
 where e1.department_id = v.department_id
   and e1.salary > v.avg_salary
   and e1.department_id = 60;

explain plan for
  select e1.last_name, e1.salary, v.avg_salary
    from employees e1,
         (select department_id, avg(salary) avg_salary
            from employees e2
           group by department_id) v
   where e1.department_id = v.department_id
     and e1.salary > v.avg_salary
     and e1.department_id = 60;

select * from table(dbms_xplan.display);

--rownum不僅會(huì)禁止謂詞推進(jìn),而且也會(huì)禁止視圖合并
select e1.last_name, e1.salary, v.avg_salary
  from employees e1,
       (select department_id, avg(salary) avg_salary
          from employees e2
         where rownum > 1 --rownum prohibits predicate pushing!
         group by department_id) v
 where e1.department_id = v.department_id
   and e1.salary > v.avg_salary
   and e1.department_id = 60;
explain plan for
  select e1.last_name, e1.salary, v.avg_salary
    from employees e1,
         (select department_id, avg(salary) avg_salary
            from employees e2
           where rownum > 1 --rownum prohibits predicate pushing!
           group by department_id) v
   where e1.department_id = v.department_id
     and e1.salary > v.avg_salary
     and e1.department_id = 60;

select * from table(dbms_xplan.display);

  • 使用物化視圖重寫查詢

--準(zhǔn)備測(cè)試數(shù)據(jù)
drop table sales;
create table sales(
channel_id number,
promo_id number,
cust_id number,
amount_sold  number,
time_id number,
prod_id number
);
drop table products;
create table products(
prod_id number,
prod_name varchar2(20)
);
drop table times;
create table times(
time_id number,
week_ending_day number
);

insert into products values(1,'衣服');
insert into products values(2,'鞋子');
insert into products values(3,'褲子');

insert into times values(1,1);
insert into times values(2,3);
insert into times values(3,5);

insert into sales values(1,1,1000,500,1,1);
insert into sales values(1,1,1000,500,2,2);
insert into sales values(1,1,1000,500,3,3);
insert into sales values(1,1,1000,500,1,3);
insert into sales values(1,1,1000,500,2,2);

--使用物化視圖進(jìn)行查詢重寫
select p.prod_id,
       p.prod_name,
       t.time_id,
       t.week_ending_day,
       s.channel_id,
       s.promo_id,
       s.cust_id,
       s.amount_sold
  from sales s, products p, times t
 where s.time_id = t.time_id
   and s.prod_id = p.prod_id;
   
   explain plan for
   select p.prod_id,
       p.prod_name,
       t.time_id,
       t.week_ending_day,
       s.channel_id,
       s.promo_id,
       s.cust_id,
       s.amount_sold
  from sales s, products p, times t
 where s.time_id = t.time_id
   and s.prod_id = p.prod_id;
   
   select * from table(dbms_xplan.display);

create materialized view sales_time_product_mv
enable query rewrite as 
  select p.prod_id,
       p.prod_name,
       t.time_id,
       t.week_ending_day,
       s.channel_id,
       s.promo_id,
       s.cust_id,
       s.amount_sold
  from sales s, products p, times t
 where s.time_id = t.time_id
   and s.prod_id = p.prod_id;
 
 select /*+ rewrite(sales_time_product_mv) */
  p.prod_id,
  p.prod_name,
  t.time_id,
  t.week_ending_day,
  s.channel_id,
  s.promo_id,
  s.cust_id,
  s.amount_sold
   from sales s, products p, times t
  where s.time_id = t.time_id
    and s.prod_id = p.prod_id;
    
 --rewrite提示來打開查詢重寫轉(zhuǎn)換
 --通過guery-rewrite_enabled參數(shù)默認(rèn)啟用的
 
 explain plan for
   select /*+ rewrite(sales_time_product_mv) */
    p.prod_id,
    p.prod_name,
    t.time_id,
    t.week_ending_day,
    s.channel_id,
    s.promo_id,
    s.cust_id,
    s.amount_sold
     from sales s, products p, times t
    where s.time_id = t.time_id
      and s.prod_id = p.prod_id;
 
 select * from table(dbms_xplan.display);

當(dāng)發(fā)生硬解析時(shí)癞松,oracle將會(huì)確定哪個(gè)計(jì)劃對(duì)于該查詢是最優(yōu)的爽撒。就是oracle訪問查詢所使用的對(duì)象并返回相應(yīng)結(jié)果數(shù)據(jù)將會(huì)采用的一系列步驟。
統(tǒng)計(jì)信息包括針對(duì)對(duì)象如表和索引收集統(tǒng)計(jì)信息响蓉,系統(tǒng)統(tǒng)計(jì)信息硕勿。
優(yōu)化器是oracle內(nèi)核中的代碼路徑,負(fù)責(zé)為查詢確定最佳執(zhí)行計(jì)劃(使用統(tǒng)計(jì)信息)枫甲。

執(zhí)行一個(gè)SQL查詢源武,解析扼褪,綁定,執(zhí)行粱栖,提取的步驟话浇。

一次fetch調(diào)用將會(huì)訪問緩沖區(qū)緩存中的一個(gè)或多個(gè)數(shù)據(jù)塊。每次訪問一個(gè)數(shù)據(jù)塊時(shí)闹究,oracle都會(huì)從該塊中取出數(shù)據(jù)行然后在一次回路中返回給客戶端幔崖。一次返回的行數(shù)是可配置的。
SQL*Plus 默認(rèn)為15, 通過 set arraysize n來更改
jdbc 默認(rèn)為10, 通過 ((OracleConnection)conn).setDefaultRowPrefetch(n)來更改渣淤。

列大小是如影響邏輯讀取的

SQL> set arraysize 5
SQL> select * from employees;

已選擇9行赏寇。


統(tǒng)計(jì)信息
----------------------------------------------------------
          0  recursive calls
          0  db block gets
          9  consistent gets
          0  physical reads
          0  redo size
       1282  bytes sent via SQL*Net to client
        427  bytes received via SQL*Net from client
          3  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
          9  rows processed

SQL> set arraysize 15
SQL> select * from employees;

已選擇9行。


統(tǒng)計(jì)信息
----------------------------------------------------------
          0  recursive calls
          0  db block gets
          8  consistent gets
          0  physical reads
          0  redo size
       1152  bytes sent via SQL*Net to client
        416  bytes received via SQL*Net from client
          2  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
          9  rows processed

SQL> set arraysize 45
SQL> select * from employees;

已選擇9行价认。


統(tǒng)計(jì)信息
----------------------------------------------------------
          0  recursive calls
          0  db block gets
          8  consistent gets
          0  physical reads
          0  redo size
       1152  bytes sent via SQL*Net to client
        416  bytes received via SQL*Net from client
          2  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
          9  rows processed

SQL語句執(zhí)行時(shí)的步驟匯總

Reference:

Oracle Concepts Guide

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末嗅定,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子刻伊,更是在濱河造成了極大的恐慌露戒,老刑警劉巖,帶你破解...
    沈念sama閱讀 207,248評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件捶箱,死亡現(xiàn)場(chǎng)離奇詭異智什,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)丁屎,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,681評(píng)論 2 381
  • 文/潘曉璐 我一進(jìn)店門荠锭,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人晨川,你說我怎么就攤上這事证九。” “怎么了共虑?”我有些...
    開封第一講書人閱讀 153,443評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵愧怜,是天一觀的道長。 經(jīng)常有香客問我妈拌,道長拥坛,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,475評(píng)論 1 279
  • 正文 為了忘掉前任尘分,我火速辦了婚禮猜惋,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘培愁。我一直安慰自己著摔,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,458評(píng)論 5 374
  • 文/花漫 我一把揭開白布定续。 她就那樣靜靜地躺著谍咆,像睡著了一般禾锤。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上卧波,一...
    開封第一講書人閱讀 49,185評(píng)論 1 284
  • 那天时肿,我揣著相機(jī)與錄音,去河邊找鬼港粱。 笑死螃成,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的查坪。 我是一名探鬼主播寸宏,決...
    沈念sama閱讀 38,451評(píng)論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼偿曙!你這毒婦竟也來了氮凝?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,112評(píng)論 0 261
  • 序言:老撾萬榮一對(duì)情侶失蹤望忆,失蹤者是張志新(化名)和其女友劉穎罩阵,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體启摄,經(jīng)...
    沈念sama閱讀 43,609評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡稿壁,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,083評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了歉备。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片傅是。...
    茶點(diǎn)故事閱讀 38,163評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖蕾羊,靈堂內(nèi)的尸體忽然破棺而出喧笔,到底是詐尸還是另有隱情,我是刑警寧澤龟再,帶...
    沈念sama閱讀 33,803評(píng)論 4 323
  • 正文 年R本政府宣布书闸,位于F島的核電站,受9級(jí)特大地震影響利凑,放射性物質(zhì)發(fā)生泄漏浆劲。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,357評(píng)論 3 307
  • 文/蒙蒙 一截碴、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧蛉威,春花似錦日丹、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,357評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽丙躏。三九已至,卻和暖如春束凑,著一層夾襖步出監(jiān)牢的瞬間晒旅,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,590評(píng)論 1 261
  • 我被黑心中介騙來泰國打工汪诉, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留废恋,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,636評(píng)論 2 355
  • 正文 我出身青樓扒寄,卻偏偏與公主長得像鱼鼓,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子该编,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,925評(píng)論 2 344

推薦閱讀更多精彩內(nèi)容