Cách sao lưu toàn bộ cơ sở dữ liệu vào tệp văn bản


7

Nếu nó ngu ngốc và nó hoạt động, nó vẫn ngu ngốc.

Sự hullabaloo về GDPR khiến tôi suy nghĩ - nếu bạn phải vào các bản sao lưu của mình và sửa đổi / xóa dữ liệu, bạn sẽ làm thế nào? Bẻ khóa mở một tập tin .bak nghe có vẻ khó khăn với tôi. Nhưng thật dễ dàng để mở tệp .txt.

Tôi có thể sao lưu cơ sở dữ liệu của mình vào một tệp văn bản thay vào đó, do đó giúp xóa lịch sử ra khỏi các bản sao lưu dễ dàng hơn không?


2
Tôi nghe thấy JSON nhanh hơn 1000 nano giây.
Erik Darling

2
Dù sao, tôi thích câu hỏi này, nhưng tôi sẽ tranh giành trước khi nó biến thành một cuộc thi PowerShell. Chúc may mắn!
Erik Darling

cười lớn! cảm ơn. Tôi đã có điều này trong google drive một thời gian, muốn chia sẻ nó.
James

1) Và câu hỏi của bạn chính xác là gì? 2) "Miễn là bạn không có bất kỳ chức năng, thủ tục lưu trữ, chế độ xem, ràng buộc hoặc chỉ mục nào." đây không giống như một bản sao lưu DB tốt đối với tôi ...
Patrick Mevzek

4
@James - khi bạn muốn trả lời câu hỏi của riêng mình, điều đó hoàn toàn ổn - thậm chí còn được khuyến khích. Chỉ cần chia câu hỏi và trả lời thành hai phần. Tôi chuyển "câu trả lời" của bạn xuống phần câu trả lời.
Brent Ozar

Câu trả lời:


2

Mặc dù đây không phải là một lựa chọn tốt cho sao lưu thực tế, có một số trường hợp sử dụng để đổ bảng vào tệp văn bản. Trong bối cảnh đó, một cách tiếp cận khác để sử dụng xp_cmdshellđể gọi BCP.EXE là sử dụng Thủ tục lưu trữ DBCLulkExport SQLCLR có sẵn trong SQL # (mà tôi đã viết). Sau đó, bạn có thể sử dụng File_GZip để nén các tệp.

Sau đây là những lợi thế và bất lợi khi sử dụng DB_BulkExport so với BCP.EXE :

Ưu điểm:

  1. Không cần kích hoạt xp_cmdshell
  2. Thêm tiêu đề cột
  3. Văn bản đủ điều kiện hoặc không có trường, tất cả các trường hoặc chỉ các trường yêu cầu nó (tức là các trường không phải là số / không nhị phân). Các trường chuỗi đủ điều kiện văn bản có nghĩa là bạn có thể sử dụng một dấu phân cách trường tiêu chuẩn (chẳng hạn như dấu phẩy hoặc tab) và dấu phân cách hàng tiêu chuẩn (như CRLF hoặc LF / NL), thay vì một ký tự hoặc chuỗi ký tự mà bạn hy vọng không phải là có mặt trong bất kỳ trường chuỗi nào. Vòng loại văn bản là do người dùng định nghĩa (thường là trích dẫn kép) và trình tự thoát cho vòng loại văn bản nhúng có thể là bất cứ điều gì bạn thích (thường là trích dẫn kép, nhưng cũng có thể là dấu gạch chéo ngược).
  4. Kiểm soát BITđại diện: 1/0, T / F hoặc Đúng / Sai.
  5. (sớm) Kiểm soát SMALLDATETIME, DATETIME, DATE, TIME, DATETIME2, và DATETIMEOFFSETđịnh dạng.

Nhược điểm:

  1. Không miễn phí ( DB_BulkExportFile_GZip chỉ có sẵn trong phiên bản đầy đủ)

Xin lưu ý rằng DB_BulkExport chỉ xuất dữ liệu; nó không ghi lại cấu trúc của tập kết quả. Điều này không khác gì BCP , cũng không thực sự khác biệt so với giải pháp được cung cấp trong câu trả lời wiki cộng đồng chính cho rằng giải pháp đó bỏ qua các đối chiếu, cột được tính toán, hầu hết các tùy chọn cột, v.v.

