【问题标题】:SQL statement strangely slowSQL语句出奇的慢
【发布时间】:2011-02-14 11:56:15
【问题描述】:
select TABLE1.FIELD1, 
       TABLE1.FIELD2, 
       TABLE1.FIELD3, 
       TABLE1.FIELD4, 
       TABLE1.FIELD5, 
       TABLE2.FIELD6, 
       TABLE2.FIELD7
  from TABLE1,
       TABLE2
 where TABLE1.FIELD8 = 'value' 
   and TABLE2.FIELD6 = TABLE1.FIELD6;

我正在从 2 个不同的表中搜索一些数据。 (Oracle 数据库 - 两个表的 wherefields 索引) 上面的查询需要 500 毫秒才能执行。 当我分别在表格中搜索相同的字段时 它们每个都在不到 20 毫秒的时间内完成。

我可以在 TABLE1 中搜索我需要的数据 (+FIELD6) 然后使用 FIELD6 在 TABLE2 中搜索其余部分。

我的问题是。为什么我加入表格时速度要慢得多。 我做错了吗?

编辑:添加 oracle 的解释计划

PLAN_TABLE_OUTPUT
----------------------------------------------------------------------------------------
| Id  | Operation                    |  Name                   | Rows  | Bytes | Cost  |
----------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT             |                         |  6318 |   586K|   620 |
|   1 |  HASH JOIN                   |                         |  6318 |   586K|   620 |
|   2 |   TABLE ACCESS BY INDEX ROWID| TABLE1                  |  6318 |   450K|     2 |
|   3 |    INDEX RANGE SCAN          | INDEX_TABLE1_FIELD8     |  2527 |       |     1 |
|   4 |   TABLE ACCESS FULL          | TABLE2                  |   430K|  9242K|   508 |
----------------------------------------------------------------------------------------

Note: cpu costing is off, 'PLAN_TABLE' is old version

【问题讨论】:

  • 您的表中有多少条记录?你试过用 ANSI 连接语法重写吗?
  • 您能否展示一下 Oracle 为“解释计划”提供了什么?
  • TABLE1 有 600000 个值 10 个字段,TABLE2 有 5000 个值 500 个字段(请不要对此发表评论,我知道这很糟糕,这不是我的数据库)。 ANSI 连接语法具有相同的结果
  • 您应该避免隐式连接,并使用inner join table2 on (table1.field6 = table2.field6) 并在 Where 子句中只保留过滤器。 (不过,与您的问题无关)。

标签: sql performance oracle optimization


【解决方案1】:

如果 TABLE1 中有 25 条记录满足 field8='value' 并且如果需要 20 毫秒到 select ... from table2 where field6=??? 则 500 毫秒是在预期时间范围内。

所以,说每个查询需要20ms是很有意义的,你还必须说明有多少记录满足TABLE1中的field8条件,平均有多少记录满足TABLE2.FIELD6的条件。

但为了消除所有猜测,您应该让 Oracle 解释查询并在此处显示(或发布)解释的计划以供进一步分析。

编辑:由于条件之间似乎存在 1:1 的关系(并且查询随后返回 1 条记录),因此不需要 500 毫秒。在这种情况下,我真的要强调解释查询的必要性。如果你不熟悉它,你可以这样做:

explain plan for
   select .... <your entire select statement goes here>
;

select * from table(dbms_xplan.display);

然后发布结果。这将使我们能够更好地帮助您。

【讨论】:

  • 每个案例只有1条记录。
【解决方案2】:

比什么慢? RDBMS 是为加入而设计的。如果您认为通过程序执行(逐行使用循环游标或类似方法)可以获得更好的响应时间,那么您在 99.9% 的情况下都是错误的。

我的猜测是,您正在比较返回所有行(如果使用 FIRST_ROWS,甚至是前 500 行左右)与程序(或手动)返回的少数记录的响应时间。苹果和橙子。

【讨论】:

    【解决方案3】:

    我看不出您的查询有什么问题,其他答案中给出的(好的)建议将帮助您详细了解发生了什么。

    但是,在概念上,您必须牢记每个表中数据的顺序,以及数据是分组还是分散。 “只需要20ms就可以找到”这句话说的很好,但是要匹配两个数据集需要多长时间呢?

    如果已知两个数据集的顺序相同,则 RDBMS 可以相对快速地对齐它们。但是 RDBMS 只能从索引中知道这一点。

    如果您在 Table1 上有一个索引,即 Field8 然后是 Field6,则所有“值”将集中在一起,然后按 Field6 排序。但是,如果您有一个 Field6 然后是 Field8 的索引,那么您感兴趣的记录将被排序,但通过索引展开。最后,如果你在这些字段上没有索引,一切都会被随机排序并散开。

    根据这些类型的因素,RDBMS 可以通过多种方式完成您的查询。为了获得最佳性能,需要了解 RDBMS 需要做什么,然后为其提供索引以使其尽可能简单。

    【讨论】:

    • 好的,问题解决了。我的索引出了点问题。我真的不知道是什么。我在 TABLE2 中有 2 个索引。一个用于 FIELD6,另一个用于此处未提及的另一个字段。我删除了它们并再次为 FIELD6 创建了一个索引。现在加入的语句只需 15 毫秒。甚至少于两个单独的陈述之一。我接受这个答案作为最接近的答案。谢谢大家。
    • 如果您在 table1.field8 上添加索引,您能告诉我们时间吗?只是好奇。
    • 我只在商业世界中使用过一次 Oracle,而且索引损坏的频率非常频繁。重建它们(或删除并重新创建它们)通常会产生巨大的差异。因此,纯粹作为推测,索引可能已损坏。
    • TABLE1.FIELD8 已编入索引。如果不是,它不会那么快。
    【解决方案4】:

    您应该知道查询计划是什么,使用报告工具或/*+ gather_plan_statistics */ 等提示。在搜索引擎上查找此信息。

    当优化器连接两个表时,它可能会使用笛卡尔积、排序合并连接、哈希连接……试试SELECT /*+ USE_HASH(table1 table2) */ …

    此外,如果优化器选择了错误的计划,您可能希望使用 DBMS_STATS.GATHER_SCHEMA_STATS 过程重新计算统计信息(如果它们不具有代表性)。这是不良优化器选择的主要来源。

    【讨论】:

    • 如果表是 Stefanos 告诉我们的索引,我会明确想要use_hash。如果它们没有(或仅部分)被索引,我会使用_hash
    • @René Nyfenegger:是的,在这种情况下,/*+ INDEX */ 提示可能会更好。
    【解决方案5】:

    您可能应该分析表...全表访问和散列连接在您的情况下没有意义。

    begin
      dbms_stats.gather_table_stats('YOURUSERNAME', 'TABLE1');
      dbms_stats.gather_table_stats('YOURUSERNAME', 'TABLE2');
    end;
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-04-27
      • 2017-11-26
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多