Skip to content
Coding With WanBi
Github

Tối ưu hóa chuyển đổi dữ liệu máy chủ với Robocopy và SQL Server

Windows Server, Robocopy, SQL Server, Database, System Administration14 min read

Giới thiệu

Việc chuyển đổi dữ liệu giữa các máy chủ (migration) thường là nỗi ác mộng với các quản trị viên hệ thống do rủi ro mất mát dữ liệu hoặc thời gian gián đoạn hệ thống (downtime) kéo dài. Đặc biệt đối với các hệ thống đang chạy cơ sở dữ liệu lớn như SQL Server 2008, việc sao lưu thủ công từng database và copy qua mạng bằng Windows Explorer thông thường rất mất thời gian và dễ gặp lỗi ngắt quãng.

Bài viết này sẽ chia sẻ một quy trình chuẩn hóa: kết hợp T-SQL Script tự động backup hàng loạt database trên SQL Server 2008 và công cụ Robocopy (công cụ sao chép mạnh mẽ có sẵn trên Windows) để di chuyển dữ liệu một cách nhanh chóng, an toàn và chuyên nghiệp nhất.


Bước 1: Tự động sao lưu toàn bộ Database trên SQL Server 2008

Trước khi di chuyển dữ liệu, việc đầu tiên là tạo ra các bản sao lưu (.bak) của toàn bộ database hiện tại. Thay vì click chuột và thực hiện backup thủ công cho từng database, bạn có thể tự động hóa hoàn toàn bằng script T-SQL dưới đây.

Kịch bản T-SQL để Backup toàn bộ Database

Bạn hãy mở SQL Server Management Studio (SSMS) trên máy chủ cũ (Source Server), chọn New Query và dán đoạn mã này vào:

DECLARE @name VARCHAR(100) -- Tên database
DECLARE @path VARCHAR(256) -- Đường dẫn lưu file
DECLARE @fileName VARCHAR(256) -- Tên file backup
DECLARE @fileDate VARCHAR(20) -- Ngày tháng để đặt tên file
-- 1. Đặt đường dẫn thư mục lưu file backup (đảm bảo thư mục này đã được tạo)
SET @path = 'C:\Backup_Databases\'
-- Lấy ngày tháng năm và thời gian để tạo tên file duy nhất tránh trùng lặp
SELECT @fileDate = CONVERT(VARCHAR(20),GETDATE(),112) + '_' + REPLACE(CONVERT(VARCHAR(20),GETDATE(),108),':','')
DECLARE db_cursor CURSOR FOR
SELECT name
FROM master.sys.databases
WHERE name NOT IN ('master','model','msdb','tempdb') -- Loại bỏ các database hệ thống mặc định
OPEN db_cursor
FETCH NEXT FROM db_cursor INTO @name
WHILE @@FETCH_STATUS = 0
BEGIN
SET @fileName = @path + @name + '_' + @fileDate + '.bak'
BACKUP DATABASE @name TO DISK = @fileName WITH FORMAT, INIT, SKIP, NOREWIND, NOUNLOAD, STATS = 10
FETCH NEXT FROM db_cursor INTO @name
END
CLOSE db_cursor
DEALLOCATE db_cursor
Kịch bản T-SQL để Backup toàn bộ Database

Hướng dẫn sử dụng:

  1. Thay đổi đường dẫn: Hãy đảm bảo biến @path khớp với thư mục mà bạn đã tạo sẵn trên ổ đĩa có dung lượng lớn của máy chủ cũ (ví dụ: C:\Backup_Databases\).
  2. Chạy Script: Nhấn Execute (F5). SQL Server sẽ sử dụng Cursor duyệt qua từng database người dùng, tự động sao lưu và đặt tên file theo định dạng DatabaseName_YYYYMMDD_HHMMSS.bak.
  3. Kiểm tra: Sau khi chạy xong, hãy vào thư mục để xác nhận các file .bak mới đã được sinh ra đầy đủ.

[!WARNING] Quyền truy cập thư mục: Nếu script báo lỗi ghi file (Access Denied), hãy đảm bảo tài khoản chạy dịch vụ SQL Server Service (ví dụ: NT Service\MSSQLSERVER) được cấp quyền Write (Ghi) vào thư mục lưu trữ đó.


Bước 2: Chuẩn bị "cửa ngõ" chia sẻ trên máy chủ cũ (Source Server)

