프린트 하기

OS 환경 : Oracle Linux 8.7 (64bit)

 

DB 환경 : Oracle Database 19.27.0.0

 

방법 : 오라클 19c 테이블에 grant시 last_ddl_time이 변경될까?

본문에서는 grant 명령시 테이블의 last_ddl_time이 변경되는지를 확인해봄

 

 

테스트
시간 단위까지 정확히 보기 위해 세션 날짜 형식 변경

1
2
3
SQL> alter session set nls_date_format = 'yyyy-mm-dd hh24:mi:ss';
 
Session altered.

 

 

테스트용 테이블 및 데이터 생성

1
2
3
4
5
SQL> 
drop table test_grant_time purge;
create table test_grant_time (id number, val varchar2(10));
insert into test_grant_time values(1, 'AAA');
commit;

 

 

권한 부여 전 LAST_DDL_TIME 확인

1
2
3
4
5
6
7
8
9
10
SQL> 
set lines 200 pages 1000
col object_name for a20
select object_name, last_ddl_time 
from dba_objects 
where object_name = 'TEST_GRANT_TIME';
 
OBJECT_NAME          LAST_DDL_TIME
-------------------- -------------------
TEST_GRANT_TIME      2026-04-10 20:42:18

2026-04-10 20:42:18임

 

 

샘플 sql 수행

1
2
3
4
5
6
7
SQL> 
select id, val from test_grant_time
where id = 1;
 
        ID VAL
---------- ----------
         1 AAA

 

 

해당 sql의 invalidations 확인(무효화 되었는지 여부)

1
2
3
4
5
6
7
8
SQL>
select sql_id, LOADED_VERSIONS, LOADS, INVALIDATIONS, substr(sql_text,1,30) sql_text from v$sql
where sql_text like '%select id, val from test_grant_time%'
and sql_text not like '%sql_text%';
 
SQL_ID        LOADED_VERSIONS      LOADS INVALIDATIONS SQL_TEXT
------------- --------------- ---------- ------------- ------------------------------------------------------------
ccnvccvkd0rm0               1          1             0 select id, val from test_grant

 

 

몇초 ~ 몇분 대기 후 grant 권한 부여

1
2
3
SQL> grant select on test_grant_time to public;
 
Grant succeeded.

 

 

권한 부여 후 LAST_DDL_TIME 재확인

1
2
3
4
5
6
7
8
9
10
SQL> 
set lines 200 pages 1000
col object_name for a20
select object_name, last_ddl_time 
from dba_objects 
where object_name = 'TEST_GRANT_TIME';
 
OBJECT_NAME          LAST_DDL_TIME
-------------------- -------------------
TEST_GRANT_TIME      2026-04-10 20:47:19

last_ddl_time이 2026-04-10 20:47:19로 변경되었음

 

 

샘플 sql 재수행

1
2
3
4
5
6
7
SQL> 
select id, val from test_grant_time
where id = 1;
 
        ID VAL
---------- ----------
         1 AAA

 

 

해당 sql의 invalidations 재확인(무효화 되었는지 여부)

1
2
3
4
5
6
7
8
SQL> 
select sql_id, loaded_versions, loads, invalidations, substr(sql_text,1,30) sql_text from v$sql
where sql_text like '%select id, val from test_grant_time%'
and sql_text not like '%sql_text%';
 
SQL_ID        LOADED_VERSIONS      LOADS INVALIDATIONS SQL_TEXT
------------- --------------- ---------- ------------- ------------------------------------------------------------
ccnvccvkd0rm0               1          2             1 select id, val from test_grant

last_ddl_time이 변경됨에 따라 sql이 무효화(invalidations) 되었고 새로 로드됨

 

 

