SQL大型事務(wù)日志備份與修復(fù)問(wèn)題

字號(hào):

問(wèn):我在備份時(shí)注意到一些異?,F(xiàn)象,希望您能解釋一下。我們需要經(jīng)常備份 62GB 的生產(chǎn)數(shù)據(jù)庫(kù),以刷新應(yīng)用程序開(kāi)發(fā)人員所使用的數(shù)據(jù)。我們總是先刪除舊副本然后再還原新副本。還原的副本與生產(chǎn)數(shù)據(jù)庫(kù)大小相同,而且數(shù)據(jù)看起來(lái)也一樣,但是與備份過(guò)程相比,還原過(guò)程所需的時(shí)間要長(zhǎng)很多。這是怎么回事?為什么還原比備份需要更長(zhǎng)的時(shí)間?
    答:其實(shí)這不屬于異常現(xiàn)象。根據(jù)您所處的環(huán)境,這種現(xiàn)象通常是預(yù)料之中的。備份和還原所需的時(shí)間之所以不同,是由于每個(gè)流程必須執(zhí)行的步驟不同。
    備份數(shù)據(jù)庫(kù)包含兩個(gè)步驟。主要就是對(duì)數(shù)據(jù)庫(kù)執(zhí)行 IO 讀取操作以及對(duì)備份設(shè)備執(zhí)行 IO 寫(xiě)入操作:
    備份步驟 1 讀取數(shù)據(jù)文件中所有分配的數(shù)據(jù),然后將其寫(xiě)入備份設(shè)備。
    備份步驟 2 讀取某些事務(wù)日志,然后將其寫(xiě)入備份設(shè)備。
    所需的事務(wù)日志數(shù)量可能會(huì)差異很大,但其數(shù)量一定能將還原的數(shù)據(jù)庫(kù)恢復(fù)到相同的時(shí)間點(diǎn)
    而還原數(shù)據(jù)庫(kù)最多可能包含四個(gè)步驟。涉及的工作要比讀寫(xiě) IO 復(fù)雜得多:
    還原步驟 1 如果數(shù)據(jù)庫(kù)文件不存在,則創(chuàng)建它們。
    還原步驟 2 從備份中讀取所有數(shù)據(jù)和事務(wù)日志,然后將其寫(xiě)入相關(guān)的數(shù)據(jù)庫(kù)文件。
    還原步驟 3 對(duì)事務(wù)日志運(yùn)行恢復(fù)過(guò)程的“重做”階段。
    還原步驟 4 對(duì)事務(wù)日志運(yùn)行恢復(fù)過(guò)程的“撤消”階段。
    兩個(gè)備份步驟所需時(shí)間與還原步驟 2 所需時(shí)間大致相同(假定硬件配置類(lèi)似并且服務(wù)器上沒(méi)有用戶活動(dòng))。如果數(shù)據(jù)文件較大并且需要進(jìn)行零初始化(這在 SQL Server 2000 中是需要執(zhí)行的操作,在 SQL Server 2005 中是默認(rèn)操作),則還原步驟 1 可能需要較長(zhǎng)時(shí)間。
    為避免花費(fèi)較長(zhǎng)時(shí)間,請(qǐng)不要在開(kāi)始還原之前刪除現(xiàn)有文件?;蛘撸部梢詥⒂眉磿r(shí)初始化,以便快速創(chuàng)建這些文件。
    還原步驟 3 和 4 是對(duì)還原的數(shù)據(jù)庫(kù)進(jìn)行恢復(fù),以便確保事務(wù)一致性;此流程與崩潰恢復(fù)期間對(duì)數(shù)據(jù)庫(kù)執(zhí)行的操作流程相同?;謴?fù)操作所需時(shí)間取決于需要處理的事務(wù)日志量。例如,如果在進(jìn)行備份時(shí)恰好有一個(gè)長(zhǎng)時(shí)間運(yùn)行的事務(wù)處于活動(dòng)狀態(tài),則該事務(wù)的所有事務(wù)日志都會(huì)被備份進(jìn)來(lái),因此屆時(shí)不得不進(jìn)行回滾。
    問(wèn):我打算在日志傳送和數(shù)據(jù)庫(kù)鏡像之間選擇一種提供生產(chǎn)數(shù)據(jù)庫(kù)冗余副本的方法。我很擔(dān)心需要在兩個(gè)服務(wù)器之間傳送的事務(wù)日志數(shù)量,尤其是對(duì)于我們每晚都需要執(zhí)行的索引重建操作。聽(tīng)說(shuō)鏡像功能發(fā)送的是實(shí)際的重建命令而非事務(wù)日志,而重建是在鏡像中完成的。真的是這樣嗎?如果是這樣,那么對(duì)于 BULK_LOGGED 恢復(fù)模式,鏡像解決方案要優(yōu)于日志傳送,對(duì)嗎?
    答:您聽(tīng)說(shuō)的觀點(diǎn)是錯(cuò)誤的。數(shù)據(jù)庫(kù)鏡像過(guò)程是通過(guò)將實(shí)際的事務(wù)日志記錄從主體數(shù)據(jù)庫(kù)發(fā)送到鏡像服務(wù)器來(lái)完成的,這些記錄在鏡像數(shù)據(jù)庫(kù)中將被“重播”。對(duì)于鏡像的數(shù)據(jù)庫(kù),既不存在任何類(lèi)型的轉(zhuǎn)換或篩選,也不存在任何類(lèi)型的 T-SQL 命令攔截。
    數(shù)據(jù)庫(kù)鏡像僅支持 FULL 恢復(fù)模式,這意味著始終會(huì)完全記錄索引重建操作。根據(jù)涉及的索引大小的不同,這可能意味著會(huì)生成大量事務(wù)日志,從而導(dǎo)致主體數(shù)據(jù)庫(kù)的日志文件很大,在將日志記錄發(fā)送到鏡像時(shí)需要占用大量的網(wǎng)絡(luò)帶寬。
    您可以將數(shù)據(jù)庫(kù)鏡像視為實(shí)時(shí)日志傳送(實(shí)際上,這正是早期在 SQL Server 2005 開(kāi)發(fā)期間該功能所使用的名稱)。在日志傳送過(guò)程中,主數(shù)據(jù)庫(kù)的事務(wù)日志備份會(huì)定期傳送到輔助服務(wù)器上,并在輔助數(shù)據(jù)庫(kù)中進(jìn)行還原。
    日志傳送功能支持 FULL 和 BULK_LOGGED 恢復(fù)模式。對(duì)于使用 FULL 恢復(fù)模式在日志傳送數(shù)據(jù)庫(kù)中所執(zhí)行的索引重建操作,生成的事務(wù)日志量將與鏡像數(shù)據(jù)庫(kù)中生成的數(shù)量完全相同。但是,在日志傳送數(shù)據(jù)庫(kù)方案中,數(shù)據(jù)是以日志備份(或系列日志備份)而非連續(xù)流的形式發(fā)送到冗余數(shù)據(jù)庫(kù)的。
    如果在索引重建完畢后在日志傳送數(shù)據(jù)庫(kù)中使用 BULK_LOGGED 恢復(fù)模式,則只會(huì)生成少量的事務(wù)日志。但是在下次事務(wù)日志備份時(shí),還將會(huì)包含被所記錄的最低限度索引重建操作改變的全部數(shù)據(jù)文件范圍。這意味著無(wú)論是納入在 BULK_LOGGED 恢復(fù)模式下重建的索引的日志備份還是納入在 FULL 恢復(fù)模式下重建的索引的日志備份,其大小都幾乎完全相同。
    因此,對(duì)于鏡像數(shù)據(jù)庫(kù)與日志傳送數(shù)據(jù)庫(kù)中的索引重建而言,需要發(fā)送到冗余數(shù)據(jù)庫(kù)的信息量幾乎完全相同。實(shí)際的差別僅在于發(fā)送信息的方式 — 是連續(xù)發(fā)送還是成批發(fā)送。
    在這兩種方法之間進(jìn)行選擇時(shí)需要考慮許多其他因素(因素太多,僅在一次 SQL 問(wèn)題解答中無(wú)法全部討論)。您應(yīng)該先了解所有這些因素與您的需求的關(guān)聯(lián)程度(例如,可接受的數(shù)據(jù)丟失限制和允許的停機(jī)時(shí)間),然后再做決定。
    問(wèn):我正在運(yùn)行 SQL Server 2005,我發(fā)現(xiàn)其中一個(gè)數(shù)據(jù)庫(kù)的事務(wù)日志一直在不斷增大。該數(shù)據(jù)庫(kù)處于完全恢復(fù)模式,我正在進(jìn)行事務(wù)日志備份。我認(rèn)為這本應(yīng)該防止事務(wù)日志不斷增大。這其中究竟發(fā)生了什么問(wèn)題?
    答:在完全恢復(fù)模式下進(jìn)行事務(wù)日志備份很重要,在這一點(diǎn)上您是對(duì)的。但是,還有其他一些因素可導(dǎo)致事務(wù)日志增大??荚?大提示這完全取決于究竟是什么在要求事務(wù)日志成為被使用的日志(或活動(dòng)日志)。除了缺乏事務(wù)日志備份以外,可能會(huì)導(dǎo)致此現(xiàn)象發(fā)生的其他常見(jiàn)因素還包括復(fù)制、數(shù)據(jù)庫(kù)鏡像和活動(dòng)事務(wù)等。
    復(fù)制過(guò)程是通過(guò)異步讀取事務(wù)日志記錄,然后加載這些事務(wù)并將其復(fù)制到單獨(dú)的分布數(shù)據(jù)庫(kù)來(lái)完成的。尚未被復(fù)制日志讀取器任務(wù)讀取的任何事務(wù)日志記錄都無(wú)法被釋放。如果您的工作負(fù)載生成了大量事務(wù)日志記錄,而您又為復(fù)制日志讀取器的運(yùn)行頻率設(shè)置了較長(zhǎng)的時(shí)間間隔,則會(huì)累積大量記錄,導(dǎo)致事務(wù)日志增大。
    如果您運(yùn)行的是異步數(shù)據(jù)庫(kù)鏡像,則可能會(huì)存在尚未從主體數(shù)據(jù)庫(kù)發(fā)送到鏡像服務(wù)器的事務(wù)日志記錄儲(chǔ)備(稱為數(shù)據(jù)庫(kù)鏡像 SEND 隊(duì)列)。這些事務(wù)日志記錄在成功發(fā)出之前無(wú)法被釋放。如果生成了大量事務(wù)日志記錄,而網(wǎng)絡(luò)帶寬又受到限制(或出現(xiàn)其他硬件問(wèn)題),則儲(chǔ)備可能會(huì)變得很大,導(dǎo)致事務(wù)日志不斷增大。
    最后,如果用戶啟動(dòng)了一個(gè)顯式事務(wù)(如使用 BEGIN TRAN 語(yǔ)句),然后進(jìn)行了某些形式的修改(如 DDL 語(yǔ)句或插入/更新/刪除操作),則所生成的事務(wù)日志記錄在用戶提交或回滾該事務(wù)前都需要進(jìn)行保留。這意味著由其他事務(wù)生成的任何后繼事務(wù)日志記錄也無(wú)法被釋放,因?yàn)槭聞?wù)日志無(wú)法選擇性地進(jìn)行釋放。如果假設(shè)該用戶當(dāng)天沒(méi)有結(jié)束該事務(wù)就下班回家了,則隨著越來(lái)越多的事務(wù)日志記錄被不斷生成而又無(wú)法釋放,事務(wù)日志就會(huì)越來(lái)越大。
    要了解事務(wù)日志無(wú)法釋放的原因,可以查詢 sys.databases 系統(tǒng)目錄視圖并查看 log_reuse_wait_desc 列,類(lèi)似于下面所示:
    SELECT name AS [Database],
    log_reuse_wait_desc AS [Reason]
    FROM master.sys.databases;
    如果證明是由于某個(gè)活動(dòng)事務(wù)所導(dǎo)致的,可使用 DBCC OPENTRAN 語(yǔ)句獲取有關(guān)該事務(wù)的更多信息:
    DBCC OPENTRAN ('dbname')
    問(wèn):我聽(tīng)說(shuō)在從損壞進(jìn)行恢復(fù)時(shí),不到萬(wàn)不得已不要使用 REPAIR_ALLOW_DATA_LOSS;而應(yīng)先使用備份進(jìn)行還原。您是否能解釋一下為什么不應(yīng)使用 SQL Server 2005 的修復(fù)功能,以及為什么在使用時(shí)要考慮“危險(xiǎn)”程度?
    答:首先,我確實(shí)編寫(xiě)過(guò)有關(guān) SQL Server 2005 修復(fù)的文章。REPAIR_ALLOW_DATA_LOSS(以下簡(jiǎn)稱為“修復(fù)”)的問(wèn)題在于其工作方式不是很清晰。之所以這樣命名此“修復(fù)”正是為了說(shuō)明運(yùn)行它可能會(huì)導(dǎo)致數(shù)據(jù)庫(kù)中的數(shù)據(jù)丟失。此功能修復(fù)損壞的數(shù)據(jù)庫(kù)結(jié)構(gòu)的方式通常是先刪除損壞的結(jié)構(gòu),然后修復(fù)數(shù)據(jù)庫(kù)中的其他所有內(nèi)容(引用已刪除結(jié)構(gòu)的或被已刪除結(jié)構(gòu)引用的)。在保持?jǐn)?shù)據(jù)庫(kù)結(jié)構(gòu)一致性方面,“修復(fù)”的確是不到萬(wàn)不得已不推薦使用的方法,因?yàn)樗闹埸c(diǎn)不是挽救用戶數(shù)據(jù)。“修復(fù)”不會(huì)故意去刪除用戶數(shù)據(jù),但它也不會(huì)主動(dòng)去挽救用戶數(shù)據(jù)。
    這樣一來(lái)您可能會(huì)認(rèn)為“修復(fù)”是一種不可靠的方式,但是當(dāng)不得不進(jìn)行修復(fù)時(shí),它可以提供一種最快捷最可靠的方法來(lái)修復(fù)損壞數(shù)據(jù)。在進(jìn)行災(zāi)難恢復(fù)時(shí),速度極為重要,并且要求絕對(duì)準(zhǔn)確。設(shè)計(jì)出經(jīng)過(guò)驗(yàn)證能在各種情況下迅速準(zhǔn)確地完成修復(fù)操作的復(fù)雜修復(fù)算法幾乎是不可能的。例如,在修復(fù)代碼中有一些復(fù)雜算法可解決為兩個(gè)索引分配同一頁(yè)面或范圍的問(wèn)題,但通常此算法都是采用此“修復(fù)”功能再加上一些修補(bǔ)。
    此外,還有其他一些需要了解的有關(guān)“修復(fù)”的問(wèn)題:
    在刪除損壞的結(jié)構(gòu)時(shí),“修復(fù)”不會(huì)考慮外鍵約束,因此,可能會(huì)刪除與其他表格有外鍵關(guān)系的表格中的記錄。如果在運(yùn)行“修復(fù)”后不運(yùn)行 DBCC CHECK­CONSTRAINTS,則無(wú)法確定是否發(fā)生了這種情況。
    “修復(fù)”不會(huì)(也無(wú)法)考慮在應(yīng)用程序級(jí)定義的、可能會(huì)被要?jiǎng)h除的某些數(shù)據(jù)破壞的任何內(nèi)在業(yè)務(wù)邏輯或數(shù)據(jù)關(guān)系。同樣,如果不運(yùn)行應(yīng)用程序中構(gòu)建的任何一種自定義的一致性檢查,則無(wú)法確定是否有關(guān)系遭到破壞。
    某些修復(fù)操作無(wú)法被復(fù)制。在對(duì)等拓?fù)渲袑?duì)發(fā)布服務(wù)器或節(jié)點(diǎn)運(yùn)行“修復(fù)”可能會(huì)在拓?fù)渲幸氩灰恢聠?wèn)題,必須手動(dòng)進(jìn)行糾正。
    鑒于以上原因,通過(guò)采用備份而非運(yùn)行“修復(fù)”來(lái)從損壞中進(jìn)行恢復(fù)始終是個(gè)不錯(cuò)的辦法。但是產(chǎn)品中也提供了“修復(fù)”,因?yàn)橐坏┏霈F(xiàn)數(shù)據(jù)庫(kù)受損而又沒(méi)有備份的情況,最起碼要有一種方法能使數(shù)據(jù)庫(kù)迅速恢復(fù)聯(lián)機(jī)狀態(tài)。
    問(wèn):我剛以一名 DBA 的身份加入一家新公司,現(xiàn)在需要負(fù)責(zé)管理多種應(yīng)用程序及其后端數(shù)據(jù)庫(kù)。其中一種應(yīng)用程序的更新性能非常差。在經(jīng)過(guò)調(diào)查后,我發(fā)現(xiàn)該應(yīng)用程序使用的每個(gè)表都包含大量索引。經(jīng)過(guò)多方詢問(wèn)后,才知道似乎是以前的 DBA 喜歡對(duì)各個(gè)表列及某些組合添加索引。我認(rèn)為并非所有索引都是必要的,但我該如何找出可以安全刪除的索引呢?我們運(yùn)行的是 SQL Server 2005。
    答:正如您所猜測(cè)的那樣,大量索引極有可能是造成性能不佳的主要因素。每次在表中插入、更新或刪除行時(shí),都需要在每個(gè)非群集索引中執(zhí)行相應(yīng)的操作??荚?大提示這將在 I/O、CPU 利用率和事務(wù)日志生成等方面增加大量的管理開(kāi)銷(xiāo)。
    在 SQL Server 2000 中,判斷正在使用哪些索引的途徑是使用配置文件和檢查查詢計(jì)劃。在 SQL Server 2005 中,則可使用新的動(dòng)態(tài)管理視圖 (DMV) -sys.dm_db_index_usage_stats,它可以跟蹤索引使用情況。
    此 DMV 會(huì)跟蹤數(shù)據(jù)庫(kù)啟動(dòng)以來(lái)的每一次索引使用及使用方式。SQL Server 關(guān)閉后所有數(shù)據(jù)庫(kù)的統(tǒng)計(jì)信息均會(huì)丟失,某個(gè)數(shù)據(jù)庫(kù)關(guān)閉或拆分后,該數(shù)據(jù)庫(kù)的統(tǒng)計(jì)信息會(huì)丟失。其想法是如果某個(gè)索引未出現(xiàn)在輸出中,則它肯定在數(shù)據(jù)庫(kù)啟動(dòng)后就未被使用過(guò)。
    隨著時(shí)間的推移來(lái)跟蹤索引使用情況的簡(jiǎn)單方法是定期拍攝 DMV 輸出的快照,然后對(duì)這些快照加以比較。許多人都忽略的一點(diǎn)是必須跟蹤索引在整個(gè)業(yè)務(wù)周期內(nèi)的使用情況。如果您只是拍攝一天的快照,則可能會(huì)發(fā)現(xiàn)多個(gè)未使用過(guò)的索引。但是,如果這些索引是具有其他用途,比如用于幫助月底報(bào)表更快速地運(yùn)行,則可能不應(yīng)該刪除這些索引。如果某索引確實(shí)在整個(gè)業(yè)務(wù)周期內(nèi)都未被使用過(guò),則很可能能夠?qū)⑵鋭h除并回收空間以提高性能。