Để máy chủ mới có thể truy cập và lấy dữ liệu về thông qua mạng nội bộ, bạn cần thiết lập chia sẻ thư mục chứa file backup:

1. Thiết lập Share (Sharing)

  • Chuột phải vào thư mục chứa backup (ví dụ: Backup_Databases) -> chọn Properties -> tab Sharing -> Advanced Sharing.
  • Tích chọn Share this folder.
  • Nhấp vào Permissions, chọn nhóm Everyone (hoặc tài khoản cụ thể) và cấp quyền Read (hoặc Full Control tùy nhu cầu bảo mật mạng nội bộ).
Thiết lập Share (Sharing)

2. Thiết lập bảo mật hệ thống (Security)

  • Cũng trong cửa sổ Properties, chuyển sang tab Security.
  • Nhấp Edit -> Add để thêm nhóm người dùng tương ứng (ví dụ: Everyone hoặc tài khoản domain cụ thể).
  • Đảm bảo tích chọn tối thiểu quyền Read & execute, List folder contents, và Read trong cột Allow.
Thiết lập bảo mật hệ thống (Security)

3. Xác nhận Network Path

  • Sau khi hoàn tất cấu hình, hệ thống sẽ hiển thị một dòng Network Path có dạng: \\TEN_MAY_CU\Backup_Databases hoặc \\IP_MAY_CU\Backup_Databases. Đây chính là đường dẫn nguồn bạn sẽ sử dụng trong lệnh Robocopy.

[!NOTE] Nếu máy chủ mới không thể truy cập Network Path trên, hãy kiểm tra lại cấu hình Windows Firewall trên máy chủ cũ để đảm bảo cổng chia sẻ file SMB (cổng 445) không bị chặn.


Bước 3: Tại sao nên dùng Robocopy thay vì Copy/Xcopy thông thường?

Khi chuyển dữ liệu lớn qua mạng, các phương pháp copy truyền thống lộ rõ nhiều nhược điểm. Hãy xem bảng so sánh dưới đây:

Tính năngWindows Explorer (Ctrl+C/V)XCopyRobocopy
Đồng bộ Delta (Delta-transfer)❌ Không❌ Hạn chế✔️ Tự động nhận diện file thay đổi
Đa luồng (Multi-threading)❌ 1 luồng❌ 1 luồng✔️ Lên tới 128 luồng cùng lúc
Tự động thử lại (Retry)❌ Dừng ngay khi lỗi❌ Dừng✔️ Tự động thử lại khi rớt mạng
Chế độ Gương (Mirroring)❌ Không❌ Không✔️ /MIR xóa file thừa ở đích
Lưu giữ thuộc tính file❌ Không✔️ Có✔️ Giữ nguyên NTFS Permissions, TimeStamp

Nhờ cơ chế đồng bộ thông minh, Robocopy sẽ chỉ sao chép những dữ liệu mới hoặc có sự thay đổi (Delta), giúp tiết kiệm tối đa băng thông mạng nội bộ và thời gian sao chép.


Bước 4: Thiết lập lệnh Robocopy an toàn

Hãy mở Command Prompt (CMD) hoặc PowerShell trên máy chủ mới (Destination Server) với quyền Administrator và sử dụng cú pháp sau để bắt đầu quá trình đồng bộ:

robocopy "\\192.168.1.100\Backup_Databases" "D:\Restore_Databases" /MIR /FFT /Z /XA:H /W:5 /R:5 /MT:32 /NP /LOG:"D:\Robocopy_Migration.log"

