I use sql server and have a huge database that partitioned by date in multiple file groups.
the database filegroups is PRIMARY, FG2010, FG2011, FG2012, FG2013, and FG2014, that FG2010, FG2011, FG2012 and FG2013 is readonly.
Now, the backup scenario is:
each Friday get a full backup at 2:00 AM
each day on week except Friday get a differential backup at 2:00 AM
I want to change this scenario to:
get a full backup of database(One Time)
get a full backup of PRIMARY and FG2014 each Friday at 2:00 AM
get a differential backup of PRIMARY and FG2014 each day except Friday at 2:00 AM
Questions 1: Can I have this scenario?
I have a recovery plan too. each day I copy backup file to another server automatically by job and then restore it, in order to have recovery test plan and also use restored database to developer and tester users.
I want to have following scenario for recovery plan:
restore full backup of database.
restore last full backup of PRIMARY and FG2014.
restore last differential backup of PRIMARY and FG2014.
Question 2: can I have this scenario to recovery plan?
Question 3: can I have better scenario to backup and restore?
Please answer my question with TSQL query.
Q1. Yes, you can. You would also need to be taking regular transaction log backups.
Q2. Yes, this would also work for a recovery strategy, again you need to be taking transaction log backups.
Q3. As you are using the backups to create a development database, I would stick with this. There are options such as log shipping but I would not implement them to keep a development database updated from production.
I have written some demo scripts which you can use to run through the scenario you suggested on your local instance.
The scripts will:-
Create a test database, with multiple filegroups which some are read only.
Create a development database from a backup of the test database.
Take filegroup backups of the test database and restore over the development database
Please have a look and run through the scripts. Let me know if you have any questions.
Before you use the scripts, just make sure that you have the following filepaths on your computer:-
C:\SQLServer\Data
C:\SQLServer\Logs
C:\SQLServer\Backups
The version of SQL Server I use is 2012 SP2 CU2 Developer Edition.
First create the test database:-
CREATE DATABASE [FGRestoreTEST]
ON PRIMARY
( NAME = N'FGRestoreTEST', FILENAME = N'C:\SQLServer\Data\FGRestoreTEST.mdf' , SIZE = 5120KB , MAXSIZE = UNLIMITED, FILEGROWTH = 1024KB ),
FILEGROUP [FG2010]
( NAME = N'FG2010', FILENAME = N'C:\SQLServer\Data\FG2010.ndf' , SIZE = 5120KB , MAXSIZE = UNLIMITED, FILEGROWTH = 1024KB ),
FILEGROUP [FG2011]
( NAME = N'FG2011', FILENAME = N'C:\SQLServer\Data\FG2011.ndf' , SIZE = 5120KB , MAXSIZE = UNLIMITED, FILEGROWTH = 1024KB ),
FILEGROUP [FG2012]
( NAME = N'FG2012', FILENAME = N'C:\SQLServer\Data\FG2012.ndf' , SIZE = 5120KB , MAXSIZE = UNLIMITED, FILEGROWTH = 1024KB ),
FILEGROUP [FG2013]
( NAME = N'FG2013', FILENAME = N'C:\SQLServer\Data\FG2013.ndf' , SIZE = 5120KB , MAXSIZE = UNLIMITED, FILEGROWTH = 1024KB ),
FILEGROUP [FG2014]
( NAME = N'FG2014', FILENAME = N'C:\SQLServer\Data\FG2014.ndf' , SIZE = 5120KB , MAXSIZE = UNLIMITED, FILEGROWTH = 1024KB )
LOG ON
( NAME = N'FGRestoreTEST_log', FILENAME = N'C:\SQLServer\Logs\FGRestoreTEST_log.ldf' , SIZE = 2048KB , MAXSIZE = 2048GB , FILEGROWTH = 10%)
GO
Then create tables in each of the filegroups:-
USE [FGRestoreTEST];
GO
CREATE TABLE [PRIMARY_TABLE]
(ID INT,
NAME CHAR(4)) ON [PRIMARY];
CREATE TABLE [FG2010_TABLE]
(ID INT,
NAME CHAR(4)) ON [FG2010];
CREATE TABLE [FG2011_TABLE]
(ID INT,
NAME CHAR(4)) ON [FG2011];
CREATE TABLE [FG2012_TABLE]
(ID INT,
NAME CHAR(4)) ON [FG2012];
CREATE TABLE [FG2013_TABLE]
(ID INT,
NAME CHAR(4)) ON [FG2013];
CREATE TABLE [FG2014_TABLE]
(ID INT,
NAME CHAR(4)) ON [FG2014];
GO
Insert data (100 rows) into each of the tables:-
INSERT INTO [PRIMARY_TABLE]
SELECT 1, 'TEST'
GO 100
INSERT INTO [FG2010_TABLE]
SELECT 1, 'TEST'
GO 100
INSERT INTO [FG2011_TABLE]
SELECT 1, 'TEST'
GO 100
INSERT INTO [FG2012_TABLE]
SELECT 1, 'TEST'
GO 100
INSERT INTO [FG2013_TABLE]
SELECT 1, 'TEST'
GO 100
INSERT INTO [FG2014_TABLE]
SELECT 1, 'TEST'
GO 100
Then set certain filegroups to read only:-
ALTER DATABASE [FGRestoreTEST]
MODIFY FILEGROUP [FG2010] READ_ONLY;
ALTER DATABASE [FGRestoreTEST]
MODIFY FILEGROUP [FG2011] READ_ONLY;
ALTER DATABASE [FGRestoreTEST]
MODIFY FILEGROUP [FG2012] READ_ONLY;
ALTER DATABASE [FGRestoreTEST]
MODIFY FILEGROUP [FG2013] READ_ONLY;
GO
Take a full backup:-
USE [master];
GO
BACKUP DATABASE [FGRestoreTEST]
TO DISK = N'C:\SQLServer\Backups\FGRestoreTEST.BAK';
GO
Then create a development database from the full backup (this will be used to restore the filegroup backups that will be taken further next):-
RESTORE DATABASE [FGRestoreTEST_Dev]
FROM DISK = N'C:\SQLServer\Backups\FGRestoreTEST.BAK' WITH
MOVE 'FGRestoreTEST' TO 'C:\SQLServer\Data\FGRestoreTEST_Dev.mdf',
MOVE 'FG2010' TO 'C:\SQLServer\Data\FG2010_Dev.ndf',
MOVE 'FG2011' TO 'C:\SQLServer\Data\FG2011_Dev.ndf',
MOVE 'FG2012' TO 'C:\SQLServer\Data\FG2012_Dev.ndf',
MOVE 'FG2013' TO 'C:\SQLServer\Data\FG2013_Dev.ndf',
MOVE 'FG2014' TO 'C:\SQLServer\Data\FG2014_Dev.ndf',
MOVE 'FGRestoreTEST_log' TO 'C:\SQLServer\Logs\FGRestoreTEST_Dev_log.ldf',
RECOVERY,STATS=5;
GO
Take backups of each of the filegroups:-
--http://msdn.microsoft.com/en-us/library/ms189906.aspx
BACKUP DATABASE [FGRestoreTEST]
FILEGROUP = 'PRIMARY'
TO DISK = 'C:\SQLServer\Backups\FGRestoreTEST_PRIMARY.bak';
BACKUP DATABASE [FGRestoreTEST]
FILEGROUP = 'FG2010'
TO DISK = 'C:\SQLServer\Backups\FGRestoreTEST_FG2010.bak';
BACKUP DATABASE [FGRestoreTEST]
FILEGROUP = 'FG2011'
TO DISK = 'C:\SQLServer\Backups\FGRestoreTEST_FG2011.bak';
BACKUP DATABASE [FGRestoreTEST]
FILEGROUP = 'FG2012'
TO DISK = 'C:\SQLServer\Backups\FGRestoreTEST_FG2012.bak';
BACKUP DATABASE [FGRestoreTEST]
FILEGROUP = 'FG2013'
TO DISK = 'C:\SQLServer\Backups\FGRestoreTEST_G2013.bak';
BACKUP DATABASE [FGRestoreTEST]
FILEGROUP = 'FG2014'
TO DISK = 'C:\SQLServer\Backups\FGRestoreTEST_FG2014.bak';
GO
Now we will modify data in the Primary & FG2014 filegroups:-
USE [FGRestoreTEST];
GO
INSERT INTO [PRIMARY_TABLE]
SELECT 1, 'TEST'
GO 100
TRUNCATE TABLE [FG2014_TABLE];
GO
Take differential backups of the filegroups:-
BACKUP DATABASE [FGRestoreTest]
FILEGROUP = 'PRIMARY'
TO DISK = 'C:\SQLServer\Backups\FGRestoreTest_PRIMARYDIFF.bak'
WITH DIFFERENTIAL;
BACKUP DATABASE [FGRestoreTest]
FILEGROUP = 'FG2014'
TO DISK = 'C:\SQLServer\Backups\FGRestoreTest_FG2014DIFF.bak'
WITH DIFFERENTIAL;
GO
Again, modify the data:-
USE [FGRestoreTEST];
GO
INSERT INTO [PRIMARY_TABLE]
SELECT 1, 'TEST'
GO 100
INSERT INTO [FG2014_TABLE]
SELECT 1, 'NEW'
GO 300
Backup the transaction log (you will probably have more than one of these in a real life environment, but for demo purposes I'm just taking one):-
USE [master];
GO
BACKUP LOG [FGRestoreTEST]
TO DISK = 'C:\SQLServer\Backups\FGRestoreTest_LogBackup.trn';
GO
OK, now we can restore the development database. First we take a Tail Log backup, putting the database into recovery. Note:- we will not use this backup!
BACKUP LOG [FGRestoreTEST_Dev]
TO DISK = 'C:\SQLServer\Backups\FGRestoreTest_TailLogBackup.trn'
WITH NORECOVERY;
GO
Now we can restore the full backups of the read-write filegroups:-
--http://msdn.microsoft.com/en-us/library/aa337540.aspx
--Restore primary filegroup
RESTORE DATABASE [FGRestoreTEST_Dev]
FILEGROUP = 'PRIMARY'
FROM DISK = 'C:\SQLServer\Backups\FGRestoreTEST_PRIMARY.bak'
WITH NORECOVERY;
GO
--Restore FG2014 filegroup
RESTORE DATABASE [FGRestoreTEST_Dev]
FILEGROUP = 'FG2014'
FROM DISK = 'C:\SQLServer\Backups\FGRestoreTEST_FG2014.bak'
WITH NORECOVERY;
GO
Then the differential backups:-
--Restore PRIMARY differential backup
RESTORE DATABASE [FGRestoreTEST_Dev]
FILEGROUP = 'PRIMARY'
FROM DISK = 'C:\SQLServer\Backups\FGRestoreTest_PRIMARYDIFF.bak'
WITH NORECOVERY;
GO
--Restore FG2014 differential backup
RESTORE DATABASE [FGRestoreTEST_Dev]
FILEGROUP = 'FG2014'
FROM DISK = 'C:\SQLServer\Backups\FGRestoreTest_FG2014DIFF.bak'
WITH NORECOVERY;
GO
Then the transaction log backup:-
RESTORE LOG [FGRestoreTEST_Dev]
FROM DISK = 'C:\SQLServer\Backups\FGRestoreTest_LogBackup.trn'
WITH NORECOVERY;
GO
Finally, the database can be recovered:-
RESTORE DATABASE [FGRestoreTest_DEV] WITH RECOVERY;
GO
And as a final test, check the data:-
USE [FGRestoreTEST_Dev];
GO
SELECT COUNT(*) AS [PRIMARY_TABLE]
FROM [PRIMARY_TABLE];
SELECT COUNT(*) AS [FG2010_TABLE]
FROM [FG2010_TABLE];
SELECT COUNT(*) AS [FG2011_TABLE]
FROM [FG2011_TABLE];
SELECT COUNT(*) AS [FG2012_TABLE]
FROM [FG2012_TABLE];
SELECT COUNT(*) AS [FG2013_TABLE]
FROM [FG2013_TABLE];
SELECT COUNT(*) AS [FG2014_TABLE]
FROM [FG2014_TABLE];
SELECT TOP (1) *
FROM [FG2014_TABLE];
GO
So, from the data changes made, we would expect to see 300 records in the PRIMARY & FG2014 filegroups, 100 in the rest and the all the values in the name column in the FG2014 set as 'NEW'.
A1: Yes you can have this scenario however, the backup strategy does not provide an ongoing way to recover FG2010 through 2013 should there be a need to, as only a one time FULL database backup exists.
A2: Yes, with some tweaking. What you are wishing to implement is called a Piecemeal Restore and the bulk of the required instruction for the method required can be found in the Books Online Example: Piecemeal Restore of Only Some Filegroups.
The key difference is you will be restoring over a previously restored full database backup, rather than a live database that has experienced an issue with specific filegroups.
You should be easily able to create a test case/proof of concept for your needs swiftly by using the above reference. If you get stuck, add your attempt/code to question and the good community chaps here will provide guidance. With a little effort from you and some direction from the community, I'm sure you can answer your own question. Teach a man to fish and all that........
Related
I have set up a database in SQL and I am running a program which downloads and populates the database. This was working for me when I first set up the database but it now does not work. The error I get is the following:
Could not allocate a new page for database 'FDSLoaderDB' because of
insufficient disk space in filegroup 'PRIMARY'. Create the necessary
space by dropping objects in the filegroup, adding additional files to
the filegroup, or setting autogrowth on for existing files in the
filegroup.
I have looked online on how to resolve this issue but non of the suggested solutions work. I have tried to update the file sizes in the figure below.
I did this by running the following code:
USE FDSLoaderDB
Go
SELECT growth*8 as filegrowth_KB FROM sys.database_files Where name = N'FDSLoaderDB_log'
Go
USE master
Go
ALTER DATABASE FDSLoaderDB MODIFY FILE (NAME = N'FDSLoaderDB_log', FILEGROWTH = 5GB, MAXSIZE = UNLIMITED) -- adjust size here
Go
USE FDSLoaderDB
Go
SELECT growth*8 as filegrowth_KB FROM sys.database_files Where name = N'FDSLoaderDB_log'
Go
USE FDSLoaderDB
Go
SELECT growth*8 as filegrowth_KB FROM sys.database_files Where name = N'FDSLoaderDB'
Go
USE master
Go
ALTER DATABASE FDSLoaderDB MODIFY FILE (NAME = N'FDSLoaderDB', FILEGROWTH = 5GB, MAXSIZE = UNLIMITED) -- adjust size here
Go
USE FDSLoaderDB
Go
SELECT growth*8 as filegrowth_KB FROM sys.database_files Where name = N'FDSLoaderDB'
Go
USE master;
Go
ALTER DATABASE tempdb
MODIFY FILE (NAME = N'tempdev', SIZE = 60GB, FILEGROWTH = 5GB, MAXSIZE = UNLIMITED)
USE master;
Go
ALTER DATABASE tempdb
MODIFY FILE (NAME = N'templog', SIZE = 20GB, FILEGROWTH = 5GB, MAXSIZE = UNLIMITED);
Go
I re-run the program to re-populate the data and I get the same errors.
The log file of the program populating the database is in the following link.
EDIT:
My congratulations.
Seems your database is bigger than 10GB and you use SQL Server express Edition which has limit 10 GB per database
https://learn.microsoft.com/en-us/sql/sql-server/editions-and-components-of-sql-server-2017?view=sql-server-ver15
I created a test database "StoredData" with a single table:
CREATE DATABASE StoredData
ON PRIMARY
( NAME = N'StoredData', FILENAME = N'C:\Program Files\Microsoft SQL Server\MSSQL14.MSSQLSERVER\MSSQL\DATA\StoredData.mdf')
LOG ON
( NAME = N'StoredData_log', FILENAME = N'C:\Program Files\Microsoft SQL Server\MSSQL14.MSSQLSERVER\MSSQL\DATA\StoredData_log.ldf')
GO
ALTER DATABASE [StoredData] SET RECOVERY FULL
GO
USE StoredData
GO
CREATE TABLE dbo.Users
(
Id INT NOT NULL,
Name NVARCHAR(50) NOT NULL
)
Then I inserted 3 records into that table:
INSERT INTO dbo.Users (Id, Name)
VALUES (1, 'John'),
(2, 'Giovanni'),
(3, 'Anna')
After that I run this query to have some active transactions:
DECLARE #i INT = 0;
WHILE #i < 1000
BEGIN
IF(#i%10 = 0) BEGIN TRAN
INSERT INTO dbo.Users
SELECT TOP 10 * FROM dbo.Users
WAITFOR DELAY '00:00:01';
IF(#i%10 = 9) COMMIT
SET #i = #i+1
END
During the last query execution I'm trying to do full database backup:
BACKUP DATABASE StoredData
TO DISK = N'C:\Program Files\Microsoft SQL Server\MSSQL14.MSSQLSERVER\MSSQL\Backup\StoredData_FullRecovery_Uncompressed.bak'
WITH FORMAT, NO_COMPRESSION
Then I'm looking into the backup file content:
RESTORE FILELISTONLY
FROM DISK = 'C:\Program Files\Microsoft SQL Server\MSSQL14.MSSQLSERVER\MSSQL\Backup\StoredData_FullRecovery_Uncompressed.bak'
And getting zero log file inside backup:
LogicalName: StoredData_log
BackupSizeInBytes: 0
You are looking at the wrong column for size of your files inside the backup file. you should look at the SIZE column, instead of BackupSizeInBytes. BackupSizeInBytes will tell you the size of your backup file it self(uncompressed size).
lets take a look at this picture:
This piece of information tells us that if we want to restore the StoredData_FullRecovery_Uncompressed.bak file, we will end up with 2 files. StoredData which will need about 8 MB space and the other StoredData_log which will need again 8 MB space.
lets clarify with an example:
suppose that I have created a database like below:
CREATE DATABASE [TestBackUp]
ON PRIMARY
( NAME = N'TestBackUp', FILENAME = N'<path>\TestBackUp.mdf' , SIZE = 8192KB , FILEGROWTH = 65536KB )
LOG ON
( NAME = N'TestBackUp_log', FILENAME = N'<path>\TestBackUp_log.ldf' , SIZE = 81920KB , FILEGROWTH = 65536KB )
I have added a mdf file with 8MB initial size and a ldf file with 80MB initial size.
Then I perform a full backup from database:
BACKUP DATABASE TestBackUp
TO DISK = N'<path>\TestBackUp.bak'
WITH FORMAT, NO_COMPRESSION
now lets see this file size on disk:
It has about 2.67MB size on disk. Now lets run the RESTORE FILELISTONLY command:
RESTORE FILELISTONLY
FROM DISK = N'<path>\TestBackUp.bak'
and lets see the output:
As we can see, our backup file has 2555904 bytes size on disk(BackupSizeInBytes) and if we restore this backup file we will end up with two files, one will have 8MB size and the other will have 80MB size on disk after restoring the database(Size)
Now lets create a table and populate some data inside it, and analyze the whole process again:
USE TestBackUp
GO
CREATE TABLE t(col1 NCHAR(2000), col2 NCHAR(2000))
GO
INSERT INTO t VALUES('a', 'b')
GO 10000
lets see the RESTORE FILELISTONLY command's output again:
The output tells us that we have a backup file which has about 84MB size on disk. After restoring we will end up with two files, one mdf file with 142606336 bytes size on disk and one ldf file with 150994944 bytes size on disk. below you can see the files information and size on disk too. you can see that size of these files are same as the value of size column in RESTORE FILELISTONLY command.
Read more at: https://blog.sqlauthority.com/2020/02/23/how-to-forecast-the-size-of-restore-of-backup-in-sql-server-interview-question-of-the-week-265/
From Microsoft Understanding Minimally Logged Operations
Minimally logged operations are available only if your database is in bulk-logged or simple recovery mode.
The code below explains what I saw.
use master;
IF DB_ID('RecoveryETL') IS NOT NULL
BEGIN
ALTER DATABASE RecoveryETL SET SINGLE_USER WITH ROLLBACK IMMEDIATE
DROP DATABASE RecoveryETL;
END
--Create sample database for testing
CREATE DATABASE RecoveryETL
ON PRIMARY
(NAME = N'RecoveryETL_Date', FILENAME = N'C:\SQLDATA\RecoveryETL_Data.Mdf', SIZE = 1024MB, MAXSIZE = UNLIMITED, FILEGROWTH = 50MB)
LOG ON
(NAME = N'RecoveryETL_Log', FILENAME = N'C:\SQLDATA\RecoveryETL_Log.LDF', SIZE = 100MB, MAXSIZE = 1024MB, FILEGROWTH = 25MB)
GO
--Set Recovery Mode to Full
ALTER DATABASE RecoveryETL SET RECOVERY FULL ;
GO
USE RecoveryETL;
GO
--Immediately perform a full backup otherwise database will remain in simple mode
BACKUP DATABASE RecoveryETL
TO DISK = 'C:\Database Backups\RecoveryETL_1.bak'
WITH RETAINDAYS = 90
, FORMAT
, INIT
, MEDIANAME = 'RecoveryETL'
, NAME = 'RecoveryETL-Full Database Backup'
, COMPRESSION ;
GO
--Create a Testing Table
IF OBJECT_ID('dbo.HeapTable') IS NOT NULL
DROP TABLE dbo.HeapTable
CREATE TABLE HeapTable
(
Fld1 INT,
Fld2 INT,
FId3 INT,
ModDate Datetime
)
--Insert Records W/O TABLOCK hint
INSERT INTO HeapTable (Fld1, Fld2, FId3, ModDate)
SELECT TOP 10000
SalesOrderDetailID, SalesOrderDetailID + 100, SalesOrderDetailID + 99, GETDATE()
FROM
AdventureWorks2012.Sales.SalesOrderDetail
--Is it minimum logged? No, more than 10,000 log records
SELECT *
FROM sys.fn_dblog(null, null)
WHERE AllocUnitName LIKE '%HeapTable%'
--Truncate logs
CHECKPOINT;
BACKUP LOG RecoveryETL
TO DISK = 'NULL'
WITH RETAINDAYS = 90
, NOINIT
, MEDIANAME = 'RecoveryETL'
, NAME = 'RecoveryETL-Log Backup'
, COMPRESSION ;
GO
--Make sure logs are gone
SELECT *
FROM sys.fn_dblog(null, null)
WHERE AllocUnitName LIKE '%HeapTable%'
--Insert records WITH TABLOCK hint
INSERT INTO HeapTable WITH(TABLOCK)(Fld1, Fld2, FId3, ModDate)
SELECT TOP 10000
SalesOrderDetailID, SalesOrderDetailID + 100, SalesOrderDetailID + 99, GETDATE()
FROM
AdventureWorks2012.Sales.SalesOrderDetail
--Minimum logged here!!!!!
SELECT *
FROM sys.fn_dblog(null, null)
WHERE AllocUnitName LIKE '%HeapTable%'
I was also trying to restore database point-in-time using the log backup with minimum logged logs, as expected I was not able to bring database out of restoring state, where I can say they are truly minimum logged. The official documentation is inaccurate?
where I can say they are truly minimum logged. The official
documentation is inaccurate?
No, you are wrong.
Yes there were changes in how INSERTs are fully logged, but under full recovery model even with TABLOCK they are still fully logged.
In SQL SERVER 2005-2008 INSERT under full recovery model was logged row by row, so if you made 10000 rows INSERT in the log file you saw at least 10000 LOP_INSERT_ROW operations (see my first pictur)
Now I made the same INSERT on SQL SERVER 2016 first under BULK_LOGGED recovery model and then under the FULL (you can see the result on my second picture). Under BULK_LOGGED you can see that only bitmap settings were logged, so operation is really minimally logged. but under FULL recovery moder the picture is different. Yes you don't see 10000 LOP_INSERT_ROW rows anymore but now you can see 38 LOP_FORMAT_PAGE operations, eand very log row corresponding to this operetion is of 8276 bytes, i.e. 8Kb, one page. These 38 pages are full page images that were formatted during the INSERT, as it was done even in 2008 for INDEX REBUILD operations. So the operation is still fully logged, the info that goes into the log is enough to completely reconstitute operation, not only to permit the rollback as in case of minimally logged operations. So INSERT into a heap even with TABLOCK hint is still fully logged operation but now it's even efficiently logged operation. I tried even to backup log after my INSERT under the FULL and I was able to restore from this log with stop at at the time prior to backup log was finished.
When a database is created a file group with a data file is created by default. Is it possible to add more than data file into a primary file group.
To add an data-file to primary filegroup:
USE [master]
GO
ALTER DATABASE [your_database]
ADD FILE
(NAME = N'logical_name',
FILENAME = N'C:\my_data.mdf', -- <--Path to physical file
SIZE = 1GB,
FILEGROWTH = 100MB
)
TO FILEGROUP [PRIMARY]
I am trying to understand the REPLACE option from various sources and have not clarified myself. I am using SQL Server 2014 version.
What is the difference between below 2 queries? Both are completing without any error. With and Without Replace.
USE [master]
RESTORE DATABASE [Test] FROM DISK = N'C:\Program Files\Microsoft SQL Server\MSSQL12.MSSQLSERVER\MSSQL\Backup\MyDatabase.bak'
WITH FILE = 3, NOUNLOAD, STATS = 5
GO
Vs
USE [master]
RESTORE DATABASE [Test] FROM DISK = N'C:\Program Files\Microsoft SQL Server\MSSQL12.MSSQLSERVER\MSSQL\Backup\MyDatabase.bak'
WITH REPLACE, FILE = 3, NOUNLOAD, STATS = 5
GO
When I try to Replace with the .mdf and .ldf of an existing database (Test2), I get an error. My understanding so far is that I can restore the backup of [Test1] db with the name [Test2] (This already exists in my server and Test1 DB also exists).
I got the statement for REPLACE "Restoring over an existing database with a backup taken of another database." from one of Microsoft Link.
USE [master]
RESTORE DATABASE [Test2] FROM DISK = N'C:\Program Files\Microsoft SQL Server\MSSQL12.MSSQLSERVER\MSSQL\Backup\MyDatabase.bak'
WITH REPLACE, FILE = 3, NOUNLOAD, STATS = 5
GO
Error:
Msg 1834, Level 16, State 1, Line 2
The file 'C:\Program Files\Microsoft SQL Server\MSSQL12.MSSQLSERVER\MSSQL\DATA\test1.mdf' cannot be overwritten. It is being used by database 'test1'.
Msg 3156, Level 16, State 4, Line 2
'test1' cannot be restored to 'C:\Program Files\Microsoft SQL Server\MSSQL12.MSSQLSERVER\MSSQL\DATA\test1.mdf'. Use WITH MOVE to identify a valid location for the file.
Msg 1834, Level 16, State 1, Line 2
What is the purpose of the REPLACE option and what it replaces behind the scene. Can any one please explain with any example?
The purpose of the REPLACE option is to allow you to overwrite a database name (clobber an existing database with a different name from the backup). Your errors are caused by you trying to overwrite the files of another database from the one you asked to restore over. So restoring over Test2 database but clobbering Test1 database files (Test1.MDB and Test1.LDB). If you don't use the MOVE clause then the RESTORE command will use the same filenames as the BACKUP. Probably not a good idea otherwise things are going to get pretty confusing. (Test2 database pointing to Test1.mdb and Test1.ldb)
My script below demonstrates the issue.
I create database Test1.
I Back it up.
I try to restore it to Test2 using REPLACE. It fails, because Test1.mdb and Test1.ldb are being used by the Test1 database.
I drop the Test1 database.
I try to restore it to Test2 using REPLACE and it now works. (But is using Test1.mdb and Test1.ldb).
CREATE DATABASE [Test1]
ON PRIMARY
( NAME = N'Test1', FILENAME = N'C:\Program Files\Microsoft SQL Server\MSSQL13.MSSQLSERVER\MSSQL\DATA\Test1.mdf' , SIZE = 8192KB , FILEGROWTH = 65536KB )
LOG ON
( NAME = N'Test1_log', FILENAME = N'C:\Program Files\Microsoft SQL Server\MSSQL13.MSSQLSERVER\MSSQL\DATA\Test1_log.ldf' , SIZE = 8192KB , FILEGROWTH = 65536KB )
GO
BACKUP DATABASE [Test1] TO DISK = N'C:\Program Files\Microsoft SQL Server\MSSQL13.MSSQLSERVER\MSSQL\Backup\Test1.bak' WITH COPY_ONLY, NOFORMAT, NOINIT, NAME = N'Test1-Full Database Backup', SKIP, NOREWIND, NOUNLOAD, STATS = 10
GO
--Fails... It is being used by database 'Test1'.
RESTORE DATABASE [Test2] FROM DISK = N'C:\Program Files\Microsoft SQL Server\MSSQL13.MSSQLSERVER\MSSQL\Backup\Test1.bak'
WITH REPLACE, NOUNLOAD, STATS = 5
GO
DROP DATABASE Test1
GO
--Now works, but the files are Test1.mdf and Test1.ldf
RESTORE DATABASE [Test2] FROM DISK = N'C:\Program Files\Microsoft SQL Server\MSSQL13.MSSQLSERVER\MSSQL\Backup\Test1.bak'
WITH REPLACE, NOUNLOAD, STATS = 5
GO
DROP DATABASE Test2
GO
CREATE DATABASE [Test2]
ON PRIMARY
( NAME = N'Test1', FILENAME = N'C:\Program Files\Microsoft SQL Server\MSSQL13.MSSQLSERVER\MSSQL\DATA\Test2.mdf' , SIZE = 8192KB , FILEGROWTH = 65536KB )
LOG ON
( NAME = N'Test1_log', FILENAME = N'C:\Program Files\Microsoft SQL Server\MSSQL13.MSSQLSERVER\MSSQL\DATA\Test2_log.ldf' , SIZE = 8192KB , FILEGROWTH = 65536KB )
GO
--Now the same command works, because Test1.mdf and Test1.ldf are not in use.
RESTORE DATABASE [Test2] FROM DISK = N'C:\Program Files\Microsoft SQL Server\MSSQL13.MSSQLSERVER\MSSQL\Backup\Test1.bak'
WITH REPLACE, NOUNLOAD, STATS = 5
GO
This is Microsoft's explanation of the REPLACE option:
https://learn.microsoft.com/en-us/sql/t-sql/statements/restore-statements-transact-sql?view=sql-server-2017#REPLACEoption
REPLACE Option Impact
REPLACE should be used rarely and only after careful consideration. Restore normally prevents accidentally overwriting a database with a different database. If the database specified in a RESTORE statement already exists on the current server and the specified database family GUID differs from the database family GUID recorded in the backup set, the database is not restored. This is an important safeguard.
The REPLACE option overrides several important safety checks that restore normally performs. The overridden checks are as follows:
Restoring over an existing database with a backup taken of another database.
With the REPLACE option, restore allows you to overwrite an existing database with whatever database is in the backup set, even if the specified database name differs from the database name recorded in the backup set. This can result in accidentally overwriting a database by a different database.
Restoring over a database using the full or bulk-logged recovery model where a tail-log backup has not been taken and the STOPAT option is not used.
With the REPLACE option, you can lose committed work, because the log written most recently has not been backed up.
Overwriting existing files.
For example, a mistake could allow overwriting files of the wrong type, such as .xls files, or that are being used by another database that is not online. Arbitrary data loss is possible if existing files are overwritten, although the restored database is complete.
The way I found is like following:
Bring your database offline -> tasks-> bring it offline
Go to your Database in the Windows Explorer and delete your mdf and log.ldf
C:\Program Files\Microsoft SQL Server\MSSQL13.MSSQLSERVER\MSSQL\DATA\Test1.mdf
Let your Sql script run
That's it.
In general I think it is better to create a backup and restore this. In the database.
right click on database -> Tasks -> Take Offline
right click on database -> Tasks -> Restore -> Database
Select a Page -> General -> chose your file under device
Select a Page -> Options -> mark Overwrite the existing database (with replace)
Let it run