全表扫描 (Full Table Scans)

参考文档:《Oracle® Database SQL Tuning Guide》

全表扫描是从表中读取所有行,然后过滤掉不符合选择条件的行。

一,何时优化器考虑全表扫描

导致Full Table Scans的常规原因:

原因解释

No index exists.

没有索引

If no index exists, then the optimizer uses a full table scan.

没有索引时,优化器使用全表扫描

The query predicate applies a function to the indexed column.

查询谓词中对索引列使用了函数。

Unless the index is a function-based index, the database indexes the values of the column, not the values of the column with the function applied. A typical application-level mistake is to index a character column, such as char_col, and then query the column using syntax such as WHERE char_col=1. The database implicitly applies a TO_NUMBER function to the constant number 1, which prevents use of the index.

除非索引是函数索引,否则数据库是为列值编索引,而不是为函数处理后的列值编索引。典型的应用级错误是为字符类型的列(如char_col)建了索引,然后使用语法(如char_col=1)查询列。数据库隐式地将TO_NUMBER函数应用于常量1,这阻止使用索引。(PS:对于SELECT语句,oracle会把字段的数据类型隐式转换为变量的数据类型,这里应该是将TO_NUMBER函数应用在列上)

A SELECT COUNT(*) query is issued, and an index exists, but the indexed column contains nulls.

当使用SELECT COUNT(*)查询时,索引中含有NULL值

The optimizer cannot use the index to count the number of table rows because the index cannot contain null entries.

当索引中有NULL值时,优化器无法利用索引来count(*)

The query predicate does not use the leading edge of a B-tree index.

查询谓词不使用b树索引的前导字段,也就是组合索引中各字段是有顺序的,在查询时没有使用放在前面的字段。

For example, an index might exist on employees(first_name,last_nam e). If a user issues a query with the predicate WHERE last_name='KING', then the optimizer may not choose an index because column first_name is not in the predicate. However, in this situation the optimizer may choose to use an index skip scan.

比如组合索引在(first_name,last_nam e)这两个字段上,当使用WHERE last_name='KING'这种语法时,由于谓词中没有使用first_name字段,因此优化器不会选择使用索引,但有可能会使用索引跳跃扫描。

The query is unselective.

查询是非选择性的

If the optimizer determines that the query requires most of the blocks in the table, then it uses a full table scan, even though indexes are available. Full table scans can use larger I/O calls. Making fewer large I/O calls is cheaper than making many smaller calls.

如果优化器确定查询需要表中的大部分块,即使索引是可用的,它仍将使用全表扫描。全表扫描会使用更大的I/O调用。较少的大型I/O调用比许多较小的调用更划算。

The table statistics are stale.

表中的统计数据已经过时了。

For example, a table was small, but now has grown large. If the table statistics are stale and do not reflect the current size of the table, then the optimizer does not know that an index is now most efficient than a full table scan.

例如,一个表曾经很小,但是现在变大了。如果表统计数据已经过时,并且没有反映表的当前大小,那么优化器不知道索引现在比全表扫描更有效。

The table is small.

表数据量很少

If a table contains fewer than n blocks under the high water mark, where n equals the setting for the DB_FILE_MULTIBLOCK_READ_COUNT initialization parameter, then a full table scan may be cheaper than an index range scan. The scan may be less expensive regardless of the fraction of tables being accessed or indexes present.

如果一个表在高水位以下的块少于n个,其中n等于DB_FILE_MULTIBLOCK_READ_COUNT初始化参数的设置,那么全表扫描可能比索引范围扫描更划算。不管访问的表的部分或存在的索引如何,扫描成本可能会更低。

The table has a high degree of parallelism.

该表具有高度的并行性。

A high degree of parallelism for a table skews the optimizer toward full table scans over range scans. Query the value in the ALL_TABLES.DEGREE column to determine the degree of parallelism.

表的高度并行性使优化器倾向于全表扫描而不是范围扫描。查询ALL_TABLES.DEGREE中的值来确定并行度。

The query uses a full table scan hint.

查询使用全表扫描提示。

The hint FULL(table alias) instructs the optimizer to use a full table scan.

FULL提示让优化器使用全表扫描。

二,全表扫描如何工作

在全表扫描中,数据库按顺序读取高水位线下的每个格式化块。数据库只读取每个块一次。下图描述了对表段的扫描,显示了扫描如何跳过高水位以下的未格式化块。

由于这些块是相邻的,因此数据库可以通过使I/O调用大于单个块(称为多块读取)来加快扫描速度。读取调用的大小范围从一个块到DB_FILE_MULTIBLOCK_READ_COUNT初始化参数。例如,将此参数设置为4指示数据库在一次调用中读取最多4个块。在全表扫描期间缓存块的算法很复杂。例如,数据库根据表的大小以不同的方式缓存块。

三,例子

1,没有索引时,全表扫描;添加主键后,变成索引唯一扫描:

建表:
SQL> create  table fts(id number,name varchar2(32),indate  date) tablespace tp;
插入数据:
SQL> insert into fts select OBJECT_ID ,OBJECT_NAME,CREATED from dba_objects;
搜集统计信息:
SQL> execute dbms_stats.gather_table_stats('MA','FTS',cascade=>true);
追踪执行计划:
SQL> set autot trace exp;
查看查询语句的执行计划:
SQL> select id,name from fts where id=99;

Execution Plan
----------------------------------------------------------
Plan hash value: 1914973097

--------------------------------------------------------------------------
| Id  | Operation         | Name | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |      |     1 |    28 |   171   (1)| 00:00:01 |
|*  1 |  TABLE ACCESS FULL| FTS  |     1 |    28 |   171   (1)| 00:00:01 |
--------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   1 - filter("ID"=99)


SQL> alter table fts add constraint fts_pk primary key(id);

SQL> execute dbms_stats.gather_table_stats('MA','FTS',cascade=>true);

SQL> select id,name from fts where id=99;

Execution Plan
----------------------------------------------------------
Plan hash value: 103190685

--------------------------------------------------------------------------------------
| Id  | Operation                   | Name   | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT            |        |     1 |    28 |     2   (0)| 00:00:01 |
|   1 |  TABLE ACCESS BY INDEX ROWID| FTS    |     1 |    28 |     2   (0)| 00:00:01 |
|*  2 |   INDEX UNIQUE SCAN         | FTS_PK |     1 |       |     1   (0)| 00:00:01 |
--------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   2 - access("ID"=99)

 

  • 0
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值