Một tùy chọn khác cho SQL Server, được đề cập bởi Kin , là mssql-scripter . Đây là một công cụ dựa trên Python miễn phí / mã nguồn mở, đa nền tảng. Tôi chưa sử dụng nó, nhưng nó dường như xuất các câu lệnh DDL và / hoặc DML có thể được thực thi để tạo lại dữ liệu và / hoặc lược đồ (bảng, ràng buộc, v.v.). Nó dường như chỉ xuất dữ liệu dưới dạng các INSERTcâu lệnh thay vì các trường được phân tách. Trông khá thú vị, nhưng vui lòng xem lại " Các vấn đề " để đảm bảo rằng không có bất kỳ điều gì sẽ ảnh hưởng đến việc sử dụng của bạn.


Ngoài ra, mặc dù câu hỏi này (và câu trả lời wiki cộng đồng chính) đề cập đến SQL Server, các vấn đề xung quanh GDPR không dành riêng cho SQL Server. Vì vậy, chỉ cần nghĩ rằng tôi sẽ đề cập rằng khả năng xuất các bảng (và thậm chí cả lược đồ, v.v.) có sẵn cho MySQL trong hai tiện ích sau đi kèm với nó:

Điều tương tự có thể được thực hiện trong PostgreSQL bằng hai tiện ích sau đi kèm với nó:

Đối với Oracle, vui lòng xem các tài nguyên sau mà tôi tin rằng ít nhất sẽ giúp bạn rất gần, nếu không hoàn toàn tương đương (nhờ Michael Kutz đã chỉ cho tôi đi đúng hướng):

Tôi không chắc chắn nếu các tiện ích tương tự đi kèm với DB2.


Bạn nên thêm mssql-cli
Kin Shah

@Kin Cảm ơn lời đề nghị. Tuy nhiên, công cụ đó chỉ là một công cụ truy vấn và dường như không phải là một tùy chọn khả thi để xuất dữ liệu sang các tệp csv / tsv. Trừ khi có một phần tài liệu mà tôi không thấy, nhưng theo như tôi có thể nói đó chỉ là một công cụ truy vấn tương tác.
Solomon Rutzky

Xấu của tôi .. Tôi có nghĩa là mssql-scripter .. github.com/Microsoft/mssql-scripter .. giống như tiện ích mysqldump.
Kin Shah

@Kin À, ok. Tôi đã xem xét dự án đó và thêm thông tin vào câu trả lời của tôi. Cảm ơn bạn đã đề cập đến nó :-)
Solomon Rutzky

Đối với Oracle, SQL*Plus12c + được thêm vào SET MARKUP CSV. Tương tự cho SQLcl. Tôi chỉ không biết nếu nó có thể thực hiện vòng lặp được yêu cầu cho mỗi bảng. Đang tải là SQL*Loader.
Michael Kutz

4

Sau đây không phải là một giải pháp sao lưu tốt. Trừ khi bạn nghỉ việc và cảm thấy muốn chơi khăm sếp trên đường ra khỏi cửa, bạn không nên sử dụng nó. Nhưng tôi đã học được một vài điều và vui vẻ viết nó, hy vọng những người khác cũng sẽ như vậy. Chúng tôi sẽ sử dụng một số khái niệm ETL có thể thực sự hữu ích trong các trường hợp khác. Các kịch bản đầy đủ ở phía dưới. Đây là những gì chúng ta sẽ làm:

Viết Lược đồ vào bảng riêng
Viết mỗi bảng trong cơ sở dữ liệu vào tệp văn bản có tên động của chính nó
Tạo lại Lược đồ cho DB mới từ tệp văn bản
Tạo lại & Hàng loạt Chèn từng bảng từ tệp văn bản của nó

Trước khi chúng tôi bắt đầu: Để thực hiện toàn bộ DB, bạn sẽ cần vài trăm GB dung lượng lưu trữ. Nếu bạn quá gà, bạn có thể đưa '1000 tập lệnh hàng đầu vào tập lệnh để giới hạn kích thước của các tệp .txt, sau đó bạn sẽ không phải giải thích với sếp về cách bạn điền vào C: \

Kích hoạt xp_cmdshell - giải thích tại đây:

https://blog.sqlauthority.com/2007/04/26/sql-server-enable-xp_cmdshell-USE-sp_ thông minh /

  1. Viết lược đồ vào một tệp văn bản

Chúng tôi sẽ kiểm tra xem bảng đã tồn tại chưa (Nếu chúng tôi đã chạy tập lệnh trước đó). Mỗi lần thả bàn sẽ dễ dàng hơn.

    if exists (select name from sys.tables st with (Nolock) where name = 'HeaderTable')

    begin
    drop table HeaderTable
    end

    SELECT
        st.name, sc.name 'Column_Name', t.Name 'Data_type',sc.max_length 'Max_Length',
        sc.precision, sc.scale, sc.is_nullable
        into HeaderTable
        FROM    
        sys.tables st
        inner join sys.columns sc on sc.object_id = st.object_id
        INNER JOIN sys.types t ON sc.user_type_id = t.user_type_id

