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

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

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

    Decode360's Blog

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

      BlogJava :: 首頁 :: 新隨筆 :: 聯系 ::  :: 管理 ::
      302 隨筆 :: 26 文章 :: 82 評論 :: 0 Trackbacks
    ??? 在查詢某表時同時使用了min和max函數,結果查詢很慢,但是單獨執行min或者max時速度很快,建個環境模擬一下:
    ?
    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函數時是走索引的
    ?
    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)
    ?
    --兩個一起的時候就全表掃描了
    ?
    ?
    ??? INDEX (FULL SCAN (MIN/MAX))算法:如果是Max,首先沿著最右邊的Root-Branch?Node-Leaf?Node,發現最右邊的Leaf?Block是空的,于是沿著逆向指針往左走,一直走到最左邊發現都是空的,于是掃描了所有的Leaf?Blocks。如果是Min,首先沿著最左邊的Root-Branch?Node-Leaf?Node,發現最左邊的Leaf?Block是空的,于是沿著順向指針往右走,走到最右邊發現都是空的,掃描了所有的Leaf blocks。
    ?
    ?
    ?
    ??? 但是如何讓min、max同時查詢時走索引?似乎不可以,以下轉載一篇非常詳細的說明文檔
    ??? http://zhyuh.itpub.net/get/334/mix_max_index
    ?
    =============================================================================================
    ?
    Table sbfi_ctry_flow_curve_wheel有大約1500萬條記錄,運行下面的sql需要4秒鐘左右,developer認為時間太長,想優化。
    SQL>select min(trade_dt), max(trade_dt) from sbfi_ctry_flow_curve_wheel;
    developer很奇怪,trade_dt列上建有一個索引,但是執行的時候,oracle總是選擇走primary key,而不選擇那個索引。
    ?
    經檢查,發現表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。結果發現運行時間沒有縮短,反而從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
    ?
    為什么會出現這種情況?我們嘗試用TRACE去跟蹤執行過程。
    ==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分析后,主要部分結果如下:
    ==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?
    ********************************************************************************
    ?
    對比后主要的不同羅列如下:
    走primary key, consistent read,即query值為 26067,fetch時間為3.84秒,訪問主鍵索引的方法為INDEX FAST FULL SCAN。
    走TRADE_DT_INDEX索引,consistent read值為19945, fetch時間為8.84秒,訪問索引TRADE_DT_INDEX的方法為INDEX FULL SCAN。
    ?
    關于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.
    ?
    關于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要快,因為它用multiblock I/O,而且可以parallelized。
    順便也注意到要調優的這句sql,只返回trade_dt列的值,滿足index (fast) full scan的條件,即返回結果的列全都包含在索引里,非空。所以該sql只要掃描索引就能返回需要的結果,不需要再根據rowid去訪問表。
    ?
    既然要掃描整個索引,FAST FULL SCAN 比 FULL SCAN 快,TRADE_DT_INDEX 的 size 比 PK 的 size 小,那對 RADE_DT_INDEX 做FFS應該是最快的訪問路徑。用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秒是快了一些。
    ?
    但是根據一般的理解,象min(),max()這樣的函數,Oracle應該直接訪問索引的最左邊或者最右邊,這樣的訪問速度才是最快的。嘗試SQL>select min(trade_dt) from sbfi_ctry_flow_curve_wheel并生成10046 trace文件,用tkprof格式化后結果如下:
    ?
    ==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時間<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對于單個的min(),max()函數,能直接訪問索引的最左邊或者最右邊取到結果,但是如果兩個函數同時出現在一個sql里,oracle就只能掃描整個索引。這一點上還是不夠智能。




    -The End-

    posted on 2009-01-27 21:38 decode360-3 閱讀(690) 評論(0)  編輯  收藏 所屬分類: SQL Dev
    主站蜘蛛池模板: 一个人免费观看视频www| av无码免费一区二区三区| 国产一区二区三区免费看| 天堂亚洲国产中文在线| 男人的好看免费观看在线视频| 亚洲成年人电影在线观看| 国产精品免费观看| 国产v亚洲v天堂a无| 成人午夜性A级毛片免费| 国产亚洲精品影视在线| 免费毛片在线播放| 久久精品国产亚洲av品善| 国产小视频在线观看免费| aa午夜免费剧场| 国产av天堂亚洲国产av天堂| 日本免费一区二区三区| 亚洲人妖女同在线播放| 午夜dj免费在线观看| 尤物视频在线免费观看| 亚洲AV无码成人精品区天堂| 中文字幕免费在线观看| 亚洲人成人伊人成综合网无码| 免费理论片51人人看电影| 黄色网址免费在线| 亚洲人成网www| 我要看免费的毛片| 九九九精品视频免费| 亚洲av永久无码精品秋霞电影影院| 最近2019中文字幕免费直播| 亚洲精品午夜国产va久久| 亚洲国产电影av在线网址| 久久午夜夜伦鲁鲁片免费无码 | 亚洲成a人片在线观| 在线免费观看中文字幕| g0g0人体全免费高清大胆视频| 久热综合在线亚洲精品| 免费鲁丝片一级观看| 久久av免费天堂小草播放| 亚洲国产成人精品电影| 国产成人精品亚洲精品| 亚洲人成在线免费观看|