نکاتی چند پیرامون پشتیبان‌گیری در SQL Server

/
/
/

نکاتی چند پیرامون پشتیبان‌گیری در SQL Server
مشکل:
آیا واقعاً مطمئن هستید؟ چه تعداد از مدیران پایگاه اطلاعاتی، توسعه دهندگان و ادمین‌های شبکه متوجه می‌شوند که پشتیبان گیری پایگاه اطلاعاتی SQL Server آن‌ها با شکست مواجه شده است؟ بعضی وقت‌ها آن‌ها زمانی متوجه این موضوع می‌شوند که دیگر دیر شده است. یعنی زمانیکه با خرابی و یا از دست دادن داده‌ها بعد از کارافتادگی کامپیوتر روبرو می‌شوند. هر دوی این‌ها برای موفقیت یک سازمان فاجعه بار و برای مدیران پایگاه اطلاعاتی، توسعه دهندگان و ادمین‌های شبکه که مسئول SQL Server Service Level Agreements (SLAs) هستند غیر قابل توجیه است.
راهکار:
آدم‌های کار درست هم ممکن است اشتباه کنند. اما اگر در شرایط عادی متوجه موفقیت انجام پشتیبان‌گیری‌ها نشوید و آن را تایید نکنید این موضوع در شرایط بحرانی فاجعه بار خواهد بود. اکثر مواقع وقتی پشتیبان‌گیری با شکست مواجه می‌شود، یک ایمیل فرستاده می‌شود یا یک ورودی در یک لاگ نوشته می‌شود تا مدیران پایگاه اطلاعاتی، توسعه دهندگان و ادمین‌های شبکه را که مسئول پشتیبان‌گیری SQL Server هستند، متوجه این موضوع نمایند. اگر پارامتر پیکربندی تغییر کند و شما ایمیل‌های مرتبط با این مشگل را که ظرف چند روز یا چند هفته و چند ماه بدتر می‌شود، دریافت نکنید، چه؟ بسته به اپلیکیشن و فرآیندی که جهت اجرای پشتیبان‌گیری‌های پایگاه اطلاعاتی SQL Server اجرا می‌شوند، job‌های SQL Server هم باید مورد بررسی قرار بگیرند تا از اجرای موفقیت‌آمیز آنها هم اطمینان حاصل گردد.
یک راه پرداختن به این مسئله، تنظیم گروهی از SQL Server Agent Jobs برای نظارت بر فرآیند کلی پشتیبان گیری در ۲۴ ساعت گذشته است. این یعنی هر روز یک نوتیفیکیشن برای پشتیبان‌گیری‌های روز گذشته برای شما ارسال خواهد شد. اگر این نوتیفیکیشن را دریافت نکردید، به سرعت می‌فهمید که مشگلی رخ داده است و فرآیند کلی باید مورد بررسی قرار بگیرد. زمانبندی پشتیبان‌گیری، محیط ( سرورها ، متعلقات و غیره) و ابزارهای نوتیفیکیشن مشخص می‌کنند که این فرآیند چگونه صورت بگیرد. برای این کار کد T-SQL باید اجرا شود تا پشتیبان‌‌های کامل، لاگ تراکنش، پشتیبان اختلافی (differential) و پشتیبان file/file group را ضبط کند. کد زیر را می‌توانید به ابزار نوتیفیکیشن مورد نظر خود اضافه کنید تا وضعیت پشتیبان برای انواع پشتیبان‌هایی که به طور منظم صادر می‌کنید، مشخص شود:

Full Database Backups
SELECT database_name, backup_start_date, type, *
FROM msdb.dbo.backupset
WHERE backup_start_date BETWEEN DATEADD(hh, -24, GETDATE()) AND GETDATE()
AND Type = ‘D’
ORDER BY backup_set_id DESC
GO
Transaction Log Backups
SELECT database_name, backup_start_date, type, *
FROM msdb.dbo.backupset
WHERE backup_start_date BETWEEN DATEADD(hh, -24, GETDATE()) AND GETDATE()
AND Type = ‘L’
ORDER BY backup_set_id DESC
GO
Differential Backups
SELECT database_name, backup_start_date, type, *
FROM msdb.dbo.backupset
WHERE backup_start_date BETWEEN DATEADD(hh, -24, GETDATE()) AND GETDATE()
AND Type = ‘I’
ORDER BY backup_set_id DESC
GO
File\File Group Backups
SELECT database_name, backup_start_date, type, *
FROM msdb.dbo.backupset
WHERE backup_start_date BETWEEN DATEADD(hh, -24, GETDATE()) AND GETDATE()
AND Type = ‘F’
ORDER BY backup_set_id DESC
GO