Giải thích chi tiết các tham số quan trọng:

  • \\192.168.1.100\Backup_Databases: Đường dẫn thư mục nguồn đã chia sẻ trên máy chủ cũ.
  • D:\Restore_Databases: Thư mục đích lưu trữ file trên máy chủ mới.
  • /MIR (Mirror): Đồng bộ hóa cấu trúc thư mục. Lệnh này sẽ sao chép toàn bộ thư mục con, đồng thời xóa bất kỳ tệp hoặc thư mục nào ở đích không còn tồn tại ở nguồn.
  • /FFT (FAT File Times): Sử dụng giả định thời gian tệp FAT thay vì NTFS. Điều này giúp tránh việc Robocopy hiểu lầm các file giống nhau là khác nhau do sự chênh lệch múi giờ hoặc sai số mili-giây giữa 2 máy chủ.
  • /Z (Restartable Mode): Cho phép tiếp tục quá trình copy từ điểm bị ngắt quãng nếu mạng bị rớt giữa chừng.
  • /XA:H: Loại bỏ các file ẩn và file hệ thống không cần thiết (System/Hidden files).
  • /W:5/R:5: Nếu gặp file lỗi hoặc bị khóa, Robocopy sẽ đợi 5 giây và thử lại tối đa 5 lần trước khi bỏ qua (mặc định của Windows là đợi 30 giây và thử lại 1 triệu lần, có thể làm lệnh bị treo mãi mãi).
  • /MT:32 (Multi-Threading): Kích hoạt chạy đa luồng với 32 luồng xử lý đồng thời, tăng tốc độ truyền tải tệp lên gấp nhiều lần.
  • /NP (No Progress): Không hiển thị tỷ lệ % tiến trình copy cho từng file trên màn hình CMD. Việc này giúp giảm tải xử lý đồ họa CMD, đẩy nhanh tốc độ copy đáng kể khi có hàng ngàn file nhỏ.
  • /LOG:"D:\Robocopy_Migration.log": Xuất toàn bộ báo cáo kết quả và nhật ký copy ra file log để bạn kiểm tra sau khi hoàn thành.

[!CAUTION] Cảnh báo về tham số /MIR:/MIR hoạt động theo cơ chế gương, nó sẽ xóa hoàn toàn các file đang có ở thư mục đích nếu chúng không tồn tại ở thư mục nguồn. Hãy đảm bảo thư mục đích là thư mục mới hoặc không chứa các dữ liệu quan trọng khác.

Mẹo chạy thử nghiệm trước khi chạy thật

Trước khi bấm chạy lệnh trên, bạn nên thêm tham số /L vào cuối câu lệnh. Tham số này biểu thị chế độ List only - Robocopy sẽ chỉ liệt kê những hành động, file nào sẽ được copy hoặc xóa mà không thực hiện ghi/xóa thật trên đĩa cứng:

robocopy "\\192.168.1.100\Backup_Databases" "D:\Restore_Databases" /MIR /FFT /Z /XA:H /W:5 /R:5 /MT:32 /NP /L

Bước 5: Quy trình giảm thiểu tối đa thời gian gián đoạn (Downtime)

Để quá trình chuyển đổi (Cut-over) diễn ra trơn tru nhất, hãy áp dụng quy trình 4 bước sau:

  1. Đồng bộ trước (Pre-sync): Chạy lệnh Robocopy trước thời điểm chuyển đổi 1-2 ngày. Lúc này 99% dữ liệu lịch sử đã được đưa sang server đích.
  2. Khóa ghi dữ liệu (Offline website/app): Đến giờ vàng chuyển đổi, đưa website cũ về trạng thái bảo trì bằng cách đặt tệp App_Offline.htm vào thư mục gốc của ứng dụng (hoặc tắt IIS/Service kết nối đến database).
  3. Sao lưu & đồng bộ lần cuối (Final Sync):
    • Chạy lại script T-SQL để tạo file backup mới nhất trên máy cũ.
    • Chạy lại lệnh Robocopy. Lần này Robocopy sẽ chạy cực kỳ nhanh (chỉ mất vài chục giây đến vài phút) vì nó chỉ copy những file backup mới sinh ra trong bước trên.
  4. Khôi phục (Restore): Tiến hành Restore cơ sở dữ liệu trên máy chủ mới và trỏ cấu hình kết nối (Connection String) của ứng dụng sang IP server mới.

Bước 6: Cách tạo 1 file Script Restore hàng loạt

Sau khi di chuyển thành công toàn bộ tệp tin .bak sang máy chủ mới bằng Robocopy, bước cuối cùng là khôi phục (Restore) chúng vào SQL Server đích. Nếu bạn có hàng chục cơ sở dữ liệu, việc thực hiện bằng giao diện SSMS sẽ cực kỳ mất thời gian.

Bạn hãy tạo một file RestoreAll.sql với nội dung tự động hóa như sau (sử dụng dữ liệu giả lập để làm mẫu):

-- Restore DB_Demo1
RESTORE DATABASE [DB_Demo1]
FROM DISK = N'C:\EAGENT\Backup_Databases\DB_Demo1_20260714_151857.bak'
WITH FILE = 1,
MOVE N'DB_Demo1' TO N'C:\EAGENT\EAGENT-DATA\EAGENT_DB_Demo1\EAGENT_DB_Demo1.mdf',
MOVE N'DB_Demo1_log' TO N'C:\EAGENT\EAGENT-DATA\EAGENT_DB_Demo1\EAGENT_DB_Demo1_1.ldf',
NOUNLOAD, REPLACE, STATS = 5;
GO
-- Restore DB_Demo2
RESTORE DATABASE [DB_Demo2]
FROM DISK = N'C:\EAGENT\Backup_Databases\DB_Demo2_20260714_151857.bak'
WITH FILE = 1,
MOVE N'DB_Demo2' TO N'C:\EAGENT\EAGENT-DATA\EAGENT_DB_Demo2\EAGENT_DB_Demo2.mdf',
MOVE N'DB_Demo2_log' TO N'C:\EAGENT\EAGENT-DATA\EAGENT_DB_Demo2\EAGENT_DB_Demo2_1.ldf',
NOUNLOAD, REPLACE, STATS = 5;
GO
-- Tiếp tục copy các khối lệnh trên cho các database còn lại...

Tại sao nên gộp các lệnh Restore vào cùng 1 file?

  • Tiết kiệm thời gian: Bạn không cần phải đóng mở file script hay thực hiện thao tác click chuột liên tục trên giao diện SSMS.
  • Kiểm soát thứ tự: Bạn biết chắc chắn database nào được restore trước, database nào sau, rất thuận tiện cho các ứng dụng có sự phụ thuộc chéo.
  • Dễ theo dõi lỗi: Nếu một lệnh bị lỗi, SQL Server sẽ dừng lại hoặc báo lỗi chi tiết ngay tại khối lệnh đó, giúp bạn biết chính xác database nào đang gặp vấn đề để xử lý ngay lập tức.

Mẹo để tạo nhanh file Script Restore hàng loạt (Automation)

