SQL Server From Squirrel’s View
Lockergnome
Home

Archive for the 'Programming' Category

Using SQL Server Reserved Words

Tuesday, January 22nd, 2008

Hello again… I hope you had a good holiday weekend for those of you who had the holiday off. Last night I came across a stored procedure that used SQL Server reserved words in the SELECT and INSERT statements. Since I am using SQL Server 2005, the words that came up as “reserved” were:
status
views
subject
user_id

If you must use SQL Server reserved words put brackets [] around them. Putting reserved words in brackets [] is a “tuning” technique that DBAs use to “optimize” T-SQL code. If you do NOT put brackets [] around the reserved words then SQL Server will need to take the time to “resolve” the word and decide if it is being used as a reserved word or if it corresponds to a column in a user table or a literal in a result set. This will take SQL Server longer to execute the T-SQL script. If the reserved words do in fact have brackets [] then SQL Server knows that it corresponds to a column name or as a literal if you use it as a column heading in a result set and will not have to do a compare.

I hope this helps you out… if you have any other way to tune or optimize please comment!

Detecting A CPU Bottleneck

Tuesday, January 15th, 2008

In SQL Server 2005 there several ways to detect a CPU bottlneck.  The first way to detect a bottleneck is by looking at the System Monitor counter Processor: % Processor Time.  If the value of this counter  is greater than 80% for  15 to 20 minutes in duration, then it is a good indication that you have a bottleneck.

You can also monitor System: Processor Queue Length.  A value of 2 or higher for a length of time also indicates a CPU bottleneck.  Another way to detect a CPU bottleneck is to utilize the new DMVs (Dynamic Management Views) in SQL Server 2005.  Execute the  following query in the master database and the query will return the count of number of worker threads in the runnable state:

Select Count(*) AS workers_waiting_for_cpu, s.scheduler_id
From sys.dm_os_workers as o
Inner Join sys.dm_os_schedulers as s
On o.scheduler_address = s.scheduler_address
And s.scheduler_id < 255
Where o.state = ‘Runnable’
Group By s.scheduler_id

I hope this helps… if you have another way to detect a CPU bottleneck post here and let us know!

Custom Stored Procedure To Restore A Database!

Thursday, December 20th, 2007

Here is a stored procedure that will restore your database without having to remember the SQL syntax of the RESTORE DATABASE command in SQL Server 2000. This stored procedure is to be compiled and run from MSDB. The stored procedure reads from the registry to figure out the data and log path of the database files. To execute this stored procedure run the following statement:

exec pr_restore_database_new ‘ database name’, ‘the path of the backup file’, ‘backup type’

The backup types are: B = Full Backup, D = Differential Backup, L = Log Backup

The caveat here is that the way the stored procedure is written the database backup needs to be in its own backup folder. So for example, D:\DBBackups\Test\Test.bak

Here is the script:

CREATE procedure pr_restore_database_new(
@bk_name nvarchar(50),
@bk_path nvarchar(120),
@bk_type char(1)
)

as

set nocount on
declare @bk_file_name nvarchar(128)
declare @sql nvarchar(1000)
declare @file int
declare @data_path nvarchar(128)
declare @log_path nvarchar(128)

declare @last_lsn numeric(25,0)

set @file = 1
set @bk_file_name = @bk_name

exec master.dbo.xp_instance_regread N‘HKEY_LOCAL_MACHINE’,N‘Software\Microsoft\MSSQLServer\MSSQLServer’,N‘DefaultData’, @data_path output
exec master.dbo.xp_instance_regread N‘HKEY_LOCAL_MACHINE’,N‘Software\Microsoft\MSSQLServer\MSSQLServer’,N‘DefaultLog’, @log_path output

set @bk_path = @bk_path + @bk_name + ‘\’

