我有两个表: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)* /选择后没有多大帮助。在这种情况下你能帮助我吗?
答案 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使用嵌套循环,但我个人强烈建议避免提示(出于很多原因 - 主要是维护)。
我的建议是
exec dbms_stats.gather_table_stats(user,'tableX')
。答案 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;
/
如果没有计划,我们无法准确预测这是否能解决问题。但是,为优化程序提供更准确的信息通常会有所帮助,而且几乎不会受到伤害。