오라클 인덱스 열 값이 null인 경우는 언제입니까?
저는 열 값 중 하나가 null일 때 Oracle이 행을 인덱싱하지 않는다고 생각했습니다.
몇 가지 간단한 실험은 이것이 사실이 아니라는 것을 보여줍니다.일부 열이 null임에도 불구하고 인덱스에만 액세스하는 일부 쿼리를 예기치 않게 실행할 수 있었습니다(물론 이는 놀라운 일이었습니다).
Google 검색 결과 일부 블로그에서 다음과 같은 상반된 답변이 나왔습니다.인덱스된 모든 열이 null인 경우 행이 인덱싱되고 인덱스의 선행 열 값이 null인 경우 행이 인덱싱된다는 것을 읽었습니다.
그렇다면 어떤 경우에 행이 인덱스에 들어가지 않을까요?이 Oracle 버전은 특정 버전입니까?
인덱스된 열에 null이 아닌 값이 포함된 경우 해당 행이 인덱스됩니다.다음 예제에서 볼 수 있듯이 하나의 행만 인덱싱되지 않으며 두 개의 인덱싱된 열에 NULL이 있는 행이 해당됩니다.또한 선행 인덱스 열에 NULL 값이 있을 때 Oracle이 행을 확실히 인덱싱한다는 것을 확인할 수 있습니다.
SQL> create table big_table as
  2       select object_id as pk_col
  3               , object_name as col_1
  4               , object_name as col_2
  5  from all_objects
  6  /
Table created.
SQL> select count(*) from big_table
  2  /
  COUNT(*)
----------
     69238
SQL> insert into big_table values (9999990, null, null)
  2  /
1 row created.
SQL> insert into big_table values (9999991, 'NEW COL 1', null)
  2  /
1 row created.
SQL> insert into big_table values (9999992, null, 'NEW COL 2')
  2  /
1 row created.
SQL> select count(*) from big_table
  2  /
  COUNT(*)
----------
     69241
SQL> create index big_i on big_table(col_1, col_2)
  2  /
Index created.
SQL> exec dbms_stats.gather_table_stats(user, 'BIG_TABLE', cascade=>TRUE)
PL/SQL procedure successfully completed.
SQL> select num_rows from user_indexes where index_name = 'BIG_I'
  2  /
  NUM_ROWS
----------
     69240
SQL> set autotrace traceonly exp
SQL>
SQL> select pk_col from big_table
  2  where col_1 = 'NEW COL 1'
  3  /
Execution Plan
----------------------------------------------------------
Plan hash value: 1387873879
-----------------------------------------------------------------------------------------
| Id  | Operation                   | Name      | Rows  | Bytes | Cost (%CPU)| Time     |
-----------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT            |           |     2 |    60 |     4   (0)| 00:00:01 |
|   1 |  TABLE ACCESS BY INDEX ROWID| BIG_TABLE |     2 |    60 |     4   (0)| 00:00:01 |
|*  2 |   INDEX RANGE SCAN          | BIG_I     |     2 |       |     3   (0)| 00:00:01 |
-----------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
   2 - access("COL_1"='NEW COL 1')
SQL> select pk_col from big_table
  2  where col_2 = 'NEW COL 2'
  3  /
Execution Plan
----------------------------------------------------------
Plan hash value: 3993303771
-------------------------------------------------------------------------------
| Id  | Operation         | Name      | Rows  | Bytes | Cost (%CPU)| Time     |
-------------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |           |     2 |    60 |   176   (1)| 00:00:03 |
|*  1 |  TABLE ACCESS FULL| BIG_TABLE |     2 |    60 |   176   (1)| 00:00:03 |
-------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
   1 - filter("COL_2"='NEW COL 2')
SQL> select pk_col from big_table
  2  where col_1 is null
  3  and col_2 = 'NEW COL 2'
  4  /
Execution Plan
----------------------------------------------------------
Plan hash value: 1387873879
-----------------------------------------------------------------------------------------
| Id  | Operation                   | Name      | Rows  | Bytes | Cost (%CPU)| Time     |
-----------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT            |           |     1 |    53 |     4   (0)| 00:00:01 |
|   1 |  TABLE ACCESS BY INDEX ROWID| BIG_TABLE |     1 |    53 |     4   (0)| 00:00:01 |
|*  2 |   INDEX RANGE SCAN          | BIG_I     |     2 |       |     3   (0)| 00:00:01 |
-----------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
   2 - access("COL_1" IS NULL AND "COL_2"='NEW COL 2')
       filter("COL_2"='NEW COL 2')
SQL> select pk_col from big_table
  2  where col_1 is null
  3  and col_2 is null
  4  /
