The transaction log for database 'xxxx' is full due to 'ACTIVE_TRANSACTION'


今天查看Job的History,發現Job 運行失敗,錯誤信息是:“The transaction log for database 'xxxx' is full due to 'ACTIVE_TRANSACTION'.”

錯誤消息表明:數據庫的事務日志文件空間耗盡,log 文件不能再存儲新的transaction log。

SQL Server將事務日志文件在邏輯上划分為多個VLF(Virtual Log Files),將這些VLF組成一個的環形結構,以VLF為重用單元。如果一個VLF 中存在Active Transaction,那么該VLF就不能被截斷和重用。如果事務日志文件沒有可用的VLF,那么SQL Server就不能處理新增的事務,並拋出事務日志文件耗盡的錯誤消息。

那為什么Active Transaction 會導致事務日志文件耗盡?

1,如果數據庫的事務日志文件太大,將整個Disk Space耗盡,那么就要考慮是什么原因造成事務日志文件大量增長,定期做事務日志備份能夠截斷事務日志文件。

2,如果數據庫的事務日志文件本身不是很大,可能的原因是SQL Server 無法為事務日志文件分配Disk Space。

3,查看數據庫中活動的事務,如果是由於一個事務運行時間太長,沒有關閉,導致事務日志的VLF不能重用,那么必須修改應用程序。

如果數據庫中某一個 Transaction 運行的時間太長,導致其他transaction雖然被commint,但是其占用的VLF仍然被標記為Active,不能被truncate和reuse,當log文件中沒有可用的VLF,而SQL Server又要處理新增的Transaction時,SQL Server就會報錯。

step1,查看事務日志文件的大小

查看日志文件的 size_gb 和 max_size_gb 字段,發現該事務日志文件的大小沒有達到最大值,並且事務日志文件占用的Disk Space並不是很大,我猜想,很可能是日志文件所在的Disk Space 被使用殆盡,沒有剩余的free space。

select db.name as database_name,
    db.is_auto_shrink_on,
    db.recovery_model_desc,
    mf.file_id,
    mf.type_desc,
    mf.name as logic_file_name,
    mf.size*8/1024/1024 as size_gb,
    mf.physical_name,
    iif(mf.max_size=-1,-1,mf.max_size*8/1024/1024) as max_size_gb,
    mf.growth,
    mf.is_percent_growth,
    mf.state_desc
from sys.databases db 
inner join sys.master_files mf 
    on db.database_id=mf.database_id
where mf.size*8/1024/1024>1  -- GB
    and db.name='database name'
    and mf.type=0
order by size_gb desc

step2,查看Disk的Free Space

查詢結果顯示,D盤空間僅僅剩下9MB,正是事務日志文件所在的Disk。

exec sys.xp_fixeddrives

step3,Disk Space 用盡,必須想辦法將大的數據文件壓縮,或者將事務日志文件截斷。

由於數據庫的恢復模式是simple,會自動截斷事務日志文件,因此,最大的可能是disk space耗盡。

1,查看數據庫空間的使用情況

exec sys.sp_spaceused

unallocated space 空閑很大,必須壓縮數據庫,以釋放disk space

2,收縮(shrink)數據庫文件

use target_database_name
go

select file_id,
    type,
    type_desc,
    data_space_id,
    name,
    size*8/1024/1024 as size_gb,
    growth,
    is_percent_growth,
    physical_name,
    max_size
from sys.database_files

dbcc shrinkfile('file logcial name',0,notruncate)
dbcc shrinkfile('file logcial name',target_size_mb,truncateonly)

3,對數據庫中的 table 和 index 壓縮存儲
3.1, 查看數據庫中,占用存儲空間非常大的table;

use target_database_name
go

select 
    t.name,
    sum(case when ps.index_id<2 then ps.row_count else 0 end) as row_count,
    sum(ps.reserved_page_count)*8/1024/1024 as reserved_gb,
    sum(ps.used_page_count)*8/1024/1024 as used_gb,
    sum( case when ps.index_id<2
                    then ps.in_row_data_page_count+ps.lob_used_page_count+ps.row_overflow_used_page_count
              else 0 end
        )*8/1024/1024 as data_used_gb,
    sum(case when ps.index_id>=2 
                then ps.in_row_data_page_count+ps.lob_used_page_count+ps.row_overflow_used_page_count
             else 0 end
        )*8/1024/1024 as index_used_gb
from sys.dm_db_partition_stats ps
inner join sys.tables t
    on ps.object_id=t.object_id
group by t.object_id, t.name
order by used_gb desc

3.2, 查看table及其Index是否被壓縮過

select p.partition_id,object_name(p.object_id) as ObjectName,
    p.index_id,
    p.rows,
    p.data_compression,
    p.data_compression_desc,
    au.Type,
    au.Type_desc,
    au.total_pages,
    au.used_pages,
    au.data_pages
from sys.partitions p
inner join sys.allocation_units au
    on p.partition_id=au.container_id 
where p.object_id=object_id('[dbo].[table_name]',N'U')

3.3,估計壓縮能夠節省的存儲空間

exec sys.sp_estimate_data_compression_savings 
                @schema_name='dbo',
                @object_name='table_name',
                @index_id=1,
                @partition_number=null,
                @data_compression ='page'

3.4, 對table及其index進行數據壓縮
對table 及其index 進行 rebuild,SQL Server將重新分配存儲空間,慎重:rebuild 反而會增加數據庫占用的存儲空間。在數據壓縮存儲之后,必須shrink 數據庫文件,才能釋放數據庫所占用的存儲空間,增加Disk的Free Space。

alter table [dbo].table_name
rebuild with(data_compression=page)

alter index index_name
on [dbo].table_name
rebuild with(data_compression=page)

4,增加事務日志文件

參考:《The transaction log for database 'tempdb' is full due to 'ACTIVE_TRANSACTION'

 

Appendix:《Log Reuse Waits Explained: ACTIVE_TRANSACTION

SQL Server will return a log_reuse_wait_desc value of ACTIVE_ TRANSACTION if it runs out of virtual log files because of an open transaction. Open transactions prevent virtual log file reuse, because the information in the log records for that transaction might be required to execute a rollback operation.

To prevent this log reuse wait type, make sure you design you transactions to be as short lived as possible and never require end user interaction while a transaction is open.

To resolve this wait, you have to commit or rollback all transactions. The safest strategy is to just wait until the transactions finish themselves. Well-designed transactions are usually short lived, but there are many reasons that can turn a normal transaction into a log running one. If you cannot afford to wait for an extra-long running transaction to finish, you might have to kill its session. However, that will cause that transaction to be rolled back. Keep this in mind when designing your application and try to keep all transactions as short as possible.

One common design mistake that can lead to very long running transactions is to require user interaction while the transaction is open. If the person that started the transaction went to lunch while the system is waiting for a response, this transaction can turn into a very-long-running transaction. During this time other transactions, if they are not blocked by this one, will eventually fill up the log and cause the log file to grow.


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM