一條簡單的sql在11g和12c中的不同
今天在檢視awr報告的時候,有一句很簡單的sql語句引起了我的注意,因為它排在SQL Order by Reads的第2位。
這條語句看起來很簡單,自己印象中這個表中有一個相關的索引。
INDEX_NAME INDEX_TYPE UNIQUENES PAR COLUMN_LIST TABLE_TYPE STATUS NUM_ROWS LAST_ANAL G
------------------------------ ---------- ---------- --------- --- ------------------------------ ---------- ------ ---------- --------- -
MO1_MEMO_1IX FUNCTION-BASED NORMAL NONUNIQUE YES SYS_NC00031$,ENTITY_TYPE_ID,APP_ID TABLE N/A 554899259 01-APR-15 N
MO1_MEMO_2IX NORMAL NONUNIQUE YES MEMO_EXTERNAL_ID TABLE N/A 478847583 01-APR-15 N
MO1_MEMO_PK NORMAL UNIQUE YES MEMO_ID,APP_ID,ENTITY_KEY,PERIOD_KEY TABLE N/A 554900387 01-APR-15 N
有一個基於函式的索引,我們可以透過exp 或者dbms_metadata來得到相關的語句,發現索引是類似下面的形式。
create index MO1_MEMO_1IX on MO1_MEMO(entity_id desc,entity_type_id,app_id);
這是一個降序索引。對於這種降序索引,會在表中建立一個隱藏列。
SQL> select owner,column_name from all_tab_cols where table_name='MO1_MEMO' and hidden_column='YES';
APPO SYS_NC00031$
有了這些資訊,感覺應該是可以走索引掃描的。
但是得到的執行計劃中卻走了全表掃描,對一個資料量5億多資料的表走全表掃描,殺傷力是很大的。
但是奇怪的是使用下面兩種形式就沒有任何問題,索引都能正常啟用。
select * from mo1_memo where entity_id in (11889308) order by memo_date desc
select * from mo1_memo where entity_id =11889308 order by memo_date desc
一般來說降序索引在其值不為空的情況會啟用,根據目前的表結構來看entity_type_id和app_id有著not null constraint,所以應該能夠啟用才對。
帶著這個問題,我在11g的環境中簡單模擬了一把。
SQL> create table test as select *from all_objects where rownum<10000;
Table created.
SQL> desc test
Name Null? Type
----------------------------------------- -------- ----------------------------
OWNER NOT NULL VARCHAR2(30)
OBJECT_NAME NOT NULL VARCHAR2(30)
SUBOBJECT_NAME VARCHAR2(30)
OBJECT_ID NOT NULL NUMBER
DATA_OBJECT_ID NUMBER
OBJECT_TYPE VARCHAR2(19)
CREATED NOT NULL DATE
LAST_DDL_TIME NOT NULL DATE
TIMESTAMP VARCHAR2(19)
STATUS VARCHAR2(7)
TEMPORARY VARCHAR2(1)
GENERATED VARCHAR2(1)
SECONDARY VARCHAR2(1)
NAMESPACE NOT NULL NUMBER
EDITION_NAME VARCHAR2(30)
SQL> create index idx_test on test(object_id desc,object_name,object_type);
Index created.
SQL> select object_id from test where rownum<3;
OBJECT_ID
----------
2880583
2880575
SQL> set autot trace exp stat
下面兩種情況的執行計劃是一致的。
但是在12c的環境中,結果卻明顯不同,可見再最佳化器內部對於這種場景已經做了最佳化。
SQL> create table test as select *from all_objects where rownum<10000;
Table created.
SQL> desc test
Name Null? Type
----------------------------------------- -------- ----------------------------
OWNER NOT NULL VARCHAR2(128)
OBJECT_NAME NOT NULL VARCHAR2(128)
SUBOBJECT_NAME VARCHAR2(128)
OBJECT_ID NOT NULL NUMBER
DATA_OBJECT_ID NUMBER
OBJECT_TYPE VARCHAR2(23)
CREATED NOT NULL DATE
LAST_DDL_TIME NOT NULL DATE
TIMESTAMP VARCHAR2(19)
STATUS VARCHAR2(7)
TEMPORARY VARCHAR2(1)
GENERATED VARCHAR2(1)
SECONDARY VARCHAR2(1)
NAMESPACE NOT NULL NUMBER
EDITION_NAME VARCHAR2(128)
SHARING VARCHAR2(13)
EDITIONABLE VARCHAR2(1)
ORACLE_MAINTAINED VARCHAR2(1)
SQL> create index idx_test on test(object_id desc,object_name,object_type);
Index created.
SQL> select object_id from test where rownum<3;
OBJECT_ID
----------
10359
10358
SQL> set autot trace exp stat
SQL> select object_name from test where object_id in(10359,10358);
Execution Plan
----------------------------------------------------------
Plan hash value: 3459894390
------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 2 | 158 | 3 (0)| 00:00:01 |
| 1 | INLIST ITERATOR | | | | | |
|* 2 | INDEX RANGE SCAN| IDX_TEST | 2 | 158 | 3 (0)| 00:00:01 |
------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access(SYS_OP_DESCEND("OBJECT_ID")=HEXTORAW('3CFDFBC4FF') OR
SYS_OP_DESCEND("OBJECT_ID")=HEXTORAW('3CFDFBC3FF'))
filter(SYS_OP_UNDESCEND(SYS_OP_DESCEND("OBJECT_ID"))=10358 OR
SYS_OP_UNDESCEND(SYS_OP_DESCEND("OBJECT_ID"))=10359)
所以技術的進步總是一點一滴,新版本中已經做了修復,但是目前來看11g還是主流,所以我們在建立降序索引的時候還是需要注意,避免一些不必要的情況發生。
Physical Reads | Executions | Reads per Exec | %Total | Elapsed Time (s) | %CPU | %IO | SQL Id | SQL Module |
13,092,700 | 0 | 9.47 | 294.8 | 52.7 | 41.06 | 6src3hcd9mpt3 | T.O.A.D. |
SQL Text |
select * from mo1_memo where entity_id in (11889308, 11889311, 11888262, 11888261, 11889301) order by memo_date desc |
INDEX_NAME INDEX_TYPE UNIQUENES PAR COLUMN_LIST TABLE_TYPE STATUS NUM_ROWS LAST_ANAL G
------------------------------ ---------- ---------- --------- --- ------------------------------ ---------- ------ ---------- --------- -
MO1_MEMO_1IX FUNCTION-BASED NORMAL NONUNIQUE YES SYS_NC00031$,ENTITY_TYPE_ID,APP_ID TABLE N/A 554899259 01-APR-15 N
MO1_MEMO_2IX NORMAL NONUNIQUE YES MEMO_EXTERNAL_ID TABLE N/A 478847583 01-APR-15 N
MO1_MEMO_PK NORMAL UNIQUE YES MEMO_ID,APP_ID,ENTITY_KEY,PERIOD_KEY TABLE N/A 554900387 01-APR-15 N
有一個基於函式的索引,我們可以透過exp 或者dbms_metadata來得到相關的語句,發現索引是類似下面的形式。
create index MO1_MEMO_1IX on MO1_MEMO(entity_id desc,entity_type_id,app_id);
這是一個降序索引。對於這種降序索引,會在表中建立一個隱藏列。
SQL> select owner,column_name from all_tab_cols where table_name='MO1_MEMO' and hidden_column='YES';
APPO SYS_NC00031$
有了這些資訊,感覺應該是可以走索引掃描的。
但是得到的執行計劃中卻走了全表掃描,對一個資料量5億多資料的表走全表掃描,殺傷力是很大的。
但是奇怪的是使用下面兩種形式就沒有任何問題,索引都能正常啟用。
select * from mo1_memo where entity_id in (11889308) order by memo_date desc
select * from mo1_memo where entity_id =11889308 order by memo_date desc
一般來說降序索引在其值不為空的情況會啟用,根據目前的表結構來看entity_type_id和app_id有著not null constraint,所以應該能夠啟用才對。
帶著這個問題,我在11g的環境中簡單模擬了一把。
SQL> create table test as select *from all_objects where rownum<10000;
Table created.
SQL> desc test
Name Null? Type
----------------------------------------- -------- ----------------------------
OWNER NOT NULL VARCHAR2(30)
OBJECT_NAME NOT NULL VARCHAR2(30)
SUBOBJECT_NAME VARCHAR2(30)
OBJECT_ID NOT NULL NUMBER
DATA_OBJECT_ID NUMBER
OBJECT_TYPE VARCHAR2(19)
CREATED NOT NULL DATE
LAST_DDL_TIME NOT NULL DATE
TIMESTAMP VARCHAR2(19)
STATUS VARCHAR2(7)
TEMPORARY VARCHAR2(1)
GENERATED VARCHAR2(1)
SECONDARY VARCHAR2(1)
NAMESPACE NOT NULL NUMBER
EDITION_NAME VARCHAR2(30)
SQL> create index idx_test on test(object_id desc,object_name,object_type);
Index created.
SQL> select object_id from test where rownum<3;
OBJECT_ID
----------
2880583
2880575
SQL> set autot trace exp stat
下面兩種情況的執行計劃是一致的。
SQL> select *from test where object_id in (2880583,2880575);
SQL> select *from test where object_id=2880583;
Execution Plan
----------------------------------------------------------
Plan hash value: 1357081020
----------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost |
----------------------------------------------------------
| 0 | SELECT STATEMENT | | 127 | 20066 | 5 |
|* 1 | TABLE ACCESS FULL| TEST | 127 | 20066 | 5 |
----------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter("OBJECT_ID"=2880575 OR "OBJECT_ID"=2880583)
SQL> select *from test where object_id in (2880583)
Execution Plan
----------------------------------------------------------
Plan hash value: 2473784974
----------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
----------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 2 | 316 | 3 (0)| 00:00:01 |
| 1 | TABLE ACCESS BY INDEX ROWID| TEST | 2 | 316 | 3 (0)| 00:00:01 |
|* 2 | INDEX RANGE SCAN | IDX_TEST | 1 | | 2 (0)| 00:00:01 |
----------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access(SYS_OP_DESCEND("OBJECT_ID")=HEXTORAW('3BFCA6F9ABFF') )
filter(SYS_OP_UNDESCEND(SYS_OP_DESCEND("OBJECT_ID"))=2880583)
根據上面的輸出,感覺降序索引的細節上還有存在一定的問題,在最佳化器中可能沒有很好的支援,檢視MOS也沒有找到相關的bug.
SQL> select *from test where object_id=2880583;
Execution Plan
----------------------------------------------------------
Plan hash value: 1357081020
----------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost |
----------------------------------------------------------
| 0 | SELECT STATEMENT | | 127 | 20066 | 5 |
|* 1 | TABLE ACCESS FULL| TEST | 127 | 20066 | 5 |
----------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter("OBJECT_ID"=2880575 OR "OBJECT_ID"=2880583)
SQL> select *from test where object_id in (2880583)
Execution Plan
----------------------------------------------------------
Plan hash value: 2473784974
----------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
----------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 2 | 316 | 3 (0)| 00:00:01 |
| 1 | TABLE ACCESS BY INDEX ROWID| TEST | 2 | 316 | 3 (0)| 00:00:01 |
|* 2 | INDEX RANGE SCAN | IDX_TEST | 1 | | 2 (0)| 00:00:01 |
----------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access(SYS_OP_DESCEND("OBJECT_ID")=HEXTORAW('3BFCA6F9ABFF') )
filter(SYS_OP_UNDESCEND(SYS_OP_DESCEND("OBJECT_ID"))=2880583)
但是在12c的環境中,結果卻明顯不同,可見再最佳化器內部對於這種場景已經做了最佳化。
SQL> create table test as select *from all_objects where rownum<10000;
Table created.
SQL> desc test
Name Null? Type
----------------------------------------- -------- ----------------------------
OWNER NOT NULL VARCHAR2(128)
OBJECT_NAME NOT NULL VARCHAR2(128)
SUBOBJECT_NAME VARCHAR2(128)
OBJECT_ID NOT NULL NUMBER
DATA_OBJECT_ID NUMBER
OBJECT_TYPE VARCHAR2(23)
CREATED NOT NULL DATE
LAST_DDL_TIME NOT NULL DATE
TIMESTAMP VARCHAR2(19)
STATUS VARCHAR2(7)
TEMPORARY VARCHAR2(1)
GENERATED VARCHAR2(1)
SECONDARY VARCHAR2(1)
NAMESPACE NOT NULL NUMBER
EDITION_NAME VARCHAR2(128)
SHARING VARCHAR2(13)
EDITIONABLE VARCHAR2(1)
ORACLE_MAINTAINED VARCHAR2(1)
SQL> create index idx_test on test(object_id desc,object_name,object_type);
Index created.
SQL> select object_id from test where rownum<3;
OBJECT_ID
----------
10359
10358
SQL> set autot trace exp stat
SQL> select object_name from test where object_id in(10359,10358);
Execution Plan
----------------------------------------------------------
Plan hash value: 3459894390
------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 2 | 158 | 3 (0)| 00:00:01 |
| 1 | INLIST ITERATOR | | | | | |
|* 2 | INDEX RANGE SCAN| IDX_TEST | 2 | 158 | 3 (0)| 00:00:01 |
------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access(SYS_OP_DESCEND("OBJECT_ID")=HEXTORAW('3CFDFBC4FF') OR
SYS_OP_DESCEND("OBJECT_ID")=HEXTORAW('3CFDFBC3FF'))
filter(SYS_OP_UNDESCEND(SYS_OP_DESCEND("OBJECT_ID"))=10358 OR
SYS_OP_UNDESCEND(SYS_OP_DESCEND("OBJECT_ID"))=10359)
所以技術的進步總是一點一滴,新版本中已經做了修復,但是目前來看11g還是主流,所以我們在建立降序索引的時候還是需要注意,避免一些不必要的情況發生。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/30215233/viewspace-1586601/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 一條執行了3天的"簡單"的sqlSQL
- 角色resource在11g和12c中的區別
- 一條"簡單"的sql語句和小兔子買麵包的故事SQL
- 對一條基於分割槽的簡單SQL的優化SQL優化
- 一條SQL語句在MySQL中如何執行的MySql
- 一條簡單的sql語句導致的系統問題SQL
- 一條簡單的sql語句執行15天的原因分析SQL
- 34條簡單的SQL優化準則SQL優化
- 一條簡單SQL語句的構成及語句解析SQL
- 簡單對比MySQL和Oracle中的一個sql解析細節MySqlOracle
- 一條SQL在 MaxCompute 分散式系統中的旅程SQL分散式
- 一條sql語句在mysql中是如何執行的MySql
- 一條 SQL 語句在 MySQL 中是如何執行的?MySql
- 34條簡單的SQL最佳化準則SQL
- 一條簡單的SQL語句優化-新年新氣象SQL優化
- 【SQL Server中SMO的簡單使用】SQLServer
- MySql和簡單的sql語句MySql
- 關於在SQL語句中ON和WHERE中條件使用的差異SQL
- SQL Server中的鎖的簡單學習SQLServer
- 一個簡單的sql稽核案例SQL
- 【SQL】SQL中if條件的使用SQL
- pl/sql中的forall簡單測試SQL
- 使用 Postman 的 Environments 和 Tests 簡化在不同環境中的切換步驟Postman
- 簡單例子展示爬蟲在不同思想下的寫法單例爬蟲
- 關於SQL Server中儲存過程在C#中呼叫的簡單示例SQLServer儲存過程C#
- 超級簡單的sql入門(一)SQL
- mybatis條件判斷及動態sql的簡單擴充MyBatisSQL
- 關於create database語句在10g,11g中的不同Database
- 簡單的SVG線條動畫SVG動畫
- 一條簡單的報警資訊發現的oracle bugOracle
- 在Mysql中執行一條SQL,會經歷什麼?MySql
- 在 Golang 中實現一個簡單的Http中介軟體GolangHTTP
- 在jsp中呼叫一個簡單工廠的問題JS
- sql簡單入門的一些操作SQL
- SQL*Plus的簡單使用之一(轉)SQL
- 共享SQL區在shared pool中釋放的條件SQL
- 一條SQL的改寫SQL
- 在elasticsearch中簡單的使用script_fieldsElasticsearch