【Oracle】where條件執行順序(上篇的問題延伸)
上篇問題連結:http://blog.itpub.net/30174570/viewspace-2148592/
問題:
為什麼語句“select value from t where name='db_block_size' and to_number(value)=8192;”執行成功,換成v$parameter卻報錯。
實驗研究過程:
一開始看到這個執行計劃很懵逼,完全搞不懂為什麼能夠執行成功,做10046,10053,改寫sql加hint還是搞不懂。
最後猜想Oracle在filter("NAME"='db_block_size' AND TO_NUMBER("VALUE")=8192)這個步驟,是先對資料做name='db_block_size'的過濾,在做to_number('value')=8192的過濾。
若是能將謂詞資訊改變成filter(TO_NUMBER("VALUE") AND "NAME"='db_block_size'=8192)並且執行報錯,那麼猜想就是正確的。
嘗試將sql語句的and條件調換位置"select value from t where to_number(value)=8192 and name='db_block_size';",不過還是和原來一樣,這裡省略步驟。
這裡構造其他測試表:
這裡執行以下4條sql語句:
①Select 'ok' From aaa where id1/id2=1 and id3/id4=2;
②Select 'ok' From aaa where id1/id2=2 and id3/id4=2;
③Select 'ok' From aaa where id3/id4=2 and id1/id2=1;
④Select 'ok' From aaa where id3/id4=2 and id1/id2=2;
其中①和③,②和④只是where後條件位置互換而已。
檢視執行結果:
②和④只是位置不同,但是一個卻正常執行,一個卻報錯了。
這裡檢視兩條sql的執行計劃:
這裡對比謂詞資訊剛好是兩個位置不同,導致執行結果不一樣。
正好說明上邊的問題的猜想:
最後猜想Oracle在filter("NAME"='db_block_size' AND TO_NUMBER("VALUE")=8192)這個步驟,是先對資料做name='db_block_size'的過濾,在做to_number('value')=8192的過濾。
若是能將謂詞資訊改變成filter(TO_NUMBER("VALUE") AND "NAME"='db_block_size'=8192)並且執行報錯,那麼猜想就是正確的。
由此問題解決。
其他:
所以where後邊條件的執行順序,實際上和執行計劃謂詞資訊的順序有關,和where的位置無關。
網上有些在10g做實驗得出結論是從右到左,在11g裡邊,按照相同步驟執行並得不出相同結論。
問題延伸:
filter("NAME"='db_block_size' AND TO_NUMBER("VALUE")=8192),這裡是一次性掃描出全部資料在進行過濾,還是一行一行獲取在判斷的。
延伸連結:http://blog.itpub.net/30174570/viewspace-2149212/
問題:
-
SYS@proc> create table t as select * from v$parameter;
-
-
Table created.
-
-
SYS@proc> select value from t where name='db_block_size' and to_number(value)=8192;
-
-
VALUE
-
--------------------------------------------------------------------------------
-
8192
-
-
SYS@proc> select value from v$parameter where name='db_block_size' and to_number(value)=8192;
-
select value from v$parameter where name='db_block_size' and to_number(value)=8192
-
*
-
ERROR at line 1:
- ORA-01722: invalid number
實驗研究過程:
-
SYS@proc> set autotrace on
-
SYS@proc> analyze table t compute statistics;
-
-
Table analyzed.
-
-
SYS@proc> select value from t where name='db_block_size' and to_number(value)=8192;
-
-
VALUE
-
--------------------------------------------------------------------------------
-
8192
-
-
-
Execution Plan
-
----------------------------------------------------------
-
Plan hash value: 1601196873
-
-
--------------------------------------------------------------------------
-
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-
--------------------------------------------------------------------------
-
| 0 | SELECT STATEMENT | | 1 | 26 | 4 (0)| 00:00:01 |
-
|* 1 | TABLE ACCESS FULL| T | 1 | 26 | 4 (0)| 00:00:01 |
-
--------------------------------------------------------------------------
-
-
Predicate Information (identified by operation id):
-
---------------------------------------------------
-
-
1 - filter("NAME"='db_block_size' AND TO_NUMBER("VALUE")=8192)
-
-
-
Statistics
-
----------------------------------------------------------
-
1 recursive calls
-
0 db block gets
-
9 consistent gets
-
0 physical reads
-
0 redo size
-
525 bytes sent via SQL*Net to client
-
523 bytes received via SQL*Net from client
-
2 SQL*Net roundtrips to/from client
-
0 sorts (memory)
-
0 sorts (disk)
- 1 rows processed
最後猜想Oracle在filter("NAME"='db_block_size' AND TO_NUMBER("VALUE")=8192)這個步驟,是先對資料做name='db_block_size'的過濾,在做to_number('value')=8192的過濾。
若是能將謂詞資訊改變成filter(TO_NUMBER("VALUE") AND "NAME"='db_block_size'=8192)並且執行報錯,那麼猜想就是正確的。
嘗試將sql語句的and條件調換位置"select value from t where to_number(value)=8192 and name='db_block_size';",不過還是和原來一樣,這裡省略步驟。
這裡構造其他測試表:
-
SYS@proc> create table a(id1 int,id2 int,id3 int,id4 int);
-
-
Table created.
-
-
SYS@proc> insert into a values(1,1,1,0);
-
-
1 row created.
-
-
SYS@proc> commit;
-
-
Commit complete.
-
-
SYS@proc> select * from a;
-
-
ID1 ID2 ID3 ID4
-
---------- ---------- ---------- ----------
- 1 1 1 0
①Select 'ok' From aaa where id1/id2=1 and id3/id4=2;
②Select 'ok' From aaa where id1/id2=2 and id3/id4=2;
③Select 'ok' From aaa where id3/id4=2 and id1/id2=1;
④Select 'ok' From aaa where id3/id4=2 and id1/id2=2;
其中①和③,②和④只是where後條件位置互換而已。
檢視執行結果:
-
SYS@proc> Select 'ok' From aaa where id1/id2=1 and id3/id4=2;
-
Select 'ok' From aaa where id1/id2=1 and id3/id4=2
-
*
-
ERROR at line 1:
-
ORA-01476: divisor is equal to zero
-
-
-
SYS@proc> Select 'ok' From aaa where id1/id2=2 and id3/id4=2;
-
-
no rows selected
-
-
SYS@proc> Select 'ok' From aaa where id3/id4=2 and id1/id2=1;
-
Select 'ok' From aaa where id3/id4=2 and id1/id2=1
-
*
-
ERROR at line 1:
-
ORA-01476: divisor is equal to zero
-
-
-
SYS@proc> Select 'ok' From aaa where id3/id4=2 and id1/id2=2;
-
Select 'ok' From aaa where id3/id4=2 and id1/id2=2
-
*
-
ERROR at line 1:
- ORA-01476: divisor is equal to zero
這裡檢視兩條sql的執行計劃:
-
SYS@proc> explain plan for Select 'ok' From aaa where id1/id2=2 and id3/id4=2;
-
-
Explained.
-
-
SYS@proc> select * from table(dbms_xplan.display());
-
-
PLAN_TABLE_OUTPUT
-
--------------------------------------------------------------------------------
-
Plan hash value: 864433273
-
-
-----------------------------------------------------------------------
-
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-
------------------------------------------------------------------------
-
| 0 | SELECT STATEMENT | | 1 | 12 | 2 (0)| 00:00:01 |
-
|* 1 | TABLE ACCESS FULL| AAA | 1 | 12 | 2 (0)| 00:00:01 |
-
-----------------------------------------------------------------------
-
-
Predicate Information (identified by operation id):
-
---------------------------------------------------
-
-
PLAN_TABLE_OUTPUT
-
--------------------------------------------------------------------------------
-
-
1 - filter("ID1"/"ID2"=2 AND "ID3"/"ID4"=2)
-
-
13 rows selected.
-
-
SYS@proc> explain plan for Select 'ok' From aaa where id3/id4=2 and id1/id2=2;
-
-
Explained.
-
-
SYS@proc> select * from table(dbms_xplan.display());
-
-
PLAN_TABLE_OUTPUT
-
--------------------------------------------------------------------------------
-
Plan hash value: 864433273
-
-
------------------------------------------------------------------------
-
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-
------------------------------------------------------------------------
-
| 0 | SELECT STATEMENT | | 1 | 12 | 2 (0)| 00:00:01 |
-
|* 1 | TABLE ACCESS FULL| AAA | 1 | 12 | 2 (0)| 00:00:01 |
-
------------------------------------------------------------------------
-
-
Predicate Information (identified by operation id):
-
---------------------------------------------------
-
-
PLAN_TABLE_OUTPUT
-
--------------------------------------------------------------------------------
-
-
1 - filter("ID3"/"ID4"=2 AND "ID1"/"ID2"=2)
-
- 13 rows selected.
正好說明上邊的問題的猜想:
最後猜想Oracle在filter("NAME"='db_block_size' AND TO_NUMBER("VALUE")=8192)這個步驟,是先對資料做name='db_block_size'的過濾,在做to_number('value')=8192的過濾。
若是能將謂詞資訊改變成filter(TO_NUMBER("VALUE") AND "NAME"='db_block_size'=8192)並且執行報錯,那麼猜想就是正確的。
由此問題解決。
其他:
-
SYS@proc> create table test (id int);
-
-
Table created.
-
-
SYS@proc> insert into test values(null);
-
-
1 row created.
-
SYS@proc> commit;
-
-
Commit complete.
-
-
SYS@proc> select * from test;
-
-
ID
-
----------
-
-
-
SYS@proc> set autotrace on
-
SYS@proc> select value from t,test a where a.id||name='db_block_size' and to_number(a.id||t.value)=8192;
-
-
VALUE
-
--------------------------------------------------------------------------------
-
8192
-
-
-
Execution Plan
-
----------------------------------------------------------
-
Plan hash value: 423998170
-
-
---------------------------------------------------------------------------
-
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-
---------------------------------------------------------------------------
-
| 0 | SELECT STATEMENT | | 1 | 39 | 6 (0)| 00:00:01 |
-
| 1 | NESTED LOOPS | | 1 | 39 | 6 (0)| 00:00:01 |
-
| 2 | TABLE ACCESS FULL| TEST | 1 | 13 | 2 (0)| 00:00:01 |
-
|* 3 | TABLE ACCESS FULL| T | 1 | 26 | 4 (0)| 00:00:01 |
-
---------------------------------------------------------------------------
-
-
Predicate Information (identified by operation id):
-
---------------------------------------------------
-
-
3 - filter(TO_CHAR("A"."ID")||"NAME"='db_block_size' AND
-
TO_NUMBER(TO_CHAR("A"."ID")||"T"."VALUE")=8192)
-
-
Note
-
-----
-
- dynamic sampling used for this statement (level=2)
-
-
-
Statistics
-
----------------------------------------------------------
-
32 recursive calls
-
0 db block gets
-
28 consistent gets
-
0 physical reads
-
0 redo size
-
525 bytes sent via SQL*Net to client
-
523 bytes received via SQL*Net from client
-
2 SQL*Net roundtrips to/from client
-
4 sorts (memory)
-
0 sorts (disk)
-
1 rows processed
-
-
SYS@proc> set autotrace off
-
SYS@proc> select value from t,test a where to_number(a.id||t.value)=8192 and a.id||name='db_block_size';
-
select value from t,test a where to_number(a.id||t.value)=8192 and a.id||name='db_block_size'
-
*
-
ERROR at line 1:
-
ORA-01722: invalid number
-
-
-
SYS@proc> explain plan for select value from t,test a where to_number(a.id||t.value)=8192 and a.id||name='db_block_size';
-
-
Explained.
-
-
SYS@proc> select * from table(dbms_xplan.display());
-
-
PLAN_TABLE_OUTPUT
-
--------------------------------------------------------------------------------
-
Plan hash value: 423998170
-
-
---------------------------------------------------------------------------
-
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-
---------------------------------------------------------------------------
-
| 0 | SELECT STATEMENT | | 1 | 39 | 6 (0)| 00:00:01 |
-
| 1 | NESTED LOOPS | | 1 | 39 | 6 (0)| 00:00:01 |
-
| 2 | TABLE ACCESS FULL| TEST | 1 | 13 | 2 (0)| 00:00:01 |
-
|* 3 | TABLE ACCESS FULL| T | 1 | 26 | 4 (0)| 00:00:01 |
-
---------------------------------------------------------------------------
-
-
-
PLAN_TABLE_OUTPUT
-
--------------------------------------------------------------------------------
-
Predicate Information (identified by operation id):
-
---------------------------------------------------
-
-
3 - filter(TO_NUMBER(TO_CHAR("A"."ID")||"T"."VALUE")=8192 AND
-
TO_CHAR("A"."ID")||"NAME"='db_block_size')
-
- 16 rows selected.
所以where後邊條件的執行順序,實際上和執行計劃謂詞資訊的順序有關,和where的位置無關。
網上有些在10g做實驗得出結論是從右到左,在11g裡邊,按照相同步驟執行並得不出相同結論。
問題延伸:
filter("NAME"='db_block_size' AND TO_NUMBER("VALUE")=8192),這裡是一次性掃描出全部資料在進行過濾,還是一行一行獲取在判斷的。
延伸連結:http://blog.itpub.net/30174570/viewspace-2149212/
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/30174570/viewspace-2148607/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- connect by與where條件執行順序問題
- Oracle中where子句中條件的物理執行順序Oracle
- 【實驗】where子句的解析順序及執行效率
- 關於defer執行順序問題
- sql中的or與and的執行順序問題SQL
- SQL語句中的AND和OR執行順序問題SQL
- 如何使用ReentrantLock的條件變數,讓多個執行緒順序執行?ReentrantLock變數執行緒
- SQL中rownum和order by的執行順序的問題SQL
- MySQL的where條件字串區分大小寫的問題MySql字串
- C++輸出流cout的執行順序問題C++
- GROUPBY 和開窗函式執行順序的問題函式
- 你瞭解一條sql的執行順序嗎SQL
- JavaScript的執行順序JavaScript
- Sql執行順序SQL
- switch拼接where條件
- [學習筆記]分組資料以及on/where/having的順序問題筆記
- unittest.TestCase中測試用例執行順序問題
- SQL 優先順序join>whereSQL
- js基礎進階–promise和setTimeout執行順序的問題JSPromise
- SQL中on條件與where條件的區別[轉]SQL
- JavaScript執行順序分析JavaScript
- 任務執行順序
- for語句執行順序
- laravel Event執行順序Laravel
- mySQL 執行語句執行順序MySql
- 關於 Promise 的執行順序Promise
- Spring Aop的執行順序Spring
- SQL 語句的執行順序SQL
- CSS規則的執行順序CSS
- Java類的基本執行順序Java
- SQL 執行順序 你懂的SQL
- pipeline的執行順序
- mysql 語句的執行順序MySql
- ajax回撥函式執行順序帶來的同步非同步問題函式非同步
- 生產資料update沒加where條件(從執行到恢復)
- thinkphp where in order 按照順序in的迴圈排序PHP排序
- sql mysql 執行順序 (4)MySql
- SQL語句執行順序SQL