Bây giờ, nếu bạn chọn nhanh * từ HeaderTable, bạn sẽ thấy mọi bảng, mọi cột, kiểu dữ liệu và max_length - mọi thứ chúng ta sẽ cần để tạo lại nó.

  1. Viết mỗi bảng trong cơ sở dữ liệu vào tệp văn bản có tên động

Đây là nơi nó bắt đầu trở nên mát mẻ. Chúng ta sẽ sử dụng một con trỏ để lặp qua sys.tables và kết xuất từng con vào .txt của riêng nó.

Chúng ta sẽ sử dụng một loạt các biến:

@table đang đi vào con trỏ. Nó sẽ giữ tên của mỗi bảng khi chúng ta đi.

@Database, @filepath, @filename, @filetype đều sẽ được sử dụng để xây dựng một tập hợp các câu lệnh SQL động.

@sql sẽ giữ các lệnh SQL cuối cùng của chúng tôi, để đặt vào sp_executesql.

Mọi thứ có một chút khó khăn với các dấu phân cách và dấu kết thúc hàng. Nếu bạn sử dụng mặc định của | và / r, bạn sẽ có một khoảng thời gian khó khăn thực sự với bảng Nhận xét. Chúng ta sẽ phải sử dụng thứ mà chúng ta biết không được sử dụng ở bất cứ đâu trong cơ sở dữ liệu StackOverflow. Bạn có thể sử dụng newid (), tàu tên lửa và đôi mắt lờ mờ hoặc bạn có thể sử dụng vần điệu yêu thích của bạn. Bất cứ điều gì, miễn là nó không có trên StackOverflow.

