在多个连接条件oracle中使用索引

时间:2013-11-21 12:34:45

标签: oracle join indexing query-optimization hint

我有两个表:tableA和tableB TableA有数百万条记录,而tableB有大约1000条记录

Table A {
aid
city,  (city is indexed)
state,
X,
Y
}

Table B {
bid,
city,
state
}

现在我的查询是

SELECT X, Y, COUNT(*) FROM A,B
WHERE A.city = B.city
and A.state=B.state
group by X,Y

此查询运行速度非常慢。然而,当我们只加入城市时,一切都很快。 现在我的查询是

SELECT X, Y, COUNT(*) FROM A,B
WHERE A.city = B.city
group by X,Y

所以我去了解释计划,在第一种情况下(慢)查询计划没有使用索引,而在第二种情况下它使用城市索引。我尝试在A表中添加状态索引,这对预期没有帮助。此外,我尝试使用索引提示,如/ * + INDEX(A,city_idx)* /选择后没有多大帮助。在这种情况下你能帮助我吗?

4 个答案:

答案 0 :(得分:0)

city state上为这两个表创建索引可能会有所帮助。

答案 1 :(得分:0)

在表A上创建一个包含所有四列的复合索引:city,state,X,Y:

CREATE INDEX index_name ON table_name (city, state, X, Y);

通过这种方式,您的查询不再需要访问表A,只需要访问新创建的索引。当然,另一个指数的缺点 - >此表中的插入/更新/删除速度较慢。

答案 2 :(得分:0)

  

TableA有数百万条记录,而tableB有大约1000条

在这种情况下,使用嵌套循环似乎是最适合作业的访问路径。 您正在请求基于表A中两列的聚合,这意味着oracle无论如何都必须访问表中的所有块。在这种情况下,在大表上创建索引将是无用的。在连接的小内部表上创建索引是有意义的。

  

在哪里A.city = B.city和A.state = B.state

     

在哪里A.city = B.city

两个州可以存在同一个城市吗?听起来不太可能......如果一个城市不能存在于一个以上的状态,那么任何状态指数(在任一表中)都将是多余的。

正如@Florin Ghita在评论中指出的那样,您可以使用提示USE_NL强制oracle使用嵌套循环,但我个人强烈建议避免提示(出于很多原因 - 主要是维护)。

我的建议是

  1. 在两个表上收集统计数据以确保oracle知道 比例并有足够的数据来估计基数 exec dbms_stats.gather_table_stats(user,'tableX')
  2. 使用并行执行测试查询 - 并行很棒 通过广播整个表来加速小桌和大桌之间的NL 工作大表块的奴隶进程的小表(得到 甚至可以在小桌子上进一步压缩。)

答案 3 :(得分:0)

城市和州是相关的,但优化者并不理解。 Oracle可以单独准确地预测每个条件,但不能一起预测。

例如,假设所有州中有10%匹配且所有城市中有10%匹配。当两个条件都存在时,Oracle将估计0.1 * 0.1 = 0.01。实数可能接近0.1。如果城市名称匹配,则州名称几乎总是匹配。

添加扩展统计信息可告知Oracle此列关系。这些统计信息可以帮助任何查询,而不仅仅是当前的问题查询。

declare
    v_name varchar2(100);
begin
    v_name := dbms_stats.create_extended_stats(user, 'A', '(city, state)');
    v_name := dbms_stats.create_extended_stats(user, 'B', '(city, state)');

    dbms_stats.gather_table_stats(user, 'A');
    dbms_stats.gather_table_stats(user, 'B');
end;
/

如果没有计划,我们无法准确预测这是否能解决问题。但是,为优化程序提供更准确的信息通常会有所帮助,而且几乎不会受到伤害。