Oracle TKPROF输出疑问:当前块读、执行计划starts值及解析次数
查询语句
select s.prod_id, p.prod_name, s.cust_id, c.cust_first_name from sh.sales s, sh.products p, sh.customers c where s.prod_id = p.prod_id and s.cust_id = c.cust_id and s.amount_sold > 1500
TKPROF输出
call count cpu elapsed disk query current rows ------- ------ -------- ---------- ---------- ---------- ---------- ---------- Parse 1 0.03 0.03 0 0 0 0 Execute 1 0.00 0.00 0 0 0 0 Fetch 542 0.32 0.72 0 3607 28 8114 ------- ------ -------- ---------- ---------- ---------- ---------- ---------- total 544 0.35 0.76 0 3607 28 8114 Misses in library cache during parse: 1 Optimizer mode: ALL_ROWS Parsing user id: SYS Number of plan statistics captured: 1 Rows (1st) Rows (avg) Rows (max) Row Source Operation ---------- ---------- ---------- --------------------------------------------------- 8114 8114 8114 HASH JOIN (cr=3607 pr=0 pw=0 time=450527 us starts=1 cost=859 size=469504 card=8384) 8114 8114 8114 NESTED LOOPS (cr=1643 pr=0 pw=0 time=253284 us starts=1 cost=859 size=469504 card=8384) 8114 8114 8114 NESTED LOOPS (cr=1643 pr=0 pw=0 time=251761 us starts=1) 8114 8114 8114 STATISTICS COLLECTOR (cr=1643 pr=0 pw=0 time=250365 us starts=1) 8114 8114 8114 HASH JOIN (cr=1643 pr=0 pw=0 time=250044 us starts=1 cost=454 size=368896 card=8384) 72 72 72 NESTED LOOPS (cr=8 pr=0 pw=0 time=863 us starts=1 cost=454 size=368896 card=8384) 72 72 72 STATISTICS COLLECTOR (cr=8 pr=0 pw=0 time=790 us starts=1) 72 72 72 TABLE ACCESS FULL PRODUCTS (cr=8 pr=0 pw=0 time=691 us starts=1 cost=3 size=2160 card=72) 0 0 0 PARTITION RANGE ALL PARTITION: 1 28 (cr=0 pr=0 pw=0 time=0 us starts=0 cost=451 size=1624 card=116) 0 0 0 TABLE ACCESS BY LOCAL INDEX ROWID BATCHED SALES PARTITION: 1 28 (cr=0 pr=0 pw=0 time=0 us starts=0 cost=451 size=1624 card=116) 0 0 0 BITMAP CONVERSION TO ROWIDS (cr=0 pr=0 pw=0 time=0 us starts=0) 0 0 0 BITMAP INDEX SINGLE VALUE SALES_PROD_BIX PARTITION: 1 28 (cr=0 pr=0 pw=0 time=0 us starts=0)(object id 101439) 8114 8114 8114 PARTITION RANGE ALL PARTITION: 1 28 (cr=1635 pr=0 pw=0 time=248277 us starts=1 cost=451 size=117376 card=8384) 8114 8114 8114 TABLE ACCESS FULL SALES PARTITION: 1 28 (cr=1635 pr=0 pw=0 time=208294 us starts=28 cost=451 size=117376 card=8384) 0 0 0 INDEX UNIQUE SCAN CUSTOMERS_PK (cr=0 pr=0 pw=0 time=0 us starts=0)(object id 101249) 0 0 0 TABLE ACCESS BY INDEX ROWID CUSTOMERS (cr=0 pr=0 pw=0 time=0 us starts=0 cost=405 size=12 card=1) 55500 55500 55500 TABLE ACCESS FULL CUSTOMERS (cr=1964 pr=0 pw=0 time=120870 us starts=1 cost=405 size=666000 card=55500) Elapsed times include waiting on following events: Event waited on Times Max. Wait Total Waited ---------------------------------------- Waited ---------- ------------ PGA memory operation 35 0.00 0.00 Disk file operations I/O 1 0.00 0.00 SQL*Net message to client 542 0.00 0.00 SQL*Net message from client 542 41.10 57.47 ********************************************************************************
问题1:未执行更新操作,为何存在28次current mode block reads?
别被current mode的名字误导——这种读取可不是DML操作的专属!Oracle在执行查询时,也会因为访问数据字典或段元数据块触发current读,因为这些块需要最新的状态,不需要生成一致性快照。
看你的执行计划,SALES是分区表,刚好覆盖1-28号分区。每次访问一个分区,Oracle都需要读取该分区的段头块(用来获取分区的存储布局、extent分布等核心信息),而段头块的读取就是current模式的。28个分区刚好对应28次current reads,这个数字完全吻合。
另外,PGA操作中的临时段管理也可能产生少量current读,但这里的数量和分区数完美匹配,所以分区段头读取是最直接的原因。
问题2:执行计划中部分步骤starts值为0,但Autotrace显示这些步骤已执行,请问这些步骤是否实际执行?若已执行,为何starts值为0?
这些starts=0的步骤完全没有执行——它们是优化器生成的备选执行分支,实际运行时Oracle选择了另一条更高效的路径。
比如你看到的INDEX UNIQUE SCAN CUSTOMERS_PK和对应的表访问步骤,是优化器考虑的“通过主键索引关联CUSTOMERS表”的方案,但实际执行时,优化器选择了用HASH JOIN直接关联全表扫描的CUSTOMERS(看执行计划最底部的TABLE ACCESS FULL CUSTOMERS,starts=1,还有cr=1964的实际读取统计)。
至于Autotrace显示这些步骤,是因为Autotrace输出的是优化器生成的完整计划树(包含所有可能的候选路径),而TKPROF的starts是实际运行时的执行统计——只有真正走的分支才会有starts>0的记录。
问题3:为何单次查询同时存在硬解析和软解析(共两次解析)?
先看你的TKPROF输出:Parse count=1,Misses in library cache during parse:1——这说明主查询只触发了1次硬解析,根本没有软解析。
如果你觉得有两次解析,大概率是把主查询的解析和Oracle内部的递归SQL解析混在一起了。当执行你的查询时,Oracle会自动运行一些递归SQL(比如查询数据字典获取分区信息、表的统计信息、权限验证等),这些递归SQL也会经历解析过程(可能是硬解析或软解析)。你可能在某个工具(比如Autotrace的详细输出)里看到了这些递归SQL的解析记录,误以为是主查询的两次解析。
简单总结:主查询本身只有1次硬解析,“两次解析”的错觉来自Oracle内部递归SQL的解析操作。
内容的提问来源于stack exchange,提问作者oramas

