故障类型
直方图引起的 sql 执行计划异常
现象错误号
业务某个模块单条 SQL 执行非常慢,执行时间是原来的好几倍。问题表格对应的列上存在直方图导致执行计划偏差,默认情况下未特殊指定列的直方图是收集的。
故障描述
直方图 (Histogram) 又称质量分布图。是一种统计报告图,由一系列高度不等的纵向条纹或线段表示数据分布的情况。 一般用横轴表示数据类型,纵轴表示分布情况。可以看出,直方图可以用来描述数据分布的情况。 Oracle 中也是如此,直方图可以准确预测列数据的分布,尤其在出现数据分布倾斜的情况下,通过直方图信息,可以选择最优的执行计划。
此处由于 account_no 值为 3301040160005763134 数量级较大, Oracle CBO 结合 account_no 列上的直方图计算误认为走全表执行计划最优。因而采用了全表扫的方式,最终导致执行性能下降。
例如,如果一到两个值构成了表中的大部分数据 ( 数据偏斜 ) ,相关的索引就可能无法帮助减少满足查询所需的 I/O 数量。创建直方图可以让基于成本的优化器知道何时使用索引才最合适,或何时应该根据 WHERE 子句中的值返回表中 80 %的记录。
故障原因分析
问题 sql 语句:
SELECT serial_no, area_code, acc_area, trans_area, trans_state, account_no, group_sub_no, gl_class, product_code, cur_type, TO_CHAR(acc_date, :"SYS_B_0"), TO_CHAR(acc_time, :"SYS_B_1"), TO_CHAR(sys_date, :"SYS_B_2"), TO_CHAR(sys_time, :"SYS_B_3"), main_code, process_code, acc_reason, detail_serial, debit_amt, credit_amt, balance, pre_balance, account_jnls_no, trans_jnls_no, refer_trans_no, account_cycle_no, clearing_times, related_cycle_no, TO_CHAR(related_acc_date, :"SYS_B_4"), cash_flag, remote_flag, d_c_flag, trans_flag, summary, summary_rem, voucher_type, voucher_no, oper_no, check_oper, terminal_no, channel_code, party_type, party_account, party_name, party_bank, party_bank_name, remark, print_flag, dac FROM account_detail WHERE account_no = :account_no__0 AND detail_serial >= :detail_serial__GE_1 ORDER BY detail_serial; |
从 sql 语句上来看 account_no 和 detail_serial 列上存在联合索引选择性较好。
进一步排查数据库中记录的执行信息。
SQL 244saaz6znbwf 的执行计划来看存在两个 hash 值 3084482491 和 3788272203 ,其中值为 3788272203 相对于 3084482491 执行计划更好一点,单条 SQL 执行时间只有 0.1 秒。
查看 SQL 244saaz6znbwf 历史执行计划
从 SQL 244saaz6znbwf 12 月 1 日的历史执行计划来看并不稳定时好时坏,询问后发现根据带入的值不同执行时间也有很大偏差,其中当 account_no 带入值为 3301040160005763134 时相应特别慢十几分钟都不出结果,此时本能反应统计信息不准确或 account_no 上存在直方图导致执行计划不稳定,进一步排查。
查看表格 account_detail 统计信息
select to_char(LAST_ANALYZED,'yyyy-mm-dd hh24:mi:ss'),NUM_ROWS,TABLE_NAME FROM DBA_TABLES WHERE TABLE_NAME='ACCOUNT_DETAIL';
LAST_ANALYZED NUM_ROWS TABLE_NAME ------------------------------------------------- ---------- 2017-12-01 1:34:47 342547333 ACCOUNT_DETAIL |
表格 account_detail 统计更新正常,排除统计信息问题,进一步排查柱状图
查看表格 account_detail 列直方图信息
select column_name,density,num_buckets,histogram from dba_tab_col_statistics where table_name='ACCOUNT_DETAIL' and column_name in ('ACCOUNT_NO','DETAIL_SERIAL');
COLUMN_NAME DENSITY NUM_BUCKETS HISTOGRAM --------------- ---------- ----------- --------------- ACCOUNT_NO .000283849 254 HEIGHT BALANCED DETAIL_SERIAL .000204876 254 HEIGHT BALANCED |
可以看到 account_no 列直方图并非为空,而且值为 3301040160005763134 的 bucket 数较多数量级是别的值的好几倍。这也刚好印证了 account_no 带入其他值时执行效率正常,而带入 3301040160005763134 时几乎无响应。此时可以判断是由于 account_no 列上存在直方图导致执行计划偏差,默认情况下未特殊指定列的直方图是收集的。
直方图 (Histogram) 又称质量分布图。是一种统计报告图,由一系列高度不等的纵向条纹或线段表示数据分布的情况。 一般用横轴表示数据类型,纵轴表示分布情况。可以看出,直方图可以用来描述数据分布的情况。 Oracle 中也是如此,直方图可以准确预测列数据的分布,尤其在出现数据分布倾斜的情况下,通过直方图信息,可以选择最优的执行计划。
此处由于 account_no 值为 3301040160005763134 数量级较大 Oracle CBO 结合 account_no 列上的直方图计算误认为走全表执行计划最优。因而采用了全表扫的方式,最终导致执行性能下降。
例如,如果一到两个值构成了表中的大部分数据 ( 数据偏斜 ) ,相关的索引就可能无法帮助减少满足查询所需的 I/O 数量。创建直方图可以让基于成本的优化器知道何时使用索引才最合适,或何时应该根据 WHERE 子句中的值返回表中 80 %的记录。