programing

오라클 인덱스 열 값이 null인 경우는 언제입니까?

starjava 2023. 7. 21. 20:26
반응형

오라클 인덱스 열 값이 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

반응형