oracle group by placement可能导致错误结果的bug
Last week I’ve mentioned on Twitter that we ran into wrong result bug. We found workaround quickly but I’ve decided to spend some time to reproduce error and write blog post to warn you about this optimizer behavior.
Special thanks to my colleague who spotted odd results which led us to this finding.
My test (virtual) environment is:
OS: Oracle Enterprise Linux 5.8
DB: Oracle EE 11.1.0.7.12
In test I will use three tables:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
CONTName Null Type ------- ---- ------------- CUST_ID NUMBER(38) CODE VARCHAR2(100) CUSTName Null Type ------- -------- ---------- CUST_ID NOT NULL NUMBER(38) DRAGName Null Type ------- ---- --------- DRAG_ID NUMBER(6) |
To gather fresh statistics for the tables:
|
1
2
3
4
5
6
|
begin dbms_stats.gather_table_stats(ownname=>user,tabname=>'CONT',estimate_percent=>100, cascade=>TRUE); dbms_stats.gather_table_stats(ownname=>user,tabname=>'CUST',estimate_percent=>100, cascade=>TRUE); dbms_stats.gather_table_stats(ownname=>user,tabname=>'DRAG',estimate_percent=>100, cascade=>TRUE);end;/ |
More details about tables:
|
1
2
3
4
5
6
7
8
9
10
|
select table_name, num_rows, blocks, partitioned, last_analyzedfrom dba_tableswhere table_name in ('CONT','CUST','DRAG');TABLE_NAME NUM_ROWS BLOCKS PARTITIONED LAST_ANALYZED ------------ ---------- ---------- ----------- -------------------CONT 1181949 2892 NO 04.02.2014 14:49:24 DRAG 314 5 NO 04.02.2014 14:49:25 CUST 576233 902 NO 04.02.2014 14:49:25 |
Information about indexes:
|
1
2
3
4
5
6
7
8
9
|
select index_name, table_name, uniqueness, distinct_keys, clustering_factorfrom dba_indexeswhere table_name in ('CONT','CUST','DRAG');INDEX_NAME TABLE_NAME UNIQUENESS DISTINCT_KEYS CLUSTERING_FACTOR-------------- ------------ ---------- ------------- -----------------I_CUST_ID CONT NONUNIQUE 468738 753983 PK_CUST_ID CUST UNIQUE 576233 878 |
We have three small and simple tables with just two indexes. CUST table has primary key on “cust_id” column.
After this little introduction it is time for some tests.
I will flush buffer cache and shared pool before every query execution.
|
1
2
3
4
5
|
SQL> alter system flush shared_pool;System altered.SQL> alter system flush buffer_cache;System altered. |
First query execution and execution plan:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
select /*+ gather_plan_statistics */ count(co.code) as cntfrom drag t, cust cus, cont cowhere 1=1and t.drag_id = cus.cust_idand cus.cust_id = co.cust_id(+) group by t.drag_id; CNT--------------- 2 2 2 2 1 2 2 2 2...303 rows |
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
SQL> select * from table(dbms_xplan.display_cursor(null,null,'ALLSTATS LAST'));PLAN_TABLE_OUTPUT----------------------------------------------------------------------------------------------------------------------------SQL_ID gpnrgy2vawafq, child number 0-------------------------------------select /*+ gather_plan_statistics */ count(co.code) as cnt fromdrag t, cust cus, cont co where 1=1 and t.drag_id =cus.cust_id and cus.cust_id = co.cust_id(+) group by t.drag_idPlan hash value: 3989628059---------------------------------------------------------------------------------------------------------------------------| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers | Reads | OMem | 1Mem | Used-Mem |---------------------------------------------------------------------------------------------------------------------------| 0 | SELECT STATEMENT | | 1 | | 303 |00:00:00.62 | 3734 | 3724 | | | || 1 | HASH GROUP BY | | 1 | 303 | 303 |00:00:00.62 | 3734 | 3724 | 1096K| 1096K| 1264K (0)||* 2 | HASH JOIN OUTER | | 1 | 792 | 1084 |00:00:00.16 | 3734 | 3724 | 1206K| 1206K| 1244K (0)||* 3 | HASH JOIN | | 1 | 314 | 314 |00:00:00.04 | 890 | 885 | 1452K| 1452K| 1470K (0)|| 4 | TABLE ACCESS FULL| DRAG | 1 | 314 | 314 |00:00:00.01 | 7 | 6 | | | || 5 | TABLE ACCESS FULL| CUST | 1 | 576K| 576K|00:00:00.02 | 883 | 879 | | | || 6 | TABLE ACCESS FULL | CONT | 1 | 1181K| 1181K|00:00:00.01 | 2844 | 2839 | | | |---------------------------------------------------------------------------------------------------------------------------Predicate Information (identified by operation id):--------------------------------------------------- 2 - access("CUS"."CUST_ID"="CO"."CUST_ID") 3 - access("T"."DRAG_ID"="CUS"."CUST_ID") |
Check result of the query - this is correct query result.
Now to simulate what we experienced in production.
|
1
2
3
4
|
SQL> alter system flush shared_pool;System altered.SQL> alter system flush buffer_cache;System altered. |
With hint I want to force PK_CUST_ID index usage because this was preferred plan in production.
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
select /*+ gather_plan_statistics index(cus PK_CUST_ID) */ count(co.code) as cntfrom drag t, cust cus, cont cowhere 1=1and t.drag_id = cus.cust_idand cus.cust_id = co.cust_id(+) group by t.drag_id; CNT--------------- 0 0 0 0 0 0 0 0 0 0... 303 rows |
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
|
SQL> select * from table(dbms_xplan.display_cursor(null,null,'ALLSTATS LAST'));PLAN_TABLE_OUTPUT------------------------------------------------------------------------------------------------------------------------------------SQL_ID 9vf9uf7mhdmdz, child number 0-------------------------------------select /*+ gather_plan_statistics index(cus PK_CUST_ID) */count(co.code) as cnt from drag t, cust cus, cont co where1=1 and t.drag_id = cus.cust_id and cus.cust_id = co.cust_id(+) groupby t.drag_idPlan hash value: 3263881209-----------------------------------------------------------------------------------------------------------------------------------| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers | Reads | OMem | 1Mem | Used-Mem |-----------------------------------------------------------------------------------------------------------------------------------| 0 | SELECT STATEMENT | | 1 | | 303 |00:00:00.70 | 3459 | 3094 | | | || 1 | HASH GROUP BY | | 1 | 303 | 303 |00:00:00.70 | 3459 | 3094 | 934K| 934K| 1267K (0)||* 2 | HASH JOIN OUTER | | 1 | 764 | 1046 |00:00:00.22 | 3459 | 3094 | 1134K| 1134K| 1198K (0)|| 3 | NESTED LOOPS | | 1 | 303 | 303 |00:00:02.02 | 615 | 255 | | | || 4 | VIEW | VW_GBC_9 | 1 | 303 | 303 |00:00:00.01 | 7 | 6 | | | || 5 | HASH GROUP BY | | 1 | 303 | 303 |00:00:00.01 | 7 | 6 | 1012K| 1012K| 1249K (0)|| 6 | TABLE ACCESS FULL| DRAG | 1 | 314 | 314 |00:00:00.01 | 7 | 6 | | | ||* 7 | INDEX UNIQUE SCAN | PK_CUST_ID | 303 | 1 | 303 |00:00:00.22 | 608 | 249 | | | || 8 | TABLE ACCESS FULL | CONT | 1 | 1181K| 1181K|00:00:00.01 | 2844 | 2839 | | | |-----------------------------------------------------------------------------------------------------------------------------------Predicate Information (identified by operation id):--------------------------------------------------- 2 - access("CUS"."CUST_ID"="CO"."CUST_ID") 7 - access("ITEM_1"="CUS"."CUST_ID") |
Check result of the query!
Count is displaying all 0 values because it received only NULLs to count.
Other functions like max and min are also affected by this error.
Check steps 4,5 and 6 in execution plan.
Instead of quick full scan on DRAG table Oracle transformed query and created inline view using smart group-by optimization.
In 10053 trace I could easily find what Oracle was doing.
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
SELECT /*+ INDEX ("CUS" "PK_CUST_ID") */ SUM("VW_GBC_9"."ITEM_2") "CNT"FROM (SELECT "T"."DRAG_ID" "ITEM_1", COUNT("CO"."CODE") "ITEM_2", "T"."DRAG_ID" "ITEM_3" FROM "ADMIN"."DRAG" "T" WHERE 1=1 GROUP BY "T"."DRAG_ID", "T"."DRAG_ID" ) "VW_GBC_9", "ADMIN"."CUST" "CUS", "ADMIN"."CONT" "CO"WHERE "VW_GBC_9"."ITEM_1"="CUS"."CUST_ID"AND "CUS"."CUST_ID" ="CO"."CUST_ID"(+)GROUP BY "VW_GBC_9"."ITEM_3"; |
Quick workaround to fix this bug:
- Set "_optimizer_group_by_placement"=FALSE.
You could check in 10053 trace value of this parameter.
In my case: _optimizer_group_by_placement = true
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
SQL> alter session set "_optimizer_group_by_placement"=FALSE;Session altered.select /*+ gather_plan_statistics index(cus PK_CUST_ID) */ count(co.code) as cntfrom drag t, cust cus, cont cowhere 1=1and t.drag_id = cus.cust_idand cus.cust_id = co.cust_id(+) group by t.drag_id; CNT---------- 2 2 2 2 1 2 2 2 2...303 rows |
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
|
SQL> select * from table(dbms_xplan.display_cursor(null,null,'ALLSTATS LAST'));PLAN_TABLE_OUTPUT----------------------------------------------------------------------------------------------------------------------------SQL_ID a91bzhvupzquh, child number 0-------------------------------------select /*+ gather_plan_statistics index(cus PK_CUST_ID)*/count(co.code) as cnt from drag t, cust cus, cont co where1=1 and t.drag_id = cus.cust_id and cus.cust_id = co.cust_id(+) groupby t.drag_idPlan hash value: 2460166079------------------------------------------------------------------------------------------------------------------------| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers | OMem | 1Mem | Used-Mem |------------------------------------------------------------------------------------------------------------------------| 0 | SELECT STATEMENT | | 1 | | 303 |00:00:00.16 | 3481 | | | || 1 | HASH GROUP BY | | 1 | 303 | 303 |00:00:00.16 | 3481 | 1096K| 1096K| 1232K (0)||* 2 | HASH JOIN OUTER | | 1 | 792 | 1084 |00:00:00.01 | 3481 | 1206K| 1206K| 1529K (0)|| 3 | NESTED LOOPS | | 1 | 314 | 314 |00:00:00.01 | 637 | | | || 4 | TABLE ACCESS FULL| DRAG | 1 | 314 | 314 |00:00:00.01 | 7 | | | ||* 5 | INDEX UNIQUE SCAN| PK_CUST_ID | 314 | 1 | 314 |00:00:00.01 | 630 | | | || 6 | TABLE ACCESS FULL | CONT | 1 | 1181K| 1181K|00:00:00.01 | 2844 | | | |------------------------------------------------------------------------------------------------------------------------Predicate Information (identified by operation id):--------------------------------------------------- 2 - access("CUS"."CUST_ID"="CO"."CUST_ID") 5 - access("T"."DRAG_ID"="CUS"."CUST_ID")27 rows selected. |
Oracle Support note associated with "_optimizer_group_by_placement" parameter.
Note.8945586.8 Ext/Pub Bug 8945586 - Wrong results using GROUP BY placement:
Description
Wrong results can occur when using GROUP BY placement where the aggregate column gets pruned from select list.
I’ve even found that “_optimizer_group_by_placement” parameter was mentioned in "Oracle® Fusion Middleware Oracle WebCenter Analytics Installation and Upgrade Guide".
Oracle 11g (11.1.0.6 and above) in default or Oracle Real Application Clusters (RAC) configuration
When running Oracle 11g versions prior to 11.1.0.7.0 the Oracle system parameter _optimizer_group_by_placement must be set to false. This can either be set in the init.ora file of the respective database instances or by by issuing an ALTER SYSTEM command as follows:
SQLPLUS /nolog
CONNECT / AS SYSDBA
ALTER SYSTEM SET "_optimizer_group_by_placement"=false
group by的优化bug还是挺多的,还有比如_optimizer_aggr_groupby_elim,但是不出bug的情况下,性能提升还是非常明显的,大家一定要仔细检查结果,不要只看性能。
oracle group by placement可能导致错误结果的bug的更多相关文章
- oracle已知会导致错误结果的bug列表(Bug Issues Known to cause Wrong Results)
LAST UPDATE: 1 Dec 15, 2016 APPLIES TO: 1 2 3 4 Oracle Database - Enterprise Edition - Versi ...
- django继承修改 User表导致的问题 fields.E304(permissions/group都会有这样的错误)
问题: django继承修改 User表时,进行migrations操作时会导致的问题 fields.E304(permissions/group都会有这样的错误)如图: 根源: django文档中有 ...
- 登陆Oracle,报oracle initializationg or shutdown in progress 错误提示
前两天,登陆Oracle,发现登陆不上去了,报”oracle initializationg or shutdown in progress 错误提示” 错误. 然后就想着怎么去解决,首先自己到win ...
- oracle:数据库版本问题导致的bug
公司开发出来的系统,由于各现场oracle数据库版本有10.2.0.4.11.2.0.1.11.2.0.3.11.2.0.4: 进而会导致版本不一导致错误问题.下面列举2个: 1.wm_concat ...
- Oracle ORA-01033: ORACLE initialization or shutdown in progress 错误解决办法
Oracle ORA-01033: ORACLE initialization or shutdown in progress 错误解决办法 登陆数据库时提示 “ORA-01033”错误在命令窗口以s ...
- oracle group by中cube和rollup字句的使用方法及区别
oracle group by中rollup和cube的区别: Oracle的GROUP BY语句除了最基本的语法外,还支持ROLLUP和CUBE语句. 如果是ROLLUP(A, B, C)的话,先 ...
- oracle所在磁盘空间不足导致了数据库异常
oracle所在磁盘空间不足导致了数据库异常.需要减小数据文件的大小来解决. 1.检查数据文件的名称和编号 select file#,name from v$datafile; 2.看哪个数据文件所占 ...
- MVC4 路由参数带点 文件名后缀导致错误
错误描述 最近在研究office在线预览,用到mvc4 apicontroller 需要传参是文件名,如test.docx导致错误"指定的目录或文件在 Web 服务器上不存在", ...
- Oracle问题之ORA-12560TNS:协议适配器错误
Oracle问题之ORA-12560TNS:协议适配器错误 一.造成ORA-12560: TNS: 协议适配器错误的问题的原因有三个: 1.监听服务没有起起来.windows平台个一如下操作:开始-- ...
随机推荐
- 11.9luffycity(4)
2018-11-9 17:57:09 明天开始自己独立写luffy部分表的接口, 越努力,越幸运!永远不要高估自己! 明天后天先不想下看视频,把接口做完,然后整理一下笔记,温故而习之,可以为师啊! 知 ...
- poj 1228
就是给你一堆点,看这些点能否构成一个 稳定的凸包. 凸包每条边上有3个及以上的点就可以了. #include <cstdio> #include <cstring> #incl ...
- Java课程寒假之开发记账本软件(网页版)之五
一.实现基本功能之后 可以添加其他功能,比如说添加账户,删除账户,以及查询页面的分页.(我都没写,滑稽) 二.基本功能部分截图
- 升级 phpstud y中的 mysql 版本
1.找到你 phpstudy 安装目录,找到 MySQL 文件夹 (我自己的实际目录 D:\pc\phpstudy\MySQL),关掉退出 phpstudy服务,删除 MySQL 文件夹里的文件,如 ...
- Eclipse使当前项目依赖另一个项目
实例说明 在Eclipse中可以创建多个项目实现不同的软件开发,也可以使用多个项目来开发单独的大型软件,每个项目负责单独的模块部门,这样可以使软件的模块分类更清晰,可以单独的维护每个模块部分.但是项目 ...
- route 配置默认网关
影响Linux系统网络中网关配置信息的3种方式 1.生效文件cat /etc/sysconfig/network-scripts/ifcfg-eth0 GATEWAY=10.0.0.254 <- ...
- jquery和js检测浏览器窗口尺寸和分辨率
jquery和js检测浏览器窗口尺寸和分辨率,转载自网络,记录备忘 <script type="text/javascript">$(document).ready(f ...
- Ubuntu 使用命令行连接无线网
一.查看可以使用的无线网: nmcli dev wifi 二.连接无线网: nmcli dev wifi connect ‘essid’(网络名称) password ‘password’(密码) 可 ...
- 浅谈AC自动机
写在前面:从10月23日开始写这篇博文,离NOIP2018只有十多天了.坚持不停课的倔强蒟蒻(我)尽量每天挤时间多搞一搞信竞(然而还要准备期中考试).NOIP争取考一个好成绩吧. 一.简介 AC自动机 ...
- vue 中使用 axios 请求接口,请求会发送两次问题
在开发项目过程中,发现在使用axios调用接口都会有两个请求,第一个请求时,看不到请求参数,也看不到请求的结果:只有第二次请求时才会有相应的请求参数以及请求结果: 那为甚么会有这么一次额外的请求呢,后 ...