【问题标题】:Use of index in multiple join condition oracle多连接条件oracle中索引的使用
【发布时间】:2013-12-05 22:24:12
【问题描述】:

我有两个表: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) */ 之类的索引提示,但这并没有太大帮助。在这种情况下你能帮帮我吗?

【问题讨论】:

  • 你应该尝试添加一个use_nl(b a)
  • 你能告诉我们计划吗?
  • 在 A(city, state) 上添加复合索引是一种解决方案,但问题是好的。如果条件A.city=B.city 导致嵌套循环使用索引,A.city = B.city and A.state=B.state 也会发生同样的情况
  • 谢谢,确实解决了问题。

标签: oracle join indexing query-optimization hint


【解决方案1】:

城市和州是相关的,但优化器不理解这一点。 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;
/

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

【讨论】:

    【解决方案2】:

    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. 收集两个表的统计信息以确保 oracle 知道 比例并有足够的数据来估计基数 exec dbms_stats.gather_table_stats(user,'tableX')
    2. 使用并行执行测试查询 - 并行非常适合 通过广播整个游戏来加速小桌和大桌之间的 NL 小表到工作大表块的从进程(获取 更进一步压缩小桌子)。

    【讨论】:

    • 表 A 有大约 1000 万条记录。现在可以有大约 100000 个不同的城市。但是,当我们通常在连接条件下获取 50-100 个城市的数据时。因此,在这种情况下,TableA 上的索引将无济于事。
    • 如果您从表 A 中获取特定的州/城市,那么是的 - 索引会有所帮助。这不是您发布的查询。
    • 查询 OP 发布获取特定状态:它们在表 B 中 :)
    【解决方案3】:

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

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

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

    【讨论】:

      【解决方案4】:

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-07-04
        • 1970-01-01
        • 2012-08-16
        • 2011-08-15
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多