Oracle 查詢行數很少,為什麼不走索引?
問題:
以下查詢涉及 90 行,只佔總行數的 90/10000 ,但使用了全表掃描:
select /*+ gather_plan_statistics */ count ( distinct junk ), count (*) from bricks where weight between 1 and 10;
COUNT(DISTINCTJUNK) COUNT(*) ______________________ ___________ 4 90
------------------------------------------------------------------------------------------- | Id | Operation | Name| Starts | E-Rows | A-Rows | A-Time| Buffers | ------------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT || 1 | | 1 |00:00:00.01 | 120 | | 1 | SORT AGGREGATE || 1 |1 | 1 |00:00:00.01 | 120 | | 2 | VIEW | VW_DAG_0 | 1 | 92 | 4 |00:00:00.01 | 120 | | 3 | HASH GROUP BY || 1 | 92 | 4 |00:00:00.01 | 120 | |* 4 | TABLE ACCESS FULL| BRICKS| 1 | 92 |90 |00:00:00.01 | 120 | ------------------------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 4 - filter(("WEIGHT"<=10 AND "WEIGHT">=1)) 22 rows selected.
以下查詢涉及
1000
行,反而使用了索引:
select /*+ gather_plan_statistics */ count ( distinct junk ), count (*) from bricks where brick_id between 1 and 1000; COUNT(DISTINCTJUNK) COUNT(*) ------------------- ---------- 4 1000
為什麼涉及行數少的查詢,反而不走索引了?
------------------------------------------------------------------------------------------------------ | Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers | ------------------------------------------------------------------------------------------------------ | 0 | SELECT STATEMENT | | 1 | | 1 |00:00:00.01 | 15 | | 1 | SORT AGGREGATE | | 1 | 1 | 1 |00:00:00.01 | 15 | | 2 | VIEW | VW_DAG_0 | 1 | 995 | 4 |00:00:00.01 | 15 | | 3 | HASH GROUP BY | | 1 | 995 | 4 |00:00:00.01 | 15 | | 4 | TABLE ACCESS BY INDEX ROWID| BRICKS | 1 | 995 | 1000 |00:00:00.01 | 15 | |* 5 | INDEX RANGE SCAN | BRICKS_PK | 1 | 995 | 1000 |00:00:00.01 | 3 | ------------------------------------------------------------------------------------------------------ Predicate Information (identified by operation id): --------------------------------------------------- 5 - access("BRICK_ID">=1 AND "BRICK_ID"<=1000) 23 rows selected.
下面用不同顏色的積木表示資料,存放積木的盒子表示資料塊。
下面我們有 4 個資料塊,儲存了不同顏色的積木,每個盒子有 2 個積木,下面需要找出紅色積木 :
select * from bricks where colour = 'red';
全表掃描方式:
1. 讀取表中所有塊。
2. 逐個塊進行查詢,選出符合條件的資料。
索引掃描方式
只掃描存在紅色積木的盒子,而不是所有盒子。
使用索引時資料庫訪問多少資料塊,取決於這些行在表中的物理位置
在使用索引時,存在兩個極端情況
1. 需要查詢的資料,全都位於同一個資料塊內。
例如紅色積木,在同一個盒子裡,在索引掃描查詢紅色積木時,只需要查 1 個盒子,即 1 次 I/O 。
2. 需要查詢的每條資料,全都分散在不同的資料庫內。
紅色積木,分佈在不同的盒子裡。在索引掃描查詢紅色積木時,只需要兩個盒子,即 2 次 I/O 。
或者每個盒子都只有一個紅積木,此時查詢紅色積木需要查詢 5 個盒子,即 5 次 I/O ,接近全面掃描 I/O 次數。
資料庫如何知道在執行查詢之前使用索引需要訪問多少個塊呢?
實際上資料庫也無法精準計算出資料塊個數,但是可以透過聚簇因子來進行評估。
什麼是聚簇因子
Oralce 資料庫系統中最普通,最為常用的即為堆表。
堆表的資料儲存方式為無序儲存,也就是任意的DML 操作都可能使得當前資料塊存在可用的空閒空間。
處於節省空間的考慮,塊上的可用空閒空間會被新插入的行填充,而不是按順序填充到最後被使用的塊上。
上述的操作方式導致了資料的無序性的產生。
當建立索引時,會根據指定的列按順序來填充到索引塊,預設的情況下為升序。
新建或重建索引時,索引列上的順序是有序的,而表上的順序是無序的,也就是存在了差異,即表現為聚簇因子。
聚簇因子是資料庫在收集表統計資訊時計算得出的一個計算器。
它會統計當前資料是否和上一條資料在同一個塊中。
如果不在一個塊中,聚簇因子計算加 1 。
如果在同一個塊中,計數器保持不變。
所以聚簇因子的下限是表的塊數,上限是表的行數。
塊數 <= 聚簇因子 <= 行數
聚簇因子越高,索引中的順序行在整個表中的分散度越高,索引效率可能越低。
聚簇因子是基於表上索引列上的一個值,每一個索引都有一個聚簇因子。
用於描述索引塊上與表塊上儲存資料在順序上的相似程度,也就說表上的資料行的儲存順序與索引列上順序是否一致。
在全索引掃描中,
CF
的值基本上等同於物理
I/O
或塊訪問數,如果相同的塊被連續讀,則
Oracle
認為只需要
1
次物理
I/O
。
好的
CF
值接近於表上的塊數,而差的
CF
值則接近於表上的行數。
聚簇因子在索引建立時就會透過表上存存在的行以及索引塊計算獲得
Oracle 如何計算聚簇因子
執行或預估一次全索引掃描。
檢查索引塊上每一個rowid 的值,檢視是否前一個 rowid 的值與後一個指向了相同的資料塊,如果指向了不相同的資料塊則 CF 的值增加 1 。
當索引塊上的每一個rowid 被檢查完畢,即得到最終的 CF 值。
這也就是為什麼在最開始的兩個 SQL ,查詢行數少的為什麼不走索引,還是因為聚簇因子的原因。
下面透過實驗來看下聚簇因子的影響
建立環境
建立表bricks和索引,及全域性臨時表bricks_temp,並在最後蒐集統計資訊:
conn cjc/******
復位隨機數
exec dbms_random.seed ( 0 );
建立表bricks,
create table bricks ( brick_id not null constraint bricks_pk primary key, colour not null, shape not null, weight not null, insert_date not null, junk default lpad ( 'x', 50, 'x' ) not null ) as with rws as ( select level x from dual connect by level <= 10000 ) select rownum brick_id, case ceil ( rownum / 2500 ) when 4 then 'red' when 1 then 'blue' when 2 then 'green' when 3 then 'yellow' end colour, case mod ( rownum, 4 ) when 0 then 'cube' when 1 then 'cylinder' when 2 then 'pyramid' when 3 then 'prism' end shape, round ( dbms_random.value ( 1, 1000 ) ), date'2022-01-01' + ( rownum/24 ) + ( mod ( rownum, 24 ) / 36 ) insert_date, lpad ( ascii ( mod ( rownum, 26 ) + 65 ), 50, 'x' ) from rws;
檢視錶結構
SQL> desc bricks Name Null? Type ----------------------------------------- -------- ---------------------------- BRICK_ID NOT NULL NUMBER COLOUR NOT NULL VARCHAR2(6) SHAPE NOT NULL VARCHAR2(8) WEIGHT NOT NULL NUMBER INSERT_DATE NOT NULL DATE JUNK NOT NULL VARCHAR2(200)
建立臨時表bricks_temp
create global temporary table bricks_temp as select * from bricks where 1 = 0;
建立索引,索引列weight
create index brick_weight_i on bricks ( weight );
建立索引,索引列shape
create index brick_shape_i on bricks ( shape );
建立索引,索引列colour
create index brick_colour_i on bricks ( colour );
建立索引,索引列insert_date
create index brick_insert_date_i on bricks ( insert_date );
收集表統計資訊
EXEC DBMS_STATS.GATHER_TABLE_STATS('CJC','BRICKS',estimate_percent=>100,method_opt=> 'FOR ALL INDEXED COLUMNS',CASCADE=> TRUE);
檢視資料,bricks表有10000行:
SQL> select count(*) from bricks; COUNT(*) ___________ 10000
查詢資料
SQL> SELECT brick_id, colour, shape, weight, insert_date FROM bricks WHERE ROWNUM <= 9;
BRICK_ID COLOUR SHAPE WEIGHT INSERT_DATE ---------- ------ -------- ---------- ------------------ 1 blue cylinder 64 01-JAN-22 2 blue pyramid 829 01-JAN-22 3 blue prism 233 01-JAN-22 4 blue cube 219 01-JAN-22 5 blue cylinder 371 01-JAN-22 6 blue pyramid 70 01-JAN-22 7 blue prism 461 01-JAN-22 8 blue cube 953 01-JAN-22 9 blue cylinder 944 01-JAN-22 9 rows selected.
junk列長度為1000,目的是將行撐大,沒有在結果集中顯示。
索引什麼時候有用?
大家通常認為,當索引定位表中的很少幾行時,它被認為是有用的。
但很少有多少?這個很難界定。我們透過示例來了解一下。
bricks表現有5個索引:
set line 300 col cols for a25 select ui.index_name, listagg ( uic.column_name, ',' ) within group ( order by column_position ) cols from user_indexes ui join user_ind_columns uic on ui.index_name = uic.index_name where ui.table_name = 'BRICKS' group by ui.index_name; INDEX_NAME COLS ------------------------------ ------------------------- BRICKS_PK BRICK_ID BRICK_COLOUR_I COLOUR BRICK_INSERT_DATE_I INSERT_DATE BRICK_SHAPE_I SHAPE BRICK_WEIGHT_I WEIGHT
以下查詢涉及90行,只佔總行數的90/10000,但使用了全表掃描:
select /*+ gather_plan_statistics */ count ( distinct junk ), count (*) from bricks where weight between 1 and 10; COUNT(DISTINCTJUNK) COUNT(*) ______________________ ___________ 4 90
SQL> select * from table(dbms_xplan.display_cursor( format => 'IOSTATS LAST')); PLAN_TABLE_OUTPUT ---------------------------------------------------------------------------------------------------- SQL_ID60p9xcp0b6cfh, child number 0 ------------------------------------- select /*+ gather_plan_statistics */ count ( distinct junk ), count (*) from bricks where weight between 1 and 10 Plan hash value: 2750714649 ------------------------------------------------------------------------------------------- | Id | Operation | Name| Starts | E-Rows | A-Rows | A-Time| Buffers | ------------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT || 1 | | 1 |00:00:00.01 | 120 | | 1 | SORT AGGREGATE || 1 |1 | 1 |00:00:00.01 | 120 | | 2 | VIEW | VW_DAG_0 | 1 | 92 | 4 |00:00:00.01 | 120 | | 3 | HASH GROUP BY || 1 | 92 | 4 |00:00:00.01 | 120 | |* 4 | TABLE ACCESS FULL| BRICKS| 1 | 92 |90 |00:00:00.01 | 120 | ------------------------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 4 - filter(("WEIGHT"<=10 AND "WEIGHT">=1)) 22 rows selected.
以下查詢涉及1000行,反而使用了索引:
select /*+ gather_plan_statistics */ count ( distinct junk ), count (*) from bricks where brick_id between 1 and 1000; COUNT(DISTINCTJUNK) COUNT(*) ------------------- ---------- 4 1000
SQL> select * from table(dbms_xplan.display_cursor( format => 'IOSTATS LAST')); PLAN_TABLE_OUTPUT ------------------------------------------------------------------------------------------------------------------------------------------------------ SQL_ID1s29r51b4ka1b, child number 0 ------------------------------------- select /*+ gather_plan_statistics */ count ( distinct junk ), count (*) from bricks where brick_id between 1 and 1000 Plan hash value: 301905156 ------------------------------------------------------------------------------------------------------ | Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers | ------------------------------------------------------------------------------------------------------ | 0 | SELECT STATEMENT | | 1 | | 1 |00:00:00.01 | 15 | | 1 | SORT AGGREGATE | | 1 | 1 | 1 |00:00:00.01 | 15 | | 2 | VIEW | VW_DAG_0 | 1 | 995 | 4 |00:00:00.01 | 15 | | 3 | HASH GROUP BY | | 1 | 995 | 4 |00:00:00.01 | 15 | | 4 | TABLE ACCESS BY INDEX ROWID| BRICKS | 1 | 995 | 1000 |00:00:00.01 | 15 | |* 5 | INDEX RANGE SCAN | BRICKS_PK | 1 | 995 | 1000 |00:00:00.01 | 3 | ------------------------------------------------------------------------------------------------------ Predicate Information (identified by operation id): --------------------------------------------------- 5 - access("BRICK_ID">=1 AND "BRICK_ID"<=1000) 23 rows selected.
物理行位置
Oracle資料庫將行存於資料塊中。您可以使用DBMS_rowid查詢行的塊號。例如: select brick_id, dbms_rowid.rowid_block_number ( rowid ) blk# from bricks where mod ( brick_id, 1000 ) = 0;
BRICK_ID BLK# ---------- ---------- 1000 654 2000 667 3000 679 4000 692 5000 705 6000 717 7000 730 8000 742 9000 755 10000 766 10 rows selected.
預設情況下,Oracle資料庫中的表時堆表(Heap table)。這意味著資料庫可以將行放在任何地方。
但是索引是有序的資料結構。新條目必須放在正確的位置。例如,如果在數字列中插入42,則在該列位於41之後,或43之前。
行的物理順序與索引的邏輯順序越接近,該索引就越有效。
Oracle資料庫中最小的I/O單元是資料塊。因此,指向同一資料庫塊的連續索引項越多,在一個I/O中獲取的行就越多。因此,索引就越有效。
下面這個SQL比較難理解,但也是本文中最精彩的部分。同時用到了分析函式和Pivot轉換:
set line 150 with rws as ( select ceil ( brick_id / 1000 ) id, ceil ( dense_rank () over ( order by dbms_rowid.rowid_block_number ( rowid ) ) / 10 ) rid from bricks ) select * from rws pivot ( count (*) for rid in ( 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 ) ) order by id;
首先看一下其中的子查詢rws:
select ceil ( brick_id / 1000 ) id, ceil ( dense_rank () over ( order by dbms_rowid.rowid_block_number ( rowid ) ) / 10 ) rid from bricks;
由於bricks表有10000行,因此這個查詢的結果也有10000行,但為了方便最終顯示,id列和rid列都進行了分組。
id被分為10段,也就是1-1000, 1001-2000,…,9001-10000。
rid被分為12段,也就是按dense_rank排序後,從1-10,11-20,…,120-130。
其實這裡有一個隱含條件沒有說,就是此表只有128個資料塊:
SQL> select blocks from user_segments where segment_name = 'BRICKS'; BLOCKS _________ 128
以上子查詢再經過pivot的count(*)計數得到以下的結果,橫向是資料塊的分段,縱向是行的分段。此圖可以看出資料的分佈(聚集度或分散度):
ID 1 2 3 45 6 7 8 9 10 11 12 ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- 1 861 139 0 00 0 0 0 0 0 0 0 2 0 721279 00 0 0 0 0 0 0 0 3 0 0580 4200 0 0 0 0 0 0 0 4 0 0 0 430 570 0 0 0 0 0 0 0 5 0 0 0 0 280 720 0 0 0 0 0 0 6 0 0 0 00 128 840 32 0 0 0 0 7 0 0 0 00 0 0 808 192 0 0 0 8 0 0 0 00 0 0 0 653 347 0 0 9 0 0 0 00 0 0 0 0 523477 0 10 0 0 0 00 0 0 0 0 0393 607 10 rows selected.
例如對於ID 1那行(對應表中的第1-1000行),所有行聚集與1-2段。這2個數加起來正好等於1000(861+139)。同理,其他行加一起也是1000。
以上是從brick_id的視角,而從weight的視角(有1000個不同值,所以它是除100,不是之前的1000),則其分佈如下。分佈比較分散:
SQL> with rws as ( select ceil ( weight / 100 ) wt, ceil ( dense_rank () over ( order by dbms_rowid.rowid_block_number ( rowid ) ) / 10 ) rid from bricks ) select * from rws pivot ( count (*) for rid in ( 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 ) ) order by wt;
WT 1 2 3 45 6 7 8 9 10 11 12 ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- 1 109 76 84 96 98 98 76 83 86 83 93 59 2 106 90 87 92 88 81 92 102 77 83 89 59 3 77 85 88 85 91 68 78 73 87 91 93 65 4 86 94 78 94 80 81 101 93 98 83 72 72 5 70 84 87 89 90 95 82 71 76 87100 56 6 81 83 82 77 76 84 92 99 89 96 91 54 7 70 91 84 80 86 80 75 80 85 87 95 59 8 81 97 90 84 89 86 62 71 74 80 81 68 9 102 72 99 66 78 90 89 83 86 91 85 49 10 79 88 80 87 74 85 93 85 87 89 71 66 10 rows selected.
SQL> select count(distinct weight) from bricks; COUNT(DISTINCTWEIGHT) --------------------- 1000
這意味著和brick_id相比,透過weight獲取同樣行數的資料,資料庫必須進行更多的I/O操作。因此,基於weight的索引不如基於brick_id的索引有效。
這種分佈實際上是由於brick_id是遞增順序插入,而weight是用隨機數生成的(dbms_random.value ( 1, 1000 ))。
因此,準確的說,在確定索引的效率時,重要的是I/O操作的數量(訪問資料庫的次數)。不是訪問多少行!
那麼最佳化器如何知道邏輯順序和物理順序的匹配程度呢?它使用聚集因子(clustering factor)進行估計。
聚集因子(clustering factor)
聚集因子是衡量邏輯索引順序與行的物理表順序匹配程度的指標。資料庫在收集統計資料時計算此值。它的計算基於:
當前索引項對應的行與上一個索引項對應的行在同一塊中,還是不同的塊中?
每次連續索引項位於不同的塊中時,最佳化器都會將計數器加1。最終該值越低,行的聚集性越好,資料庫使用索引的可能性越大。
聚集因子可如下檢視,可以看出,BRICK_WEIGHT_I的聚集因子遠高於BRICKS_PK的聚集因子。
從另一個角度,如果CLUSTERING_FACTOR和BLOCKS數值接近,則表示聚集性越好:
select index_name, clustering_factor, ut.num_rows, ut.blocks from user_indexes ui join user_tables ut on ui.table_name = ut.table_name where ui.table_name = 'BRICKS';
INDEX_NAME CLUSTERING_FACTOR NUM_ROWSBLOCKS ------------------------------ ----------------- ---------- ---------- BRICK_INSERT_DATE_I 877 10000 127 BRICK_COLOUR_I 119 10000 127 BRICK_SHAPE_I 468 10000 127 BRICK_WEIGHT_I 9572 10000 127 BRICKS_PK 117 10000 12
獲取部分聚集的行
部分聚集(Partly Clustered)指聚集因子比較“平均”。此時資料庫傾向於全表掃描:
select /*+ gather_plan_statistics */ count ( distinct junk ), count (*) from bricks where insert_date >= date'2022-02-01' and insert_date < date'2022-02-21';
COUNT(DISTINCTJUNK) COUNT(*) ------------------- ---------- 4 480
select * from table(dbms_xplan.display_cursor( format => 'IOSTATS LAST')); ------------------------------------------------------------------------------------------- | Id | Operation | Name| Starts | E-Rows | A-Rows | A-Time| Buffers | ------------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT || 1 | | 1 |00:00:00.01 | 120 | | 1 | SORT AGGREGATE || 1 |1 | 1 |00:00:00.01 | 120 | | 2 | VIEW | VW_DAG_0 | 1 | 479 | 4 |00:00:00.01 | 120 | | 3 | HASH GROUP BY || 1 | 479 | 4 |00:00:00.01 | 120 | |* 4 | TABLE ACCESS FULL| BRICKS| 1 | 479 | 480 |00:00:00.01 | 120 | ------------------------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 4 - filter(("INSERT_DATE"<TO_DATE(' 2022-02-21 00:00:00', 'syyyy-mm-dd hh24:mi:ss') AND "INSERT_DATE">=TO_DATE(' 2022-02-01 00:00:00', 'syyyy-mm-dd hh24:mi:ss'))) 25 rows selected.
但是從月的角度看,資料的聚集度還是不錯的:
with rws as ( select trunc ( insert_date, 'mm' ) dt, ceil ( dense_rank () over ( order by dbms_rowid.rowid_block_number ( rowid ) ) / 10 ) rid from bricks ) select * from rws pivot ( count (*) for rid in ( 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 ) ) order by dt;
DT 1 2 3 45 6 7 8 9 10 11 12 ------------------ ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- 01-JAN-22 734 0 0 00 0 0 0 0 0 0 0 01-FEB-22 127 545 0 00 0 0 0 0 0 0 0 01-MAR-22 0 315429 00 0 0 0 0 0 0 0 01-APR-22 0 0430 2900 0 0 0 0 0 0 0 01-MAY-22 0 0 0 560 184 0 0 0 0 0 0 0 01-JUN-22 0 0 0 0 666 54 0 0 0 0 0 0 01-JUL-22 0 0 0 00 744 0 0 0 0 0 0 01-AUG-22 0 0 0 00 50 694 0 0 0 0 0 01-SEP-22 0 0 0 00 0 146 574 0 0 0 0 01-OCT-22 0 0 0 00 0 0 266 478 0 0 0 01-NOV-22 0 0 0 00 0 0 0 367 353 0 0 01-DEC-22 0 0 0 00 0 0 0 0 517227 0 01-JAN-23 0 0 0 00 0 0 0 0 0643 101 01-FEB-23 0 0 0 00 0 0 0 0 0 0 506 14 rows selected.
這是因為有幾行在兩個資料塊之間來回跳躍,導致聚集因子變大,從而帶給最佳化器以假象:
with rws as ( select brick_id, to_char ( insert_date, 'DD MON HH24:MI' ) dt, dbms_rowid.rowid_block_number ( rowid ) current_block, lag ( dbms_rowid.rowid_block_number ( rowid ) ) over ( order by insert_date ) prev_block from bricks where insert_date >= date '2022-01-01' and insert_date < date '2022-02-01' ) select * from rws where current_block <> prev_block order by dt;
BRICK_ID DT CURRENT_BLOCK PREV_BLOCK ---------- --------------------- ------------- ---------- 96 05 JAN 00:00 644 643 87 05 JAN 01:00 643 644 97 05 JAN 01:40 644 643 174 08 JAN 10:00 645 644 165 08 JAN 11:00 644 645 175 08 JAN 11:40 645 644 166 08 JAN 12:40 644 645 176 08 JAN 13:20 645 644 167 08 JAN 14:20 644 645 177 08 JAN 15:00 645 644 264 12 JAN 00:00 646 645 255 12 JAN 01:00 645 646 265 12 JAN 01:40 646 645 256 12 JAN 02:40 645 646 266 12 JAN 03:20 646 645 257 12 JAN 04:20 645 646 267 12 JAN 05:00 646 645 258 12 JAN 06:00 645 646 268 12 JAN 06:40 646 645 259 12 JAN 07:40 645 646 269 12 JAN 08:20 646 645 346 15 JAN 16:40 647 646 432 19 JAN 00:00 648 647 423 19 JAN 01:00 647 648 433 19 JAN 01:40 648 647 424 19 JAN 02:40 647 648 434 19 JAN 03:20 648 647 425 19 JAN 04:20 647 648 435 19 JAN 05:00 648 647 426 19 JAN 06:00 647 648 436 19 JAN 06:40 648 647 427 19 JAN 07:40 647 648 437 19 JAN 08:20 648 647 428 19 JAN 09:20 647 648 438 19 JAN 10:00 648 647 429 19 JAN 11:00 647 648 439 19 JAN 11:40 648 647 430 19 JAN 12:40 647 648 440 19 JAN 13:20 648 647 431 19 JAN 14:20 647 648 441 19 JAN 15:00 648 647 518 22 JAN 23:20 649 648 604 26 JAN 06:40 650 649 595 26 JAN 07:40 649 650 605 26 JAN 08:20 650 649 596 26 JAN 09:20 649 650 606 26 JAN 10:00 650 649 597 26 JAN 11:00 649 650 607 26 JAN 11:40 650 649 598 26 JAN 12:40 649 650 608 26 JAN 13:20 650 649 599 26 JAN 14:20 649 650 609 26 JAN 15:00 650 649 696 30 JAN 00:00 651 650 687 30 JAN 01:00 650 651 697 30 JAN 01:40 651 650 688 30 JAN 02:40 650 651 698 30 JAN 03:20 651 650 689 30 JAN 04:20 650 651 699 30 JAN 05:00 651 650 60 rows selected.
如何解決類似問題呢,從12C開始,改進大部分聚集的行的統計資訊,可透過調整TABLE_CACHED_BLOCKS實現,先不演示TABLE_CACHED_BLOCKS使用方法。
參考:
《甲骨文技術》 -Oracle 開發者效能第 5 課:為什麼我的查詢不使用索引?
https://blog.csdn.net/stevensxiao/article/details/121043980
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/29785807/viewspace-2913326/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- oracle為什麼不走索引Oracle索引
- 索引為什麼能提供查詢效能...索引
- PostgreSQL/LightDB 不走並行是為什麼?SQL並行
- 為什麼我使用了索引,查詢還是慢?索引
- 為什麼有時Oracle資料庫不用索引來查詢資料?(轉)Oracle資料庫索引
- 【索引】Oracle查詢指定索引提高查詢效率索引Oracle
- MySQL 為什麼全文索引查中文找不結果MySql索引
- 什麼情況下需要建立索引? 索引的作用?為什麼能夠提高查詢速度?(索引的原理) 索引有什麼副作用嗎?索引
- 技術分享 | 為什麼 SELECT 查詢選擇全表掃描,而不走索引?索引
- 【MOS:1549181.1】為何在查詢中索引未被使用--為什麼索引沒有被使用索引
- 為什麼該SQL的執行計劃不走索引???SQL索引
- 一個很簡單的查詢,為什麼用不到索引索引
- 【TUNE_ORACLE】你建立的索引為什麼不工作了?(一)Oracle索引
- 【TUNE_ORACLE】你建立的索引為什麼不工作了?(三)Oracle索引
- 【TUNE_ORACLE】你建立的索引為什麼不工作了?(二)Oracle索引
- MySQL查詢為什麼沒走索引?這篇文章帶你全面解析MySql索引
- 為什麼 SQL 語句使用了索引,但卻還是慢查詢?SQL索引
- phpstrom用模型where查詢,欄位為什麼不會提示?PHP模型
- 【轉載】為什麼 MySQL 不推薦使用子查詢和 joinMySql
- [轉載] 為什麼 MySQL 不推薦使用子查詢和 joinMySql
- oracle 查詢所有表的行數Oracle
- Python 的切片為什麼不會索引越界?Python索引
- ClickHouse為什麼查詢速度快?
- 一個查詢不走索引的例子索引
- MySQL索引憑什麼能讓查詢效率提高這麼多?MySql索引
- 表和索引並行查詢索引並行
- mysql 外來鍵索引入門介紹,為什麼工作中很少有人使用?MySql索引
- 什麼是並行查詢及其原理並行
- (轉)Oracle為什麼不使用我的索引?Oracle索引
- 為何在查詢中索引未被使用索引
- 為什麼所有的查詢條件都命中索引還是那麼慢?記一次慢查詢優化過程索引優化
- 【索引】oracle查詢使用索引和不使用索引的比較索引Oracle
- Elasticsearch 中為什麼選擇倒排索引而不選擇 B 樹索引Elasticsearch索引
- 為什麼 Redis 的查詢很快, Redis 如何保證查詢的高效Redis
- 為什麼所有的查詢條件都命中索引還是那麼慢?記一次慢查詢最佳化過程索引
- 當查詢A表的時候,查詢還沒執行完,為什麼能夠對錶進行刪除?
- [20220328]查詢游標為什麼不共享指令碼.txt指令碼
- 為什麼像RedHat那樣的開源旗手很少?Redhat