زمانی که مشگلی رخ می‌دهد. اگر دسترسی بسیار بالا یا ابزار بازیابی فاجعه ندارید، به پشتیبان‌های پایگاه اطلاعاتی SQL Server خود به عنوان اولین و آخرین خط دفاعی تکیه می‌کنید. پس برای پشتیبان‌های خود وقت بگذارید تا در زمانی که به آن‌ها نیاز دارید به کمک شما بیایند.
– توجه داشته باشید که پشتیبان‌ها چقدر مهم هستند، همیشه این را در ذهن داشته باشید که ” پشیبان‌ها برای نمایش هستند، اما بازگردانی‌ها (restores) برای امنیت کار” معنی این عبارت آن است که پشتیبان‌ها از همان ابتدا مهم و حائز اهمیت‌اند؛ اما عدم توانایی در بازگردان موفق پایگاه اطلاعاتی، آن پشتیبان‌های را نیز بی ارزش می‌کند. پس فرآیند پشیبان‌گیری و بازیابی و اپلیکیشن‌ مربوطه را پس از تغییر فرآیند، آمازیش کنید و آخرین ورژن‌های اپلیکیشن پشتیبان خود را به اجرا دربیاورید.
ابتدا قبل از ایجاد هرگونه پشتیبان دیگری از وجود پشتیبان‌ کامل پایگاه اطلاعاتی SQL Server اطمینان حاصل کنید.

مشگل:
ما معمولاً برای هر پایگاه اطلاعاتی خیلی بزرگ، پشتیبان‌های تفاضلی و file/file group را به همراه پشتیبان کامل پایگاه اطلاعاتی به طرح پشتیبان‌گیری خود اضافه می‌کنیم. در برخی موارد، پشتیبان‌های تفاضلی قبل از آن که تغییر عمده‌ای در پایگاه اطلاعاتی اعمال شود، مورد استفاده قرارمی‌گیرند. پشتیبان‌ها می‌توانند برای بازگرداندن آن تغییرات در صورت نیاز استفاده شوند. چالش استفاده از این نوع پشتیبان‌ها این است که آن‌ها به عنوان نقطه شروع فرآیند بازگردانی، به یک پشتیبان کامل نیاز دارند. چگونه مطمئن شویم که یک کپی کامل از پشتیبان‌های کامل پایگاه اطلاعاتی داریم، قبل از آنکه بخواهیم انواع دیگر پشتیبان‌ها را ایجاد نماییم؟
راهکار:
شما باید مطمئن شوید که اگر در حال ایجاد پشتیبان‌های تفاضلی یا هر نوع پشتیبان دیگری غیر از پشتیبان کامل پایگاه اطلاعاتی هستید، پشتیبان کامل پایگاه اطلاعاتی حتماً وجود داشته باشد. این موضوع بخصوص در مواردی که نیاز به اعمال یک تغییر عمده در پایگاه اطلاعاتی خود دارید و می‌خواهید برای rollback کردن اطلاعات در مواقع ضروری، یک پشتیبان در دست داشته باشید؛ بسیار مفید مواقع می‌شود. ما سازمان‌هایی را دیده‌ایم که از مزایای داشتن تصاویر فوری در SQL Server 2005 به منظورrollback کردن استفاده نمی‌کنند. از آنجایی که این تنها ویژگی ویرایش سازمانی (Enterprise Edition) است، آن‌ها باید هم از پشتیبان‌های تفاضلی و هم پشتیبان کامل برای rollback کردن تغییرات استفاده نمایند.
اسکریپت زیر یک رویه ذخیره شده می‌سازد که برای ایجاد پشتیبان‌های تفاضلی مورد استفاده قرار می‌گیرد. شما می‌توانید آن را به هرنوع پشتیبانی که می‌خواهید تغییر دهید اما ما به منظور هدفی که داریم از آن برای پشتیبان تفاضلی استفاده می‌کنیم.
رویه ذخیره شده با بررسی تاریخچه پشتیبان، کار می‌کند و به دنبال آخرین پشتیبان پایگاه اطلاعاتی و فایل مربوطه می‌گردد. اگر آخرین پشتیبان پایگاه اطلاعاتی وجود نداشته باشد یا این که تا کنون از پایگاه اطلاعاتی پشتیبان‌گیری به عمل نیامده باشد، پشتیبان تفاضلی بی نتیجه می‌ماند. رویه ذخیره شده پارامتری را می‌پذیرد که شامل محل پشتیبان تفاضلی با یک مقدار پیش فرض از محل از پیش تعریف شده پشتیبان شما باشد.
CREATE PROCEDURE sp_generateDifferentialBackups
@strBackupPath NVARCHAR (25) =’D:\backups\’–variable for location of DIFFERENTIAL backups
AS
SET NOCOUNT ON
— Get the name of all user databases
DECLARE @strTimeStamp NVARCHAR(12) –variable for timestamp value
DECLARE @strSQL NVARCHAR(100) — used for generating dynamic SQL statements
DECLARE @databaseName NVARCHAR(128) — used as variable to store database names
DECLARE dbCursor CURSOR FOR — used for cursor allocation
SELECT NAME
FROM MASTER.SYS.DATABASES
WHERE [database_id] > 0
AND NAME NOT IN (‘MASTER’,’MODEL’,’MSDB’,’TEMPDB’) –does not include the system databases

