<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 :: 首頁 :: 新隨筆 :: 聯系 ::  :: 管理 ::
      397 隨筆 :: 33 文章 :: 29 評論 :: 0 Trackbacks
    min/max函數的index問題
    ?
    ??? 在查詢某表時同時使用了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就只能掃描整個索引。這一點上還是不夠智能。
    =============================================================================================
    ?
    ?
    posted on 2009-01-27 21:38 decode360 閱讀(490) 評論(0)  編輯  收藏 所屬分類: 05.SQL
    主站蜘蛛池模板: 亚洲日韩乱码中文无码蜜桃| 亚洲国产人成网站在线电影动漫| 亚洲永久中文字幕在线| 二个人看的www免费视频| 五月婷婷亚洲综合| 最新亚洲人成无码网站| 日韩免费观看一级毛片看看| 亚洲夂夂婷婷色拍WW47| 欧美三级在线电影免费| 亚洲人成图片网站| 女人18毛片水最多免费观看 | 免费a级毛片视频| 国产成人 亚洲欧洲| 亚洲国产av无码精品| 国产精品偷伦视频免费观看了| 中文字幕无码精品亚洲资源网| 中国一级毛片免费看视频| 亚洲AV午夜成人片| 亚洲一区免费观看| 亚洲1区1区3区4区产品乱码芒果| 成人免费777777| 日亚毛片免费乱码不卡一区| 狠狠色婷婷狠狠狠亚洲综合| 两个人看的www免费| 91亚洲一区二区在线观看不卡| 91在线视频免费看| 老子影院午夜伦不卡亚洲| 亚洲综合最新无码专区| 玖玖在线免费视频| www.亚洲日本| 日韩精品成人亚洲专区| 手机看片国产免费永久| 97se亚洲综合在线| 成年女人永久免费观看片| 国产免费人成视频尤勿视频| 亚洲人成在线电影| 成人免费看吃奶视频网站| 色婷婷综合缴情综免费观看| 亚洲美女视频网址| 日韩中文无码有码免费视频 | 亚洲国产综合无码一区二区二三区|