避免全表扫描
Posted
技术标签:
【中文标题】避免全表扫描【英文标题】:Avoiding full table scan 【发布时间】:2009-10-21 12:21:32 【问题描述】:我有以下查询,它从事务表和事务详细信息中获取事务。两个表都有大量的条目,所以这个查询需要一段时间才能返回结果。
SELECT * FROM transactions t LEFT JOIN transac_detail tidts ON (tidts.id_transac = t.id);
但是,我更担心的是,Oracle 根据解释计划对两个表进行全表扫描,即使 t.id 和 tidts.id_transac 有索引。
有什么方法可以在不触及表结构的情况下优化它?
【问题讨论】:
甲骨文是做什么的?哈希连接?散列连接非常快,通常比使用索引的执行计划更快。向我们展示您的解释计划并检查统计数据是否准确。 【参考方案1】:我认为 SQL 不一定最好与全表扫描一起使用。如果两者之间有外键,这确实是最明显的,但即使这样也可能有例外。
我认为关键问题是:“每个表中的行应包含在结果集中的比例是多少?”。如果答案是“100% 来自每个”,那么您有一个明确的案例进行全表扫描(和散列连接)。
但是考虑表 A 和 B 连接的情况,表 A 包含 5 行,表 B(父表)的外键包含一百万行。显然,在这里您会寻找对 A 的完整扫描,其中包含与 B 的嵌套循环连接(表 B 上的连接列将被索引,因为它必须是主键或唯一键)。
在 OP 的情况下,虽然看起来您希望从每个表中返回 100% 的行。我希望看到对这两个表的完整扫描,并首先访问带有 TRANSACTIONS(可能是较小的表)的哈希连接并将其构建到哈希表中。这将是最佳的连接方法,我只是在寻找 TRANSACTIONS 对于单遍哈希连接来说太大的情况。如果连接溢出到磁盘,那么这可能是性能问题,您必须考虑增加内存分配或对两个表进行等分区以减少内存需求。
【讨论】:
非常彻底的答案,一如既往。 +1【参考方案2】:由于给定的查询无论如何都会返回所有内容,因此全表扫描实际上可能是获得最终结果的最快方式。由于 I/O 与 CPU 时间相比非常昂贵,因此将所有内容拉入内存并在那里进行最终连接可能比在一个表上循环进行索引查找更有效。
要确定查询实际上是否可以更快地运行,您可以尝试以下方法:
仅查看数据子集(例如,ID 范围)的查询计划 尝试对不同大小的子集进行查询,看看您在此处绘制什么样的曲线【讨论】:
【参考方案3】:您没有 WHERE 子句,因此 Oracle 认为,由于它必须返回两个表中的所有记录,因此全表扫描将是最有效的。
如果你添加一个使用索引的 WHERE 子句,我想你会发现 EXPLAIN PLAN 将不再使用全表扫描。
【讨论】:
【参考方案4】:全表扫描不一定是坏事——看来您并没有以任何方式限制结果集,这可能是执行查询的最有效方式。您始终可以通过使用索引提示并确定由此产生的性能变化来验证这一点。
【讨论】:
以上是关于避免全表扫描的主要内容,如果未能解决你的问题,请参考以下文章