OPEN dbCursor

FETCH NEXT FROM dbCursor INTO @databaseName

WHILE (@@FETCH_STATUS = 0)
BEGIN
PRINT ‘Checking for the latest FULL database backup for: [‘ + @databaseName +’]’

DECLARE @strphysical_device_name NVARCHAR(100) — variable for physical_device_name
DECLARE @cursor NVARCHAR(400)

— Reads the MSDB database to check for the latest FULL database backup
SELECT @cursor=(‘DECLARE TabCursor CURSOR FAST_FORWARD GLOBAL FOR ‘ +
‘SELECT TOP 1 physical_device_name
FROM msdb.dbo.backupset a INNER JOIN msdb.dbo.backupmediafamily b
ON a.media_set_id = b.media_set_id
WHERE database_name=”’ + @databaseName + ”’
AND type=”D”
ORDER BY backup_finish_date desc’)
EXEC sp_executesql @cursor
OPEN TabCursor

FETCH NEXT FROM TabCursor INTO @strphysical_device_name
–Check if the database does not have any FULL backups at all
IF @@FETCH_STATUS <> 0
BEGIN
PRINT ‘*****WARNING: Database [‘ + @databaseName + ‘] does not have any FULL database backups at all. Generate the FULL database backup first. Aborting DIFFERENTIAL backup command.*****’
END
ELSE
–If the database has FULL backups,
WHILE @@FETCH_STATUS = 0
BEGIN
DECLARE @result INT
EXEC xp_fileexist @strphysical_device_name, @result output
IF (@result = 1) –@result will return 1 if the specified file exists, if it doesn’t, it will return 0
BEGIN
SET @strTimeStamp=CONVERT(CHAR(8), GETDATE(), 112)
SET @strTimeStamp=@strTimeStamp + REPLACE(CONVERT(CHAR(8), GETDATE(), 108),’:’,”)
EXEC (‘BACKUP DATABASE ‘ + @databaseName + ‘ TO DISK=”’ + @strBackupPath + @databaseName + ‘_DIFF_’ + @strTimeStamp + ‘.BAK” WITH INIT, DIFFERENTIAL, DESCRIPTION=”DIFFERENTIAL Backup for ‘ + @databasename + ‘ database”’) — change this value should you decide to change the backup type to something other than differential
PRINT ‘===========================================================================================’
PRINT ‘DIFFERENTIAL Backup generated for database: [‘ + @databaseName + ‘]’
PRINT ‘Corresponding FULL database backup: ‘ + @strphysical_device_name
PRINT ‘DIFFERENTIAL database backup: ‘ + @strBackupPath + @databaseName + ‘_DIFF_’ + @strTimeStamp + ‘.BAK’
END
ELSE
PRINT ‘*********WARNING: FULL database backup file is missing. Generate the FULL database backup first. Aborting DIFFERENTIAL backup command.*********’

FETCH NEXT FROM TabCursor INTO @strphysical_device_name
END
CLOSE TabCursor
DEALLOCATE TabCursor

PRINT ‘===========================================================================================’
PRINT ‘ ‘
PRINT ‘ ‘
PRINT ‘ ‘

FETCH NEXT FROM dbCursor INTO @databaseName
END

CLOSE dbCursor
DEALLOCATE dbCursor