상세 분석
grant시 10046 트레이스를 수행해 확인해보니 내부적으로 obj$를 업데이트하는 부분이 확인됨

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
PARSING IN CURSOR #139937448094744 len=409 dep=1 uid=0 oct=6 lid=0 tim=164939067877 hv=696165170 ad='634d3b98' sqlid='c3utnxsnrx8tk'
update obj$ set obj#=:4, type#=:5,ctime=:6,mtime=:7,stime=:8,status=:9,dataobj#=:10,flags=:11,oid$=:12,spare1=:13,spare2=:14,spare3=:15,signature=:16,spare7=:17,spare8=:18,spare9=:19, dflcollid=decode(:20,0,null,:20),creappid=:21,creverid=:22, modappid=:23,modverid=:24,crepatchid=:25,modpatchid=:26 where owner#=:1 and name=:2 and namespace=:3 and remoteowner is null and linkname is null and subname is null
END OF STMT
PARSE #139937448094744:c=320,e=320,p=0,cr=0,cu=0,mis=1,r=0,dep=1,og=4,plh=0,tim=164939067876
BINDS #139937448094744:
 
 Bind#0
  oacdty=02 mxl=22(22) mxlc=00 mal=00 scl=00 pre=00
  oacflg=00 fl2=1000001 frm=00 csi=00 siz=48 off=0
  kxsbbbfp=7f45b9d1f588  bln=22  avl=04  flg=05
  value=44808
 Bind#1
  oacdty=02 mxl=22(22) mxlc=00 mal=00 scl=00 pre=00
  oacflg=00 fl2=1000001 frm=00 csi=00 siz=0 off=24
  kxsbbbfp=7f45b9d1f5a0  bln=22  avl=02  flg=01
  value=2
...
 Bind#25
  oacdty=01 mxl=32(15) mxlc=00 mal=00 scl=00 pre=00
  oacflg=10 fl2=0001 frm=01 csi=846 siz=32 off=0
  kxsbbbfp=811cf356  bln=32  avl=15  flg=09
  value="TEST_GRANT_TIME"
 Bind#26
  oacdty=02 mxl=22(22) mxlc=00 mal=00 scl=00 pre=00
  oacflg=00 fl2=1000001 frm=00 csi=00 siz=24 off=0
  kxsbbbfp=7f45b9d1f400  bln=22  avl=02  flg=05
  value=1
EXEC #139937448094744:c=1228,e=2020,p=0,cr=2,cu=1,mis=1,r=1,dep=1,og=4,plh=2683643009,tim=164939069983
STAT #139937448094744 id=1 cnt=0 pid=0 pos=1 obj=18 op='UPDATE  OBJ$ (cr=2 pr=0 pw=0 str=1 time=79 us)'
STAT #139937448094744 id=2 cnt=1 pid=1 pos=1 obj=37 op='INDEX RANGE SCAN I_OBJ2 (cr=2 pr=0 pw=0 str=1 time=15 us cost=2 size=109 card=1)'
CLOSE #139937448094744:c=0,e=0,dep=1,type=3,tim=164939070052
EXEC #139937448121440:c=26003,e=40518,p=0,cr=81,cu=11,mis=0,r=0,dep=0,og=1,plh=0,tim=164939070179
WAIT #139937448121440: nam='log file sync' ela= 470 buffer#=474 sync scn=14005678 p3=0 obj#=-1 tim=164939070695
WAIT #139937448121440: nam='SQL*Net message to client' ela= 1 driver id=1650815232 #bytes=1 p3=0 obj#=-1 tim=164939070725
WAIT #139937448121440: nam='SQL*Net message from client' ela= 341 driver id=1650815232 #bytes=1 p3=0 obj#=-1 tim=164939071077
CLOSE #139937448121440:c=2,e=2,dep=0,type=0,tim=164939071109

바인드 변수를 확인해보니 TEST_GRANT_TIME 테이블 오브젝트값을 업데이트 하는것이었음
이부분에서 mtime이 업데이트 되는데 이게 last_ddl_time이라고 함

 

 

