2013-11-21 45 views
1

我有两个表:表A和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 

所以我而在第二种情况下,它用的是城市索引的查询计划不使用索引去解释计划,并在第一种情况下(慢)。我试图在表中添加状态索引,这没有像预期的那样有帮助。此外,我试图使用索引提示像/ * + INDEX(A,city_idx)* /选择后没有什么帮助。你能帮我解决这个问题吗?

+0

你应该尝试添加'use_nl(b a)' –

+1

你能告诉我们这些计划吗? –

+1

在A(城市,州)上添加复合索引将是一个解决方案,但问题是好的。如果条件'A.city = B.city'导致索引使用嵌套循环,同样的情况应该发生在'A.city = B.city和A.state = B.state' –

回答

0

citystate上的两个表创建索引可能会有所帮助。

0

上创建具有所有四列的表格中的一个综合指数:城市,州,X,Y:

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

这样,您的查询将不再需要访问表A,只有新创建的索引。当然,另一个索引的缺点 - 在这个表中插入/更新/删除会更慢。

0

TableA中有上百万的记录和tableB的有1000个

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

WHERE A.city = B.city和A.state = B.state

WHERE A.city = B.city

可以在同一个城市两种状态存在?听起来不太可能......如果一个城市不能存在于多于一个状态中,那么任何状态索引(在任何一个表中)都将是多余的。作为@Florin Ghita在他的评论中指出,你可以使用提示USE_NL强制oracle使用嵌套循环,但个人而言,我强烈建议避免提示(因为很多原因 - 主要是维护)。

我的建议是

  1. 聚集在这两个表的统计信息,以确保它知道 比例,并有足够的数据来估计基数 exec dbms_stats.gather_table_stats(user,'tableX')
  2. 测试与并行执行的查询 - 并行是 通过广播整个 小桌子到从属进程工作的大桌子块大大小小的表之间的超速NL大(获得 甚至进一步压缩小桌子上) 。
+0

表A有大约1000万条记录。现在可以有大约10万个不同的城市。但是,当我们通常在连接条件下获取50-100个城市的数据时。所以在这种情况下,TableA上的索引不会有帮助。 – user1479802

+0

如果您从表A中获取特定的州/城市,那么是 - 索引将有所帮助。这不是您发布的查询。 – haki

+0

查询OP发布提取特定状态:它们在表B中:) –

0

城市与州相关,但优化者不理解这一点。甲骨文可能可以准确地预测每种情况,但不能在一起。

例如,假设所有州的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; 
/

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