PRINT ‘FINISHED’
GO

شما می‌توانید پارامتری را تایید کنید که شامل محل پشتیبان باشد، جاییکه قصد دارید پشتیبان تفاضلی را ذخیره کنید یا رویه ذخیره شده را همانگونه که هست فرابخوانید.
نمونه خروجی پس از ساخت و اجرا رویه ذخیره شده.

به غیر از استفاده از این رویه ذخیره شده برای ایجاد پشتیبان‌های تفاضلی اختصاصی، می‌توان از آن به عنوان گزینه‌ای برای طرح‌های حفظ و نگهداری پایگاه اطلاعاتی استفاده کرد. به جای استفاده از Backup Database Task ، می‌توانید از Execute TSQL استفاده نمایید و این رویه ذخیره شده را فرابخوانید. با انجام این کار، مطمئن می‌شوید که پشتیبان‌های تفاضلی، پشتیبان‌های کامل پایگاه اطلاعاتی مربوط به خود را دارند. درصورتیکه پشتیبان تفاضلی از دادن اطلاعات در مورد از دست رفتن پشتیبان کامل پایگاه اطلاعاتی، یا عدم پشتیبان‌گیری از پایگاه اطلاعاتی به شما صرف نظر کرد، می‌توانید این اسکریپت را برای فرستادن هشدارها اختصاصی کنید.
تابع CLR برای حذف فایل‌های قدیمی لاگ و پشتیبان در SQL Server
در این تابع CLR قصد داریم به سراغ این پارامترها برویم:
مسیر فایل
روزهای نگهداری فایل
پسوند فایل
و باز گرداندن شماری از فایل‌هایی که حذف شده‌اند
گام اول- کد CLR
اولین چیزی که برای انجام این کار نیاز داریم نوشتن کد CLR است. این کد را می‌توان هم در C#.NET یا در VB.NET نوشت. در این مثال ما از VB.NET استفاده می‌کنیم.
کد زیر دارای Class (CLRFunctions) و Function (DeleteFiles) است. این تابع سه پارامتر دارد که مقدار صحیح را باز می‌گرداند.
کد زیر را در فایلی به نام c:\CLRFunctions.vb کپی و ذخیره کنید.
Imports System.IO

Public Class CLRFunctions

Public Shared Function DeleteFiles(sPath As String, iDaysToKeep As Integer, sFileExtension As String) As Integer

Dim arrFiles As Array
Dim dateToday As Date
Dim myFileInfo As FileInfo
Dim myDirectoryInfo As DirectoryInfo
Dim iFileCount As Integer

Try
iFileCount = 0

myDirectoryInfo = New DirectoryInfo(sPath)

arrFiles = myDirectoryInfo.GetFiles()

dateToday = DateAdd(“d”, -iDaysToKeep, Today)

For Each myFileInfo In arrFiles
If myFileInfo.Extension = sFileExtension And myFileInfo.LastWriteTime < dateToday Then
myFileInfo.Delete()
iFileCount = iFileCount + 1
End If
Next

Return iFileCount

Catch
Return 0
End Try

End Function

End Class

گام دوم- کامپایل کردن کد CLR
برای استفاده از این کد ، این کد باید ابتدا کامپایل شود.
فرمان زیر از خط فرمان اجرا می‌شود تا با استفاده از اپلیکیشن vbc.exe کد CLR را کامپایل کند. این فرمان در دایرکتوری فریم ورک .NET 2.0 یافت می‌شود. این فرمان ممکن است در سرور یا دسکتاپ شما متفاوت باشد و همچنین این کد باید در ماشینی که قرار است آن را اجرا کند، کامپایل شود.
بنابراین از خط فرمان، فرمانی نظیر این را اجرا کنید:
C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\vbc /target:library C:\CLRFunctions.vb

این کد حالا باید در فایلی به نام C:\CLRFunction.dll کامپایل شود.
گام سوم- ساخت اسمبلی و تابع
بعد از این که کد کامپایل شد، باید با SQL Server اسمبلی و تابع بسازید. برای این کار، فرمان‌های زیر را در پایگاه اطلاعاتی که می‌خواهید از این تابع استفاده کنید، اجرا نمایید.
این اسمبلی یک آبجکت داخلی را به DLL خارجی که ساخته شده وصل می‌کند و این تابع شبیه یک تابع معمولی SQL Server است.
در مورد این تابع سه مولفه می‌بینید CLRFunctions.CLRFunctions. DeleteFiles

