1. 程式人生 > >(轉)SQLServer查詢數據庫各種歷史記錄

(轉)SQLServer查詢數據庫各種歷史記錄

power count 沒有 列表 scrip 分享 lose try 計劃

原文地址https://www.cnblogs.com/seusoftware/p/4826958.html

在SQL Server數據庫中,從登陸開始,然後做了什麽操作,以及數據庫裏發生了什麽,大多都是有記錄可循的,但是也有一些確實無從查起。

. 數據庫啟動記錄

1. 最近一次啟動SQL Server的時間

技術分享圖片
select sqlserver_start_time from sys.dm_os_sys_info;

--也可參考系統進程創建的時間,比服務啟動時間略晚(秒級)
select login_time from sysprocesses where spid = 1 
select login_time from sys.dm_exec_sessions where session_id = 1

--也可參考tempdb數據庫創建的時間,比服務啟動時間略晚(秒級)
select create_date from sys.databases 
where database_id=2
技術分享圖片

2. 最近幾次啟動SQL Server的時間

技術分享圖片
--參考error log,系統默認保留6個歸檔,共7個文件
exec xp_readerrorlog 0,1, NSQL Server is startingexec xp_readerrorlog 1,1, NSQL Server is startingexec xp_readerrorlog 2,1, NSQL Server is startingexec xp_readerrorlog 3,1, NSQL Server is startingexec xp_readerrorlog 4,1, NSQL Server is startingexec xp_readerrorlog 5,1, NSQL Server is startingexec xp_readerrorlog 6,1, NSQL Server is starting--之前關鍵字用N‘Server process ID is‘並不嚴謹,改為N‘SQL Server is starting‘
技術分享圖片

3. 歷史上更多次啟動SQL Server的時間

查看windows event log,SQL語句無法直接讀取event log,如果想用命令行,可以試試VBS,Powershell。

Event Viewer/Windows logs下Application 或者 System 事件裏都有服務啟動的記錄。

二. 登錄數據庫記錄

1. 查看error log

默認情況下,只有失敗的登錄會被記錄在error log裏,如果想登錄失敗/成功都被記錄到error log,需要開啟如圖選項:

技術分享圖片

用SQL語句修改註冊表,也同樣可以開啟,鍵值對應關系如下:

0, None

1, Failed

2, Successful

3, Both failed and successful

USE [master]
GO
EXEC xp_instance_regwrite NHKEY_LOCAL_MACHINE‘, NSoftware\Microsoft\MSSQLServer\MSSQLServer‘, NAuditLevel‘, REG_DWORD, 3
GO

在error log裏查看登錄記錄:

exec xp_readerrorlog 0,1, NLogin‘, Nfor user‘, null, null, NDESC

2. 利用LOGON 觸發器進行記錄

從SQL Server 2005 SP2開始引入了LOGON Trigger,可以用它在登錄時做個記錄,實現如下:

技術分享圖片
--創建LOGON觸發器
CREATE database DBA
GO

USE DBA
GO

IF OBJECT_ID(login_history‘,U‘) is not null
    DROP TABLE login_history
GO

CREATE TABLE login_history
(
FACT_ID         bigint IDENTITY(1,1) primary key,
LOGIN_NAME      nvarchar(1024),
LOGIN_TIME      datetime
)
GO

IF EXISTS(select 1 from sys.server_triggers where name = login_history_trigger)
    DROP TRIGGER login_history_trigger ON ALL SERVER
GO

CREATE TRIGGER login_history_trigger
ON ALL SERVER
FOR LOGON
AS
BEGIN
    --IF SUSER_NAME() NOT LIKE ‘NT AUTHORITY\%‘ AND 
    --   SUSER_NAME() NOT LIKE ‘NT SERVICE\%‘
    IF ORIGINAL_LOGIN() NOT LIKE NT AUTHORITY\%AND
       ORIGINAL_LOGIN() NOT LIKE NT SERVICE\%BEGIN
        INSERT INTO DBA..login_history
        VALUES(ORIGINAL_LOGIN(),GETDATE());
    END;
END;
GO

--登錄後查看記錄
SELECT * FROM login_history
技術分享圖片

3. 實例:查詢某login的最後一次登錄

系統表/試圖裏,並沒有這樣的字段記錄,syslogins裏accdate也是不對的,如果要查可以通過上面2個方法裏的一種:

(1) ERROR LOG,得設置記錄Login Auditing 的“Both failed and successful” 選項,默認為”Failed”;

