SQL Server Contention Monitor (super-alpha) posted to Codeplex

(Obviously with Codeplex long gone, I migrated over to Github – I don’t have the commit history anymore but maybe this code is still interesting to somebody)

In response to some conversation in an Experts-Exchange question, I decided to post an application I wrote about four years ago and never did anything with (or add much polish, as you’ll see). It’s a small VB.NET application that polls MSSQL servers and displays information about currently blocked SPIDs, as well as the block chain and age of blocked processes.

It’s something I’ve used when I troubleshoot blocking on a SQL Server, and generally leave running in my system tray – it will pop up a balloon when there’s a blocked process that lasts longer than some pre-determined threshold, and then optionally pop another balloon when it’s resolved. It works well as an early warning system for a critical server, and I’ve often used it when I’m performing maintenance on a production server that I’m concerned might block legitimate use – running the application lets me know within a few seconds when I’ve gotten in somebody’s way so I can act accordingly.

It’s still very much a work in progress and is pretty rough around the edges (and well inside the edges), but I’ve posted it to a Codeplex project Github repository for anybody else who might find it useful. Though I’m working on a few other things right now and haven’t done any development with this app in almost four years, I’ll keep an eye on the issues list at Codeplex Github (or feedback here) and try to address anything that comes up.

Without any further ado, here it is!

https://mssqlblockmonitor.codeplex.com/ https://github.com/rwmnau/sql-contention-monitor/

Powershell command to get current sessions on an IIS site

After a Powershell session at SQL Saturday (Phoenix #131) this weekend, I’m now suddenly on the lookout for handy powershell commands. The first one lets you see the number of Active* sessions on your IIS site (* because HTTP is stateless, it’s really the number of connections that have been opened recently – not what’s currently active, which is likely next to zero. I tried browsing around on a test site and it showed only my one user connected).

To get the currently active user count, here’s the powershell:

# Ensure you use the server's actual name, not LOCALHOST, which won't work
$Servername = "Your Server Name"
$Sitename = "Name of your IIS Site"

Get-Counter "\\$ServerName\web service($SiteName)\current connections"

Presenting a pair of lightning sessions at SQL Saturday in Phoenix

I’ll be presenting a pair of lightning sessions at SQL Saturday in Phoenix, AZ, on April 28th – if you’re in the area and up for a day of free training on everything database-related, as well as some networking time with your fellow DBAs and Developers, please join us!

Here’s the summary for my two lightning sessions (they’ll be 15 minutes each):

Automating SQL Server source control – This session will look at a quick and easy process that takes regular snapshots of object definitions in the database and stores any changes.

Representing SQL Server data spaces visually – This session will take a quick look at a Codeplex Github project that does this, SQL Space Map, and how it accomplishes it by leveraging a library from Microsoft Research (Obviously with Codeplex no more, I’ve migrated this code to Github, though it still hasn’t been updated in probably 10 years)

If you’d like to see what else is planned for the day, http://sqlsaturday.com/131/schedule.aspx. You can also follow the event on twitter at #sqlsat131

Export from SQL Server to XLS and email results

Sometimes you want to take some query results and export them directly to an XLS file – here’s how you can set that up in SQL Server. The biggest caveat is that you need to run it from an x86 instance of SQL Server – the x64 instance won’t have access to the Jet driver needed to write the Excel file (Microsoft.Jet.OLEDB.4.0), where the x86 version will. In fact, we maintain an older x86 instance of SQL Server for random processes like this that need it – x64 is better in almost every case, but we can’t see to completely ditch x86… 🙂

I use a stored proc that I call from a SQL Agent Job, which works great. The actual process is a bit awkward – for starters, you’ll need access to xp_cmdshell. SQL Server can’t create a new Excel file from scratch, so you have to keep a blank Excel file around, make a copy of it, and then insert into the copy to get your final result.

That said, here’s the code to generate the XLS file from your query results:

SELECT Column1, Column2, Column3, Column4
  INTO ##YourTempTable
  FROM SomeOtherTable

SET @Folder = 'C:\Temp\'
SET @DocumentBlank = 'Your Document - Blank'
SET @DocumentLong = 'Your Document - ' + CONVERT(VARCHAR(10), GETDATE(), 120)

DECLARE @CMD NVARCHAR(4000)
SET @CMD = 'COPY "' + @folder + @DocumentBlank + '.xls" "' + @Folder + @DocumentLong + '.xls"'
exec master..xp_cmdshell @CMD

-- Export the Excel sheet
SET @CMD = 'insert into OPENROWSET(''Microsoft.Jet.OLEDB.4.0'',
	''Excel 8.0;Database=' + @Folder + @DocumentLong + '.xls;'',
	''SELECT * FROM [Sheet1$]'')
	select Column1, Column2, Column3, Column4 from ##YourTempTable'

exec sp_executesql @CMD

Once that’s exported, you can just set up the email process using sp_send_dbmail and attach the file you just generated:

DECLARE @Body VARCHAR(2000)

SET @Attachments = @Folder + @DocumentLong  + '.xls'
SET @Body = 'Your file has been generated for ' + CONVERT(VARCHAR(10), GETDATE(), 120)

exec msdb..sp_send_dbmail @profile_name = 'YourMailProfile',
	@Recipients = 'Recipients@YourDomain.biz',
	@subject = 'Your file is ready',
	@Body = @Body,
	@file_attachments = @DocumentLong

Return a list of all dates between a start and end date

In some situations, you’ll need to work with a list of numbers or dates that are between some start or end, and you don’t have a complete list handy for joining to. Using the script below, you can create one to use in your query – if you wanted to use this in-line in another SQL Statement (and assuming you’re using SQL 2005+), you could either do a subquery or a WITH CTE clause and then join directly to it.

To do it, I’m using a table that has a large number of rows in it, even in an empty database (sys.columns), and then doing a cross-join to ensure that I’ll have enough rows to satisfy my entire range. This table has about 890 rows in an empty databases (or you can use the “model” database if you don’t have any user databases handy), meaning that the cross join yields about 800,000 rows – enough for almost 2200 years of days, or 100 years of hourly increments (change the “dd” in the “DATEADD” statements below to “hh” or even “mi” to do any increment of time you want).

The code:

DECLARE @StartDate DATETIME,
	    @EndDate   DATETIME

	SET @StartDate = '2012-12-01'
	SET @EndDate   = '2015-12-31'

;WITH numberlist(number)
   AS (SELECT RANK() over(order by c1.object_id,
								   c1.column_id,
								   c2.object_id,
								   c2.column_id)
	     from sys.columns c1
   	    cross
	     join sys.columns c2)
SELECT DATEADD(dd, number-1, @StartDate)
  FROM numberlist
 WHERE DATEADD(dd, number-1, @StartDate) <= @EndDate

I’m using dates above, but if you wanted to use INT instead, it’s pretty straightforward:

DECLARE @Start INT,
		@End   INT

	SET @Start = 1500
	SET @End   = 64000

;WITH numberlist(number)
   AS (SELECT RANK() over(order by c1.object_id,
								   c1.column_id,
								   c2.object_id,
								   c2.column_id)
	     from sys.columns c1
   	    cross
	     join sys.columns c2)
SELECT @Start + number - 1
  FROM numberlist
 WHERE @Start + number - 1 <= @End