Execution Plan
----------------------------------------------------------
Plan hash value: 3993303771
-------------------------------------------------------------------------------
| Id  | Operation         | Name      | Rows  | Bytes | Cost (%CPU)| Time     |
-------------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |           |     1 |    53 |   176   (1)| 00:00:03 |
|*  1 |  TABLE ACCESS FULL| BIG_TABLE |     1 |    53 |   176   (1)| 00:00:03 |
-------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
   1 - filter("COL_1" IS NULL AND "COL_2" IS NULL)
SQL>
이 예제는 오라클 11.1.0.6에서 실행됩니다.하지만 모든 버전에 해당된다고 확신합니다.
APC의 답변 외에도 NULL 값을 인덱스할 때 인덱스에 상수 식을 추가할 수 있습니다.
예:
SQL> select * from v$version where rownum = 1
  2  /
BANNER
----------------------------------------------------------------
Oracle Database 10g Enterprise Edition Release 10.2.0.4.0 - 64bi
1 rij is geselecteerd.
SQL> create table t (id,status,fill)
  2  as
  3   select level
  4        , nullif(ceil((level-1)/1000),0)
  5        , lpad('*',1000,'*')
  6     from dual
  7  connect by level <= 10000
  8  /
Tabel is aangemaakt.
SQL> select status
  2       , count(*)
  3    from t
  4   group by status
  5  /
    STATUS   COUNT(*)
---------- ----------
         1       1000
         2       1000
         3       1000
         4       1000
         5       1000
         6       1000
         7       1000
         8       1000
         9       1000
        10        999
                    1
11 rijen zijn geselecteerd.
SQL> create index i_status on t(status)
  2  /
Index is aangemaakt.
SQL> exec dbms_stats.gather_table_stats(user,'t',cascade=>true)
PL/SQL-procedure is geslaagd.
SQL> set autotrace traceonly
SQL> select *
  2    from t
  3   where status is null
  4  /
1 rij is geselecteerd.
Uitvoeringspan
----------------------------------------------------------
   0      SELECT STATEMENT Optimizer=ALL_ROWS (Cost=201 Card=1 Bytes=1007)
   1    0   TABLE ACCESS (FULL) OF 'T' (TABLE) (Cost=201 Card=1 Bytes=1007)
Statistics
----------------------------------------------------------
          1  recursive calls
          0  db block gets
        364  consistent gets
          0  physical reads
          0  redo size
       1265  bytes sent via SQL*Net to client
        242  bytes received via SQL*Net from client
          2  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
          1  rows processed
전체 테이블 스캔 및 364개의 일관된 gets에 유의하십시오.
SQL> set autotrace off
SQL> create index i_status2 on t(status,1)
  2  /
Index is aangemaakt.
SQL> set autotrace traceonly
SQL> select *
  2    from t
  3   where status is null
  4  /
1 rij is geselecteerd.
Uitvoeringspan
----------------------------------------------------------
   0      SELECT STATEMENT Optimizer=ALL_ROWS (Cost=1 Card=1 Bytes=1007)
   1    0   TABLE ACCESS (BY INDEX ROWID) OF 'T' (TABLE) (Cost=1 Card=1 Bytes=1007)
   2    1     INDEX (RANGE SCAN) OF 'I_STATUS2' (INDEX) (Cost=1 Card=1)
Statistics
----------------------------------------------------------
          1  recursive calls
          0  db block gets
          3  consistent gets
          1  physical reads
          0  redo size
       1265  bytes sent via SQL*Net to client
        242  bytes received via SQL*Net from client
          2  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
          1  rows processed
그리고 이제 인덱스를 사용하고 3개의 일관된 get만 가지고 있습니다.
안녕, 롭.
APC의 응답 외에도 NULLS는 비트맵 인덱스에서 인덱싱됩니다.
언급URL : https://stackoverflow.com/questions/1230786/when-does-oracle-index-null-column-values
'programing' 카테고리의 다른 글
| Tomcat에 배포된 스프링 부트는 404개를 제공하지만 독립 실행형으로 작동합니다. (0) | 2023.07.21 | 
|---|---|
| @Spring Boot 2.6.0에서 실패한 테스트에서 자동 구성 사용(=... 제외) (0) | 2023.07.21 | 
| mvn spring-boot에서 시작한 프로그램에 JVM 옵션을 추가하는 방법:run (0) | 2023.07.21 | 
| 열에서 대문자 단어를 찾는 SQL (0) | 2023.07.21 | 
| SpringBoot WebClient를 사용할 때 요청을 가로채기 (0) | 2023.07.21 |