(2) Logon Trigger;

. 創建,修改,刪除記錄 (DDL)

1. 服務器對象的創建,修改

技術分享圖片
--創建數據庫
select name, create_date from sys.databases

--創建,修改登錄
select name, createdate, updatedate from syslogins
select name, create_date, modify_date from sys.server_principals 

--創建,修改LOGON觸發器
select name, create_date, modify_date from sys.server_triggers 
技術分享圖片

2. 數據庫對象創建,修改

--創建,修改數據庫對象
select name, create_date, modify_date from sys.objects 

--創建,修改觸發器,DDL觸發器不在sys.objects裏
select name, create_date, modify_date from sys.triggers 

註意:

(1) 索引的創建,修改並沒有記錄

技術分享圖片
sys.objects --裏面沒有0,1 之外的索引
sys.indexes --裏面沒有日期
objectproperty() --沒有日期屬性
indexproperty()  --沒有日期屬性

sys.dm_db_index_operational_stats 
sys.dm_db_index_usage_stats
sys.dm_db_index_physical_stats --也都沒有

STATS_DATE (table_id, index_id) --是索引的統計信息最後更新時間
技術分享圖片

(2) 關於creator和owner

SQL Server裏只有owner,數據庫裏對象的owner必須是一個有效的database principal (user或者role),沒有creator,很難知道是誰創建了這個對象,因為owner並不準確:

首先,數據庫對象的owner可以被修改,ALTER AUTHORIZATION或者sp_changeobjectowner都行;

其次,就算owner沒被修改過,默認情況下數據庫對象的owner沿用schema的owner,除非在創建schema時特意指定了某個owner;

最後,系統表並沒有記錄creator,如果想要查詢,也許得利用DDL 觸發器來記錄。

關於owner簡單舉例如下:

技術分享圖片 object owner

3. 默認跟蹤裏的創建,修改,刪除對象 (create, alter, drop)

從sql server 2005開始引入了默認跟蹤,這是sql server默認開啟的跟蹤,並定義了事件、文件大小,個數,查看定義如下:

技術分享圖片
--系統定義好的默認跟蹤事件
select t.eventid, te.name
from (select distinct eventid from sys.fn_trace_geteventinfo(1)) t
inner join sys.trace_events te
on t.eventid = te.trace_event_id

--最多5個文件,每個文件20MB,依次滾動覆蓋
select * from sys.traces
where id = 1
技術分享圖片

示例,利用默認跟蹤查看刪除數據庫記錄如下:

技術分享圖片
DECLARE @path varchar(1024)

SELECT @path = path
FROM sys.traces
WHERE id = 1

SELECT *
FROM fn_trace_gettable(@path, default) --default讀取當前所有trace文件,包括正在用的
WHERE DatabaseName = DBAand EventClass = 47    --46表示Create對象,47表示Drop對象,164表示修改對象
and ObjectType = 16964 --16964表示數據庫
技術分享圖片

註意:

(1) 其他對象比如表的刪除等也都可以查到;

(2) 默認跟蹤返回的列值有很多定義,沒有系統表記載,需要去翻幫助,比如ObjectType列值參考這個列表:

https://msdn.microsoft.com/en-us/library/ms180953.aspx

(3) 註意默認跟蹤的時效性,5個20MB的文件,也許想要看的信息很快就被覆蓋了;

(4) truncate table並沒有被默認跟蹤記錄。

. 數據庫表的各種記錄

匯總一下對表的各種歷史操作記錄的查看:

(1) create table, alter table記錄,查看sys.objects 或者默認跟蹤;

(2) drop table記錄,查看默認跟蹤;

(3) truncate table 也許只有去打開數據庫log文件查看了,最後會簡單介紹下;

(4) DML操作表中數據的記錄,查看sys.dm_db_index_usage_stats,如下:

技術分享圖片
SELECT o.name as table_name, 
       s.last_user_seek,
       s.last_user_scan,
       s.last_user_lookup,
       s.last_user_update
from sys.indexes i 
left join sys.dm_db_index_usage_stats s 
on s.object_id = i.object_id and 
   s.index_id = i.index_id 
inner join sys.objects o
on i.object_id = o.object_id
where i.index_id <= 1
and o.is_ms_shipped = 0
order by o.name
技術分享圖片

註意:動態管理視圖(DMV) 中采集來的信息都是從sql server啟動後開始的,也就是說重啟後就沒了。