• CLRFunctions- مرجع اسمبلی
• CLRFunctions – مرجع کلاس در کد VB
• DeleteFiles – مرجع تابع در کد VB

• CREATE ASSEMBLY CLRFunctions FROM ‘C:\CLRFunctions.dll’
WITH PERMISSION_SET = UNSAFE
GO

CREATE FUNCTION dbo.DeleteFiles
(
@FolderPath AS NVARCHAR(100),
@DaysToKeep AS integer,
@FileExtension AS NVARCHAR(50)
)
RETURNS integer
AS EXTERNAL NAME CLRFunctions.CLRFunctions.DeleteFiles
GO

هنگام کامپایل کردن زمانی که سعی دارید کد را کامپایل کنید، اگر پیام خطا دریافت کردید، ممکن است لازم باشد با استفاده از فرمان زیر پایگاه اطلاعاتی را تغییر دهید و سپس مجدداً سعی کنید تا اسمبلی و تابع را بسازید.
ALTER DATABASE test1 SET trustworthy ON

گام چهارم- امتحانش کنید
برای امتحان کردن این تابع، دستور SELECT زیر را براساس مقادیری که می‌خواهید برای این تابع تصویب کنید، اجرا نمایید.
در این مثال ما فایل‌هایی را در فولدر “C:\Backups” حذف می‌کنیم که مربوط به ۱۴ روز گذشته و یا قدیمی‌تر هستند و دارای پسوند “.BAK” می‌باشند.
SELECT dbo.DeleteFiles(‘C:\Backups’, 14, ‘.BAK’) AS FilesDeleted

در این مثال ما فایل‌هایی را در فولدر “C:\Backups” حذف می‌کنیم که مربوط به ۷ روز گذشته و یا قدیمی تر هستند و دارای پسوند “.trn” می‌باشند.
SELECT dbo.DeleteFiles(‘C:\Backups’, 7, ‘.trn’) AS FilesDeleted

در این مثال ما فایل‌هایی را در فولدر “C:\Backups” حذف می‌کنیم که مربوط به ۱۴ روز گذشته و یا قدیمی تر هستند و دارای پسوند “.LOG” می‌باشند.
SELECT dbo.DeleteFiles(‘C:\Backups’, 14, ‘.LOG’) AS FilesDeleted

گام پنجم- پاکسازی
برای خلاص شدن از این کد باید DLL که در مرحله کامپایل ساخته شده و همچنین فایل VB که ساخته شده است را حذف نمایید.
بعلاوه، برای حذف آبجکت‌های ساخته شده، کدT-SQL را اجرا کنید.
DROP FUNCTION dbo.DeleteFiles
GO
DROP ASSEMBLY CLRFunctions
GO
نکته قابل ذکر این که زمانیکه فایل‌ها حذف می‌شوند، در سطل زباله قرار نمی‌گیرند، بنابراین حتماً آن را در محیط آزمایش امتحان کنید تا مطمئن شوید که قرار است چه اتفاقی بیافتد قبل از اینکه آن را در سرورهای تولید خود اجرایی نمایید.
استفاده از فرمان FORFILES برای حذف پشتیبان‌های SQL Server
مشگل:
این فرآیند پشتیبان‌گیری نه تنها از تمام پایگاه‌های اطلاعاتی که ما تعیین می‌کنیم پشتیبان می‌گیرد، بلکه همزمان فرمان‌های پشتیبان را در صورتیکه فرآیند پشتیبان‌گیری یک پشتیبان کامل پایگاه اطلاعاتی در یک فایل باشد، در فرمت F-YYYYMMDD.sql و در صورتیکه فرآیند پشتیبان‌گیری یک پشتیبان تفاضلی (D) یا لاگ تراکنشی (T) باشد،در فرمت D|T_YYMMDD_HHMMSS.sql ، اسکریپت می‌کند. این فایل‌های اسکریپت سپس در یک زیر فولدر تحت دایرکتوری پشتیبان در SQL Server ذخیره می‌شوند. این فرآیند خوب کار می‌کند، اما ما نمی‌خواهیم تمام فایل‌های .sql را نگه داریم. فقط می‌خواهیم این اسکریپت‌های را تا ۳۰ روز حفظ کنیم. آیا راهی وجود دارد که بتوانیم فرآیند حذف فایل را در این SQL Server خودکار کنیم؟
راهکار:
در حالی که راه‌های زیادی برای کنترل کردن فرآیند حذف با کد T-SQL وجود دارد. ما از فرمان xp_cmdshell همراه با فرمان FORFILES برای مواردی که گفتید، استفاده می‌کنیم. فرمان FORFILES زیرمجموعه‌ای از فایل‌ها را انتخاب می‌کند و فرمانی را در مقابل این مجموعه اجرا می‌نماید. این فرمان به پارامترهای زیر نیاز دارد و متغییرهای زیر را می‌پذیرد.
پارامترها
Parameters
نام پارامتر توضیح
/p مسیر
/m Search Mask (default is *.*)
/s اگر این پارامتر اضافه شود، زیردایرکتوری‌ها به صورت بازگشتی جستجو می‌شوند
/c فرمان در مقابل هر فایل در مجموعه نتایج اجرا می‌شود، فرمان‌ها باید داخل گیومه باشند، پیش فرض “cmd c/echo @file” است.
/d دامنه تاریخ برای انتخاب فایل، استفاده از Last Modified Date به عنوان معیاری برای فایل. وقتی پارامتر /d در فرم MM/DD/YYYY است، هنگام تلاقی فایل با معیار +/- تاریخ معین اضافه می‌گردد. وقتی در فرمت
smallint (-32,768-32,768) است، فایل‌های +/-، فایل هایی با تاریخ اصلاح شده +/- و چند روز از تاریخ جاری به مجموعه نتایج فایل اضافه می‌گردند.

