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的列,建立點陣圖索引可走索引
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的列,建立點陣圖索引可走索引
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/26870952/viewspace-2151469/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- undefined與null與?. ??UndefinedNull
- oracle invisible index與unusable index的區別OracleIndex
- JavaScript undefined與null區別JavaScriptUndefinedNull
- Elasticsearch之索引模板index template與索引別名index aliasElasticsearch索引Index
- [20200317]NULL與排序輸出.txtNull排序
- 索引與null(二):組合索引索引Null
- 索引與null(一):單列索引索引Null
- hive orc表'orc.create.index'='true'與'orc.create.index'='false'HiveIndexFalse
- MySQL explain結果Extra中"Using Index"與"Using where; Using index"區別MySqlAIIndex
- mysql中null與“空值”的坑MySqlNull
- 【NULL】Oracle null值介紹NullOracle
- in、exists操作與null的一點總結Null
- PHP7 ?? 與 ?: 的作用和區別(null合併運算子, null條件運算子)PHPNull
- [20200326]繫結變數抓取與NULL值.txt變數Null
- Hashtable/HashMap與key/value為null的關係HashMapNull
- JS中判斷null、undefined與NaN的方法JSNullUndefinedNaN
- MySQL中IS NULL、IS NOT NULL、!=不能用索引?胡扯!MySqlNull索引
- PropertyChanged == nullNull
- MySQL NULLMySqlNull
- JS 應用篇(一):Undefined與Null的區別JSUndefinedNull
- TreeSet的null值與元素型別的約束Null型別
- MySQL null值儲存,null效能影響MySqlNull
- 2>/dev/null和>/dev/null 2>&1和2>&1>/dev/null的區別devNull
- mysql中key 、primary key 、unique key 與index區別MySqlIndex
- Index of /virtualboxIndex
- PostgreSQL:INDEXSQLIndex
- NULL列時,如何使得IS NULL或者IS NOT NULL可以使用索引來提高查詢效率Null索引
- 為什麼索引無法使用is null和is not null索引Null
- MYSQL timestamp NOT NULL插入NULL的報錯問題MySqlNull
- Oracle vs PostgreSQL,研發注意事項(12) - NULL與索引OracleSQLNull索引
- null 和 undefinedNullUndefined
- Python, pandas: how to sort dataframe by index// Merge two dataframes by indexPythonIndex
- create index .. onlineIndex
- index.jspIndexJS
- 面試題((A)null).fun()——java中null值的強轉面試題NullJava
- PostgreSQL DBA(119) - pgAdmin(LIMIT:Index Scan vs Bitmap Index Scan)SQLMITIndex
- 小程式報錯Invoke event bindViewTap in page: pages/index/indexViewIndex
- Artificial Intelligence Index:2018年AI Index報告出爐IntelIndexAI