Đây là kịch bản:

    declare @table varchar(255),
    @Database varchar(255),
    @filepath varchar(255),
    @filename varchar(255),
    @filetype varchar(255),
    @sql nvarchar(max),
    @delimiter varchar(255),
    @rowterminator varchar(255)

    set @Database = 'StackOverflow'
    set @filepath = 'C:\Data\' -- fix pretty-print mishandling of not-truly escaped ' 
    set @filetype = '.txt'
    set @delimiter = 'WhimmyWhammyWozzle'
    set @rowterminator = 'WubaLubaDubDub'

    declare c cursor local for

    select name from sys.tables with (Nolock)

    open c

    fetch from c into @table

    while @@FETCH_STATUS = 0
    begin

    SET @filename = @table

    --output to txt
    set @sql = N'declare @bcp varchar(4000)
    set @bcp = ''bcp " select top 10000 * from ' + @table + ' " queryout '
    + @filepath +  @filename + @filetype + ' -t "' + @delimiter + '" -r "'
     + @rowterminator + '" -c -T -d ' + @Database + '''
    print @bcp

    EXECUTE master.dbo.xp_cmdshell @BCP'

    print @sql
    --exec sp_executesql @sql

    fetch next from c into @table
    end

    close c

    deallocate c

Lưu ý rằng tôi đã đặt sự an toàn trong trường hợp bạn vừa dán nó vào và nhấn F5. Không phải ai cũng sẽ làm điều đó, phải không? exec sp_executesql @sql sẽ không chạy cho đến khi bạn xóa các bình luận viên. Tôi cũng đã bao gồm 10000 đầu.

Đi đến đường dẫn tệp của bạn và bạn sẽ thấy một loạt các tệp văn bản.

Đi trước và mở một lên và thay đổi một số dữ liệu. Nếu bạn nghĩ việc mở chúng theo cách thủ công là dành cho nông dân, bạn có thể sử dụng Fart.exe để tìm và thay thế trong tất cả các tệp văn bản.

  1. Viết lại tiêu đề

Đi trước và tạo một cơ sở dữ liệu mới.

Chúng tôi sẽ mã hóa giải trí của bảng tiêu đề và sử dụng nó để xây dựng lại phần còn lại.

khôi phục tiêu đề:

    if exists (select name from sys.tables where name = 'HeaderTable')
    begin
    drop table HeaderTable
    end

    create table HeaderTable
    (Table_Name varchar(255),
    Column_Name  varchar(255),
    Data_type  varchar(255),
    Max_Length  varchar(255),
    precision  varchar(255),
    scale varchar(255),
    is_nullable  varchar(255))

Và bây giờ, chúng tôi sẽ chèn hàng loạt Schema của chúng tôi vào HeaderTable:

    set @sql = 'BULK INSERT HeaderTable FROM ''' + @filepath + 'HeaderTable'+ @filetype + ''' WITH (FIELDTERMINATOR = '''
     + @delimiter + ''', ROWTERMINATOR = ''' + @rowterminator + ''')'
    print @sql
    --exec sp_executesql @sql

    We will have to tidy it up a bit, to make the next steps easier:

    update HeaderTable
    set Max_Length = 'max'
    where Max_length = -1

    update HeaderTable
    set Max_Length = '(' + Max_Length + ')'

    update HeaderTable
    set Max_Length = ''
    where Data_type in ( 'int', 'bigint', 'smallint', 'tinyint',
    'date','datetime', 'uniqueidentifier', 'sysname', 'bit')
  1. Tạo lại & hàng loạt Chèn từng bảng từ tệp văn bản của nó

Và đây là nơi mọi thứ trở nên mát mẻ trở lại. Chúng ta sẽ lặp qua HeaderTable và tạo lại mỗi bảng, nối câu lệnh Tạo với STUFF (). Đừng hỏi tôi công cụ () hoạt động như thế nào - một đồng nghiệp cũ (Mike Ignatoski) đã đưa nó cho tôi nhiều năm trước. Các nguồn đáng tin cậy nói rằng ban đầu anh ta đã nhận được nó từ một số người tên là Solomon.

    declare @table varchar(255),
    @column_string nvarchar(max),
    @sql nvarchar(max),
    @string nvarchar(max),
    @filepath varchar(255),
    @filename varchar(255),
    @filetype varchar(255),
    @sql nvarchar(max),
    @delimiter varchar(255),
    @rowterminator varchar(255)


    set @filepath = 'C:\Data\' -- fix pretty-print mishandling of not-truly escaped '
    set @filetype = '.txt'
    set @delimiter = 'WhimmyWhammyWozzle'
    set @rowterminator = 'WubaLubaDubDub'

    declare c cursor local for

    select distinct Table_Name from HeaderTable
    where Table_Name != 'HeaderTable'

    open c
    fetch from c into @table

    while @@FETCH_STATUS = 0
    begin

    set @string = null

    set @string = (select stuff( (
    select ', ' + Column_Name + ' ' + Data_type  + Max_Length from HeaderTable
    where Table_Name = @table
    for xml path ('')),1,2,''))

    print @string

    set @sql =  ' if not exists (select top 1 name from sys.tables where name = ''' + @table + ''') begin
    create table ' + @table + ' (' + @string + ') end'

    print @sql
    exec sp_executesql @sql

    --populate the table
    set @sql = 'BULK INSERT ' + @table + ' FROM ''' + @filepath + @table + '.txt'' WITH (FIELDTERMINATOR = '''
    + @delimiter  + ''', ROWTERMINATOR = ''' + @rowterminator + ''' )'

    print @sql
    exec sp_executesql @sql

    fetch next from c into @table

    end

    close c

    deallocate c

Và ở đó bạn có nó - cơ sở dữ liệu của bạn đã được khôi phục từ các tệp văn bản. Bạn có thể ký gửi tệp .bak vào đống rác lịch sử! Miễn là bạn không có bất kỳ chức năng, thủ tục lưu trữ, chế độ xem, ràng buộc hoặc chỉ mục nào.

Dưới đây là các kịch bản đầy đủ: Bad Idea Jeans Backup:

    declare @table varchar(255),
    @Database varchar(255),
    @filepath varchar(255),
    @filename varchar(255),
    @filetype varchar(255),
    @sql nvarchar(max),
    @delimiter varchar(255),
    @rowterminator varchar(255)

    set @Database = 'StackOverflow'
    set @filepath = 'C:\Data\' -- fix pretty-print mishandling of not-truly escaped '
    set @filetype = '.txt'
    set @delimiter = 'WhimmyWhammyWozzle'
    set @rowterminator = 'WubaLubaDubDub'

    --create database header

    if exists (select name from sys.tables st with (Nolock) where name = 'HeaderTable')

    begin
    drop table HeaderTable
    end

    SELECT
        st.name, sc.name 'Column_Name', t.Name 'Data_type',sc.max_length 'Max_Length',
        sc.precision, sc.scale, sc.is_nullable
        into HeaderTable
        FROM    
        sys.tables st
        inner join sys.columns sc on sc.object_id = st.object_id
        INNER JOIN sys.types t ON sc.user_type_id = t.user_type_id

        select * from HeaderTable

    declare c cursor local for

    select name from sys.tables so with (Nolock)

    open c

    fetch from c into @table

    while @@FETCH_STATUS = 0
    begin

    SET @filename = @table


    --output to txt
    set @sql = N'declare @bcp varchar(4000)
    set @bcp = ''bcp " select top 10000 * from ' + @table + ' " queryout '
    + @filepath +  @filename + @filetype + ' -t "' + @delimiter + '" -r "'
     + @rowterminator + '" -c -T -d ' + @Database + '''
    print @bcp

    EXECUTE master.dbo.xp_cmdshell @BCP'

    print @sql
     exec sp_executesql @sql

    fetch next from c into @table
    end

    close c

    deallocate c

