(注:在某些情况下,CBO没有足够的时间来评估每个可能的计划;在这些情况下,它只选择到目前为止成本最低的计划)
一般来说,缓慢查询的最大因素之一是读取服务查询(块,更精确)的行数,因此成本将部分基于优化程序估计需要的行数读取。
例如,假设您有以下查询:
SELECT emp_id FROM employees WHERE months_of_service = 6;
(months_of_service列有一个NOT NULL约束和一个普通的索引。)
优化器可能在这里选择两个基本计划:
>计划1:读取“employees”表中的所有行,为每个行检查谓词是否为true(months_of_service = 6)。
>计划2:读取其中months_of_service = 6的索引(这将产生一组ROWID),然后根据返回的ROWID访问该表。
让我们假设“employees”表有1,000,000(100万)行。让我们进一步想象,months_of_service的值范围从1到12,并且由于某种原因相当均匀地分布。
计划1的成本(涉及全扫描)将是读取employees表中所有行的成本,大约等于1,000;但由于Oracle通常能够使用多块读取来读取块,因此实际成本会更低(取决于数据库的设置方式)。让我们设想多块读取计数为10 – 全扫描的计算成本将为1,000 / 10;成本= 100,000。
计划2的成本(其涉及INDEX RANGE SCAN和由ROWID进行的表查找)将是扫描索引的成本加上通过ROWID访问表的成本。我不会进入索引范围扫描的成本,但让我们想象索引范围扫描的成本是每行1;我们期望在12个案例中的1个中找到匹配,所以索引扫描的成本是1,000 / 12 = 83,333;加上访问表的成本(假定每个访问一个块读取,我们不能在这里使用多块读取)= 83,333;总成本= 166,666。
如您所见,计划1(全扫描)的成本比计划2(按rowid的索引扫描访问)的成本低,这意味着CBO将选择全扫描。
如果优化器在这里做出的假设是真的,那么实际上计划1将是比计划2更好和更有效率,这反驳了FULL扫描总是“坏”的神话。
如果优化器目标是FIRST_ROWS(n),而不是ALL_ROWS,那么结果将是完全不同的 – 在这种情况下,优化器将偏好Plan 2,因为它通常会以更快的速度返回前几行,但代价是整个查询的效率较低。