亚洲免费在线-亚洲免费在线播放-亚洲免费在线观看-亚洲免费在线观看视频-亚洲免费在线看-亚洲免费在线视频

收縮SQL Server日志不是那么簡單

系統 2331 0

收縮SQL Server日志不是那么簡單的(翻譯)

?

原文地址: http://rusanu.com/2012/07/27/how-to-shrink-the-sql-server-log/

說明:本文為了更好的說明收縮的過程,在原文翻譯的基礎上增加了一些個人的理解,省略了部分內容,建議大家在閱讀本文時參考原文。

?

一、問題場景

我的數據庫日志文件已經增大到200G了,我也嘗試去收縮數據庫,但大小沒有改變,請問該如何減小日志文件的大小?這個問題實際上就是說執行 DBCC ? SHRINKFILE 沒有減小日志文件的大小,到底是什么原因導致的呢?

?

二、準備知識

?

1、LSN

LSN用來標識特定日志在日志文件中位置(詳情請見 什么是LSN:日志序列號 ),它由兩部分組成:一部分用來標識VLF(虛擬日志文件)的序列號,剩下的用來標識該日志在VLF中的具體的位置。

根據LSN不同,日志一般分為兩類:首日志(最新的活動日志序號)和尾日志(保留時間最長的活動日志序號)。隨著數據庫的操作不斷增加(如數據庫中的update操作),首日志LSN序號不斷變化。尾日志的序號只有在日志備份后才會變化。

收縮SQL Server日志不是那么簡單

(圖一)日志文件結構圖

?

2、VLF

?

你可以通過DCC LOGINFO去分析數據庫LDF中VLF(虛擬日志文件),LDF、VLF、日志的關系是:LDF包括多個VLF,每個VLF中包括多個日志記錄。在VLF中,當事物日志增加時,日志的頭部(首日志)不斷向前移動,日志將占用越來越多的剩余空間,當這個VLF被占滿后,新的日志寫入到其他未被使用的VLF中,這個時候LDF并不會增大。當LDF中沒有可用的VLF時,數據庫會創建一個新的VLF。從而使得LDF文件物理增大,占用更多的磁盤空間。

收縮SQL Server日志不是那么簡單

(圖二)日志增長

三、解決方法詳細闡述

1、日志的截斷

?

上圖演示了首日志向前移動的場景,結合圖一和圖二可以看到,當VLF2的空間被日志填滿后,數據庫擴充LDF文件(向操作系統申請更多的磁盤空間),并在擴充后的LDF中新建一個VLF3用來填充新的日志記錄。盡管VLF1中存在剩余空間,但因為VLF1中存在活動日志(哪怕只有一條),所以數據庫無法利用這個VLF的剩余空間,(詳細原因可以參考這篇文章 什么是LSN:日志序列號 )。

這個時候做日志備份就會發生日志截斷的現象。一般會將截斷理解為"刪除"一些日志記錄(非活動),實際上它只是意味著尾日志的向前移動:尾日志序號會被刷新成 最小的活動日志 序號,而從原來尾日志的位置到新位置之間的空間被標記為"可重新利用"。這個過程并不會減少LDF已占用的磁盤空間。如下圖,整個VLF1的和部分VLF2上的日志(非活動)被截斷了。

收縮SQL Server日志不是那么簡單

日志截斷示意圖(圖三)

隨著事務日志不斷增加,VLF3中日志頭部所在的位置將不斷向前移動,當VLF3的空間被占滿后,數據庫會重新利用VLF1的空間,這種寫入、截斷、再寫入的方式形成一個寫日志的循環。在此期間LDF并不會物理上增大。

收縮SQL Server日志不是那么簡單

日志循環使用示意圖(圖四)

2、為什么日志不能收縮

?

現在我們再來看一個日志無法收縮的場景:

