http://yangtingkun.itpub.net/post/468/474904
今天同事问了我一个问题,对于一个NUMBER(1)的列,查询中的WHERE条件如果分别是大于3和大于等于4,二者是否等价。
对于整数大于3和大于等于4是否一样:http://yangtingkun.itpub.net/post/468/474742
这里继续讨论二者在索引扫描上的区别。
昨天和同事讨论这个问题,同事认为如果是大于3的话,走索引扫描,会从3开始扫描,而大于等于4,会从4开始扫描,下面我们来验证一下这个观点是否正确。
根据这个观点对于大于3的情况,Oracle会先找到索引键值为3的块,然后开始扫描。而对于大于等于4的情况,则会找到索引键值为4的块,然后执行扫描。如果表中包含大量索引键值为3的记录,这两个查询就可能存在性能上的差异。
看一个具体的例子:
SQL> CREATE TABLE T_NUM (ID NUMBER, NAME VARCHAR2(30));
表已创建。
SQL> CREATE INDEX IND_T_NUM_ID ON T_NUM (ID);
索引已创建。
SQL> INSERT INTO T_NUM SELECT 3, OBJECT_NAME FROM DBA_OBJECTS;
已创建54688行。
SQL> INSERT INTO T_NUM SELECT * FROM T_NUM;
已创建54688行。
SQL> INSERT INTO T_NUM SELECT * FROM T_NUM;
已创建109376行。
SQL> INSERT INTO T_NUM SELECT * FROM T_NUM;
已创建218752行。
SQL> COMMIT;
提交完成。
创建一张测试表,表中所有的ID都等于3,下面插入一条ID为4记录:
SQL> INSERT INTO T_NUM VALUES (4, 'TEST');
已创建 1 行。
SQL> COMMIT;
提交完成。
下面执行查询语句:
SQL> SET AUTOT ON
SQL> SET TIMING ON
SQL> SELECT * FROM T_NUM WHERE ID > 3;
ID NAME
---------- ------------------------------
4 TEST
已用时间: 00: 00: 00.06
执行计划
----------------------------------------------------------
Plan hash value: 3388343191
--------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 30 | 3 (0)| 00:00:01 |
| 1 | TABLE ACCESS BY INDEX ROWID| T_NUM | 1 | 30 | 3 (0)| 00:00:01 |
|* 2 | INDEX RANGE SCAN | IND_T_NUM_ID | 1 | | 2 (0)| 00:00:01 |
--------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("ID">3)
Note
-----
- dynamic sampling used for this statement
统计信息
----------------------------------------------------------
0 recursive calls
0 db block gets
4 consistent gets
0 physical reads
0 redo size
465 bytes sent via SQL*Net to client
385 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
1 rows processed
SQL> SELECT * FROM T_NUM WHERE ID >= 4;
ID NAME
---------- ------------------------------
4 TEST
已用时间: 00: 00: 00.06
执行计划
----------------------------------------------------------
Plan hash value: 3388343191
--------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 30 | 3 (0)| 00:00:01 |
| 1 | TABLE ACCESS BY INDEX ROWID| T_NUM | 1 | 30 | 3 (0)| 00:00:01 |
|* 2 | INDEX RANGE SCAN | IND_T_NUM_ID | 1 | | 2 (0)| 00:00:01 |
--------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("ID">=4)
Note
-----
- dynamic sampling used for this statement
统计信息
----------------------------------------------------------
0 recursive calls
0 db block gets
4 consistent gets
0 physical reads
0 redo size
465 bytes sent via SQL*Net to client
385 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
1 rows processed
可以看到,无论是执行时间,还是逻辑读,两个SQL没有任何的差别。为了更好的证明Oracle并没有读取ID等于3的记录,执行下面的查询:
SQL> SELECT COUNT(*) FROM T_NUM WHERE ID = 3;
COUNT(*)
----------
437504
已用时间: 00: 00: 00.10
执行计划
----------------------------------------------------------
Plan hash value: 3557129504
--------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 13 | 291 (1)| 00:00:04 |
| 1 | SORT AGGREGATE | | 1 | 13 | | |
|* 2 | INDEX FAST FULL SCAN| IND_T_NUM_ID | 406K| 5164K| 291 (1)| 00:00:04 |
--------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - filter("ID"=3)
Note
-----
- dynamic sampling used for this statement
统计信息
----------------------------------------------------------
10 recursive calls
2 db block gets
2655 consistent gets
0 physical reads
93896 redo size
410 bytes sent via SQL*Net to client
385 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
1 rows processed
其实看过Concept对索引结构有一定了解就知道,根据Oracle索引结构的特点,无论是大于3还是大于等于4,二者的查询是扫描的叶节点都是同一个,因此不会在这一点上不会存在性能的差别。
yangtingkun 发表于:2008.12.05 23:38 ::分类: ( ORACLE ) ::阅读:(1876次) :: 评论 (0)