2014-09-26 49 views
2

我有一个表,它是在一个数值列(ROW_ID)分区列表,甲骨文分区忽略不工作联接使用

TABLEA (ROW_ID NUMERIC(38), TB_KEY NUMERIC(38), ROW_DATA VARCHAR(20)); 

分区修整时,我从表中查询没有联接工作

SELECT A.* FROM TABLEA A 
WHERE ROW_ID IN (SELECT ID FROM TABLEB WHERE DT_COL = SYSDATE); 

分区修剪失败当我左外连接到表B

SELECT A.* FROM TABLEA A 
LEFT OUTER JOIN TABLEB B ON A.TB_KET = B.TB_KEY 
WHERE ROW_ID IN (SELECT ID FROM TABLEB WHERE DT_COL = SYSDATE); 

分区修剪当我改变左外工作加入到内部连接

SELECT A.* FROM TABLEA A 
INNER JOIN TABLEB B ON A.TB_KET = B.TB_KEY 
WHERE ROW_ID IN (SELECT ID FROM TABLEB WHERE DT_COL = SYSDATE); 

分区修剪工作当我做左外连接到表B,并且不使用IN子句

SELECT A.* FROM TABLEA A 
LEFT OUTER JOIN TABLEB B ON A.TB_KET = B.TB_KEY 
WHERE ROW_ID = 123; 

分区修剪工程当我离开外连接到TableB和使用IN子句的静态值

SELECT A.* FROM TABLEA A 
LEFT OUTER JOIN TABLEB B ON A.TB_KET = B.TB_KEY 
WHERE ROW_ID IN (123, 345); 

有人能解释一下为什么左外连接会导致分区修剪失败,当我查询表上的分区使用IN子句与子查询结果的列?

回答

0

分区修剪可以使用LEFT OUTER JOININ子查询。您可能会看到一个非常具体的问题,需要更具体的测试用例。

示例模式

drop table tableb purge; 
drop table tablea purge; 

create table tablea (row_id numeric(38),tb_key numeric(38),row_data varchar(20)) 
partition by list(row_id) 
(partition p1 values (1),partition p123 values(123),partition p345 values(345)); 
create table tableb (id numeric(38), dt_col date, tb_key numeric(38)); 

begin 
    dbms_stats.gather_table_stats(user, 'TABLEA'); 
    dbms_stats.gather_table_stats(user, 'TABLEB'); 
end; 
/

查询

--Partition pruning works when i query from table with no joins: 
explain plan for 
SELECT A.* FROM TABLEA A 
WHERE ROW_ID IN (SELECT ID FROM TABLEB WHERE DT_COL = SYSDATE); 
select * from table(dbms_xplan.display); 

--Partition Pruning fails when I do left outer join to TableB 
explain plan for 
SELECT A.* FROM TABLEA A 
LEFT OUTER JOIN TABLEB B ON A.TB_KEY = B.TB_KEY 
WHERE ROW_ID IN (SELECT ID FROM TABLEB WHERE DT_COL = SYSDATE); 
select * from table(dbms_xplan.display); 

--Partition Pruning works when I change left outer join to inner join 
explain plan for 
SELECT A.* FROM TABLEA A 
INNER JOIN TABLEB B ON A.TB_KEY = B.TB_KEY 
WHERE ROW_ID IN (SELECT ID FROM TABLEB WHERE DT_COL = SYSDATE); 
select * from table(dbms_xplan.display); 

--Partition Pruning works when I do left outer join to TableB and do not use IN clause 
explain plan for 
SELECT A.* FROM TABLEA A 
LEFT OUTER JOIN TABLEB B ON A.TB_KEY = B.TB_KEY 
WHERE ROW_ID = 123; 
select * from table(dbms_xplan.display); 

--Partition Pruning works when I do left outer join to TableB and use static values for IN clause 
explain plan for 
SELECT A.* FROM TABLEA A 
LEFT OUTER JOIN TABLEB B ON A.TB_KEY = B.TB_KEY 
WHERE ROW_ID IN (123, 345); 
select * from table(dbms_xplan.display); 

输出

这里不显示完整的执行计划,以节省空间。唯一重要的列是PstartPstop,这意味着使用分区修剪。

执行计划看起来像下列之一:

... ----------------- 
... | Pstart| Pstop | 
... ----------------- 
... 
... | KEY | KEY | 
... | KEY | KEY | 
... 
... ----------------- 

OR 

... ----------------- 
... | Pstart| Pstop | 
... ----------------- 
... 
... |  2 |  2 | 
... |  2 |  2 | 
... 
... ----------------- 

OR 

... ----------------- 
... | Pstart| Pstop | 
... ----------------- 
... 
... |KEY(I) |KEY(I) | 
... |KEY(I) |KEY(I) | 
... 
... ----------------- 

这是如何帮助?

不是很多。尽管您提供的信息比典型问题多得多,但需要更多信息来解决此问题。

至少现在你知道问题不是由分区修剪中的通用限制造成的。这里有一个非常具体的问题,很可能与优化器统计有关。深入了解这些问题可能需要很长时间。我建议从上面的示例数据开始,添加更多的功能和数据,直到分区修剪消失。

通过修改问题在这里发布新的测试用例,并且有人应该能够解决这个问题。