解释TKPROF
输出时,有助于了解常见陷阱。
本节包含以下主题:
- 避免参数陷阱的准则 : 如果您不知道在运行时绑定的值,则有可能陷入参数陷阱。
- 避免读取一致性陷阱的指南在 : 不知道未提交的事务对列进行了一系列更新的情况下,很难理解为什么会发生这么多的块访问。
- 避免架构陷阱的指南 : 在某些情况下,一个看似直接的索引查询将查看许多数据库块并以当前模式对其进行访问。
- 避免时间陷阱的指南 : 在某些情况下,查询会花费很长的时间。
22.5.4.1避免参数陷阱的指南
如果您不知道在运行时绑定的值,则有可能陷入参数陷阱。
EXPLAIN PLAN
无法根据SQL语句的文本确定绑定变量的类型,并且始终假定类型为VARCHAR
。如果绑定变量实际上是数字或日期,则TKPROF
可能导致隐式数据转换,这可能导致执行效率低下的计划。为避免这种情况,请在查询中尝试使用不同的数据类型,然后自己执行转换。
22.5.4.2避免读取一致性陷阱的指南
在不知道未提交的事务对列进行了一系列更新的情况下,很难理解为什么会发生如此多的块访问。
这种情况通常是不可重复的。如果再次运行该流程,则另一个事务不太可能以相同的方式与其交互。
SELECT name_id FROM cq_names WHERE name = 'FLOOR'; call count cpu elapsed disk query current rows ---- ----- --- ------- ---- ----- ------- ---- Parse 1 0.10 0.18 0 0 0 0 Execute 1 0.00 0.00 0 0 0 0 Fetch 1 0.11 0.21 2 101 0 1 Misses in library cache during parse: 1 Parsing user id: 01 (USER1) Rows Execution Plan e---- --------- ---- 0 SELECT STATEMENT 1 TABLE ACCESS (BY ROWID) OF 'CQ_NAMES' 2 INDEX (RANGE SCAN) OF 'CQ_NAMES_NAME' (NON_UNIQUE)
复制
22.5.4.3避免架构陷阱的准则
在某些情况下,一个看似直接的索引查询将查看许多数据库块并以当前模式访问它们。
以下示例显示了模式陷阱的一个极端示例(因此很容易检测到):
SELECT name_id FROM cq_names WHERE name = 'FLOOR'; call count cpu elapsed disk query current rows -------- ------- -------- --------- ------- ------ ------- ---- Parse 1 0.06 0.10 0 0 0 0 Execute 1 0.02 0.02 0 0 0 0 Fetch 1 0.23 0.30 31 31 3 1 Misses in library cache during parse: 0 Parsing user id: 02 (USER2) Rows Execution Plan ------- --------------------------------------------------- 0 SELECT STATEMENT 2340 TABLE ACCESS (BY ROWID) OF 'CQ_NAMES' 0 INDEX (RANGE SCAN) OF 'CQ_NAMES_NAME' (NON-UNIQUE)
复制
有两个统计数据表明该查询可能是通过全表扫描执行的:当前模式块访问,以及计划中来自“表访问”行源的行数。原因是所需的索引是在生成跟踪文件之后但在TKPROF
运行之前生成的。生成新的跟踪文件将提供以下数据:
SELECT name_id FROM cq_names WHERE name = 'FLOOR'; call count cpu elapsed disk query current rows ----- ------ ------ -------- ----- ------ ------- ----- Parse 1 0.01 0.02 0 0 0 0 Execute 1 0.00 0.00 0 0 0 0 Fetch 1 0.00 0.00 0 2 0 1 Misses in library cache during parse: 0 Parsing user id: 02 (USER2) Rows Execution Plan ------- --------------------------------------------------- 0 SELECT STATEMENT 1 TABLE ACCESS (BY ROWID) OF 'CQ_NAMES' 2 INDEX (RANGE SCAN) OF 'CQ_NAMES_NAME' (NON-UNIQUE)
复制
在正确的版本中,解析调用花费了10毫秒的CPU时间和20毫秒的经过时间,但是查询显然没有时间执行和执行提取。这些异常的出现是因为10毫秒的时钟滴答声相对于执行和获取数据所花费的时间太长。在这种情况下,重要的是要使语句多次执行,这样您就可以得到统计上有效的数字。
22.5.4.4避免时间陷阱的准则
在某些情况下,查询会花费很长时间。
例如,以下对7行的更新将在19秒内执行:
UPDATE cq_names SET ATTRIBUTES = lower(ATTRIBUTES) WHERE ATTRIBUTES = :att call count cpu elapsed disk query current rows -------- ------- -------- --------- -------- -------- ------- ---------- Parse 1 0.06 0.24 0 0 0 0 Execute 1 0.62 19.62 22 526 12 7 Fetch 0 0.00 0.00 0 0 0 0 Misses in library cache during parse: 1 Parsing user id: 02 (USER2) Rows Execution Plan ------- --------------------------------------------------- 0 UPDATE STATEMENT 2519 TABLE ACCESS (FULL) OF 'CQ_NAMES'
复制
解释是来自另一笔交易的干扰。在这种情况下,另一个事务在cq_names
发布更新之前和之后都在表上持有共享锁几秒钟。诊断经验是否正在发生需要经验。一方面,当干扰仅造成短时延迟(或在先前示例中,块访问量略有增加)时,比较数据至关重要。但是,如果干扰仅造成适度的开销,并且如果该语句实质上是有效的,则可能不需要分析其统计信息。