共計 5248 個字符,預計需要花費 14 分鐘才能閱讀完成。
這期內容當中丸趣 TV 小編將會給大家帶來有關如何進行 null 與 index 的分析,文章內容豐富且以專業的角度為大家分析和敘述,閱讀完這篇文章希望大家可以有所收獲。
今天在測試過程中遇到一問題, SQL 該走 Index 的, 沒走. 加 index hint 也不行. 描述如下:
1. 建立測試表
create table t1
as
select object_id, object_name from dba_objects;
2. 在 object_name 列上建立 b -tree index
create index idx_t1_name on t1(object_name);
3. 如果我是 select object_name from t1, 按理說 CBO 應該會選擇走 Index scan. 但奇怪的是結果走的 full table scan.
SQL set autotrace trace exp
SQL select object_name from t1;
Execution Plan
———————————————————-
Plan hash value: 3617692013
————————————————————————–
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
————————————————————————–
| 0 | SELECT STATEMENT | | 50934 | 3282K| 57 (2)| 00:00:01 |
| 1 | TABLE ACCESS FULL| T1 | 50934 | 3282K| 57 (2)| 00:00:01 |
————————————————————————–
Note
—–
– dynamic sampling used for this statement
[@more@]
3. 使用 index hint 想強行走 Index, 結果還是 full table scan. 我就奇怪了. hint 咋個不起做用呢? 郁悶.
SQL select /*+ index(t1, idx_t1_name) */ object_name from t1;
Execution Plan
———————————————————-
Plan hash value: 3617692013
————————————————————————–
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
————————————————————————–
| 0 | SELECT STATEMENT | | 50934 | 3282K| 57 (2)| 00:00:01 |
| 1 | TABLE ACCESS FULL| T1 | 50934 | 3282K| 57 (2)| 00:00:01 |
————————————————————————–
Note
—–
– dynamic sampling used for this statement
4. 偶然看了下表結構
SQL desc t1
Name Null? Type
—————————————– ——– —————————-
OBJECT_ID NUMBER
OBJECT_NAME VARCHAR2(128)
NULL 列引起我的注意. OBJECT_NAME 可以為 null !! 而在 oracle 中單個列上建 b -tree Index, null 是不會存進 Index 的 (復合索引可以, 只要整個 Index columns 不為 null). 那就是說如果有些行的 object_name 是 null, 那走 Index 取值不是會丟掉 object_name 為 null 的行. 那如果我讓 object_name not null 呢?
SQL alter table t1 modify object_name not null;
Table altered.
SQL desc t1
Name Null? Type
—————————————– ——– —————————-
OBJECT_ID NUMBER
OBJECT_NAME NOT NULL VARCHAR2(128)
再試一試
SQL select object_name from t1;
Execution Plan
———————————————————-
Plan hash value: 3617692013
————————————————————————–
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
————————————————————————–
| 0 | SELECT STATEMENT | | 50934 | 3282K| 57 (2)| 00:00:01 |
| 1 | TABLE ACCESS FULL| T1 | 50934 | 3282K| 57 (2)| 00:00:01 |
————————————————————————–
結果還是 full table scan : (
試試用 hint
SQL select /*+ index(t1, idx_t1_name) */ object_name from t1;
Execution Plan
———————————————————-
Plan hash value: 1352742509
——————————————————————————–
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
——————————————————————————–
| 0 | SELECT STATEMENT | | 50934 | 3282K| 264 (1)| 00:00:04 |
| 1 | INDEX FULL SCAN | IDX_T1_NAME | 50934 | 3282K| 264 (1)| 00:00:04 |
這回 hint 起作用了. 這說明并不是 Hint 失效, 只是滿足走 Index 的條件一開始沒有具備. 看來 null 是個潛在殺手, 得小心防范.
現在強走 index 是 ok 了. 但, 是什么東西會影響 CBO 的判斷不走 Index 呢? 想到統計信息可能會是原因之一, 于是查看了一下.
SQL select index_name, LAST_ANALYZED from user_indexes;
INDEX_NAME LAST_ANALYZED
—————————————————————————————— —————
IDX_T1_NAME 01-MAR-18
SQL select table_name, LAST_ANALYZED from user_tables;
TABLE_NAME LAST_ANALYZED
—————————————————————————————— —————
T1
看到剛建的表沒有做過統計. 于是 go to analyze table, 結果如下:
SQL exec dbms_stats.gather_table_stats(TEST , T1
PL/SQL procedure successfully completed.
SQL select table_name, LAST_ANALYZED from user_tables;
TABLE_NAME LAST_ANALYZED
—————————————————————————————— —————
T1 01-MAR-18
再來看看執行結果有沒有變化:
SQL select object_name from t1;
Execution Plan
———————————————————-
Plan hash value: 222950081
————————————————————————————
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
————————————————————————————
| 0 | SELECT STATEMENT | | 49917 | 1218K| 57 (2)| 00:00:01 |
| 1 | INDEX FAST FULL SCAN| IDX_T1_NAME | 49917 | 1218K| 57 (2)| 00:00:01 |
————————————————————————————
這下終于走 Index 這條路老 : ) 在 Index 中, key value 是排序存放的. Index Fast full scan 它是按照 block 的存儲順序來讀取數據, 并可以一次 I / O 多塊讀取提高效率 (參數 readdb_file_multiblock_read_count), 但返回的值是沒有排序的. 而
Index full scan 會按照 Key value 順序讀取值, 返回排了序的結果. 所以, 做個 order by 會是走 Index full scan.
SQL select object_name from t1 order by object_name;
Execution Plan
———————————————————-
Plan hash value: 1352742509
——————————————————————————–
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
——————————————————————————–
| 0 | SELECT STATEMENT | | 49917 | 1218K| 249 (1)| 00:00:03 |
| 1 | INDEX FULL SCAN | IDX_T1_NAME | 49917 | 1218K| 249 (1)| 00:00:03 |
——————————————————————————–
對于定義為 NULL 的列,創建位圖索引可走索引
上述就是丸趣 TV 小編為大家分享的如何進行 null 與 index 的分析了,如果剛好有類似的疑惑,不妨參照上述分析進行理解。如果想知道更多相關知識,歡迎關注丸趣 TV 行業資訊頻道。