帮别人看了个案例,远程看的,没深入追究具体原因,问题是一个查询出的记录为0,但是在加上限制条件后,查询出来的记录就不为0了,一听说有这样的问题,也感到奇怪,决定先看下执行计划,看是否能在执行计划中看出什么问题,版本是10.2.0.4
下面是有问题的查询的执行计划
select /*+ gather_plan_statistics */ count(*) from ic_general_b b left join ic_general_h h on b.cgeneralhid = h.cgeneralhid
left join ts_batchcode c on b.vbatchcode = c.vbatchcode left join ts_batchcode_b d on c.pk_batchcode = d.pk_batchcode where
h.cbilltypecode = '47' and b.dr = 0 and h.dr = 0 and d.dr = 0 and d.leibie in ('1', '2', '3', '4', '0') and b.dbizdate
= '2016-02-04' -- and h.vbillcode='WW1602040014'
Plan hash value: 525439825
-----------------------------------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers | OMem | 1Mem | Used-Mem |
-----------------------------------------------------------------------------------------------------------------------------------------------
| 1 | SORT AGGREGATE | | 1 | 1 | 1 |00:00:00.05 | 7522 | | | |
|* 2 | TABLE ACCESS BY INDEX ROWID | TS_BATCHCODE_B | 1 | 1 | 0 |00:00:00.05 | 7522 | | | |
| 3 | NESTED LOOPS | | 1 | 1957 | 1 |00:00:00.05 | 7522 | | | |
|* 4 | HASH JOIN | | 1 | 1732 | 0 |00:00:00.05 | 7522 | 909K| 909K| 178K (0)|
|* 5 | TABLE ACCESS BY INDEX ROWID | IC_GENERAL_H | 1 | 1829 | 0 |00:00:00.05 | 7522 | | | |
|* 6 | INDEX SKIP SCAN | I_IC_GENERAL_H_JSZC01 | 1 | 7318 | 7335 |00:00:00.01 | 893 | | | |
| 7 | NESTED LOOPS | | 0 | 3931 | 0 |00:00:00.01 | 0 | | | |
|* 8 | TABLE ACCESS BY INDEX ROWID| IC_GENERAL_B | 0 | 4152 | 0 |00:00:00.01 | 0 | | | |
|* 9 | INDEX RANGE SCAN | I_IC_GENERAL_B_11 | 0 | 16607 | 0 |00:00:00.01 | 0 | | | |
| 10 | TABLE ACCESS BY INDEX ROWID| TS_BATCHCODE | 0 | 1 | 0 |00:00:00.01 | 0 | | | |
|* 11 | INDEX RANGE SCAN | I_IND_BATCHCODE | 0 | 1 | 0 |00:00:00.01 | 0 | | | |
|* 12 | INDEX RANGE SCAN | XX_IDX_PK_BATCHCODE | 0 | 3 | 0 |00:00:00.01 | 0 | | | |
-----------------------------------------------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - filter(("D"."DR"="C"."SYS_NC00270$" AND (INTERNAL_FUNCTION("D"."LEIBIE") OR "D"."LEIBIE"="C"."SYS_NC00270$")))
4 - access("B"."CGENERALHID"="H"."CGENERALHID")
5 - filter("H"."DR"="C"."SYS_NC00270$")
6 - access("H"."CBILLTYPECODE"='47')
filter("H"."CBILLTYPECODE"='47')
8 - filter("B"."DR"="C"."SYS_NC00270$")
9 - access("B"."DBIZDATE"='2016-02-04')
11 - access("B"."VBATCHCODE"="C"."VBATCHCODE" AND "B"."DR"="C"."SYS_NC00270$")
12 - access("C"."PK_BATCHCODE"="D"."PK_BATCHCODE")
看到执行计划中预估是有返回值得,但是实际上带有索引的返回值都是0,这个就很奇怪了,为什么索引查询出的都是0,而且在谓词中看到d.dr=0的过滤,优化器全部都转换成了"D"."DR"="C"."SYS_NC00270$" 这种形式,把索引都禁用后,查询是正确的,看来是索引导致的这个问题。
下面的是没有问题的查询的执行计划
select /*+ gather_plan_statistics */ count(*) from ic_general_b b left join ic_general_h h on
b.cgeneralhid = h.cgeneralhid left join ts_batchcode c on b.vbatchcode = c.vbatchcode left join
ts_batchcode_b d on c.pk_batchcode = d.pk_batchcode where h.cbilltypecode = '47' and b.dr = 0
and h.dr = 0 and d.dr = 0 and d.leibie in ('1', '2', '3', '4', '0') and b.dbizdate =
'2016-02-04' and h.vbillcode='WW1602040014'
Plan hash value: 2934471753
------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers |
------------------------------------------------------------------------------------------------------------------
| 1 | SORT AGGREGATE | | 1 | 1 | 1 |00:00:00.01 | 439 |
|* 2 | TABLE ACCESS BY INDEX ROWID | TS_BATCHCODE_B | 1 | 1 | 693 |00:00:00.01 | 439 |
| 3 | NESTED LOOPS | | 1 | 1 | 771 |00:00:00.01 | 410 |
| 4 | NESTED LOOPS | | 1 | 1 | 77 |00:00:00.01 | 249 |
| 5 | NESTED LOOPS | | 1 | 1 | 77 |00:00:00.01 | 16 |
|* 6 | TABLE ACCESS BY INDEX ROWID| IC_GENERAL_H | 1 | 1 | 1 |00:00:00.01 | 4 |
|* 7 | INDEX RANGE SCAN | I_IC_GENERAL_H_1 | 1 | 3 | 1 |00:00:00.01 | 3 |
|* 8 | TABLE ACCESS BY INDEX ROWID| IC_GENERAL_B | 1 | 1 | 77 |00:00:00.01 | 12 |
|* 9 | INDEX RANGE SCAN | I_IC_GENERAK_B_6 | 1 | 6 | 77 |00:00:00.01 | 5 |
| 10 | TABLE ACCESS BY INDEX ROWID | TS_BATCHCODE | 77 | 1 | 77 |00:00:00.01 | 233 |
|* 11 | INDEX UNIQUE SCAN | U_IND_BATCHCODE | 77 | 1 | 77 |00:00:00.01 | 156 |
|* 12 | INDEX RANGE SCAN | XX_IDX_PK_BATCHCODE | 77 | 3 | 693 |00:00:00.01 | 161 |
------------------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - filter(("D"."DR"=0 AND (INTERNAL_FUNCTION("D"."LEIBIE") OR "D"."LEIBIE"=0)))
6 - filter(("H"."CBILLTYPECODE"='47' AND "H"."DR"=0))
7 - access("H"."VBILLCODE"='WW1602040014')
8 - filter(("B"."DR"=0 AND "B"."DBIZDATE"='2016-02-04'))
9 - access("B"."CGENERALHID"="H"."CGENERALHID")
11 - access("B"."VBATCHCODE"="C"."VBATCHCODE")
12 - access("C"."PK_BATCHCODE"="D"."PK_BATCHCODE")
看到实际的执行计划都正常
检查后,发现在一个列上有两个索引
create unique index U_IND_BATCHCODE on TS_BATCHCODE (VBATCHCODE);
create index I_IND_BATCHCODE on TS_BATCHCODE (VBATCHCODE, 0);
看到是由于使用了i_ind_batchcode这个索引导致了错误,11 - access("B"."VBATCHCODE"="C"."VBATCHCODE" AND "B"."DR"="C"."SYS_NC00270$")
看来对于常量联合索引的处理,oracle在处理的时候有bug。