我对Oracle 11g R2上的CBO有一个有趣的问题,我似乎无法解决。假设以下内容(请注意,为简洁起见,这是为了减少DDL);
create or replace object o_primary_key ( id number(38,0) );
create or replace type t_primary_key table of o_primary_key;
create table customer (
customer_id number(38, 0) primary key,
parent_customer_id number(38, 0),
... additional columns ommitted ...
)
create table orders (
order_id number(38, 0) not null primary key,
customer_id number(38, 0) not null,
date_applied date not null,
deleted_on date null,
amount number(18, 9) not null,
... additional columns ommitted ...
)
index idx_orders_1 on orders (customer_id, date_applied, deleted_on, order_id);
index idx_customers_1 on customer (parent_customer_id, case when parent_customer_id is not null then customer_id else null end) compute statistics;
CUSTOMERS表有大约200,000行,ORDERS表有大约600万行。我有一个查询,如下面的内容和此查询的意图 是显示给定客户ID的所有订单,或者如果客户ID是父级,则显示其子级的所有订单。
with c_ids as (
select 1 as id from dual union all
select 2 as id from dual union all
select 3 as id from dual
),
c_customer_ids as (
select t.id customer_id,
c.parent_customer_id joining_customer_id
from c_ids t
join customers c
on t.id = c.customer_id
or t.id = c.parent_customer_id
)
select *
from c_customer_ids
join orders o
on o.customer_id = c.joining_customer_id
where o.date_applied bewteen '10/MAY/15' and '13/MAY/15'
and o.deleted_on is null
order by o.customer_id,
o.date_applied;
当我运行此查询时,CBO正确(我相信)决定使用CONCATENATION操作重写查询的OR部分,使其部分地针对CUSTOMER_ID和 然后作为第二次运行反对PARENT_CUSTOMER_ID。这两个使用查询都使用索引,并且一致获取的数量非常低(大约200)。
请注意,在我正在测试的情况下,我正在考虑 从总计600万行中的1,800行。
但是,当我运行这样的查询时,它会变得很有趣;
with c_customer_ids as (
select t.id customer_id,
c.parent_customer_id joining_customer_id
from table(t_primary_key(o_primary_key(1), o_primary_key(2), o_primary_key(3))) t
join customers c
on t.id = c.customer_id
or t.id = c.parent_customer_id
)
select *
from c_customer_ids
join orders o
on o.customer_id = c.joining_customer_id
where o.date_applied bewteen '10/MAY/15' and '13/MAY/15'
and o.deleted_on is null
order by o.customer_id,
o.date_applied;
当使用类型来定义数字时,CBO决定错误地(我相信)使用ORDERS表上的全表扫描将其作为单个查询运行,因此获得者大约130,000并且 查询运行速度很慢。
为什么使用类型导致这种差异?
谢谢, 该隐