如何使用Oracle SQL语句解决性能问题

时间:2020-03-06 14:27:06  来源:igfitidea点击:

我有两个几乎完全相同的insert语句,它们在同一Oracle实例上的两个不同模式下运行。插入语句的外观并不重要,我在这里寻找故障排除策略。

两种模式都具有99%相同的结构。几列的名称略有不同,只是名称相同。 insert语句几乎完全相同。一个解释程序的成本为6,另一解释程序的成本为7. 两组插入语句中涉及的表具有完全相同的索引。已经收集了两种模式的统计信息。

一个insert语句在5秒钟内插入12,000条记录。

另一个insert语句在4分19秒内插入25,000条记录。

插入的记录数正确。在执行时间上的巨大差异使我感到困惑。鉴于说明计划中没有什么突出的内容,我们将如何确定是什么原因导致运行时出现这种差异?

(我正在Windows框中使用Oracle 10.2.0.4)。

编辑:问题最终是效率低下的查询计划,涉及不需要进行的笛卡尔合并。明智地使用索引提示和哈希联接提示可以解决此问题。现在需要10秒钟。 Sql Trace / TKProf为我指明了方向,因为它向我显示了计划中每个步骤花费了几秒钟,以及正在生成多少行。因此,TKPROF向我展示了:

Rows     Row Source Operation
-------  ---------------------------------------------------
  23690  NESTED LOOPS OUTER (cr=3310466 pr=17 pw=0 time=174881374 us)
  23690   NESTED LOOPS  (cr=3310464 pr=17 pw=0 time=174478629 us)
2160900    MERGE JOIN CARTESIAN (cr=102 pr=0 pw=0 time=6491451 us)
   1470     TABLE ACCESS BY INDEX ROWID TBL1 (cr=57 pr=0 pw=0 time=23978 us)
   8820      INDEX RANGE SCAN XIF5TBL1 (cr=16 pr=0 pw=0 time=8859 us)(object id 272041)
2160900     BUFFER SORT (cr=45 pr=0 pw=0 time=4334777 us)
   1470      TABLE ACCESS BY INDEX ROWID TBL1 (cr=45 pr=0 pw=0 time=2956 us)
   8820       INDEX RANGE SCAN XIF5TBL1 (cr=10 pr=0 pw=0 time=8830 us)(object id 272041)
  23690    MAT_VIEW ACCESS BY INDEX ROWID TBL2 (cr=3310362 pr=17 pw=0 time=235116546 us)
  96565     INDEX RANGE SCAN XPK_TBL2 (cr=3219374 pr=3 pw=0 time=217869652 us)(object id 272084)
      0   TABLE ACCESS BY INDEX ROWID TBL3 (cr=2 pr=0 pw=0 time=293390 us)
      0    INDEX RANGE SCAN XIF1TBL3 (cr=2 pr=0 pw=0 time=180345 us)(object id 271983)

请注意其中的操作是MERGE JOIN CARTESIAN和BUFFER SORT的行。使我着眼这一点的事情是生成的行数(超过200万!),以及每个操作所花费的时间(与其他操作相比)。

解决方案

使用SQL跟踪工具和TKPROF。

插入速度下降的主要原因是索引,约束和插入触发器。在不进行任何删除的情况下进行测试,看看它是否很快。然后将它们重新引入,看看是哪个引起了问题。

我看到过这样的系统,它们在大容量插入之前删除索引并最终进行重建-而且速度更快。

首先要意识到的是,正如文档所述,我们看到的显示成本是相对于其中一个查询计划的。 2种不同解释的费用无法比较。其次,成本是基于内部估算的。尽管Oracle尽力而为,但这些估计并不准确。当优化器行为异常时尤其如此。情况表明,有两种查询计划,根据Oracle的说法,它们的性能非常接近。但是实际上,它们的表现却大不相同。

我们要查看的实际信息是实际的说明计划本身。那可以准确地告诉我们Oracle如何执行该查询。它具有许多技术精湛的技巧,但是我们真正关心的是知道它从最缩进的部分开始工作,并且在每一步都根据少数规则之一合并。这将告诉我们在两个实例中Oracle在做什么方面的不同。

接下来是什么?嗯,有各种各样的策略可以调整错误的陈述。如果我们使用的是Oracle 10g,我建议的第一个选择是尝试使用他们的SQL调整顾问,看看是否进行更详细的分析会告诉Oracle错误的方式。然后,它可以存储该计划,我们将使用效率更高的计划。

如果我们不能执行此操作,或者该操作不起作用,则需要进行诸如提供查询提示,手动存储的查询大纲等工作。那是一个复杂的话题。这是拥有真正的DBA的地方。如果不这样做,那么我们将要开始阅读文档,但是请注意,还有很多东西要学习。 (Oracle也有一个SQL调优类,该类过去非常好,或者至少以前非常好。不过,它并不便宜。)

我同意以前的说法,SQL Trace和tkprof是一个很好的起点。我还强烈推荐《优化Oracle性能》一书,该书讨论了用于跟踪执行和分析输出的类似工具。

我提出了要检查以提高性能的一般事项清单,以回答另一个问题:

最喜欢的性能调整技巧

...尽管它不是特定于Oracle的,但作为清单还是有帮助的。

仅当我们有权使用这些工具时,SQL Trace和tkprof才是好的。我工作的大多数大公司都不允许开发人员访问Oracle UNIX ID下的任何内容。

我相信我们应该能够通过首先了解所提出的问题并阅读每个查询的解释计划来确定问题。很多时候,我发现最大的区别是有些表和索引尚未进行分析。

提出了查询调优的通用技术的另一个很好的参考是Dan Tow撰写的《 SQL Tuning》一书。

分析oI还强烈建议《优化Oracle性能》一书,该书讨论了用于跟踪执行和输出的类似工具。