실제 sys유저로 접속하여 아래와 같이 수정해보면 last_ddl_time이 변경되는것을 확인할 수 있음
*obj$를 수정하는것을 위험하기 때문에 테스트 환경에서만 테스트해보고 꼭 rollback 하는게 좋음

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
var b1 number;
var b2 varchar2(128);
var b3 number;
var b4 number;
var b5 number;
var b6 varchar2(30);
var b7 varchar2(30);
var b8 varchar2(30);
var b9 number;
var b10 number;
var b11 number;
var b12 varchar2(128);
var b13 number;
var b14 number;
var b15 number;
var b16 varchar2(128);
var b17 number;
var b18 number;
var b19 number;
var b20 number;
var b21 number;
var b22 number;
var b23 number;
var b24 number;
var b25 number;
var b26 number;
 
exec :b1  := 85;
exec :b2  := 'TEST_GRANT_TIME';
exec :b3  := 1;
exec :b4  := 44808;
exec :b5  := 2;
exec :b6  := '4/11/2026 14:27:20';
exec :b7  := '4/30/2026 14:28:5';  <<<---- b7(mtime)을 4월30일로 지정
exec :b8  := '4/11/2026 14:27:20';
exec :b9  := 1;
exec :b10 := 44808;
exec :b11 := 0;
exec :b12 := null;
exec :b13 := 6;
exec :b14 := 1;
exec :b15 := 85;
exec :b16 := '87FB8B715FCD39F9E5751815B217F1';
exec :b17 := 0;
exec :b18 := 0;
exec :b19 := 0;
exec :b20 := 16382;
exec :b21 := null;
exec :b22 := null;
exec :b23 := null;
exec :b24 := null;
exec :b25 := null;
exec :b26 := null;
 
update obj$ 
set obj#=:b4, 
    type#=:b5,
    ctime=TO_DATE(:b6, 'MM/DD/YYYY HH24:MI:SS'),
    mtime=TO_DATE(:b7, 'MM/DD/YYYY HH24:MI:SS'),
    stime=TO_DATE(:b8, 'MM/DD/YYYY HH24:MI:SS'),
    status=:b9,
    dataobj#=:b10,
    flags=:b11,
    oid$=:b12,
    spare1=:b13,
    spare2=:b14,
    spare3=:b15,
    signature=:b16,
    spare7=:b17,
    spare8=:b18,
    spare9=:b19, 
    dflcollid=decode(:b20, 0, null, :b20),
    creappid=:b21,
    creverid=:b22, 
    modappid=:b23,
    modverid=:b24,
    crepatchid=:b25,
    modpatchid=:b26
where owner#=:b1 
  and name=:b2 
  and namespace=:b3 
  and remoteowner is null 
  and linkname is null 
  and subname is null;
 
1 row updated.
 
set lines 200 pages 1000
col object_name for a20
select object_name, to_char(last_ddl_time, 'yyyy/mm/dd hh24:mi:ss') last_ddl_time
from dba_objects 
where object_name = 'TEST_GRANT_TIME';
 
OBJECT_NAME          LAST_DDL_TIME
-------------------- -------------------
TEST_GRANT_TIME      2026/04/30 14:28:05  <<<---- 4월 30일로 변경됨
 
rollback;

 

 

결론 :
DDL이 아닌 DCL인 grant 명령으로도 테이블의 last_ddl_time이 변경됨(내부적으로 obj$를 업데이트 하는 구문이 수행됨)
이로 인해 해당 테이블을 조회하는 sql들도 무효화 되었고, 이로 인해 플랜이 변경될 가능성도 충분히 존재함

 

 

 

참조 : https://docs.oracle.com/en/database/oracle/oracle-database/19/refrn/ALL_OBJECTS.html#
https://docs.oracle.com/en/database/oracle/oracle-database/19/refrn/ALL_TABLES.html
https://docs.oracle.com/en/database/oracle/oracle-database/19/refrn/V-SQL.html