<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    Decode360's Blog

    業(yè)精于勤而荒于嬉 QQ:150355677 MSN:decode360@hotmail.com

      BlogJava :: 首頁 :: 新隨筆 :: 聯(lián)系 ::  :: 管理 ::
      397 隨筆 :: 33 文章 :: 29 評(píng)論 :: 0 Trackbacks
    min/max函數(shù)的index問題
    ?
    ??? 在查詢某表時(shí)同時(shí)使用了min和max函數(shù),結(jié)果查詢很慢,但是單獨(dú)執(zhí)行min或者max時(shí)速度很快,建個(gè)環(huán)境模擬一下:
    ?
    create table t1_t(a int,b varchar2(50));
    ?
    insert into t1_t(a,b) (select mod(rownum,50) rn,object_name from user_objects);
    insert into t1_t(a,b) (select * from t1_t);
    insert into t1_t(a,b) (select * from t1_t);
    insert into t1_t(a,b) (select * from t1_t);
    insert into t1_t(a,b) (select * from t1_t);
    ?
    commit;
    ?
    create index t1_a_index on t1_t(a);
    create index t1_b_index on t1_t(b);
    ?
    ?
    select min(a) from t1_t;
    ?
    Execution Plan
    ----------------------------------------------------------
    ?? 0????? SELECT STATEMENT Optimizer=ALL_ROWS (Cost=3242 Card=1 Bytes=3)
    ?? 1??? 0?? SORT (AGGREGATE)
    ?? 2??? 1???? INDEX (FULL SCAN (MIN/MAX)) OF 'T1_T_INDEX' (INDEX)
    ?
    --只有min函數(shù)時(shí)是走索引的
    ?
    select min(a),max(a) from t1_t;
    Execution Plan
    ----------------------------------------------------------
    ?? 0????? SELECT STATEMENT Optimizer=ALL_ROWS (Cost=3242 Card=1 Bytes=3)
    ?? 1??? 0?? SORT (AGGREGATE)
    ?? 2??? 1???? TABLE ACCESS (FULL) OF 'T1_T' (TABLE) (Cost=3242 Card=3591122 Bytes=10773366)
    ?
    --兩個(gè)一起的時(shí)候就全表掃描了
    ?
    ?
    ??? INDEX (FULL SCAN (MIN/MAX))算法:如果是Max,首先沿著最右邊的Root-Branch Node-Leaf Node,發(fā)現(xiàn)最右邊的Leaf Block是空的,于是沿著逆向指針往左走,一直走到最左邊發(fā)現(xiàn)都是空的,于是掃描了所有的Leaf Blocks。如果是Min,首先沿著最左邊的Root-Branch Node-Leaf Node,發(fā)現(xiàn)最左邊的Leaf Block是空的,于是沿著順向指針往右走,走到最右邊發(fā)現(xiàn)都是空的,掃描了所有的Leaf blocks。
    ?
    ?
    ?
    ??? 但是如何讓min、max同時(shí)查詢時(shí)走索引?似乎不可以,以下轉(zhuǎn)載一篇非常詳細(xì)的說明文檔:
    ???
    http://zhyuh.itpub.net/get/334/mix_max_index
    =============================================================================================
    ?
    Table sbfi_ctry_flow_curve_wheel有大約1500萬條記錄,運(yùn)行下面的sql需要4秒鐘左右,developer認(rèn)為時(shí)間太長(zhǎng),想優(yōu)化。
    SQL>select min(trade_dt), max(trade_dt) from sbfi_ctry_flow_curve_wheel;
    developer很奇怪,trade_dt列上建有一個(gè)索引,但是執(zhí)行的時(shí)候,oracle總是選擇走primary key,而不選擇那個(gè)索引。
    ?
    經(jīng)檢查,發(fā)現(xiàn)表sbfi_ctry_flow_curve_wheel的索引情況如下:
    SQL> list
    ? 1? select index_name,column_name,column_position from user_ind_columns
    ? 2? where table_name=upper('sbfi_ctry_flow_curve_wheel')
    ? 3? order by 1
    ? 4* ,3
    SQL> /
    ?
    INDEX_NAME???????????????????? COLUMN_NAME? COLUMN_POSITION
    ------------------------------ ------------ ---------------
    SBFI_CTRY_FLOW_CURVE_WHEEL_PK? TRADE_DT?????????????????? 1
    SBFI_CTRY_FLOW_CURVE_WHEEL_PK? CTRY_CODE????????????????? 2
    SBFI_CTRY_FLOW_CURVE_WHEEL_PK? MONTH????????????????????? 3
    TRADE_DT_INDEX???????????????? TRADE_DT?????????????????? 1
    ?
    嘗試加hint /*+ index(sbfi_ctry_flow_curve_wheel TRADE_DT_INDEX) */,讓oracle選擇走索引TRADE_DT_INDEX。結(jié)果發(fā)現(xiàn)運(yùn)行時(shí)間沒有縮短,反而從4秒增加到7秒。
    SQL> select /*+ index(sbfi_ctry_flow_curve_wheel TRADE_DT_INDEX) */ min(trade_dt), max(trade_dt) from bfi_ctry_flow_curve_wheel;
    ?
    MIN(TRADE MAX(TRADE
    --------- ---------
    01-JAN-01 07-SEP-07
    ?
    Elapsed: 00:00:06.91
    ?
    為什么會(huì)出現(xiàn)這種情況?我們嘗試用TRACE去跟蹤執(zhí)行過程。
    ==session 1, don't use hint
    alter session set timed_statistics=true
    /
    alter session set max_dump_file_size=unlimited
    /
    alter session set tracefile_identifier='PRIMARY_KEY'
    /
    alter session set events '10046 trace name context forever, level 12'
    /
    select min(trade_dt), max(trade_dt) from sbfi_ctry_flow_curve_wheel
    /
    alter session set events '10046 trace name context off'
    /
    ?
    ==session 2, use hint
    alter session set timed_statistics=true
    /
    alter session set max_dump_file_size=unlimited
    /
    alter session set tracefile_identifier='TRADE_DT_INDEX'
    /
    alter session set events '10046 trace name context forever, level 12'
    /
    select /*+ index(sbfi_ctry_flow_curve_wheel TRADE_DT_INDEX) */ min(trade_dt), max(trade_dt) from sbfi_ctry_flow_curve_wheel
    /
    alter session set events '10046 trace name context off'
    /
    ?
    兩種情況的trace用tkprof分析后,主要部分結(jié)果如下:
    ==session1, don't use hint
    ********************************************************************************
    select min(trade_dt), max(trade_dt)
    from
    sbfi_ctry_flow_curve_wheel
    ?

    call???? count?????? cpu??? elapsed?????? disk????? query??? current??????? rows
    ------- ------? -------- ---------- ---------- ---------- ----------? ----------
    Parse??????? 1????? 0.00?????? 0.34????????? 0????????? 0????????? 0?????????? 0
    Execute????? 1????? 0.00?????? 0.00????????? 0????????? 0????????? 0?????????? 0
    Fetch??????? 2????? 2.14?????? 3.84????? 26044????? 26067????????? 0?????????? 1
    ------- ------? -------- ---------- ---------- ---------- ----------? ----------
    total??????? 4????? 2.14?????? 4.18????? 26044????? 26067????????? 0?????????? 1
    ?
    Misses in library cache during parse: 1
    Optimizer mode: CHOOSE
    Parsing user id: 89?
    ?
    Rows???? Row Source Operation
    -------? ---------------------------------------------------
    ????? 1? SORT AGGREGATE
    7538400?? INDEX FAST FULL SCAN SBFI_CTRY_FLOW_CURVE_WHEEL_PK (object id 35844)
    ?

    Elapsed times include waiting on following events:
    ? Event waited on???????????????????????????? Times?? Max. Wait? Total Waited
    ? ----------------------------------------?? Waited? ----------? ------------
    ? SQL*Net message to client?????????????????????? 2??????? 0.00????????? 0.00
    ? db file scattered read?????????????????????? 1649??????? 0.14????????? 2.26
    ? SQL*Net message from client???????????????????? 2??????? 4.15????????? 4.15
    ********************************************************************************
    ?
    ==session2, use hint
    ********************************************************************************
    select /*+ index(sbfi_ctry_flow_curve_wheel TRADE_DT_INDEX) */ min(trade_dt),
    ? max(trade_dt)
    from
    sbfi_ctry_flow_curve_wheel
    ?

    call???? count?????? cpu??? elapsed?????? disk????? query??? current??????? rows
    ------- ------? -------- ---------- ---------- ---------- ----------? ----------
    Parse??????? 1????? 0.00?????? 0.00????????? 0????????? 0????????? 0?????????? 0
    Execute????? 1????? 0.00?????? 0.00????????? 0????????? 0????????? 0?????????? 0
    Fetch??????? 2????? 3.21?????? 8.84????? 19945????? 19945????????? 0?????????? 1
    ------- ------? -------- ---------- ---------- ---------- ----------? ----------
    total??????? 4????? 3.21?????? 8.85????? 19945????? 19945????????? 0?????????? 1
    ?
    Misses in library cache during parse: 1
    Optimizer mode: CHOOSE
    Parsing user id: 89?
    ?
    Rows???? Row Source Operation
    -------? ---------------------------------------------------
    ????? 1? SORT AGGREGATE
    7538400?? INDEX FULL SCAN TRADE_DT_INDEX (object id 35830)
    ?

    Elapsed times include waiting on following events:
    ? Event waited on???????????????????????????? Times?? Max. Wait? Total Waited
    ? ----------------------------------------?? Waited? ----------? ------------
    ? SQL*Net message to client?????????????????????? 2??????? 0.00????????? 0.00
    ? db file sequential read???????????????????? 19945??????? 0.05????????? 5.93
    ? SQL*Net message from client???????????????????? 2??????? 6.10????????? 6.10?
    ********************************************************************************
    ?
    對(duì)比后主要的不同羅列如下:
    走primary key, consistent read,即query值為 26067,fetch時(shí)間為3.84秒,訪問主鍵索引的方法為INDEX FAST FULL SCAN。
    走TRADE_DT_INDEX索引,consistent read值為19945, fetch時(shí)間為8.84秒,訪問索引TRADE_DT_INDEX的方法為INDEX FULL SCAN。
    ?
    關(guān)于INDEX FAST FULL SCAN,oracle文檔中解釋如下:
    Fast full index scans are an alternative to a full table scan when the index contains all the columns that are needed for the query, and at least one column in the index key has the NOT NULL constraint. A fast full scan accesses the data in the index itself, without accessing the table. It cannot be used to eliminate a sort operation, because the data is not ordered by the index key. It reads the entire index using multiblock reads, unlike a full index scan, and can be parallelized.
    You can specify fast full index scans with the initialization parameter OPTIMIZER_FEATURES_ENABLE or the INDEX_FFS hint. Fast full index scans cannot be performed against bitmap indexes.
    A fast full scan is faster than a normal full index scan in that it can use multiblock I/O and can be parallelized just like a table scan.
    ?
    關(guān)于INDEX FAST FULL SCAN:
    A full scan is available if a predicate references one of the columns in the index. The predicate does not need to be an index driver. A full scan is also available when there is no predicate, if both the following conditions are met:
    All of the columns in the table referenced in the query are included in the index.
    At least one of the index columns is not null.
    A full scan can be used to eliminate a sort operation, because the data is ordered by the index key. It reads the blocks singly.
    ?
    上面明確講到了fast full scan比full scan要快,因?yàn)樗胢ultiblock I/O,而且可以parallelized。
    順便也注意到要調(diào)優(yōu)的這句sql,只返回trade_dt列的值,滿足index (fast) full scan的條件,即返回結(jié)果的列全都包含在索引里,非空。所以該sql只要掃描索引就能返回需要的結(jié)果,不需要再根據(jù)rowid去訪問表。
    ?
    既然要掃描整個(gè)索引,F(xiàn)AST FULL SCAN 比 FULL SCAN 快,TRADE_DT_INDEX 的 size 比 PK 的 size 小,那對(duì) RADE_DT_INDEX 做FFS應(yīng)該是最快的訪問路徑。用index_ffs hint:
    SQL> select /*+ index_ffs(sbfi_ctry_flow_curve_wheel TRADE_DT_INDEX) */ min(trade_dt), max(trade_dt) from bfi_ctry_flow_curve_wheel;
    ?
    MIN(TRADE MAX(TRADE
    --------- ---------
    01-JAN-01 07-SEP-07
    ?
    Elapsed: 00:00:02.61
    ?
    相比上面的4秒和7秒是快了一些。
    ?
    但是根據(jù)一般的理解,象min(),max()這樣的函數(shù),Oracle應(yīng)該直接訪問索引的最左邊或者最右邊,這樣的訪問速度才是最快的。嘗試SQL>select min(trade_dt) from sbfi_ctry_flow_curve_wheel并生成10046 trace文件,用tkprof格式化后結(jié)果如下:
    ?
    ==session 3, single function
    ********************************************************************************
    select max(trade_dt)
    from
    sbfi_ctry_flow_curve_wheel
    ?

    call???? count?????? cpu??? elapsed?????? disk????? query??? current??????? rows
    ------- ------? -------- ---------- ---------- ---------- ----------? ----------
    Parse??????? 2????? 0.00?????? 0.00????????? 0????????? 0????????? 0?????????? 0
    Execute????? 2????? 0.00?????? 0.00????????? 0????????? 0????????? 0?????????? 0
    Fetch??????? 4????? 0.00?????? 0.00????????? 0????????? 6????????? 0?????????? 2
    ------- ------? -------- ---------- ---------- ---------- ----------? ----------
    total??????? 8????? 0.00?????? 0.01????????? 0????????? 6????????? 0?????????? 2
    ?
    Misses in library cache during parse: 1
    Optimizer mode: CHOOSE
    Parsing user id: 89?
    ?
    Rows???? Row Source Operation
    -------? ---------------------------------------------------
    ????? 1? SORT AGGREGATE
    ????? 1?? INDEX FULL SCAN (MIN/MAX) SBFI_CTRY_FLOW_CURVE_WHEEL_PK (object id 35844)
    ?

    Elapsed times include waiting on following events:
    ? Event waited on???????????????????????????? Times?? Max. Wait? Total Waited
    ? ----------------------------------------?? Waited? ----------? ------------
    ? SQL*Net message to client?????????????????????? 4??????? 0.00????????? 0.00
    ? SQL*Net message from client???????????????????? 4????? 494.34??????? 501.34
    ********************************************************************************
    一些重要的信息: consistent read值為6, 相比以前的26067(PK)/19945(index),fetch時(shí)間<0.01秒,相比3.84s(PK)/8.84s(index)。訪問索引的方法為INDEX FULL SCAN (MIN/MAX)。這是oracle文檔庫里沒有提到的訪問方法,但是
    http://www.juliandyke.com/Optimisation/Operations/IndexFullScanMinMax.html 有一些介紹:Returns the first or last entry in the index。
    ?
    看來oracle對(duì)于單個(gè)的min(),max()函數(shù),能直接訪問索引的最左邊或者最右邊取到結(jié)果,但是如果兩個(gè)函數(shù)同時(shí)出現(xiàn)在一個(gè)sql里,oracle就只能掃描整個(gè)索引。這一點(diǎn)上還是不夠智能。
    =============================================================================================
    ?
    ?
    posted on 2009-01-27 21:38 decode360 閱讀(489) 評(píng)論(0)  編輯  收藏 所屬分類: 05.SQL
    主站蜘蛛池模板: 亚洲成人一级电影| 国内精品久久久久久久亚洲| 亚洲情综合五月天| a级男女仿爱免费视频| 亚洲一区二区三区免费| 精品一区二区三区高清免费观看| 亚洲乱码无码永久不卡在线| 91在线免费视频| 老牛精品亚洲成av人片| 亚洲VA综合VA国产产VA中| h视频免费高清在线观看| 亚洲成人中文字幕| 一二三四免费观看在线视频中文版 | 一二三四免费观看在线电影| 国精产品一区一区三区免费视频| 78成人精品电影在线播放日韩精品电影一区亚洲 | 中文字幕免费在线看| 亚洲精品永久www忘忧草| 免费观看的a级毛片的网站| 亚洲人成77777在线观看网| 国产无遮挡裸体免费视频| 久久久久久噜噜精品免费直播| 亚洲av第一网站久章草| 亚洲乱色熟女一区二区三区丝袜| 免费人成网站在线高清| 免费播放一区二区三区| 久久久久se色偷偷亚洲精品av| 国产婷婷高清在线观看免费| 成人爽A毛片免费看| 中国国产高清免费av片| 一级毛片在线播放免费| 亚洲人成网站日本片| 亚洲天堂中文字幕在线| www.91亚洲| 国产在线观看免费观看不卡| 特级一级毛片免费看| 亚洲最大的成网4438| 亚洲精品视频免费| 日韩中文字幕精品免费一区| 国产a视频精品免费观看| 一级毛片a免费播放王色电影|