从前面的两个测试来看,优化器评估出来的SQL返回的行数要么是5739(表BSS_ORG的总行数),要么是6(总行数/BSS_PARENT_ORG_ID的Disctint Values)。但无论如何,随着不同的start with条件,这个行数(cardinality)与实际返回的结果行数可能会存在非常大的差异。如果仅仅是测试中这样一个简单的SQL,实际上不会有什么问题,很容易出现问题的地方在于,一个复杂的SQL中,有类似于测试SQL这样的子查询,这样使得表连接的评估出现很大的偏差,这样容易引起非常大的性能问题。 在9i下,如果BSS_PARENT_ORG_ID上如果没有索引,那么最后一个测试SQL的执行计划如下: SQL> explain plan for 2 SELECT * 3 FROM bss_org t 4 START WITH bss_org_id = 832044754 5 CONNECT BY bss_parent_org_id = 6 PRIOR bss_org_id 7 ; 已解释。 SQL> @showplan ---------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost | ---------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 5739 | 297K| 9 | |* 1 | CONNECT BY WITH FILTERING | | | | | | 2 | TABLE ACCESS BY INDEX ROWID| BSS_ORG | | | | |* 3 | INDEX UNIQUE SCAN | PK_BSS_ORG | 1 | 7 | 1 | | 4 | HASH JOIN | | | | | | 5 | CONNECT BY PUMP | | | | | | 6 | TABLE ACCESS FULL | BSS_ORG | 5739 | 297K| 9 | | 7 | TABLE ACCESS FULL | BSS_ORG | 5739 | 297K| 9 | ---------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 1 - filter("T"."BSS_ORG_ID"=832044754) 3 - access("T"."BSS_ORG_ID"=832044754) SQL> explain plan for 2 SELECT * 3 FROM bss_org t 4 START WITH bss_org_id = 832044754 5 CONNECT BY bss_parent_org_id = 6 PRIOR bss_org_id 7 ; 已解释。 SQL> @showplan ---------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost | ---------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 5739 | 297K| 9 | |* 1 | CONNECT BY WITH FILTERING | | | | | | 2 | TABLE ACCESS BY INDEX ROWID| BSS_ORG | | | | |* 3 | INDEX UNIQUE SCAN | PK_BSS_ORG | 1 | 7 | 1 | | 4 | HASH JOIN | | | | | | 5 | CONNECT BY PUMP | | | | | | 6 | TABLE ACCESS FULL | BSS_ORG | 5739 | 297K| 9 | | 7 | TABLE ACCESS FULL | BSS_ORG | 5739 | 297K| 9 | ---------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 1 - filter("T"."BSS_ORG_ID"=832044754) 3 - access("T"."BSS_ORG_ID"=832044754) 前段时间就遇上由于connect by语句引起的性能问题。数据库为Oracle 9208,开始由于bss_org表的bss_parent_org_id列上没有索引,导致connect by部分得到的cardinality为5739,结果SQL性能非常差,在bss_parent_org_id上建索引后,执行计划改变,connect by 部分得到的cardinality为6,SQL性能大幅提升。 对于Oracle优化器不能准确评估connect by 语句的cardinality,目前没有比较好的解决办法。必要的时候只有考虑使用Hint了。 |