[20160213]關於ansi語法.txt
[20160213]關於ansi語法.txt
--曾經寫過幾篇關於ansi語法的blog,參考連結:
[20120410]使用ANSI join syntax好嗎?.txt
http://blog.itpub.net/267265/viewspace-720875/
[20150423]left right join.txt
http://blog.itpub.net/267265/viewspace-1593068/
--我以前並不是學習計算機,我一開始學習連線就非常不習慣寫left join,right join的語法.
--oracle sql 語法裡面存在left join,right join連線,而且這種寫法是sql ansi標準.
--我個人工作習慣特別不喜歡這種寫法,使用(+)方式更多一些.
-- 實際上我以前開始學習oracle的時候,對於使用(+)那邊輸出NULL非常混亂.每次都拿scott schema的dept,emp來測試一次.
-- 後來我簡單的記憶是+表示多的意思,也就這個(+)對應的表不存在時輸出NULL值.
--正好春節前<Apress.Expert.Oracle.SQL.Optimization.Deployment.and.Statistics.1430259779.pdf>看完.很明顯作者喜歡使用ansi
--的語法.正好我想起以前最佳化的一個專案,裡面就大量的使用left,right連線的語法,我遇到這個問題我總是腦子轉換成+的寫法.關於這
--些我講講我個人的一些看法:
1.sql ansi語法是標準,自然許多人在用,我看過一些國外的論壇也有一些討論,我認為老外喜歡這種語法,我個人的感覺英文是他們的母語
而使用這種語法非常接近自然語言.而使用+ 我認為跟接近邏輯的表示.
而使用left 相當於在右邊加加號. right 正好相反.
除了一種情況,目前連線不支援兩邊有加號寫法.而使用full join.
2.如果還存在附加條件,使用left,right的語法相對簡單.
--實際上這個問題我第一次遇到實際上開發寫錯.很少遇到,我透過例子在重複說明看看;
SCOTT@test01p> @ver1
PORT_STRING VERSION BANNER CON_ID
-------------------- ---------- ---------------------------------------------------------------------------- ------
IBMPC/WIN_NT64-9.1.0 12.1.0.1.0 Oracle Database 12c Enterprise Edition Release 12.1.0.1.0 - 64bit Production 0
create table t1 as select rownum id,rownum||'t1' name from dual connect by level<=5;
create table t2 as select rownum+1 id,rownum||'t2' name from dual connect by level<=5;
create unique index i_t1_id on t1(id);
create unique index i_t2_id on t2(id);
--分析表略.
SCOTT@test01p> set null NULL
SCOTT@test01p> select * from t1 left join t2 on t1.id=t2.id and t2.id=2;
ID NAME ID NAME
---------- -------------------- ---------- --------------------
2 2t1 2 1t2
5 5t1 NULL NULL
4 4t1 NULL NULL
3 3t1 NULL NULL
1 1t1 NULL NULL
--我想實際的應用很少有查詢這樣的結果,實際上開發的本意是select * from t1 left join t2 on t1.id=t2.id where t2.id=2;
SCOTT@test01p> select * from t1 left join t2 on t1.id=t2.id where t2.id=2;
ID NAME ID NAME
---------- -------------------- ---------- --------------------
2 2t1 2 1t2
--再會過頭看上面的執行計劃:
Plan hash value: 2681112282
-------------------------------------------------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows |E-Bytes| Cost (%CPU)| E-Time | A-Rows | A-Time | Buffers | OMem | 1Mem | Used-Mem |
-------------------------------------------------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | | 4 (100)| | 5 |00:00:00.01 | 5 | | | |
|* 1 | HASH JOIN OUTER | | 1 | 5 | 70 | 4 (0)| 00:00:01 | 5 |00:00:00.01 | 5 | 1645K| 1645K| 1043K (0)|
| 2 | TABLE ACCESS FULL | T1 | 1 | 5 | 35 | 3 (0)| 00:00:01 | 5 |00:00:00.01 | 3 | | | |
| 3 | TABLE ACCESS BY INDEX ROWID| T2 | 1 | 1 | 7 | 1 (0)| 00:00:01 | 1 |00:00:00.01 | 2 | | | |
|* 4 | INDEX UNIQUE SCAN | I_T2_ID | 1 | 1 | | 0 (0)| | 1 |00:00:00.01 | 1 | | | |
-------------------------------------------------------------------------------------------------------------------------------------------------------------
Query Block Name / Object Alias (identified by operation id):
-------------------------------------------------------------
1 - SEL$0E991E55
2 - SEL$0E991E55 / T1@SEL$1
3 - SEL$0E991E55 / T2@SEL$1
4 - SEL$0E991E55 / T2@SEL$1
Predicate Information (identified by operation id):
---------------------------------------------------
1 - access("T1"."ID"="T2"."ID")
4 - access("T2"."ID"=2)
Note
-----
- this is an adaptive plan
D:\tools\sqllaji>cat 10053x.sql
execute dbms_sqldiag.dump_trace(p_sql_id=>'&1',p_child_number=>&2,p_component=>'Compiler',p_file_id=>'&&1');
SCOTT@test01p> @10053x bzjahpxh02m63 0
PL/SQL procedure successfully completed.
--檢視轉儲檔案:
Final query after transformations:******* UNPARSED QUERY IS *******
SELECT "T1"."ID" "ID","T1"."NAME" "NAME","T2"."ID" "ID","T2"."NAME" "NAME"
FROM "SCOTT"."T1" "T1","SCOTT"."T2" "T2"
WHERE "T1"."ID" = "T2"."ID"(+)
AND "T2"."ID"(+) = 2;
--相當於執行如下:
select * from t1,t2 where t1.id= t2.id(+) and t2.id(+) = 2;
--從這裡可以在oracle內部實際上最終轉化為使用+的格式。
3.再來看看另外一種查詢情況:
--僅僅把後面的查詢條件t2.id=2 換成 t1.id=2. 上班環境變成11G,繼續測試。
select * from t1 left join t2 on t1.id=t2.id where t1.id=2;
PLAN_TABLE_OUTPUT
-------------------------------------
SQL_ID 5katgcygcphpc, child number 0
-------------------------------------
select * from t1 left join t2 on t1.id=t2.id and t1.id=2
Plan hash value: 1823443478
------------------------------------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows |E-Bytes| Cost (%CPU)| E-Time | A-Rows | A-Time | Buffers | OMem | 1Mem | Used-Mem |
------------------------------------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | | 6 (100)| | 5 |00:00:00.01 | 5 | | | |
|* 1 | HASH JOIN OUTER | | 1 | 5 | 70 | 6 (0)| 00:00:01 | 5 |00:00:00.01 | 5 | 1645K| 1645K| 897K (0)|
| 2 | TABLE ACCESS FULL| T1 | 1 | 5 | 35 | 3 (0)| 00:00:01 | 5 |00:00:00.01 | 2 | | | |
| 3 | TABLE ACCESS FULL| T2 | 1 | 5 | 35 | 3 (0)| 00:00:01 | 5 |00:00:00.01 | 3 | | | |
------------------------------------------------------------------------------------------------------------------------------------------------
Query Block Name / Object Alias (identified by operation id):
-------------------------------------------------------------
1 - SEL$9E43CB6E
2 - SEL$9E43CB6E / T1@SEL$2
3 - SEL$9E43CB6E / T2@SEL$1
Predicate Information (identified by operation id):
---------------------------------------------------
1 - access("T1"."ID"="T2"."ID" AND "T1"."ID"=CASE WHEN ("T2"."ID" IS NOT NULL) THEN 2 ELSE 2 END )
--注意我僅僅修改查詢條件:t2.id=2 換成 t1.id=2。這個時候建立在t1.id上的索引就沒有用,變成了全表掃描。
SCOTT@book> @&r/10053x 5katgcygcphpc 0
BEGIN dbms_sqldiag.dump_trace(p_sql_id=>'5katgcygcphpc',p_child_number=>0,p_component=>'Compiler',p_file_id=>'5katgcygcphpc'); END;
*
ERROR at line 1:
ORA-44003: invalid SQL name
ORA-06512: at "SYS.DBMS_ASSERT", line 206
ORA-06512: at "SYS.DBMS_SQLDIAG", line 1185
ORA-06512: at line 1
--奇怪使用dbms_sqldiag.dump_trace會報錯。先放棄,使用10053跟蹤看看:
SCOTT@book> @ &r/10053on 12
Session altered.
SCOTT@book> Select * from t1 left join t2 on t1.id=t2.id and t1.id=2;
ID NAME ID NAME
---------- -------------------- ---------- --------------------
2 2t1 2 1t2
4 4t1
3 3t1
1 1t1
5 5t1
--注意要產生1次硬分析,我修改select的第一個字母大寫。
SCOTT@book> @ &r/10053off
Session altered.
--檢查轉儲跟蹤檔案:
Final query after transformations:******* UNPARSED QUERY IS *******
SELECT "T1"."ID" "ID","T1"."NAME" "NAME","T2"."ID" "ID","T2"."NAME" "NAME"
FROM "SCOTT"."T1" "T1","SCOTT"."T2" "T2"
WHERE "T1"."ID" = "T2"."ID"(+)
AND "T1"."ID" =
CASE
WHEN ("T2"."ID"(+) IS NOT NULL) THEN 2
ELSE 2
END
--從這些資訊可以發現在oracle內部實際上是轉化為+的語法。
4.再在10g下測試看看:
SCOTT@test> @ &r/ver1
PORT_STRING VERSION BANNER
------------------------------ -------------- ----------------------------------------------------------------
x86_64/Linux 2.4.xx 10.2.0.4.0 Oracle Database 10g Enterprise Edition Release 10.2.0.4.0 - 64bi
--建表分析略。
SCOTT@test> @ &r/10053on 12
Session altered.
SCOTT@test> Select * from t1 left join t2 on t1.id=t2.id and t1.id=2;
ID NAME ID NAME
---------- -------------------- ---------- --------------------
1 1t1
2 2t1 2 1t2
3 3t1
4 4t1
5 5t1
SCOTT@test> @ &r/10053off
Session altered.
PLAN_TABLE_OUTPUT
-------------------------------------
SQL_ID 6cmyybkz1mmna, child number 0
-------------------------------------
Select * from t1 left join t2 on t1.id=t2.id and t1.id=2
Plan hash value: 2158509815
-------------------------------------------------------------------------------------------
| Id | Operation | Name | E-Rows |E-Bytes| Cost (%CPU)| E-Time |
-------------------------------------------------------------------------------------------
| 1 | NESTED LOOPS OUTER | | 5 | 215 | 8 (0)| 00:00:01 |
| 2 | TABLE ACCESS FULL | T1 | 5 | 35 | 3 (0)| 00:00:01 |
| 3 | VIEW | | 1 | 36 | 1 (0)| 00:00:01 |
|* 4 | FILTER | | | | | |
| 5 | TABLE ACCESS BY INDEX ROWID| T2 | 1 | 7 | 1 (0)| 00:00:01 |
|* 6 | INDEX UNIQUE SCAN | I_T2_ID | 1 | | 0 (0)| |
-------------------------------------------------------------------------------------------
Query Block Name / Object Alias (identified by operation id):
-------------------------------------------------------------
1 - SEL$64EAE176
2 - SEL$64EAE176 / T1@SEL$2
3 - SEL$1 / from$_subquery$_004@SEL$2
4 - SEL$1
5 - SEL$1 / T2@SEL$1
6 - SEL$1 / T2@SEL$1
Predicate Information (identified by operation id):
---------------------------------------------------
4 - filter("T1"."ID"=2)
6 - access("T2"."ID"=2)
Note
-----
- Warning: basic plan statistics not available. These are only collected when:
* hint 'gather_plan_statistics' is used for the statement or
* parameter 'statistics_level' is set to 'ALL', at session or system level
--10g下可以使用t2.id的索引。檢視轉儲檔案:(顯示的方便我做了格式化處理)
******* UNPARSED QUERY IS *******
SELECT "T1"."ID" "ID","T1"."NAME" "NAME","
FROM $_subquery$_004"."ID" "ID","
FROM $_subquery$_004"."NAME" "NAME"
FROM "SCOTT"."T1" "T1", LATERAL( (
SELECT "T2"."ID" "ID","T2"."NAME" "NAME"
FROM "SCOTT"."T2" "T2"
WHERE "T1"."ID" = 2
AND "T2"."ID" = 2))(+) "FROM $_subquery$_004";
--奇怪10g就出現LATERAL語法,不過這裡顯示的是UNPARSED QUERY IS。看不到轉化後的sql語句
--在10g如果你執行如下:
SELECT "T1"."ID" "ID","T1"."NAME" "NAME","T2"."ID" "ID","T2"."NAME" "NAME"
FROM "SCOTT"."T1" "T1","SCOTT"."T2" "T2"
WHERE "T1"."ID" = "T2"."ID"(+)
AND "T1"."ID" =
CASE
WHEN ("T2"."ID"(+) IS NOT NULL) THEN 2
ELSE 2
END;
ID NAME ID NAME
---------- -------------------- ---------- --------------------
2 2t1 2 1t2
--僅僅輸出1行,與前面不符合。執行計劃如下:
Plan hash value: 1933428060
-----------------------------------------------------------------------------------------
| Id | Operation | Name | E-Rows |E-Bytes| Cost (%CPU)| E-Time |
-----------------------------------------------------------------------------------------
| 1 | NESTED LOOPS OUTER | | 1 | 14 | 2 (0)| 00:00:01 |
| 2 | TABLE ACCESS BY INDEX ROWID| T1 | 1 | 7 | 1 (0)| 00:00:01 |
|* 3 | INDEX UNIQUE SCAN | I_T1_ID | 1 | | 0 (0)| |
| 4 | TABLE ACCESS BY INDEX ROWID| T2 | 5 | 35 | 1 (0)| 00:00:01 |
|* 5 | INDEX UNIQUE SCAN | I_T2_ID | 1 | | 0 (0)| |
-----------------------------------------------------------------------------------------
Query Block Name / Object Alias (identified by operation id):
-------------------------------------------------------------
1 - SEL$1
2 - SEL$1 / T1@SEL$1
3 - SEL$1 / T1@SEL$1
4 - SEL$1 / T2@SEL$1
5 - SEL$1 / T2@SEL$1
Predicate Information (identified by operation id):
---------------------------------------------------
3 - access("T1"."ID"=2)
5 - access("T1"."ID"="T2"."ID")
5.從以上的分析,我個人的感覺應該在開發內部同一程式設計風格,我更傾向於使用+的方式。
而且我發現剛剛畢業好像更喜歡使用left,right這類的寫法,我估計在學校老師講課就是使用這樣的語法。
一些有一定閱覽的程式設計師才使用+這類語法。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/267265/viewspace-1988395/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- [20180912]關於ANSI joins語法.txt
- [20230207]ANSI DATE and TIMESTAMP SQL syntax.txtSQL
- ANSI C定義的一些關於可移植性的術語說明
- [20230905]奇怪的語法.txt
- 關於輸出的小語法點
- 關於PHP的語法介紹,新手必看PHP
- [20200227]使用tcpdump or and ()語法問題.txtTCP
- [20191202]關於hugepages相關問題.txt
- 【Vue3.0】關於 script setup 語法糖的用法Vue
- [201804012]關於hugepages 3.txt
- [20180306]關於DEFERRED ROLLBACK.txt
- [20210506]]關於ORA-01450.txt
- 關於ES6、ES7的常用語法整理
- [20181123]關於降序索引問題.txt索引
- [20181212]關於truncate reuse storage.txt
- [20190401]關於semtimedop函式呼叫.txt函式
- [20180705]關於hash join 2.txt
- [20190821]關於CPU成本計算.txt
- [20191129]關於hugepages的問題.txt
- [20180306]關於DEFERRED ROLLBACK2.txt
- [20180403]關於時區問題.txt
- [20210527]關於v$wait_chain.txtAI
- [20210410]關於time命令的解析.txt
- Python相關語法2Python
- 關於刷表法
- [20190415]關於shared latch(共享栓鎖).txt
- [20190918]關於函式索引問題.txt函式索引
- [20200223]關於latch and mutext的優化.txtMutex優化
- [20201104]關於稀疏檔案(sparse files).txt
- [20181229]關於字串的分配問題.txt字串
- [20230317]關於TIME_WAIT問題.txtAI
- [20210520]關於主鍵索引問題.txt索引
- CMakeLists.txt 語法介紹與例項演練
- [20191220]關於共享記憶體段相關問題.txt記憶體
- [20190402]關於semtimedop函式呼叫2.txt函式
- [20181124]關於降序索引問題4.txt索引
- [20181124]關於降序索引問題3.txt索引
- [20181124]關於降序索引問題2.txt索引
- [20190910]關於降序索引問題5.txt索引