[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这类的写法,我估计在学校老师讲课就是使用这样的语法。
  一些有一定阅览的程序员才使用+这类语法。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值