Create Table #HeaderOnly(
BackupName nvarchar(128),
BackupDescription nvarchar(255),
BackupType smallint,
ExpirationDate datetime,
Compressed tinyint,
Position smallint,
DeviceType tinyint,
UserName nvarchar(128),
ServerName nvarchar(128),
DatabaseName nvarchar(128),
DatabaseVersion int,
DatabaseCreateionDate datetime,
BackupSize numeric(20, 0),
FirstLSN numeric(25, 0),
LastLSN numeric(25, 0),
CheckpointLSN numeric(25, 0),
DatabaseBackupLSN numeric(25, 0),
BackupStartDate datetime,
BackupFinishDate datetime,
SortOrder smallint,
CodePage smallint,
UnicodeLocaleId int,
UnicodeComarisonStyle int,
CompatibilityLevel tinyint,
SoftwareVendorId int,
SoftwareVersionMajory int,
SoftwareVersionMinor int,
SoftwareVersionBuild int,
MachineName nvarchar(128),
Flags int,
BindingID uniqueidentifier,
RecoverForkID uniqueidentifier,
Collation nvarchar(128)
)

Create Table #FileListOnly(
LogicalName nvarchar(128),
PhysicalName nvarchar(128),
Type char(1),
FileGroupName nvarchar(128),
Size numeric(20,0),
MaxSize numeric(20,0)
)

if(@bk_type = ‘B’)
Begin

Declare @LogicalName nvarchar(128)
Declare @PhysicalName nvarchar(128)
Declare @Type char(1)

–*************************** Get The Logical Names from the Backup ****************************

set @bk_file_name = @bk_file_name + ‘_full’
set @sql = ‘Restore FileListOnly From disk = ”’ + @bk_path + @bk_file_name + ‘.bak”’

insert into #FileListOnly
execute sp_executesql @sql

set @sql = ‘Restore Database ‘ + @bk_name + char(13)
set @sql = @sql + ‘From Disk = ”’ + @bk_path + @bk_file_name + ‘.bak”’ + char(13)
set @sql = @sql + ‘With’ + char(13)

