避免全表扫描

时间:2009-10-21 12:21:32

标签: sql oracle

我有以下查询从事务表和事务详细信息中获取事务。两个表都有大量条目,因此此查询需要一段时间才能返回结果。

SELECT * FROM transactions t LEFT JOIN transac_detail tidts ON (tidts.id_transac = t.id);

然而,我更担心的是,根据解释计划,Oracle在两个表上都进行了全表扫描,即使t.id和tidts.id_transac有索引。

有没有办法在不触及表结构的情况下优化它?

4 个答案:

答案 0 :(得分:4)

我不认为SQL必须通过全表扫描得到最好的服务。在两者之间存在外键的情况下,这确实是最明显的,但即便如此,也可能有例外。

我认为关键问题是:“每个表中预计包含在结果集中的行的比例是多少?”。如果答案是“100%来自每个”,那么您就可以清楚地了解全表扫描(以及散列连接)。

但是考虑表A和B连接的情况,表A包含5行,其中包含一百万行的表B(父)的外键。显然,在这里你要寻找A的完整扫描,其中嵌套循环连接到B(表B上的连接列将被索引,因为它必须是主键或唯一键)。

在OP的情况下,虽然看起来你希望从每个表返回100%的行。我期望看到两个表的完整扫描,并且首先访问具有TRANSACTIONS(可能是较小的表)的散列连接并将其内置到散列表中。这将是最佳的连接方法,我只是在寻找一种情况,其中TRANSACTIONS对于单次通过散列连接来说太大了。如果连接溢出到磁盘,那么这可能是性能问题,您必须考虑增加内存分配或对两个表进行等分,以减少内存需求。

答案 1 :(得分:2)

由于给定的查询无论如何都会返回所有内容,因此全表扫描实际上可能是到达最终结果的最快方式。由于I / O与CPU时间相比非常昂贵,因此将所有内容拉入内存并在那里进行最终连接可能更有效,而不是在一个表的循环中进行索引查找。

要确定查询是否可以更快地运行,您可以尝试以下方法:

  • 仅查看数据子集的查询计划(例如,id的范围)
  • 尝试查询不同大小的子集,查看您在此处绘制的曲线类型

答案 2 :(得分:0)

全表扫描不一定是坏的 - 看起来你没有以任何方式限制结果集,这可能是执行查询的最有效方式。您始终可以使用索引提示并确定最终的性能更改来验证这一点。

答案 3 :(得分:0)

你没有WHERE子句,因此Oracle认为既然必须从两个表中返回所有记录,那么全表扫描将是最有效的。

如果你要添加一个使用索引的WHERE子句,我想你会发现EXPLAIN PLAN将不再使用全表扫描。