yangtingkun
===========================================================
缺少GROUP BY表达式可以顺利执行的问题
===========================================================

Oracle9204上执行一个明显语法错误的SQL,却可以得到查询结果。


首先重现一下问题:

SQL> CREATE TABLE T1 AS SELECT * FROM DBA_OBJECTS;

表已创建。

SQL> CREATE TABLE T2 AS SELECT * FROM DBA_USERS;

表已创建。

SQL> SELECT OWNER, OBJECT_TYPE, COUNT(*) CN FROM T1 GROUP BY OBJECT_TYPE;
SELECT OWNER, OBJECT_TYPE, COUNT(*) CN FROM T1 GROUP BY OBJECT_TYPE
*
1 行出现错误:
ORA-00979:
不是 GROUP BY 表达式

这个SQL由于GROUP BY语句中确少OWNER字段,因此执行报错。

但是把这个SQL内嵌到子查询中,居然可以得到结果:

SQL> SELECT USERNAME, OBJECT_TYPE, CN
2 FROM (SELECT OWNER, OBJECT_TYPE, COUNT(*) CN FROM T1 GROUP BY OBJECT_TYPE), T2
3 WHERE USERNAME = OWNER
4 AND USERNAME LIKE 'SYS%';

USERNAME OBJECT_TYPE CN
------------------------------ ------------------ ----------
SYS LOB 28
SYS TYPE 478
SYS VIEW 2112
.
.
.
SYSTEM INDEX PARTITION 48
SYSTEM TABLE PARTITION 53

已选择42行。

检查SQL的执行计划,发现是MERGE JOIN

SQL> SELECT USERNAME, OBJECT_TYPE, CN
2 FROM (SELECT OWNER, OBJECT_TYPE, COUNT(*) CN FROM T1 GROUP BY OBJECT_TYPE), T2
3 WHERE USERNAME = OWNER
4 AND USERNAME LIKE 'SYS%';

执行计划
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE
1 0 SORT (GROUP BY)
2 1 MERGE JOIN
3 2 SORT (JOIN)
4 3 TABLE ACCESS (FULL) OF 'T2'
5 2 SORT (JOIN)
6 5 TABLE ACCESS (FULL) OF 'T1'

想想也有道理,Oracle先对OWNER字段进行排序,进行MERGE JOIN连接后,再对OBJECT_TYPE字段进行GROUP BY

如果使用HASH_JOIN提示,Oracle也可以得到执行结果:

SQL> SET AUTOT TRACE EXP
SQL> SELECT /*+ USE_HASH(T2) */ USERNAME, OBJECT_TYPE, CN
2 FROM (SELECT OWNER, OBJECT_TYPE, COUNT(*) CN FROM T1 GROUP BY OBJECT_TYPE), T2
3 WHERE USERNAME = OWNER
4 AND USERNAME LIKE 'SYS%';

执行计划
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE (Cost=54 Card=1467 Bytes=76284)
1 0 SORT (GROUP BY) (Cost=54 Card=1467 Bytes=76284)
2 1 HASH JOIN (Cost=45 Card=1467 Bytes=76284)
3 2 TABLE ACCESS (FULL) OF 'T2' (Cost=2 Card=2 Bytes=48)
4 2 TABLE ACCESS (FULL) OF 'T1' (Cost=42 Card=5867 Bytes=164276)

不过这个SQL也很有意思,只需要将上面的USERNAME改成OWNER,就会报错:

SQL> SELECT OWNER, OBJECT_TYPE, CN
2 FROM (SELECT OWNER, OBJECT_TYPE, COUNT(*) CN FROM T1 GROUP BY OBJECT_TYPE), T2
3 WHERE USERNAME = OWNER
4 AND USERNAME LIKE 'SYS%';
WHERE USERNAME = OWNER
*
3 行出现错误:
ORA-00979:
不是 GROUP BY 表达式

这时即使加上HINT也不行:

SQL> SELECT /*+ USE_HASH(T2) */ OWNER, OBJECT_TYPE, CN
2 FROM (SELECT OWNER, OBJECT_TYPE, COUNT(*) CN FROM T1 GROUP BY OBJECT_TYPE) T1, T2
3 WHERE USERNAME = OWNER
4 AND USERNAME LIKE 'SYS%';
WHERE USERNAME = OWNER
*
3 行出现错误:
ORA-00979:
不是 GROUP BY 表达式

这个问题在10R2中只能通过RULE方式再现,通过使用USE_MERGEUSE_HASH提示已经无法再现了:

SQL> CONN TEST/TEST@TESTZJ已连接。
SQL> SELECT * FROM V$VERSION;

BANNER
----------------------------------------------------------------
Oracle Database 10g Enterprise Edition Release 10.2.0.3.0 - 64bi
PL/SQL Release 10.2.0.3.0 - Production
CORE 10.2.0.3.0 Production
TNS for Linux: Version 10.2.0.3.0 - Production
NLSRTL Version 10.2.0.3.0 - Production

SQL> CREATE TABLE T1 AS SELECT * FROM DBA_OBJECTS;

表已创建。

SQL> CREATE TABLE T2 AS SELECT * FROM DBA_USERS;