. 歷史SQL語句記錄

有些數據庫本身,會記錄所有歷史的SQL命令。比如:mysql和pgsql都有專門的log文本文件來存放所有歷史的SQL命令;

也有些數據庫在保存log文本的同時,還保留最近的N條SQL命令在數據庫裏,以方便查詢。

SQL Server並沒有這樣的實現,只有sys.dm_exec_query_stats緩存了一部分 (sql server服務開啟後執行的語句,某些不被緩存執行計劃的語句並不記錄)。

這個視圖主要是對執行計劃的統計,包含消耗成本,運行次數等等,並沒有session,user,每次被執行的時間等信息:

技術分享圖片
SELECT st.text as sql_statement,
       qs.creation_time as plan_last_compiled,
       qs.last_execution_time as plan_last_executed,
       qs.execution_count as plan_executed_count,
       qp.query_plan
FROM sys.dm_exec_query_stats qs
CROSS APPLY sys.dm_exec_sql_text(qs.plan_handle) st
CROSS APPLY sys.dm_exec_query_plan(qs.plan_handle) qp
order by total_elapsed_time/execution_count desc
技術分享圖片

當然,開啟跟蹤,審計之類的方法,是可以記錄所有操作的,但是這個開銷有可能會影響系統性能,所以一般並不在生產環境啟用。

. 數據庫備份還原歷史記錄

備份還原的記錄都在msdb裏。

1. 備份記錄

技術分享圖片
SELECT 
     bs.backup_set_id,
     bs.database_name,
     bs.backup_start_date,
     bs.backup_finish_date,
     CAST(CAST(bs.backup_size/1000000 AS INT) AS VARCHAR(14)) + + MBAS [Size],
     CAST(DATEDIFF(second, bs.backup_start_date,
     bs.backup_finish_date) AS VARCHAR(4)) + + Seconds[TimeTaken],
     CASE bs.[type]
         WHEN DTHEN Full BackupWHEN ITHEN Differential BackupWHEN LTHEN TLog BackupWHEN FTHEN File or filegroupWHEN GTHEN Differential fileWHEN PTHEN PartialWHEN QTHEN Differential PartialEND AS BackupType,
     bmf.physical_device_name,
     CAST(bs.first_lsn AS VARCHAR(50)) AS first_lsn,
     CAST(bs.last_lsn AS VARCHAR(50)) AS last_lsn,
     bs.server_name,
     bs.recovery_model
 FROM msdb.dbo.backupset bs
 INNER JOIN msdb.dbo.backupmediafamily bmf 
 ON bs.media_set_id = bmf.media_set_id
 ORDER BY bs.server_name,bs.database_name,bs.backup_start_date;
GO
技術分享圖片

如果server_name是本機,那麽備份是在本機生成的;

如果server_name是別的主機名,那麽備份是被拿到本機做過數據庫還原;

2. 還原紀錄

技術分享圖片
SELECT 
     rs.[restore_history_id],
     rs.[restore_date],
     rs.[destination_database_name],
     bmf.physical_device_name,
     rs.[user_name],
     rs.[backup_set_id],
     CASE rs.[restore_type]
         WHEN DTHEN DatabaseWHEN ITHEN DifferentialWHEN LTHEN LogWHEN FTHEN FileWHEN GTHEN FilegroupWHEN VTHEN VerifyonlyEND AS RestoreType,
     rs.[replace],
     rs.[recovery],
     rs.[restart],
     rs.[stop_at],
     rs.[device_count],
     rs.[stop_at_mark_name],
     rs.[stop_before]
FROM [msdb].[dbo].[restorehistory] rs
INNER JOIN [msdb].[dbo].[backupset] bs
--on rs.backup_set_id = bs.media_set_id
ON rs.backup_set_id = bs.backup_set_id
INNER JOIN msdb.dbo.backupmediafamily bmf 
ON bs.media_set_id = bmf.media_set_id
GO
技術分享圖片

還原數據庫的時候是會寫backupset和backupmediafamily系統表的,用來記錄還原所用到的備份文件信息。

. 作業,維護計劃,數據庫郵件歷史記錄

作業,維護計劃,數據庫郵件的歷史記錄,也都在msdb裏。

1. 作業歷史記錄

