在执行SQL查询时,如果WHERE子句中包含使用表达式的谓词,例如
function(column) = constant
,优化器默认情况下可能无法准确估计谓词的选择性。这是因为除非存在基于函数的索引,否则优化器不知道该函数如何影响列的分布和谓词的基数。为了解决这个问题,Oracle提供了一种名为表达式统计信息的功能,通过收集有关表达式本身的统计信息来提供更准确的估计。
当优化器没有访问表达式统计信息时,它只能依赖于列本身的统计信息来生成查询计划。这可能导致优化器生成次优计划,特别是在查询中使用了转换或函数操作列时。通过为这些表达式收集统计信息,优化器可以获得更准确的估计,从而生成更优的执行计划。
示例:优化基于函数的查询
考虑以下两个查询,它们都旨在从
sh.customers
表中检索位于加利福尼亚州(CA)的客户数量。第一个查询使用了直接的列比较:
SELECT COUNT(*) FROM sh.customers WHERE cust_state_province = 'CA';
该查询返回3341,这是一个精确的结果。
然而,当我们应用一个函数到列上,比如使用
LOWER()
函数来进行不区分大小写的比较:
SELECT * FROM sh.customers WHERE LOWER(cust_state_province) = 'ca';
如果没有适当的表达式统计信息,优化器生成的计划可能基于不准确的行估计值,如以下执行计划所示:
Plan hash value: 2008213504
-------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 555 | 108K| 406 (1)| 00:00:05 |
|* 1 | TABLE ACCESS FULL| CUSTOMERS | 555 | 108K| 406 (1)| 00:00:05 |
-------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter(LOWER("CUST_STATE_PROVINCE")='ca')
在这个例子中,由于缺少表达式
LOWER(cust_state_province)='ca'
的统计信息,优化器估计只有555行匹配,这明显偏离了实际的行数。
解决方案:收集表达式统计信息
为了解决这个问题,我们可以使用
DBMS_STATS
包来为特定表达式收集统计信息。这将使优化器能够访问与查询中使用的表达式相对应的统计信息,从而产生更准确的估计和更优的执行计划。
BEGIN
DBMS_STATS .GATHER_TABLE_STATS (
ownname => 'sh' ,
tabname => 'customers' ,
method_opt => 'FOR ALL COLUMNS SIZE AUTO FOR COLUMNS (LOWER(cust_state_province))'
) ;
END ;
通过收集表达式统计信息,优化器现在可以准确评估基于函数的谓词的选择性,从而生成更接近实际情况的执行计划。