Nếu bạn có tới 20-30 database như trong ảnh, đừng gõ tay từng khối lệnh. Bạn có thể dùng các mẹo sau để tạo nhanh:

  1. Sử dụng Notepad++ / VS Code:

    • Mở Notepad hoặc trình soạn thảo code của bạn.
    • Sao chép một khối lệnh mẫu phía trên.
    • Nhân bản (Duplicate) khối lệnh đó lên bằng đúng số lượng database bạn cần restore.
    • Sử dụng tính năng Find & Replace (Ctrl + H): Thay thế nhanh tên database DB_Demo1 bằng tên các database thực tế khác của bạn.
  2. Sử dụng SQL Query để sinh code tự động: Bạn cũng có thể chạy lệnh SQL sau trên Server cũ để tự động sinh ra chuỗi các câu lệnh Restore một cách chính xác nhất:

    SELECT 'RESTORE DATABASE [' + name + '] FROM DISK = N''D:\Backup_Databases\' + name + '.bak'' WITH FILE = 1, MOVE N''' + name + ''' TO N''D:\SQLData\' + name + '.mdf'', MOVE N''' + name + '_log'' TO N''D:\SQLData\' + name + '_log.ldf'', NOUNLOAD, REPLACE, STATS = 5;' + CHAR(13) + CHAR(10) + 'GO'
    FROM sys.databases
    WHERE name NOT IN ('master','model','msdb','tempdb')
  3. Sử dụng PowerShell để quét thư mục con và tự động xuất file script: Trong trường hợp thực tế, cấu trúc thư mục dữ liệu SQL Server đích có thể chứa nhiều thư mục con tương ứng cho từng database (ví dụ: C:\EAGENT\EAGENT-DATA\EAGENT_ANBINH), việc chỉ định một đường dẫn phẳng sẽ bị lỗi. Để giải quyết, bạn có thể sử dụng đoạn script PowerShell thông minh dưới đây để tự động quét thư mục con, tìm chính xác tệp .mdf, .ldf và xuất câu lệnh Restore ra tệp .txt (hoặc .sql):

    # Đường dẫn chứa các file .bak đã copy sang
    $backupPath = "C:\EAGENT\Backup_Databases"
    # Đường dẫn thư mục chứa các thư mục con (ví dụ: EAGENT_ANBINH)
    $dataRootPath = "C:\EAGENT\EAGENT-DATA"
    # Đường dẫn file kết quả
    $outputFile = "C:\EAGENT\RestoreScript.txt"
    $backups = Get-ChildItem -Path $backupPath -Filter *.bak
    $result = @()
    foreach ($file in $backups) {
    $dbName = $file.BaseName # Ví dụ: ANBINH
    # Tìm thư mục con tương ứng (ví dụ: C:\EAGENT\EAGENT-DATA\EAGENT_ANBINH)
    $subFolder = Get-ChildItem -Path $dataRootPath -Filter "EAGENT_$dbName" -Directory | Select-Object -First 1
    if ($subFolder) {
    # Tìm file .mdf và .ldf bên trong thư mục con đó
    $mdfFile = Get-ChildItem -Path $subFolder.FullName -Filter "*.mdf" | Select-Object -First 1
    $ldfFile = Get-ChildItem -Path $subFolder.FullName -Filter "*.ldf" | Select-Object -First 1
    if ($mdfFile -and $ldfFile) {
    $cmd = "RESTORE DATABASE [$dbName] FROM DISK = N'$($file.FullName)' WITH FILE = 1, MOVE N'$dbName' TO N'$($mdfFile.FullName)', MOVE N'$dbName" + "_log' TO N'$($ldfFile.FullName)', NOUNLOAD, REPLACE, STATS = 5;`r`nGO"
    $result += $cmd
    }
    }
    }
    # Xuất ra file txt
    $result | Out-File -FilePath $outputFile -Encoding utf8
    Write-Host "Đã xuất script xong tại: $outputFile"

Lưu ý quan trọng cho buổi tối "Cut-over":

  • Đường dẫn thư mục chứa dữ liệu: Hãy chắc chắn thư mục D:\SQLData\ trên máy chủ mới đã được tạo sẵn trước khi chạy script restore. Nếu thư mục này chưa tồn tại, SQL Server sẽ báo lỗi không tìm thấy đường dẫn đĩa và quá trình khôi phục sẽ thất bại.

  • Kiểm tra chính xác Logical File Name (Tránh lỗi Msg 3234): Trước khi chạy script Restore, hãy dùng lệnh RESTORE FILELISTONLY để kiểm tra chính xác tên file logic (tên trong mệnh đề MOVE N'...') của từng database.

    Nếu bạn gặp lỗi:

    Msg 3234, Level 16, State 2, Line 1
    Logical file 'DB_Demo1' is not part of database 'DB_Demo1'.

    Điều này nghĩa là tên logic lưu trong file backup khác với tên bạn chỉ định trong lệnh MOVE. Ví dụ, nhiều database trong hệ thống multi-tenant được clone từ một DB gốc tên là GOC thì tên logic của chúng vẫn sẽ là GOCGOC_log.

    Bạn hãy chạy lệnh sau để kiểm tra:

    RESTORE FILELISTONLY FROM DISK = N'D:\Backup_Databases\DB_Demo1.bak'

    Sau đó, lấy chính xác giá trị ở cột LogicalName để đưa vào mệnh đề MOVE N'LogicalName'.


FAQ - Các câu hỏi thường gặp

1. Tại sao Robocopy báo lỗi "ERROR 5 (0x00000005) Accessing Source Directory"?

Đây là lỗi phân quyền hệ thống. Bạn cần:

  • Chạy CMD/PowerShell dưới quyền Administrator (Run as Administrator).
  • Kiểm tra lại tab Security và tab Sharing trên thư mục nguồn xem tài khoản bạn đang dùng đã được cấp quyền đọc dữ liệu chưa.

2. Hai máy chủ không cùng Domain (Workgroup) thì kết nối bằng Robocopy thế nào?

Nếu hai máy chủ nằm ở hai mạng khác nhau hoặc không cùng Domain, trước khi chạy Robocopy, bạn hãy thực hiện lệnh authenticate bằng lệnh net use trên máy đích:

net use "\\192.168.1.100\Backup_Databases" "MatKhauMayCu" /user:"TenDangNhapMayCu"

Sau khi lệnh net use báo thành công, bạn có thể chạy lệnh Robocopy bình thường mà không lo bị chặn quyền truy cập.


Hy vọng bài hướng dẫn này giúp bạn xây dựng được quy trình di chuyển cơ sở dữ liệu hệ thống Windows & SQL Server một cách an toàn và chuyên nghiệp nhất!

Bạn có cần hỗ trợ viết thêm script RESTORE hàng loạt tự động cho máy chủ mới không? Hãy để lại ý kiến dưới phần bình luận nhé!

© 2026 by Coding With WanBi.
Được xây dựng bởi WanBi