技術分享圖片
if OBJECT_ID(tempdb..#tmp_job‘) is not null
    drop table #tmp_job

--只取最後一次結果
select job_id,
       run_status,
       CONVERT(varchar(20),run_date) run_date,
       CONVERT(varchar(20),run_time) run_time,
       CONVERT(varchar(20),run_duration) run_duration
  into #tmp_job
  from msdb.dbo.sysjobhistory jh1
 where jh1.step_id = 0
   and (select COUNT(1) from msdb.dbo.sysjobhistory jh2 
        where jh2.step_id = 0 
          and (jh1.job_id = jh2.job_id)
          and (jh1.instance_id <= jh2.instance_id))=1

--排除syspolicy_purge_history這個系統作業
select a.name job_name,
       case b.run_status when 0 then Failedwhen 1 then Succeededwhen 2 then Retrywhen 3 then Canceledelse Unknownend as job_status,
       LEFT(run_date,4)+-+SUBSTRING(run_date,5,2)+-+RIGHT(run_date,2)
       +SPACE(1)
       +LEFT(RIGHT(1000000+run_time,6),2)+:+SUBSTRING(RIGHT(1000000+run_time,6),3,2)+:+RIGHT(RIGHT(1000000+run_time,6),2) as job_started_time,
       +LEFT(RIGHT(1000000+run_duration,6),2)+:+SUBSTRING(RIGHT(1000000+run_duration,6),3,2)+:+RIGHT(RIGHT(1000000+run_duration,6),2) as job_duration
  from msdb.dbo.sysjobs a 
  left join    #tmp_job b 
    on a.job_id=b.job_id 
 where a.name not in (syspolicy_purge_history)
   and a.enabled = 1
 order by b.run_status asc,a.name,b.run_duration desc
技術分享圖片

2. 維護計劃歷史記錄

select * from msdb..sysdbmaintplan_history

--新的系統表也可以
select * from msdb..sysmaintplan_log
select * from msdb..sysmaintplan_logdetail

維護計劃最終是作為作業在運行的,也可以直接查看同名作業的歷史記錄。

3. 數據庫郵件歷史記錄

技術分享圖片
--直接查系統表
select * from msdb..sysmail_mailitems
select * from msdb..sysmail_log

--也可查看基於這2個系統表的系統視圖
select * from msdb..sysmail_allitems
select * from msdb..sysmail_sentitems
select * from msdb..sysmail_unsentitems
select * from msdb..sysmail_faileditems
select * from msdb..sysmail_event_log

--更多系統表和視圖
use msdb
GO
select * from sys.objects 
where name like %sysmail%and type in(U‘,V)
order by type,name
技術分享圖片

. 查看數據庫日誌文件

數據庫日誌文件裏對於DDL,DML操作肯定是有記錄的,有2個內置函數可以用來解析,但是並不那麽輕松,簡單介紹如下:

1. fn_dblog 讀取當前在線的日誌

select * from fn_dblog(null,null) --2個null代表起始的日誌LSN

返回的結果集中字段定義:

(1) AllocUnitName: 對象名

(2) Operation: 操作類型,常見的有 ‘LOP_INSERT_ROWS‘, ‘LOP_DELETE_ROWS‘, ‘LOP_MODIFY_ROW‘

(3) [RowLog Contents 0], [RowLog Contents 1], 2,3,4,5: 字段內容,但是是二進制的,和dbcc page看到的類似

試著查看truncate table記錄如下:

技術分享圖片
IF OBJECT_ID(test_truncate‘,U‘) is not null
    DROP TABLE test_truncate
GO

CREATE TABLE test_truncate(ID int)
INSERT INTO test_truncate values(1)
TRUNCATE TABLE test_truncate

--查看truncate table記錄
select * from fn_dblog(null,null)
where AllocUnitName like %test_truncate%and Description like Deallocated%
技術分享圖片

2. fn_dump_dblog 讀取數據庫備份裏的日誌

參數介紹:前面兩2個NULL和fn_dblog一樣代表起始的日誌LSN,DISK表示設備類型,1表示備份文件個數,最多64個,這裏以1個文件為例:

技術分享圖片
backup database DBA to disk = C:\backup\dba.bakSELECT *
FROM
    fn_dump_dblog (
        NULL, NULL, NDISK‘, 1, NC:\backup\dba.bak,
        DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT,
        DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT,
        DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT,
        DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT,
        DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT,
        DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT,
        DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT,
        DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT,
        DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT);
GO
技術分享圖片

這2個函數返回的信息量很大,如果有興趣,不妨多做點測試。

(轉)SQLServer查詢數據庫各種歷史記錄