متغییرها
نام متغییر توضیح
@FILE نام فایل
@FNAME نام فایل بدون پسوند
@EXT پسوند فایل
@PATH مسیر کامل فایل
@RELPATH مسیر نسبی فایل
@ISDIR اگر نوع فایل یک دایرکتوری است به عنوانTRUE ارزیابی می‌شود
@FSIZE اندازه فایل به بایت
@FDATE آخرین datestamp اصلاح شده روی فایل
@FTIME آخرین timestamp اصلاح شده روی فایل

مثال‌های زیر با استفاه از این پارامترها اجرا می‌شوند تا مراقب نگرانی شما در مورد حذف فایل‌های اسکریپت پشتیبان باشند. شما می‌توانید اسکریپت‌ها را بر اساس نوع پشتیبان یا اصلاح تاریخ/ زمان بسازید. حتی می‌توانید اسکریپت‌هایی را اجرا کنید که از هر دو معیار استفاده می‌کنند. حال نگاه عمیق‌تری به این اسکریپت‌های بالقوه می‌اندازیم. به خاطر داشته باشید که شما آن‌ها را از کد T-SQL اجرا می‌کنید، بنابراین باید دستورها را در داخل فراخوان xp-cmdshell در فرمت EXEC xp_cmdshell ‘FORFILES COMMAND’ قرار دهید. لطفا توجه داشته باشید که در تمام نمونه‌ها ما از فلگ /Q و/F برای فرمان del استفاده می‌کنیم. در این صورت مشخص می‌شود که این فرمان از quiet mode (/Q) استفاده خواهد کرد و حتی فایل‌های read-only (/F) حذف خواهند شد.
مثال‌ها
تمام فایل های .sql در دایرکتوری C:\Backup و زیر داکتوری‌های آن را در جایی که تاریخ اصلاح شده فایل قدیمی‌تر از ۱۰/۱۸/۲۰۰۸ است، حذف کن.
EXEC xp_cmdshell ‘FORFILES /p c:\BACKUP /s /m *.sql /d 10/18/2008 /c “CMD /C del /Q /F @FILE”‘
تمام فایل های .sql در دایرکتوری C:\Backup و زیر داکتوری‌های آن را در جایی که تاریخ اصلاح شده فایل بیش از ۳۰ روز پیش است، حذف کن.
EXEC xp_cmdshell ‘FORFILES /p c:\BACKUP /s /m *.sql /d -30 /c “CMD /C del /Q /F @FILE”‘
تمام فایل های .sql در دایرکتوری C:\Backup و زیر داکتوری‌های آن را در جایی که تاریخ اصلاح شده فایل بیش از ۳۰ روز گذشته است و نام فایل با “F_” آغاز می‌شود، حذف کن.
EXEC xp_cmdshell ‘FORFILES /p c:\BACKUP /s /m F_*.sql /d -30 /c “CMD /C del /Q /F @FILE”‘

It is main inner container footer text