圖四中,VLF1中的日志不斷增加,直到VLF1的所有空間都被填滿(如圖五),此時因為沒有發生截斷,尾日志都在VLF2上,且VLF2和VLF3都被標記為不可重新利用,數據庫只能擴充LDF、新建一個VLF4用來記錄新的日志,首日志的位置將出現在VLF4中,整個寫日志的(從圖一到圖四)順序為VLF2——>VLF3——>VLF1——>VLF4。這個過程會導致數據庫的日志文件在物理上增大。

收縮SQL Server日志不是那么簡單

日志增長示意圖(圖五)

這時我們再來截斷事物日志,如上文所說,尾日志的會被更新,最后可能出現尾日志和首日志在同一個VLF上的場景。從日志文件記錄的架構上來看,我們可以將這個過程簡單地理解為:截斷的順序會按照首日志移動的順序移動,從VLF2——>VLF3——>VLF1——>VLF4,最終尾日志和首日志出現在同一個VLF上。

收縮SQL Server日志不是那么簡單

日志截斷示意圖二(圖六)

?

如上圖,這個LDF文件包括3個空的和1個只有小部分活動日志的VLF文件,首日志和尾日志在同一個VLF中,這種情況下,試圖通過DBCC SHRINKFILE是不會減小LDF文件的大小的。

日志文件能被收縮的原因是該文件尾部的數據被清除了,使得該部分空間被釋放,而不是逃過尾部去刪除文件首部或者中間部分的內容。這點與MDF文件不同,MDF文件中的數據是不能被刪除的,只能將文件尾部的數據遷移到其他區域的剩余空間上,然后釋放尾部占用的空間。

在LDF中 ,日志是不能被遷移的,而且也沒有遷移的必要,因為當事物被提交后,日志變為不活動狀態,通過事物日志備份即可將其截斷(特殊情況下日志備份不一定能截斷,如發布訂閱的環境)。

綜上所述,日志文件能被收縮的前提是:日志文件的最后一個VLF必須是free狀態,從后向前推,只要是free狀態的VLF都會被收縮,據此可以估算一個日志文件可以釋放的空間大小。

如下我們看一個實際的例子:

USE ? DBname

DBCC ? loginfo

? 收縮SQL Server日志不是那么簡單

VLF 狀態示意圖(圖七)

?

從上圖可以看到,這個數據庫的日志文件共有13個VLF,其中有前12個處于free狀態,最后1個處于活動狀態,因此,我們可以推斷首日志和尾日志的位置都在這個VLF上。這個時候執行文件收縮將看不到文件減小的效果。

3、如何解決這個問題

那么碰到這種情況,該怎么去收縮日志呢:盡可能多的執行一些能夠產生大量日志的操作,這些日志將導致數據庫重新利用startoffset靠前的非活動狀態的VLF,將首日志的位置定位到這個startoffset,然后做一次事務日志備份,將尾日志也遷移到startoffset靠前的非活動狀態的VLF中,如下圖,最后再執行 DBCC ? SHRINKFILE 即可收縮日志文件。

?

收縮SQL Server日志不是那么簡單

日志截斷示意圖三(圖六)

四、重要說明

?

前文中一直在說通過日志備份即可解決日志截斷的問題,其實這只是最簡單的場景。在實際環境中可能有很多因素會影響日志的截斷,如:

  • 活動的事物日志

日志備份只能截斷非活動的日志,如果一個事物長時間運行,此時備份事物日志將不會引起截斷發生。

  • 事物日志分發