Declare c1 cursor for
select LogicalName, reverse((left(reverse(PhysicalName), charindex(’\', reverse(PhysicalName)) - 1))) as PhysicalName, Type
from #FileListOnly
order by Type

open c1

fetch next from c1
into @LogicalName, @PhysicalName, @Type

while @@fetch_status = 0
begin
if(@Type = ‘D’)
begin
set @sql = @sql + char(9) + ‘Move ”’ + @logicalName + ”’ to ”’ + @data_path + @PhysicalName + ”’,’ + char(13)
end
else
begin
set
@sql = @sql + char(9) + ‘Move ”’ + @logicalName + ”’ to ”’+ @log_path + @PhysicalName + ”’,’ + char(13)
end

fetch next from c1
into @LogicalName, @PhysicalName, @Type
end
close
c1
deallocate c1

set @sql = @sql + char(9) + ‘Standby = ”’ + @data_path + @bk_name + ‘.stb”’

–print @sql
execute sp_executesql @sql
End
else if
(@bk_type = ‘D’)
begin

set @bk_file_name = @bk_file_name + ‘_’ + cast(datepart(dw, getdate()) as varchar)
set @sql = ‘Restore HeaderOnly From disk = ”’ + @bk_path + @bk_file_name + ‘_Diff.bak”’

insert into #HeaderOnly
execute sp_executesql @sql

set @file = (select max(position) from #HeaderOnly)

truncate table #HeaderOnly

if(@file is not null)
begin
set
@sql = ‘Restore Database ‘ + @bk_name + char(13)
set @sql = @sql + ‘From Disk = ”’ + @bk_path + @bk_file_name + ‘_Diff.bak”’ + char(13)
set @sql = @sql + ‘With’ + char(13)
set @sql = @sql + char(9) + ‘File = ‘ + cast(@file as varchar) + ‘, ‘ + char(13)
set @sql = @sql + char(9) + ‘Standby = ”’ + @data_path + @bk_name + ‘.stb”’

–print @sql
execute sp_executesql @sql
end
end
else if
(@bk_type = ‘L’)
begin
while
(@file is not null)
begin

set @sql = ‘Restore HeaderOnly From disk = ”’ + @bk_path + @bk_name + ‘_Log.bak”’

set @last_lsn = (select last_lsn from backupset
where backup_set_id = (select backup_set_id
from restorehistory
where restore_history_id = (select max(restore_history_id)
from restorehistory
where destination_database_name = @bk_name)))

insert into #HeaderOnly
execute sp_executesql @sql

set @file = (select position
from #HeaderOnly
where(FirstLsn <= @last_lsn and LastLsn > @last_lsn))

truncate table #HeaderOnly

if(@file is not null)
begin
set
@sql = ‘Restore Log ‘ + @bk_name + char(13)
set @sql = @sql + ‘From Disk = ”’ + @bk_path + @bk_name + ‘_Log.bak”’ + char(13)
set @sql = @sql + ‘With’ + char(13)
set @sql = @sql + char(9) + ‘File = ‘ + cast(@file as varchar) + ‘, ‘ + char(13)
set @sql = @sql + char(9) + ‘Standby = ”’ + @data_path + @bk_name + ‘.stb”’

– print @sql
execute sp_executesql @sql
end
end
end
else if
(@bk_type = ‘R’)
begin
set
@sql = ‘Restore Database ‘ + @bk_name + char(13)
set @sql = @sql + ‘With’ + char(13)
set @sql = @sql + char(9) + ‘Recovery’

print @sql
–execute sp_execute @sql
end

Drop Table #FileListOnly
Drop Table #HeaderOnly

GO

How To Mark A Database For Replication in SQL Server 2000

Monday, December 17th, 2007

Today I am going to cover how to mark a database in SQL Server 2000 for replication. This is important when you are attempting to shrink a transaction log that has transaction marked for replication but have not been flushed out of the log yet. I have come across this situation when restoring a backup of a replicated production database to a staging environment or a development environment. Once you get the database restored to your destination server the first thing you want to do is to allow access to the system tables. Here are the steps to accomplish ‘marking’ a database for replication:

Step 1 - Allow access to the system tables
use master
go
exec sp_configure ‘allow updates’, 1
reconfigure with override
go

Step 2 - Update the ‘category’ column in the master.dbo.sysdatabases table for the database you want to update.
update sysdatabases
set category = 1
where name = <database name>

Step 3 - Remove access to the system tables
use master
go
exec sp_configure ‘allow updates’, 0 — Does not allow updates
reconfigure with override
go

If you query the master.dbo.sysdatabases table now you will see the category column is now set to 1. You are able to remove the replicated transactions now and shrink the file. If you have another way to remove replicated transactions let me know!

Victim Of Parameter Sniffing?

Friday, December 14th, 2007

Have you come across a time when a stored procedure takes a lot longer to run than normal but the T-SQL itself runs a lot faster in Query Analyzer? This might be due to “parameter sniffing”. During compilation of a stored procedure the query optimizer attempts to “sniff” or “seek out” the values being passed in… in order to create an optimized query plan. The problem occurs when values that are passed in does not match a plan in the procedure cache and SQL Server attempts to create a new plan in the cache. This will cause the procedure to take much longer to execute and performance decreases.

The “fix” for parameter sniffing is to create local variables within the stored procedure that match the parameters being passed in. So for example,

Create Procedure myProc @name varchar(30), @age int

As

Declare @name_local varchar(30), @age_local int

Set @name_local = @name

Set @age_local = @age

Then use @name_local and @age_local throughout your stored procedure and you will get the same execution times as if you were running the straight T-SQL in query analyzer. Let me know if this helps!

Scripting SQL Server 2005 Logins

Thursday, December 6th, 2007

I thought today I would share with you a great way to move SQL Server logins from one SQL Server 2005 server (source) to another SQL Server 2005 server (destination).  In the past I have tried to use DTS to move logins (passwords and SIDs) from one server to another but without much success.  As I was surfing the Internet, I came across 2 stored procedures from Microsoft that you create in the master database.  Once compiled, run the primary stored procedure and the result set produces the CREATE LOGIN statements with the correct passwords and SIDs for every login in the source server.  Once this script has been created, you can then copy it and execute the script in a query window on the destination server.  Once you restore the user databases from the source server to the destination server the SIDs found in the user database will then be sync’d to the logins in the master database. 

You will find both stored procedures below in one script.  The primary stored procedure you execute to generate the CREATE LOGIN script is the stored procedure:  sp_help_revlogin   Here is the correct syntax to run the procedure for ALL logins.  exec sp_help_revlogin

Here is the script with the 2 stored procedures:

USE master
GO

IF OBJECT_ID (’sp_hexadecimal’) IS NOT NULL
DROP PROCEDURE sp_hexadecimal
GO

CREATE PROCEDURE sp_hexadecimal
@binvalue VARBINARY(256),
@hexvalue VARCHAR(514) OUTPUT

AS

/*
**********************************************************************
**
** Object Name: sp_hexadecimal
** Object Type: Stored Procedure
** File Name: sp_hexadecimal.sql
** Database Name: master
** Author: < Name of the person who wrote the T-SQL
** script >
** Creation Date: 07.10.08 - use ANSI format
** Description: This procedure is involved in scripting out
** logins, passwords and SIDs in SQL Server 2005.
** Special Note: This script is also available from the
** Microsoft website.
** Modified Tables: None
** Called Procedures: None
** Called Jobs: None
** Called UDFs: None
** Calling Procedures: sp_help_revlogin
** Calling Jobs: None
** Calling UDFs: None
** Return Statuses: @hexvalue as OUTPUT
**
**********************************************************************
*/

– Declaration section
DECLARE @charvalue VARCHAR(514)
DECLARE @i INT
DECLARE @length INT
DECLARE @hexstring CHAR(16)

– Initialization section
SELECT @charvalue = ‘0x’
SELECT @i = 1
SELECT @length = DATALENGTH(@binvalue)
SELECT @hexstring = ‘0123456789ABCDEF’

WHILE (@i <= @length)
BEGIN
– Declaration section
DECLARE @tempint INT
DECLARE @firstint INT
DECLARE @secondint INT

– Initialization section
SELECT @tempint = CONVERT(INT, SUBSTRING(@binvalue,@i,1))
SELECT @firstint = FLOOR(@tempint/16)
SELECT @secondint = @tempint - (@firstint*16)
SELECT @charvalue = @charvalue +

SUBSTRING(@hexstring, @firstint+1, 1) + SUBSTRING(@hexstring, @secondint+1, 1)

SELECT @i = @i + 1
END
SELECT @hexvalue = @charvalue
GO

/******************************************************************************/
IF OBJECT_ID (’sp_help_revlogin’) IS NOT NULL
DROP PROCEDURE sp_help_revlogin
GO

CREATE PROCEDURE sp_help_revlogin
@login_name SYSNAME = NULL

AS

/*
**********************************************************************
**
** Object Name: sp_help_revlogin
** Object Type: Stored Procedure
** File Name: sp_help_revlogin.sql
** Database Name: master
** Author: < Name of the person who wrote the T-SQL
** script >
** Creation Date: 07.10.08 - use ANSI format
** Description: This procedure creates the actual T-SQL ‘Create
** Login’ statement with the information from
** the security tables in SQL Server 2005.
** Special Note: This script is also available from the
** Microsoft website.
** Modified Tables: None
** Called Procedures: sp_hexadecimal
** Called Jobs: None
** Called UDFs: None
** Calling Procedures: None
** Calling Jobs: None
** Calling UDFs: None
** Return Statuses: None
**
**********************************************************************
*/

– Declaration section
DECLARE @name SYSNAME
DECLARE @type VARCHAR(1)
DECLARE @hasaccess INT
DECLARE @denylogin INT
DECLARE @is_disabled INT
DECLARE @PWD_varbinary VARBINARY(256)
DECLARE @PWD_string VARCHAR(514)
DECLARE @SID_varbinary VARBINARY(85)
DECLARE @SID_string VARCHAR(514)
DECLARE @tmpstr VARCHAR(1024)
DECLARE @is_policy_checked VARCHAR(3)
DECLARE @is_expiration_checked VARCHAR(3)

IF @login_name IS NULL
DECLARE login_curs CURSOR FOR
SELECT
p.sid,
p.[name],
p.[type],
p.is_disabled,
l.hasaccess,
l.denylogin
FROM sys.server_principals AS p
LEFT JOIN sys.syslogins AS l
ON l.[name] = p.[name]
WHERE p.[type] IN( ‘S’, ‘G’, ‘U’ )
AND p.[name] <> ’sa’
ELSE
DECLARE login_curs CURSOR FOR
SELECT p.sid,
p.[name],
p.[type],
p.is_disabled,
l.hasaccess,
l.denylogin
FROM sys.server_principals AS p
LEFT JOIN sys.syslogins AS l
ON l.[name] = p.[name]
WHERE p.[type] IN( ‘S’, ‘G’, ‘U’ )
AND p.[name] = @login_name

OPEN login_curs

FETCH NEXT FROM login_curs
INTO @SID_varbinary, @name, @type, @is_disabled, @hasaccess, @denylogin

IF (@@FETCH_STATUS= -1)
BEGIN
PRINT ‘No login(s) found.’
CLOSE login_curs
DEALLOCATE login_curs
RETURN -1
END

SET @tmpstr = ‘/* sp_help_revlogin script ‘

PRINT @tmpstr

SET @tmpstr = ‘** Generated ‘ + CONVERT (VARCHAR, GETDATE()) + ‘ on ‘ + @@SERVERNAME + ‘ */’

PRINT @tmpstr
PRINT

WHILE ( @@FETCH_STATUS <> -1)
BEGIN
IF (@@FETCH_STATUS <> -2)
BEGIN
PRINT
SET @tmpstr = ‘– Login: ‘ + @name
PRINT @tmpstr

IF (@type IN ( ‘G’, ‘U’))
BEGIN – NT authenticated account/group
SET @tmpstr = ‘CREATE LOGIN ‘ + QUOTENAME( @name ) + ‘FROM WINDOWS’
END
ELSE
BEGIN
– SQL Server authentication
– obtain password and sid
SET @PWD_varbinary = CAST( LOGINPROPERTY( @name, ‘PasswordHash’ ) AS VARBINARY(256))
EXEC sp_hexadecimal @PWD_varbinary, @PWD_string OUT
EXEC sp_hexadecimal @SID_varbinary, @SID_string OUT

– obtain password policy state
SELECT @is_policy_checked =
CASE is_policy_checked WHEN 1 THEN ‘ON’ WHEN 0 THEN ‘OFF’ ELSE NULL END
FROM
sys.sql_logins
WHERE [name] = @name

SELECT @is_expiration_checked =
CASE is_expiration_checked WHEN 1 THEN ‘ON’ WHEN 0 THEN ‘OFF’ ELSE NULL END
FROM
sys.sql_logins
WHERE [name] = @name

SET @tmpstr = ‘CREATE LOGIN ‘ + QUOTENAME( @name )
+ ‘ WITH PASSWORD = ‘ + @PWD_string
+ ‘ HASHED, SID = ‘ + @SID_string

IF ( @is_policy_checked IS NOT NULL )
BEGIN
SET
@tmpstr = @tmpstr + ‘, CHECK_POLICY = ‘ + @is_policy_checked
END

IF ( @is_expiration_checked IS NOT NULL )
BEGIN
SET @tmpstr = @tmpstr + ‘, CHECK_EXPIRATION = ‘ + @is_expiration_checked
END
END

IF (@denylogin = 1)
BEGIN – login is denied access
SET @tmpstr = @tmpstr + ‘; DENY CONNECT SQL TO ‘ + QUOTENAME( @name )
END
ELSE IF
(@hasaccess = 0)
BEGIN – login has exists but does not have access
SET @tmpstr = @tmpstr + ‘; REVOKE CONNECT SQL TO ‘ + QUOTENAME( @name )
END

IF (@is_disabled = 1)
BEGIN — login is disabled
SET @tmpstr = @tmpstr + ‘; ALTER LOGIN ‘ + QUOTENAME( @name ) + ‘ DISABLE’
END

PRINT @tmpstr
END

FETCH NEXT FROM login_curs
INTO @SID_varbinary, @name, @type, @is_disabled, @hasaccess, @denylogin

END

CLOSE login_curs
DEALLOCATE login_curs

RETURN 0
GO

Getting Space Used For Tables

Tuesday, December 4th, 2007

I have been looking for a more efficient way of getting space used requirements for all of my tables in a given database.  It seems like Microsoft has answered my prayers.  Microsoft has now given us the sp_MSforeachtable stored procedure.  This procedure is not currently documented within BOL.  The T-SQL script below demonstrates how to use this procedure to retrieve space utilization for all tables within a given database.  If you have a better or different way please post and let us know!

CREATE TABLE #TemptableforspaceUsed
(name SYSNAME,
rows bigINT,
reserved VARCHAR(20),
data VARCHAR(20),
index_size VARCHAR(20),
unused VARCHAR(20))
GO
INSERT #TemptableforspaceUsed
EXEC sp_MSforeachtable ’sp_spaceused ”?”’

update #TemptableforspaceUsed
set reserved=replace (reserved,’KB’,”)

select top 10 name, reserved

from #TemptableforspaceUsed

order by convert(bigint,reserved) desc
drop table #TemptableforspaceUsed

Documentation Header For Your Scripts

Saturday, December 1st, 2007

Hello there!

I thought today I would share with you the documentation header that I use for my T-SQL scripts. The header has evolved from the days of just the name of the script, the author and the date. Through my years of experience I have made the header more descriptive and always looking to improve it. The header has saved me lots of time from searching through my T-SQL code to see if a particular stored procedure is called, user defined function, etc. Here is the documentation header I use:

/*
**********************************************************************
**
** Object Name: < Object Name>
** Object Type: < Stored Procedure, User Defined Function, etc. >
** File Name: < Name of the file.. normally followed by .sql >
** Database Name: < The name of the database the object will reside in >
** Author: < Name of the person who wrote the T-SQL script >
** Creation Date: < Date the T-SQL script was created with ANSI date >
** Description: < Detailed description of what the script does >
** Special Note: < Any special remarks about the script >
** Modified Tables: < List tables that the data is modified by this script >

** Called Procedures < List procedures that this script calls >
** Called Jobs: < List SQL Agent jobs that this script calls >
** Called UDFs: < List user defined functions that this script calls >
** Calling Procedures: < List procedures that call this script >

** Calling Jobs: < List SQL Agent jobs that call this script >
** Calling UDFs: < List User Defined Functions that call this script >
** Return Statuses: < List return status that this script returns >
**
**********************************************************************
*/

If you would like to suggest adding something more to the document header please comment!

Identify Version Number, Service Pack And Edition For SQL Server 2005

Friday, November 30th, 2007

Hello and welcome back!

Today I am going to cover how easily it is to verify the version number, service pack and edition that is installed on SQL Server 2005. When you run the following T-SQL statement it will give you the Product Version, Product Level and the Edition.

Step 1 - Connect to a valid SQL Server 2005 server.

Step 2 - After connecting, open up a query window. It does not matter what database is specified when opening up the query window.

Step 3 - Type and execute the following T-SQL statement:

SELECT SERVERPROPERTY(‘productversion’) AS [Product Version], SERVERPROPERTY (‘productlevel’) AS [Product Level], SERVERPROPERTY (‘edition’) AS [Edition]

This will give you the detailed information you are looking for. If you have another way of identifying this information please post your solution!

Removing Transactions That Are Marked For Replication

Thursday, November 29th, 2007

Hello once again… today I am covering how to remove transactions that are marked for replication in the transaction log of a restored database. Now I have seen this occur in SQL Server 2000 so many times that I have created a T-SQL script that I execute step by step to ‘unmark’ these transactions so that I am able to shrink the log of the restored database.

Here is the scenario… there is a production database that is involved in replication and the developers want to restore the backup of this database to a development server to develop against. This database will no longer participate in replication while residing on the development server. Once the production database gets restored to the development server the database is still ‘marked’ for replication as well as the transactions that were in the log at the time of the full database backup. Now in order to conserve space on the development server the log needs to be shrunken down. When a DBCC ShrinkDatabase or DBCC ShrinkFile is executed on the database the transaction log does not truncate and the log does not shrink. This is what we do to fix this…

Step 1 - Make sure that the Recovery Model for the restored database is set to ‘Full’.

Step 2 - Make sure in the master.dbo.sysdatabases table (on the development server) that the category column for the restored database is set to 1 (the database is marked for replication).

Step 3 - Run the following T-SQL script in the restored database:

EXEC sp_repldone @xactid = NULL, @xact_segno = NULL, @numtrans = 0, @time = 0, @reset = 1

This will ‘unmark’ the transactions (for replication) in the log

Step 4 - Backup the Log

BACKUP LOG <database name> WITH NO_LOG

Step 5 - Shrink the log

USE <database name> DBCC SHRINKFILE (N’<database name>_log’)

The log will now be down to a size reasonable size. To keep your log small on the development server, set the Recovery Model to ‘Simple’. Let me know how this process works for you!