表已创建。

SQL> SELECT USERNAME, OBJECT_TYPE, CN
2 FROM (SELECT OWNER, OBJECT_TYPE, COUNT(*) CN FROM T1 GROUP BY OBJECT_TYPE), T2
3 WHERE USERNAME = OWNER
4 AND USERNAME LIKE 'SYS%';
FROM (SELECT OWNER, OBJECT_TYPE, COUNT(*) CN FROM T1 GROUP BY OBJECT_TYPE), T2
*
2 行出现错误:
ORA-00979:
不是 GROUP BY 表达式

SQL> SET AUTOT ON EXP
SQL> SELECT /*+ RULE */ USERNAME, OBJECT_TYPE, CN
2 FROM (SELECT OWNER, OBJECT_TYPE, COUNT(*) CN FROM T1 GROUP BY OBJECT_TYPE), T2
3 WHERE USERNAME = OWNER
4 AND USERNAME LIKE 'SYS%';

USERNAME OBJECT_TYPE CN
------------------------------ ------------------- ----------
SYS JOB 4
SYS LOB 95
SYS RULE 4
SYS TYPE 933
.
.
.
SYSTEM INDEX PARTITION 64
SYSTEM TABLE PARTITION 53

已选择53行。

执行计划
----------------------------------------------------------

-------------------------------------
| Id | Operation | Name |
-------------------------------------
| 0 | SELECT STATEMENT | |
| 1 | SORT GROUP BY | |
| 2 | MERGE JOIN | |
| 3 | SORT JOIN | |
|* 4 | TABLE ACCESS FULL| T2 |
|* 5 | SORT JOIN | |
|* 6 | TABLE ACCESS FULL| T1 |
-------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

4 - filter("USERNAME" LIKE 'SYS%')
5 - access("USERNAME"="OWNER")
filter("USERNAME"="OWNER")
6 - filter("OWNER" LIKE 'SYS%')

SQL> SELECT /*+ USE_MERGE(T2) */ USERNAME, OBJECT_TYPE, CN
2 FROM (SELECT OWNER, OBJECT_TYPE, COUNT(*) CN FROM T1 GROUP BY OBJECT_TYPE), T2
3 WHERE USERNAME = OWNER
4 AND USERNAME LIKE 'SYS%';
FROM (SELECT OWNER, OBJECT_TYPE, COUNT(*) CN FROM T1 GROUP BY OBJECT_TYPE), T2
*
2 行出现错误:
ORA-00979:
不是 GROUP BY 表达式


SQL> SELECT /*+ USE_HASH(T2) */ USERNAME, OBJECT_TYPE, CN
2 FROM (SELECT OWNER, OBJECT_TYPE, COUNT(*) CN FROM T1 GROUP BY OBJECT_TYPE), T2
3 WHERE USERNAME = OWNER
4 AND USERNAME LIKE 'SYS%';
FROM (SELECT OWNER, OBJECT_TYPE, COUNT(*) CN FROM T1 GROUP BY OBJECT_TYPE), T2
*
2 行出现错误:
ORA-00979:
不是 GROUP BY 表达式

看来虽然Oracle10gCBO已经修正了这个问题,但是RBO中依然存在,而且在Metalink中并没有看到类似的问题描述,怀疑是CBO优化器的升级使得这个bug不可能在新版中再现,而并非是Oracle有意去修正这个问题。

yangtingkun 发表于:2008.01.11 23:14 ::分类: ( ORACLE , Bug ) ::阅读:(1554次) :: 评论 (4)
re: 缺少GROUP BY表达式可以顺利执行的问题 [回复]

merge 的问题吧
10.2.0.3
SELECT/*+ MERGE(t) */ USERNAME, OBJECT_TYPE, CN
FROM (SELECT OWNER, OBJECT_TYPE, COUNT(*) CN FROM t1 GROUP BY OBJECT_TYPE) t,
t2
WHERE USERNAME = OWNER
AND USERNAME LIKE 'SYS%'
也可以

gclizh 评论于: 2008.01.14 13:04
re: 缺少GROUP BY表达式可以顺利执行的问题 [回复]

也不能说merge join的问题。

因为9i中hash join也存在这个问题。

yangtingkun 评论于: 2008.01.14 13:37
re: 缺少GROUP BY表达式可以顺利执行的问题 [回复]

不是merge join ,merge(不是use_merge) 这个hint的意思是先join 后group by,应该是sql 重写带来的问题

gclizh 评论于: 2008.01.15 09:05
re: 缺少GROUP BY表达式可以顺利执行的问题 [回复]

确实是merge操作造成的。
以前经常用NO_MERGE,居然没有注意到有个对应的MERGE的hint,感谢gclizh的提醒。

yangtingkun 评论于: 2008.01.15 10:01

发表评论
标题

在此添加评论
表情符号: smile laughing tongue angry crying sad wassat wink

称呼

邮箱地址(可选)

个人主页(可选)

 authimage


切换风格
新闻聚合
博客日历
文章归档...
最新发表...
最新评论...
最多阅读文章...
最多评论文章...
博客统计...
Blog信息
网站链接...