Below are some Microsoft SQL Server (MSSQL) scripts I find myself coming back to from time to time. Feel free to use anything you want and check back occasionally as this page will be under a perpetual state of construction.
Table of Contents
Cursor Template
Custom DB Role: db_execute
Databases Failing Backup SLAs
Date/Time Partition Function
Maintenance Plan Execution History
Script out a Database Role
Server\Instance Information
Superfluous Indexes
Cursor Template
I created this when I first started as a DBA. Since I rarely use cursors I reference this if I ever find a need for one:
-- Declare the cursor DECLARE myCursor CURSOR FOR SELECT Col1, Col2, etc... FROM Table1 WHERE Condition = 'something' ORDER BY IsNotNecessary -- Declare your parameters that will hold that current row's values -- when traversing through the cursor DECLARE @myCol1 INT, @myCol2 VARCHAR(50), @myetc... -- Inject the data into the cursor OPEN myCursor FETCH NEXT FROM myCursor INTO @myCol1, @myCol2, @myetc... -- Enter the While Loop. This loop will end when you reach the -- end of the data you injected into the cursor. WHILE @@FETCH_STATUS = 0 BEGIN -- Here you can manipulate any part of your parameters -- The following is an example INSERT INTO #somePreviousDeclaredTempTable (Columns..., @myCol1, @myCol2, @myetc...) VALUES ((SELECT COLUMNS FROM OtherTable WHERE PKEY = @myCol1), @myCol1, @myCol2, @myetc...) -- Traverse the Data in the cursor FETCH NEXT FROM myCursor INTO @myCol1, @myCol2, @myetc... END -- Close and deallocate the cursor because you've finished traversing all it's data CLOSE myCursor DEALLOCATE myCursor
Databases Failing Backup SLAs
Here’s a handy script to determine which database(s) within your organization are failing to meet your established backup SLAs. This will fit easily into a SQL Server job that emails you the report (if any output is present) on a daily basis to allow for streamlined administration.
Custom DB Role: DB_EXECUTE
This is a custom database role I often add to the model database during my Post-Installation Configuration process. This role grants execute rights against any stored procedure in the database. This is helpful for those users that require read/write/execute permissions.
USE [model] GO CREATE ROLE [db_execute] GRANT EXECUTE TO [db_execute]
Date/Time Partition Function
This scalar-valued UDF converts any date/time value passed to it into a 15 minute bucket of time. I’ve put comments into it going over the calculation so you can modify it for buckets of your choosing. This can be helpful when aggregating data by chunks of time.
CREATE FUNCTION dbo.TimePartition ( @myDate SMALLDATETIME ) RETURNS SMALLDATETIME AS BEGIN RETURN ( SELECT CONVERT(SMALLDATETIME, CONVERT(NUMERIC(10, 5), -- Convert to an INT for easier math CONVERT(INT, CONVERT(NUMERIC(10, 5), -- Date is inconsiquential because we want increments of time. -- Strip off Date by Subtracting Day 0 from the Date CONVERT(NUMERIC(10, 5), @myDate) - DATEDIFF(d, 0, @myDate) ) -- Multiply by Number of Hours in a day, then by Number of Partitions you want per Hour -- and the 0/1 will determine if bucket falls "down" or "up" to the next partition * 24 /*Hours in a Day*/ * 4 /*# of Partitions/Hour*/ + 0 /*0 if go down 1 if go up*/ ) -- divide by this same amount to strip any excess information off of the partitions ) / 24 / 4 -- Add back the Date taken off in the second step and Convert back to Datetime + DATEDIFF(d, 0, @myDate)) ) END
Maintenance Plan Execution History
If you utilize Maintenance Plans in SQL Server, you may often find that the job history is absent of sufficient detail. This routine will show all execution history available for the Maintenance Plan you specify.
-- Enter the Maintenance Plan Name in the Variable below. -- If thre is a . in the name, enter everything before that, -- e.g. if Backup Databases.Daily, enter Backup Databases DECLARE @PlanName NVARCHAR(255) SET @PlanName = 'Maintenance Plan Name' SELECT ld.line1 AS Line1, ld.line2 AS Line2, ld.line3 AS Line3, ld.line4 AS Line4, ld.line5 AS Line5, ld.server_name AS ServerName, ld.start_time AS StartTime, ld.end_time AS EndTime, ld.succeeded AS Succeeded, ld.error_number AS ErrorNumber, ld.error_message AS ErrorMessage, ld.command AS Command FROM msdb.dbo.sysmaintplan_plans s INNER JOIN msdb.dbo.sysmaintplan_subplans sp ON sp.plan_id = s.id INNER JOIN msdb.dbo.sysmaintplan_log spl ON spl.subplan_id = sp.subplan_id INNER JOIN msdb.dbo.sysmaintplan_logdetail ld ON ld.task_detail_id = spl.task_detail_id WHERE s.name = @PlanName ORDER BY StartTime DESC
Script out a Database Role
One of the shortcommings of SQL Server Management Studio is it’s inability to script out a database role. I went to some lengths to come up with a custom script that will do this for you rather quickly. Check out the full post here.
Server\Instance Information
This will return expanded server information and instance information of your choosing. If you wish to expand the information returned about the instance look at the SERVERPROPERTY function for more options.
-- Expanded Server Information EXEC xp_msver -- Instance Information (http://msdn.microsoft.com/en-us/library/ms174396.aspx) SELECT SERVERPROPERTY('ProductVersion') AS [Version], SERVERPROPERTY('ProductLevel') AS [Service Pack], SERVERPROPERTY('Edition') AS [Edition], SERVERPROPERTY('ProcessID') AS [Task Manager PID]
Superfluous Indexes
This will display all non-clustered indexes in a database that have more than 10000 records, but have been accessed less than 100 times since the most recent instance restart, time of index creation, or detach/attach operation for said database. Feel free to adjust the number of records and reads as required to hone in on superfluous (aka underutilized) indexes in your environment.
SELECT OBJECT_NAME(s.OBJECT_ID) AS [TableName], i.name AS [IndexName], i.index_id AS [IndexID], user_seeks + user_scans + user_lookups AS [TotalReads], user_updates AS [Updates], p.ROWS AS [Records], (ps.used_page_count * 8 )/ 1024 AS [IndexSize(MB)] FROM sys.dm_db_index_usage_stats s JOIN sys.indexes i ON i.index_id = s.index_id AND s.OBJECT_ID = i.OBJECT_ID JOIN sys.partitions p ON p.index_id = s.index_id AND s.OBJECT_ID = p.OBJECT_ID JOIN sys.dm_db_partition_stats ps ON ps.index_id = i.index_id AND ps.OBJECT_ID = i.OBJECT_ID WHERE OBJECTPROPERTY(s.OBJECT_ID,'IsUserTable') = 1 AND s.database_id = DB_ID() AND i.type_desc = 'NonClustered' -- Adjust the following values as needed AND p.ROWS > 10000 AND user_seeks + user_scans + user_lookups < 100 ORDER BY TotalReads, Records DESC