【DB筆試面試449】如何監控數據庫的登陸登出、DDL語句等內容?
- 2019 年 10 月 11 日
- 筆記
如何監控數據庫的登陸登出、DDL語句等內容?
答案部分
系統中一些常用的監控都可以使用DDL觸發器和系統觸發器來實現。可以先創建一張記錄DDL語句的表XB_AUDIT_DDL_LHR(由於該表記錄數會很大,所以,需創建成按月自動分區的分區表),並創建合適的索引,然後創建存儲過程用於插入DDL信息到該日誌表中。最後再創建系統觸發器就可以將DDL語句或系統事件的信息插入日誌表中。下面詳細說明DDL觸發器和系統觸發器的使用。
首先創建一張記錄DDL語句的表XB_AUDIT_DDL_LHR,由於該表記錄數很大,所以,創建成按月自動分區的分區表,代碼如下所示:
CREATE TABLE XB_AUDIT_DDL_LHR( ID NUMBER PRIMARY KEY, INST_ID NUMBER, OPER_DATE DATE, OPERATION VARCHAR2(30), OBJECT_OWNER VARCHAR2(255), OBJECT_TYPE VARCHAR2(30), OBJECT_NAME VARCHAR2(30), SQL_TEXT VARCHAR2(4000), SQL_FULLTEXT CLOB, OS_USER VARCHAR2(255), CLIENT_IP VARCHAR2(20), CLIENT_HOSTNAME VARCHAR2(30), DB_SCHEMA VARCHAR2(30), SID NUMBER, SERIAL# NUMBER, SPID NUMBER, SESSION_TYPE VARCHAR2(1000), DATABASE_NAME VARCHAR2(255), ERRORS_INFOR VARCHAR2(4000), SQL_ID VARCHAR2(13), PREV_SQL_ID VARCHAR2(13) ) NOLOGGING PARTITION BY RANGE(OPER_DATE) INTERVAL(NUMTOYMINTERVAL(1,'MONTH')) SUBPARTITION BY HASH(OPERATION) SUBPARTITION TEMPLATE ( SUBPARTITION SP1 , SUBPARTITION SP2 , SUBPARTITION SP3) (PARTITION P201610 VALUES LESS THAN(TO_DATE('201610','YYYYMM'))); ------創建主鍵列的用到的序列及其它常用列的索引 CREATE SEQUENCE S_XB_AUDIT_DDL_LHR START WITH 1 INCREMENT BY 1 CACHE 2000; SELECT S_XB_AUDIT_DDL_LHR.NEXTVAL FROM DUAL; CREATE INDEX IND_AUDIT_DDL_OBJECT_NAME ON XB_AUDIT_DDL_LHR(OBJECT_NAME,OPERATION) LOCAL NOLOGGING ; CREATE INDEX IND_AUDIT_DDL_OS_USER ON XB_AUDIT_DDL_LHR(OS_USER) LOCAL NOLOGGING; CREATE INDEX IND_AUDIT_DDL_SID ON XB_AUDIT_DDL_LHR(SID,SERIAL#) LOCAL NOLOGGING; CREATE INDEX IND_AUDIT_DDL_OBJECT_DATE ON XB_AUDIT_DDL_LHR(OPER_DATE,OPERATION,OS_USER) LOCAL NOLOGGING ; GRANT SELECT ON XB_AUDIT_DDL_LHR TO PUBLIC; 創建存儲過程,用於插入DDL信息到日誌表中,如下所示: CREATE OR REPLACE PROCEDURE PRO_TRI_DDL_INSET_LHR(P_SQL_FULLTEXT VARCHAR2) AUTHID CURRENT_USER AS SP_XB_AUDIT_DDL_LHR XB_AUDIT_DDL_LHR%ROWTYPE; V_TMP VARCHAR2(255); BEGIN SELECT A.SID, A.SERIAL#, (SELECT B.SPID FROM GV$PROCESS B WHERE B.ADDR = A.PADDR AND B.INST_ID = USERENV('INSTANCE')) SPID, UPPER(A.OSUSER) OSUSER, A.MACHINE || '--' || A.PROGRAM || '--' || A.MODULE || '--' || A.ACTION SESSION_TYPE, SUBSTR(P_SQL_FULLTEXT, 1, 3900), A.SQL_ID, A.PREV_SQL_ID, A.USERNAME, A.INST_ID INTO SP_XB_AUDIT_DDL_LHR.SID, SP_XB_AUDIT_DDL_LHR.SERIAL#, SP_XB_AUDIT_DDL_LHR.SPID, SP_XB_AUDIT_DDL_LHR.OS_USER, SP_XB_AUDIT_DDL_LHR.SESSION_TYPE, SP_XB_AUDIT_DDL_LHR.SQL_TEXT, SP_XB_AUDIT_DDL_LHR.SQL_ID, SP_XB_AUDIT_DDL_LHR.PREV_SQL_ID, SP_XB_AUDIT_DDL_LHR.DB_SCHEMA, SP_XB_AUDIT_DDL_LHR.INST_ID FROM GV$SESSION A WHERE A.AUDSID = USERENV('SESSIONID') AND A.INST_ID = USERENV('INSTANCE'); INSERT INTO XB_AUDIT_DDL_LHR (ID, INST_ID, OPER_DATE, OPERATION, OBJECT_TYPE, OBJECT_NAME, SQL_TEXT, SQL_FULLTEXT, OS_USER, CLIENT_IP, CLIENT_HOSTNAME, DB_SCHEMA, SID, SERIAL#, SPID, SESSION_TYPE, DATABASE_NAME, OBJECT_OWNER, ERRORS_INFOR, SQL_ID, PREV_SQL_ID) VALUES (S_XB_AUDIT_DDL_LHR.NEXTVAL, USERENV('INSTANCE'), -- sp_xb_audit_ddl_lhr.INST_ID ora_instance_num SYSDATE, ORA_SYSEVENT, --sys.sysevent ORA_DICT_OBJ_TYPE, ORA_DICT_OBJ_NAME, SP_XB_AUDIT_DDL_LHR.SQL_TEXT, P_SQL_FULLTEXT, UPPER(SYS_CONTEXT('USERENV', 'OS_USER')), -- sp_xb_audit_ddl_lhr.os_user SYS_CONTEXT('userenv', 'ip_address'), --ora_client_ip_address SYS_CONTEXT('userenv', 'terminal'), --sys_context('userenv', 'host') NVL2(ORA_LOGIN_USER, SYS_CONTEXT('USERENV', 'SESSION_USER'), SP_XB_AUDIT_DDL_LHR.DB_SCHEMA), -- SYS_CONTEXT('USERENV', 'SESSION_USER') sys.login_user SP_XB_AUDIT_DDL_LHR.SID, ---- SYS_CONTEXT('USERENV', 'SID'), SP_XB_AUDIT_DDL_LHR.SERIAL#, SP_XB_AUDIT_DDL_LHR.SPID, SP_XB_AUDIT_DDL_LHR.SESSION_TYPE || V_TMP, ORA_DATABASE_NAME, --sys_context('USERENV', 'DB_NAME') ORA_DICT_OBJ_OWNER, DBMS_UTILITY.FORMAT_ERROR_STACK, SP_XB_AUDIT_DDL_LHR.SQL_ID, SP_XB_AUDIT_DDL_LHR.PREV_SQL_ID); COMMIT; EXCEPTION WHEN OTHERS THEN ROLLBACK; END PRO_TRI_DDL_INSET_LHR; 下面的觸發器將會話退出和數據庫關閉的信息加入日誌表XB_AUDIT_DDL_LHR中: CREATE OR REPLACE TRIGGER TRI_AUDIT_LOGOFF_LHR BEFORE LOGOFF OR SHUTDOWN ON DATABASE --database 、 SCHEMA --退出、數據庫關閉 DECLARE PRAGMA AUTONOMOUS_TRANSACTION; BEGIN -- 調用存過 PRO_TRI_DDL_INSET_LHR(''); EXCEPTION WHEN OTHERS THEN ROLLBACK; END; 此時若有會話退出的話,查詢日誌表XB_AUDIT_DDL_LHR可以看到如下的信息: 下面再創建登錄和DDL觸發器,腳本如下所示: CREATE OR REPLACE TRIGGER TRI_AUDIT_DDL_LHR -- AFTER DDL OR servererror OR logon OR STARTUP ON DATABASE --database 、 SCHEMA --ddl語句、服務器報錯、用戶登陸、用戶退出、數據庫啟動、數據庫關閉 AFTER DDL OR SERVERERROR OR LOGON OR STARTUP ON DATABASE /* WHEN (ora_dict_obj_name NOT IN ('XB_AUDIT_DDL_LHR', 'PRO_TRI_DDL_INSET_LHR') OR ora_dict_obj_name IS NULL)*/ DECLARE PRAGMA AUTONOMOUS_TRANSACTION; N NUMBER; V_SQL_FULLTEXT VARCHAR2(32767) := NULL; SQL_TEXT ORA_NAME_LIST_T; BEGIN IF ORA_SYSEVENT = 'LOGON' THEN ----------- 填充 v$session 的 CLIENT_INFO 和 CLIENT_IDENTIFIER 列 DBMS_APPLICATION_INFO.SET_CLIENT_INFO(SYS_CONTEXT('userenv', 'ip_address')); DBMS_SESSION.SET_IDENTIFIER(SYS_CONTEXT('userenv', 'HOST')); ELSE --得到執行的DDL語句 BEGIN N := ORA_SQL_TXT(SQL_TEXT); FOR I IN 1 .. N LOOP V_SQL_FULLTEXT := V_SQL_FULLTEXT || SQL_TEXT(I); END LOOP; EXCEPTION WHEN OTHERS THEN ROLLBACK; END; END IF; --插入日誌 PRO_TRI_DDL_INSET_LHR(V_SQL_FULLTEXT); EXCEPTION WHEN OTHERS THEN ROLLBACK; END TRI_AUDIT_DDL_LHR; 測試DDL觸發器,創建表、TRUNCATE表、刪除表,如下所示: CREATE TABLE TEST_DDL AS SELECT * FROM DUAL; TRUNCATE TABLE TEST_DDL; DROP TABLE TEST_DDL; SELECT * FROM XB_AUDIT_DDL_LHR T WHERE T.OBJECT_NAME='TEST_DDL'; 若有服務器的錯誤,也可以被記錄下來,如下所示: SELECT * FROM XB_AUDIT_DDL_LHR T WHERE T.OPERATION='SERVERERROR'; 本小節的監控內容也解決了前面提出的一個問題,「如何監控會話的登錄登出情況?」,可以通過查詢日誌表XB_AUDIT_DDL_LHR來解決,如下所示: SELECT T.OS_USER, T.CLIENT_IP, COUNT(1) FROM XB_AUDIT_DDL_LHR T GROUP BY T.OS_USER, T.CLIENT_IP;
About Me:小麥苗
● 本文作者:小麥苗,只專註於數據庫的技術,更注重技術的運用
● 作者博客地址:http://blog.itpub.net/26736162/abstract/1/
● 本系列題目來源於作者的學習筆記,部分整理自網絡,若有侵權或不當之處還請諒解
● 版權所有,歡迎分享本文,轉載請保留出處
● 題目解答若有不當之處,還望各位朋友批評指正,共同進步