事物日志分發中,只有當日志讀取器代理已經讀取完待分發的日志后,日志才能變得非活動狀態。(之前我處理過一個類似問題,大家可以通過這個鏈接看看 http://www.cnblogs.com/i6first/p/3281437.html 。)

  • 數據庫鏡像和AlwaysOn

這兩種數據庫技術都需要將日志傳遞到接受端,在傳遞還沒有完成時,日志會一直保留,即使是備份日志也無法截斷。

.NET 使用CouchBase 基礎篇

?

?

2011年2月,CouchOne和memebase合并后,改名為Couchbase,官網地址(www.couchbase.com)。membase最后一個版本為1.7.2,可在Couchbase的官網下載( http://www.couchbase.com/downloads-all )。

這里不介紹couchbase的安裝,只介紹.NET Client Librarye 使用。

  1. 獲得CouchBase For Net的SDK有兩種方式
    1. 通過nuget,Install-Package CouchbaseNetClient
    2. 通過官網下載 http://www.couchbase.com/communities/net

    ?

  2. 開始CouchBase之旅
    1. 創建項目,這里需要提醒的是, 在vs2010中我們創建類Console應用程序時項目默認使用.NET Framework Client Profile,我們需要手動切換至full .NET Framework

      ?

    2. 在程序中配置CouchBase,CouchBase提供編碼配置和配置文件配置,當然使用app.config是最靈活的,這里是我們的首選,添加以下信息至你的配置文件,

    <?xml ? version = "1.0" ?>
    <configuration>
    ?? <configSections>
    ? ?? <section ? name = "couchbase" ? type = "Couchbase.Configuration.CouchbaseClientSection, Couchbase" />
    ?? </configSections>
    ?? <couchbase>
    ? ?? <servers ? bucket = "default" ? bucketPassword = "" >
    ? ? ?? <add ? uri = "http://192.168.0.2:8091/pools" />
    ? ? ?? <add ? uri = "http://192.168.0.3:8091/pools" />
    ? ?? </servers>
    ?? </couchbase>
    </configuration>

    這里使用了集群配置的url列表,當然在你本地調試只需要一個地址,默認CouchBase在安裝時會創建一個沒有密碼的default的緩存桶(bucket),你可以自由修改這塊的信息。(如果對bucket不太明白,請自行google)。

    ?

    1. 添加引用

using Couchbase;

using Couchbase.Configuration;

using Couchbase.Extensions;

using Enyim.Caching;

using Enyim.Caching.Configuration;

using Enyim.Caching.Memcached;

根據實際引用添加引用

?

  1. 創建實例及使用

var client? = ?new CouchbaseClient (); // 創建實例

client . Store ( StoreMode . Add ,? "somekey" ,? "somevalue" ); //存儲數據

var someValue? = ?client . Get ( "somekey" ) ? as ? string ; //獲取數據

var someValue? = ?client . Get < string >( "somekey" ); //獲取數據

以上是簡單基本類型的使用,下面我們介紹一下復雜類型。先申明一個類

[ Serializable ]
public ? class ?Beer? {
? ?? public ?Guid Id? { ?get ; ?set ; ? }
? ?? public ? string ?Name? { ?get ; ?set ; ? }
? ?? public ? string ?Brewery? { ?get ; ?set ; ? }
}

?

var key? = ?Guid . NewGuid ();
var beer =
? new ?Beer? {
? ? Id? = ?key,
? ? Name? = ? "Old Yankee Ale" ,
? ? Brewery? = ? "Cottrell Brewing Company"
};
client . Store ( StoreMode . Add ,? "beer_" ?+ ?key, beer );

?

var beer? = ?client . Get < Beer >( "beer_" ?+ ?key );

?

在CouchBase2.0正式版就開始支持json,這一點讓人激動人心。

?

存儲json數據

public ? static ? bool ?StoreJson < T >( this ? CouchbaseClient client, StoreMode storeMode,? string ?key, T value ) ? where ?T? : ? class ? {
? ? var ms? = ? new ?MemoryStream ();
? ? var serializer? = ? new ?DataContractJsonSerializer ( typeof ( T ));
? ? serializer . WriteObject ( ms, value );
? ? var json =
?Encoding . Default . GetString ( ms . ToArray ());
? ? ms. Dispose ();
? ?? return ?client. Store ( storeMode, key, json ); ?? ? ? ? ? ?
}

?

獲取json數據

public ? static ?T GetJson < T >( this ?CouchbaseClient client,? string ?key) ? where ?T? : ? class ? { ?? ?
? ? var json? = ?client . Get < string >( key ); ?? ?
? ? var ms? = ? new
?MemoryStream(
Encoding . Default . GetBytes ( json ));
? ? var serializer =
? new
?DataContractJsonSerializer( typeof (
T )); ?? ? ? ? ? ? ? ? ? ? ? ? ? ?
? ? var obj? = ?serializer . ReadObject ( ms ) ? as ?T ;
? ? ms. Dispose ();
? ?? return ?obj;
?? ? ? ? ? ? ? ? ? ? ? ?
}

?

Client使用方法

var key = Guid.NewGuid();
var beer = new Beer {
? ? Id = key,
? ? Name = "American Ale",
? ? Brewery = "Thomas Hooker Brewing Company",
? ? Type = "beer"
};
client.StoreJson<Beer>(StoreMode.Add, "beer_" + key, beer);

var beer = client.GetJson<Beer>("beer_" + key);

?

  1. 檢查和操作結果

    官方的說明

    For check and set operations, the return values are wrapped in a CasResult instance.? The success of the operation is still determined by a Boolean and detailed failures still require logging.?

var result = client.GetWithCas("foo");
var bar = "bar";?
var result = client.Cas(StoreMode.Set, "foo", bar, result.Cas);
if (result.Result) {
? ?Console.WriteLine("CAS operation was successful");
}

?

  1. 獲取詳細操作結果

    如果你需要獲取運行時的詳細信息,你可以使用IoperationResult API方法,下面是官方給的API屬性的說明。

    Each of these methods shares its name with a method from the single-value return API, but prefixed with "Execute." For example, Get() becomes ExecuteGet() and Store() becomes ExecuteStore().

?

Property

Interface

Description

Success

IOperationResult

Whether the operation succeeded

Message

IOperationResult

Error, warning or informational message

StatusCode

IOperationResult

Nullable status code from server

InnerResult

IOperationResult

Nested result.? Populated by low-level I/O failures.

Value

INullableOperationResult

Extended by IGetOperationResult, where Value is item for given key.?

HasValue

INullableOperationResult

Shortcut for null Value check.?

Cas

ICasOperationResult

Extended by IGetOperationResult, IMutateOperationResult, IConcatOperationResult and IStoreOperationResult.? Contains possible CAS value for operations.

var getResult? = ?client . ExecuteGet < Beer >( "beer_heady_topper" );
if ? ( getResult . Success ?&& ?getResult . HasValue ) ? { ???
? ?

? ?var beer? = ?getResult . Value ;
? ?beer. Brewery ?=
? "The Alchemist" ;
? ?var casResult? = ?client . ExecuteCas ( StoreMode . Set ,? "beer_heady_topper" , beer, getResult. Cas );

? ? if ? ( casResult . Success ) ? {
? ? ? ?Console. WriteLine ( "CAS operation was successful" );
? ?}

} ? else ? {
? ?Console. WriteLine ( "Get operation failed with message {0} and exception {1} " ,?
? ? ? ? ? ? ? ? ? ? ? ? ? getResult. Message , getResult. Exception );
}

?

  1. 配置日志

    CouchBase支持Log4Net和Nlog,你可以自己現在或者從CouchBase提供的SDK獲取。

    ?

    Log4Net 配置參考。

<?xml version="1.0" encoding="utf-8"?>
<configuration>
? <configSections>
? ? <sectionGroup name="enyim.com">
? ? ? <section name="log" type="Enyim.Caching.Configuration.LoggerSection, Enyim.Caching" />
? ? </sectionGroup>
? ? <section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net" />
? </configSections>
? <enyim.com>
? ? <log factory="Enyim.Caching.Log4NetFactory, Enyim.Caching.Log4NetAdapter" />
? </enyim.com>
? <log4net debug="false">
? ? <appender name="LogFileAppender" type="log4net.Appender.FileAppender,log4net">
? ? ? <param name="File" value="c:\\temp\\error-log.txt" />
? ? ? <param name="AppendToFile" value="true" />
? ? ? <layout type="log4net.Layout.PatternLayout,log4net">
? ? ? ? <param name="ConversionPattern" value="%d [%t] %-5p %c [%x] &lt;%X{auth}&gt; - %m%n" />
? ? ? </layout>
? ? </appender>
? ? <root>
? ? ? <priority value="ALL" />
? ? ? <level value="DEBUG" />
? ? ? <appender-ref ref="LogFileAppender" />
? ? </root>
? </log4net> ?
</configuration>

更多Log4Net配置可參考: http://logging.apache.org/log4net/release/manual/configuration.html .

?

?

Nlog配置參考

<?xml version="1.0" encoding="utf-8"?>
<configuration>
? <configSections>
? ? <sectionGroup name="enyim.com">
? ? ? <section name="log" type="Enyim.Caching.Configuration.LoggerSection, Enyim.Caching" />
? ? </sectionGroup>
? ? <section name="nlog" type="NLog.Config.ConfigSectionHandler, NLog" />
? </configSections>
? <enyim.com>
? ? <log factory="Enyim.Caching.NLogFactory, Enyim.Caching.NLogAdapter" />
? </enyim.com>
? <nlog>
? ? <targets>
? ? ? <target name="logfile" type="File" fileName="c:\temp\error-log.txt" />
? ? </targets>
? ? <rules>
? ? ? <logger name="*" minlevel="Info" writeTo="logfile" />
? ? </rules>
? </nlog>
? <startup>
? ? <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0" />
? </startup>
</configuration>

更多Nlog配置可參考: http://nlog-project.org/wiki/Configuration_file

?

?

總結 : 以上信息來源官方的Getting Started,另附一份自己整理的Demo。(通過office word 發布的文檔格式有些變形)

Demo源碼

著意耕耘,自有收獲

收縮SQL Server日志不是那么簡單


更多文章、技術交流、商務合作、聯系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號聯系: 360901061

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。

【本文對您有幫助就好】

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描上面二維碼支持博主2元、5元、10元、自定義金額等您想捐的金額吧,站長會非常 感謝您的哦!!!

發表我的評論
最新評論 總共0條評論
主站蜘蛛池模板: 日本特黄在线观看免费 | 天天干网站 | 午夜美女久久久久爽久久 | 久久只精品 | 久久久久无码国产精品一区 | 久久草在线视频免费 | 怡红院成人永久免费看 | 亚洲在线小视频 | 精品成人免费播放国产片 | 成人欧美在线 | 九九精品视频在线观看九九 | 欧美成人性视频在线黑白配 | 四虎影院最新 | 97在线观看免费 | 一本一本久久a久久综合精品蜜桃 | 奇米视频7777 | 成年网站视频在线观看 | 亚洲精品乱码久久久久久v 亚洲精品乱码久久久久久麻豆 | 欧美日韩在线成人免费 | 在线看的毛片 | 97国产成人精品视频 | 亚洲精品高清国产麻豆专区 | 久久资源在线 | 欧美大狠狠大臿蕉香蕉大视频 | 香蕉视频在线观看视频 | 人与拘一级a毛片 | 私人免费影院入口 | 日本一级毛片高清免费观看视频 | 波多野结衣高清在线播放 | 欧美日本日韩 | 国产精品人成人免费国产 | 青青热久免费精品视频在线观看 | 亚洲精品线在线观看 | 中文字幕热久久久久久久 | 一级做受视频免费是看美女 | 久青草资源福利视频 | 91青青青国产在观免费影视 | 久热精品视频 | 日本xxxx色视频在线观看免 | 国产成人aa在线观看视频 | 日韩高清欧美精品亚洲 |