Khôi phục ý tưởng quần jean xấu:

declare @table varchar(255),
    @column_string nvarchar(max),
    @sql nvarchar(max),
    @string nvarchar(max),
    @filepath varchar(255),
    @filename varchar(255),
    @filetype varchar(255),
    @delimiter varchar(255),
    @rowterminator varchar(255)


    set @filepath = 'C:\Data\' -- fix pretty-print mishandling of not-truly escaped '
    set @filetype = '.txt'
    set @delimiter = 'WhimmyWhammyWozzle'
    set @rowterminator = 'WubaLubaDubDub'

    --restore header
    if exists (select name from sys.tables where name = 'HeaderTable')
    begin
    drop table HeaderTable
    end

    create table HeaderTable
    (Table_Name varchar(255),
    Column_Name  varchar(255),
    Data_type  varchar(255),
    Max_Length  varchar(255),
    precision  varchar(255),
    scale varchar(255),
    is_nullable  varchar(255))

    set @sql = 'BULK INSERT HeaderTable FROM ''' + @filepath + 'HeaderTable'+ @filetype + ''' WITH (FIELDTERMINATOR = '''
     + @delimiter + ''', ROWTERMINATOR = ''' + @rowterminator + ''')'
    print @sql
    exec sp_executesql @sql

    --make some changes so that we can concatenate our create tables more easily
    update HeaderTable
    set Max_Length = 'max'
    where Max_length = -1

    update HeaderTable
    set Max_Length = '(' + Max_Length + ')'

    update HeaderTable
    set Max_Length = ''
    where Data_type in ( 'int', 'bigint', 'smallint', 'tinyint',
    'date','datetime', 'uniqueidentifier', 'sysname', 'bit')

    select * from HeaderTable

    --restore DB

    declare c cursor local for

    select distinct name from sys.columns
    where name != 'HeaderTable'

    open c
    fetch from c into @table

    while @@FETCH_STATUS = 0
    begin

    set @string = null

    set @string = (select stuff( (
    select ', ' + Column_Name + ' ' + Data_type  + Max_Length from HeaderTable
    where name = @table
    for xml path ('')),1,2,''))

    print @string

    set @sql =  ' if not exists (select top 1 name from sys.tables where name = ''' + @table + ''') begin
    create table ' + @table + ' (' + @string + ') end'

    print @sql
    --exec sp_executesql @sql

    set @sql = 'BULK INSERT ' + @table + ' FROM ' + '' + @filepath + @table + '.txt'' WITH (FIELDTERMINATOR = '''
    + @delimiter  + ''', ROWTERMINATOR = ''' + @rowterminator + ''' )'

    print @sql
    --exec sp_executesql @sql

    fetch next from c into @table

    end

    close c

    deallocate c

1
Mặc dù điều này không bắt đầu với "Đây không phải là một giải pháp tốt", nhưng cần có thêm cảnh báo trong trường hợp ai đó cố gắng sử dụng mã này do các vấn đề sau: 1) không xử lý đúng nhiều kiểu dữ liệu: DECIMAL, SQL_VariANT, XML, CLR , Vân vân; 2) không xử lý Lược đồ; 3) không đặt đối chiếu; 4) không xử lý các cột được tính toán; 5) không xử lý các tùy chọn cột: ROWGUID, SPARSE, IDENTITY, v.v; 6) mất dữ liệu chuỗi có thể từ việc buộc tất cả các trang mã và Unicode vào trang mã mặc định của hệ thống; 8) Lỗi tiềm năng chính: các bảng có thể được tạo lại bằng các cột theo thứ tự khác với bảng gốc; 9) nhiều hơn?
Solomon Rutzky
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.