full backups occasionally skipping certain databases - sql

We have a job set up to run a script every night to do a full backup on all of our databases. Recently, we noticed that sometimes the last two databases are skipped, but not all of the time. We have a tracking table that we are inserting the state of each database in when we do the backups. On the nights that the last two databases are skipped, the state for those databases doesn't get recorded in the tracking table either. We can't figure out why those databases are being skipped. This is the backup script we are using:
DECLARE #dbname VARCHAR(100),
#dbid INT,
#rcmodel VARCHAR(50),
#state VARCHAR(60),
#date VARCHAR(50),
#time VARCHAR(50),
#sql VARCHAR(3000),
#dir VARCHAR(1000),
#path VARCHAR(100),
#type VARCHAR(10)
SET #path = 'E:\Backups\'
SET #type = 'Full'
SET #date = REPLACE(CONVERT(date,GETDATE(),101),'-','_')
SET #time = REPLACE(CONVERT(TIME(0), GETDATE()),':','_')
SET #path = #path + CONVERT(VARCHAR(30),##SERVERNAME) + '\' + #type + '\'
DECLARE BackupCur CURSOR FOR
SELECT NAME, database_id, recovery_model_desc, state_desc
FROM sys.databases
WHERE NAME <> 'tempdb'
OPEN BackupCur
FETCH NEXT FROM BackupCur INTO #dbname, #dbid, #rcmodel, #state
WHILE ##FETCH_STATUS = 0
BEGIN
INSERT INTO backuptrackingtable (db, statedesc, datecreated)
values (#dbname, #state, GETDATE())
IF #type = 'Full' AND #state = 'ONLINE'
BEGIN
SET #dir = 'EXECUTE master.dbo.xp_create_subdir N'''+#path+#dbname+''''
SET #sql = 'BACKUP DATABASE '+#dbname+' TO DISK = N'''+#path+#dbname+'\'+#dbname+'_'+#date+'.bak'' WITH NOFORMAT, INIT, SKIP, REWIND, NOUNLOAD, COMPRESSION'
PRINT 'Backing up ' + #dbname
EXEC (#dir)
EXEC (#sql)
END
IF #type = 'Log' AND #dbid > 4 AND #rcmodel = 'FULL' AND #state = 'ONLINE'
BEGIN
SET #dir = 'EXECUTE master.dbo.xp_create_subdir N'''+#path+#dbname+''''
SET #sql = 'BACKUP LOG '+#dbname+' TO DISK = N'''+#path+#dbname+'\'+#dbname+'_'+#date+'__'+#time+'.bak'' WITH NOFORMAT, INIT, SKIP, REWIND, NOUNLOAD, COMPRESSION'
PRINT 'Backing up ' + #dbname
EXEC (#dir)
EXEC (#sql)
END
FETCH NEXT FROM BackupCur INTO #dbname, #dbid, #rcmodel, #state
END
CLOSE BackupCur
DEALLOCATE BackupCur

Can think of three possible explanations.
They aren't being returned from the query against sys.databases because they don't exist or the user running the query doesn't have permissions on them.
An unhandled error means that the script aborts before processing them.
##FETCH_STATUS returns -2 at some point because a database has been dropped since the keyset cursor opened.
You would need to put more logging in to investigate further. But you might want to consider using a maintenance plan (dependant on edition) or Ola Hallengren's DB maintenance scripts rather than re-inventing the wheel anyway.

Related

SQL GO disrupts chain of local variables

I use script for DB backup as below:
---- INITIALIZATION
-- UNIFIED DATE
DECLARE #DAT DATETIME
SELECT #DAT = GETDATE()
-- DEFAULT BACKUPS LOCATION
DECLARE #PATH VARCHAR(20)
SELECT #PATH = 'Q:\DBbackup\Default\'
---- DATABASE BACKUPS
-- DB1
DECLARE #DBNAME VARCHAR(64)
SELECT #DBNAME = 'DB1'
DECLARE #BACKUPNAME VARCHAR(64)
DECLARE #DESCRIPTION VARCHAR (255)
SELECT #BACKUPNAME = (#PATH + #DBNAME +'_'+ CONVERT(VARCHAR(19),#DAT,121) + '.bak')
SELECT #DESCRIPTION = #DBNAME + ' Full ad hoc backup ' + CONVERT(VARCHAR(20),#DAT)
SELECT #BACKUPNAME
BACKUP DATABASE #DBNAME TO DISK = #BACKUPNAME WITH FORMAT, INIT, NAME = #DESCRIPTION, SKIP, NOREWIND, NOUNLOAD, STATS = 10, COMPRESSION
GO
-- DB2
DECLARE #DBNAME VARCHAR(64)
SELECT #DBNAME = 'DB2'
DECLARE #BACKUPNAME VARCHAR(64)
DECLARE #DESCRIPTION VARCHAR (255)
SELECT #BACKUPNAME = (#PATH + #DBNAME + '_' + CONVERT(VARCHAR(19),#DAT,121) + '.bak')
SELECT #DESCRIPTION = #DBNAME + ' Full ad hoc backup ' + CONVERT(VARCHAR(20),#DAT)
BACKUP DATABASE #DBNAME TO DISK = #BACKUPNAME WITH FORMAT, INIT, NAME = #DESCRIPTION, SKIP, NOREWIND, NOUNLOAD, STATS = 10, COMPRESSION
GO
However, for backup DB2 the variables #PATH and #DAT are not found as they apply only to first backup. It seems the GO command cancels the effect of local variables for DB2 backup. Is there any workaround for this situation? I want to use the variables in INIT only once, not duplicate them for each database backup.
SQL Server does not know what GO means. That's an SSMS feature. It causes multiple batches to be sent. Either remove GO (and restructure the variables so that they are declared only once) or store that data in a persistent location such as a temp table.
Unfortunately, no great options. T-SQL is a stone-age language.

get sql log file name from within a script

We have a few test databases that we are throwing test indexes into and the log file gets bloated real quickly due to us dropping the contents of the table and repopulating it.
I have found, thanks to Stack Overflow, a few scripts and put them together to do what I need.
Here is the script:
USE SSSIndexes
GO
ALTER DATABASE SSSIndexes SET RECOVERY SIMPLE WITH NO_WAIT
GO
DBCC SHRINKFILE(N'SSSIndexes_Log', 1) <-- my issue is here
GO
The problem is the log file name. Is there a way to get the log file name without having to look it up manually and include it in the script to where this part is automated?
Btw, we never intend on restore this database. These are temporary indexes.
Thanks!
USE SSSIndexes
GO
ALTER DATABASE SSSIndexes SET RECOVERY SIMPLE WITH NO_WAIT
GO
DECLARE #Name NVARCHAR(50)
DECLARE cur CURSOR FOR
SELECT [name]
FROM [sys].[database_files]
where [type] = 1
OPEN cur
FETCH NEXT FROM cur INTO #Name
WHILE ##FETCH_STATUS = 0
BEGIN
DBCC SHRINKFILE(#Name, 1)
FETCH NEXT FROM cur INTO #Name
END
CLOSE cur
DEALLOCATE cur
You can use this to generate script for log file truncating of all databases on a specific server. To stick to specific databases use a filter.
SELECT
' USE [' + name + ']; GO
-- Truncate the log by changing the database recovery model to SIMPLE.
ALTER DATABASE [' + name + '] SET RECOVERY SIMPLE;
GO
-- Shrink the truncated log file to 1 MB.
DECLARE #logname varchar(128);
SELECT TOP 1 #logname=[name] FROM [' + name + '].[sys].[database_files] WHERE [type] = 1;
DBCC SHRINKFILE (#logname, 1);
GO
-- Reset the database recovery model.
ALTER DATABASE [' + name + '] SET RECOVERY FULL;
GO
' AS qry FROM master.dbo.sysdatabases
WHERE dbid > 6
WARNING!!!: YOU SHOULD ONLY DO THIS ON TEST DB SERVERS. Production DBs typically WANT to have FULL recovery mode. Test DBs you usually don't care.
Expanding on Abdul's answer (I had trouble getting it to show in new lines) and Dis' answers this finds the first db that has recovery FULL, sets it to simple and shrinks it... just keep clicking execute until it returns null
declare #dbname nvarchar(50)
declare #logfilename nvarchar(100)
select top(1) #dbname = name from sys.databases where recovery_model_desc <> 'SIMPLE' AND name <> 'tempdb'
declare #shrinkdb nvarchar(500)
set #shrinkdb = 'USE master
ALTER DATABASE [' + #dbname + '] SET RECOVERY SIMPLE
'
select #shrinkdb
execute sp_executesql #shrinkdb
set #shrinkdb = 'USE [' + #dbname + ']
DECLARE #Name NVARCHAR(50)
DECLARE cur CURSOR FOR
SELECT [name]
FROM [sys].[database_files]
where [type] = 1
OPEN cur
FETCH NEXT FROM cur INTO #Name
WHILE ##FETCH_STATUS = 0
BEGIN
DBCC SHRINKFILE(#Name, 1)
FETCH NEXT FROM cur INTO #Name
END
CLOSE cur
DEALLOCATE cur
'
select #shrinkdb
execute sp_executesql #shrinkdb

SQL Server: backup all databases

I was wondering if there was any way of making a backup of an entire SQL Server (we are using SQL Server 2008) at regular intervals to a specific location. I know we are able to backup single specific databases but for ease of use and not having to set up a backup each time I want a new database, is there a way to do this?
If there is however, I must have a way of restoring just a single database from that server backup easily as though I have backed them up individually.
The method used will just be a pure backup and not a difference so no need to worry about complications.
You can run the following script, just change the #path variable to where you want to store the databases.
DECLARE #name VARCHAR(50) -- database name
DECLARE #path VARCHAR(256) -- path for backup files
DECLARE #fileName VARCHAR(256) -- filename for backup
DECLARE #fileDate VARCHAR(20) -- used for file name
SET #path = 'C:\Backup\'
SELECT #fileDate = CONVERT(VARCHAR(20),GETDATE(),112)
DECLARE db_cursor CURSOR FOR
SELECT name
FROM master.dbo.sysdatabases
WHERE name NOT IN ('master','model','msdb','tempdb')
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
FETCH NEXT FROM db_cursor INTO #name
END
CLOSE db_cursor
DEALLOCATE db_cursor
Obtained from:
http://www.mssqltips.com/sqlservertip/1070/simple-script-to-backup-all-sql-server-databases/
Consider backing up hidden resource database as well
Use master
GO
--enable
sp_configure 'show advanced options'
GO
/* 0 = Disabled , 1 = Enabled */
sp_configure 'xp_cmdshell', 1
GO
RECONFIGURE WITH OVERRIDE
GO
--===Resource file details
SELECT 'ResourceDB' AS 'Database Name'
, NAME AS [Database File]
, FILENAME AS [Database File Location]
FROM sys.sysaltfiles
WHERE DBID = 32767
ORDER BY [Database File]
GO
--===Copy resource files
DECLARE #ResDataFile VARCHAR(1000), #ResLogFile VARCHAR(1000)
SELECT
#ResDataFile = CASE NAME WHEN 'Data' THEN FILENAME ELSE #ResDataFile END,
#ResLogFile = CASE NAME WHEN 'Log' THEN FILENAME ELSE #ResLogFile END
FROM sys.sysaltfiles
WHERE DBID = 32767
SELECT #ResDataFile, #ResLogFile
DECLARE #cmd VARCHAR(1000)
--===Copy data file
SELECT #cmd = 'COPY /Y "' + #ResDataFile + '" "G:\SQLBackups"'
--PRINT #cmd
EXEC xp_cmdshell #cmd
--===Copy log file
SELECT #cmd = 'COPY /Y "' + #ResLogFile + '" "G:\SQLBackups"'
--PRINT #cmd
EXEC xp_cmdshell #cmd
GO
--Disable
sp_configure 'show advanced options'
GO
/* 0 = Disabled , 1 = Enabled */
sp_configure 'xp_cmdshell', 0
GO
RECONFIGURE WITH OVERRIDE
GO

how to pass all database (fast) since sql server 2008 express to sql server 2008 R2 (NO express)

well i had sql 2008 express, and now i have installed, sql server, now i want to delete sql express, but in that instance i have all my database i have worked (plus of 20), so they are very important for me, how can i pass it to sql server 2008 r2, i know i can do database of all but i dont want to work a lot of, there is a way short, for to pass al database? coping a folder? something? thanks!
I Attached all database, and i added, all (but one for one) i added all in the same windows and in 5 minutos i had all database in sql (no express)
Create an SSIS package with 4 steps.
First, a Execute SQL task that backups all DBs to a specific location:
exec sp_msforeachdb '
IF DB_ID(''?'') > 4
Begin
BACKUP DATABASE [?] TO DISK = N''\\Backups\?.BAK'' WITH NOFORMAT, INIT,
NAME = N''?-Full Database Backup'', SKIP, NOREWIND, NOUNLOAD
declare #backupSetId as int
select #backupSetId = position from msdb..backupset where database_name=N''?''
and backup_set_id=(select max(backup_set_id) from msdb..backupset
where database_name=N''?'' )
if #backupSetId is null begin
raiserror(N''Verify failed. Backup information for database ''''?'''' not found.'', 16, 1)
end
RESTORE VERIFYONLY FROM DISK = N''\\Backups\?.BAK'' WITH
FILE = #backupSetId, NOUNLOAD, NOREWIND
End
'
Second, Create a SP to restore DBs using a variable for location and DB name:
CreatePROCEDURE [dbo].[uSPMas_RestoreDB] #DBname NVARCHAR(200),
#BackupLocation NVARCHAR(2000)
AS
BEGIN
SET nocount ON;
create table #fileListTable
(
LogicalName nvarchar(128),
PhysicalName nvarchar(260),
[Type] char(1),
FileGroupName nvarchar(128),
Size numeric(20,0),
MaxSize numeric(20,0),
)
insert into #fileListTable EXEC('RESTORE FILELISTONLY FROM DISK = '''+#BackupLocation+#dbname+'.bak''')
Declare #Dname varchar(500)
Set #Dname = (select logicalname from #fileListTable where type = 'D')
Declare #LName varchar(500)
Set #LName = (select logicalname from #fileListTable where type = 'L')
declare #sql nvarchar(4000)
SET #SQL = 'RESTORE DATABASE ['+ #dbname +'] FROM
DISK = N'''+#BackupLocation + #dbname +'.BAK'' WITH FILE = 1,
MOVE N'''+ #Dname +''' TO N''E:\YourLocation\'+ #dbname +'.mdf'',
MOVE N'''+ #LName +''' TO N''D:\Your2ndLocation\'+ #dbname +'_log.ldf'',
NOUNLOAD, REPLACE, STATS = 10'
exec sp_executesql #SQL
drop table #fileListTable
END
Third, Create a ForEach Loop Container and put a Execute Sql Statement with variable:
EXEC uSPMas_RestoreDB ? , ?
Use the for ForEach Loop Container to pass the variables
Fourth, Create a 'Transfer Logins' task to move over all DB logins

How to clean sys.conversation_endpoints

I have a table, a trigger on the table implemented using service broker. More than Half million records are inserted daily into the table.
The asynchronous SP is used to check sveral condition by using inserted data and update other tables. It was running fine for last 1 month and the SP was get executed withing 2-3 seconds of insertion of record. But now it take more than 90 minute.
At present sys.conversation_endpoints have too much records.
(Note that all the table are truncated daily as I do not need those records day after)
Other database activities are normal (average 60% CPU Utilization).
Now where i need to look??
I can re-create database without any problem but i don't think it is a good way to resolve the problem
you can 'end conversation #handle' or 'end conversation #handle with cleanup'
Script to end all conversations for a particular service:
DECLARE #sql NVARCHAR(MAX)
,#far_service NVARCHAR(256) = N'far_service_name';
WHILE EXISTS (
SELECT COUNT(*)
FROM sys.conversation_endpoints
WHERE far_service = #far_service
)
BEGIN
SET #sql = N'';
SELECT TOP 1000 #sql = #sql + N'END CONVERSATION ''' + CAST(conversation_handle AS NVARCHAR(50)) + N''' WITH CLEANUP;
'
FROM sys.conversation_endpoints
WHERE far_service = #far_service;
--PRINT #sql;
EXEC sys.sp_executesql #stmt = #sql;
--RETURN;
END;
GO
Here is my solution, after modifying code from #thesqldev
USE [MY_DATABASE_NAME_HERE]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE PROCEDURE [dbo].[mqConversationsClearAll]
AS
-- Note: you can check the queue by running this query
-- SELECT * FROM sys.conversation_endpoints GO
DECLARE #getid CURSOR
,#sql NVARCHAR(MAX)
,#conv_id NVARCHAR(100)
,#conv_handle NVARCHAR(100)
,#conv_service NVARCHAR(100)
-- ,#far_service NVARCHAR(256) = N'One_Specific_Service_Target';
-- want to create and execute a chain of statements like this, one per conversation
-- END CONVERSATION 'FE851F37-218C-EA11-B698-4CCC6AD00AE9' WITH CLEANUP;
-- END CONVERSATION 'A4B4F603-208C-EA11-B698-4CCC6AD00AE9' WITH CLEANUP;
SET #getid = CURSOR FOR
SELECT [conversation_id], [conversation_handle], [far_service]
FROM sys.conversation_endpoints
WHERE NOT([State] = 'CO')
-- CO = CONVERSING [State]
-- alternatively, might like one service name only
-- WHERE far_service = #far_service
OPEN #getid
FETCH NEXT
FROM #getid INTO #conv_id, #conv_handle, #conv_service
WHILE ##FETCH_STATUS = 0
BEGIN
SET #sql = 'END CONVERSATION ' + char(39) + #conv_handle + char(39) + ' WITH CLEANUP;'
EXEC sys.sp_executesql #stmt = #sql;
FETCH NEXT
FROM #getid INTO #conv_id, #conv_handle, #conv_service
END
CLOSE #getid
DEALLOCATE #getid
Then you can execute the newly created stored procedure "mqConversationsClearAll" whenever you want to clear sys.conversation_endpoints