Wednesday, 6 July 2016

Tempdb monitoring - Free space alert

SQL Server uses tempdb for many features, including row versioning, service broker and query execution amongst others.  During the execution of queries, data used for sorts and hash joins can be “spilled” to tempdb if the memory granted to the query isn't enough to store the data.  If this happens for a very big query or lots of small queries or for queries on instance that makes extensive use read committed snapshot or any combination of many reasons, an error resembling the one below can be received...


Msg 1105, Level 17, State 2, Line 3
Could not allocate space for object 'dbo.SORT temporary run storage: 140737494384640' in database 'tempdb' because the 'PRIMARY' filegroup is full. Create disk space by deleting unneeded files, dropping objects in the filegroup, adding additional files to the filegroup, or setting autogrowth on for existing files in the filegroup.

Due to the way I configure tempdb (a single drive dedicated to the datafiles with multiple equal sized datafiles all pre-grown to their maximum size) the advice offered in the error message wont work. Instead, I create a SQL Agent alert to warn me before the space is all used up.

Recreating the problem

Running the following query in Adventure Works will create a plan with sorts and hash joins, but with the correct statistics and enough memory available, will not need to use tempdb...

SELECT * 
FROM Sales.SalesOrderDetail s1 
INNER HASH JOIN Sales.SalesOrderDetail s2 
ON s1.rowguid = s2.rowguid 
ORDER BY s1.rowguid












PerfMon confirms that the free space in tempdb doesn't change...



















By fooling the optimiser into thinking there's only 1 row in the table...

UPDATE STATISTICS Sales.SalesOrderDetail WITH ROWCOUNT = 1

...the query plan generated will include a spill to tempdb because the estimated number of rows is very wrong and the subsequent memory grant is too low.










...and tempdb will have to store the data, as can be seen in PerfMon.




















This isn't a problem if the space in tempdb is available but if the there isn't enough space, errors will occur.
 









Solutions

What can be done when tempdb becomes full? Creating more space is the obvious answer. Enabling autogrowth on the datafile(s) can help but its best practise to have multiple, equal sized tempdb datafiles. Turning on trace flag 1117, which expands all datafiles in a filegroup at the same rate is a good idea although this is a server wide setting so will affect other databases on the instance.

My solution, creating an alert, doesn't really solve the problem but at least gives an early warning so evasive action can be taken.

“Tempdb is getting full” alert

Although I call it an alert, its actually made up of the following 3 things...

1 – A SQL Agent alert
2 – A SQL Agent job
3 – A stored procedure

Starting from the bottom, the stored procedure is used to find what's using tempdb and then send an email with this info. I check current running queries, the size of the row store and the size of permanent tables created in tempdb although other checks can be added. To check the current running queries, I use Adam Mechanics sp_whoisactive to look for queries with a tempdb_allocation above zero and insert the 5 with the highest values into a temporary table (yes, I realise what I'm doing here :-) ). I use sys.dm_os_performance_stats for the row store size and sys.allocation_units for the permanent table size.

Once all the tempdb checks are collected, a dynamic HTML block of code is built to be used to email the DBA team using sp_send_dbmail.

USE [master]
GO
CREATE PROC [dbo].[spTempDBSizeInfo]
AS
DECLARE @subject varchar(500)
DECLARE @body NVARCHAR(MAX)
DECLARE @body_format varchar(20) = 'HTML'

SELECT @subject = 'Free TempDB space on ' + @@ServerName + ' - ' + CAST(100 - cast((A.TotalSpaceInMB-cntr_value/1024)*100/A.TotalSpaceInMB as int) AS VARCHAR(3)) + '% left of ' + cast(A.TotalSpaceInMB as varchar(12)) + 'MB'
FROM sys.dm_os_performance_counters
CROSS APPLY (select sum(size)*8/1024 as TotalSpaceInMB from tempdb.sys.database_files where type = 0) AS A
WHERE counter_name = 'Free Space in tempdb (KB)'


CREATE TABLE [dbo].[#tblWhoIsActive](
[dd hh:mm:ss.mss] [varchar](8000) NULL,
[session_id] [smallint] NOT NULL,
[sql_text] [xml] NULL,
[login_name] [nvarchar](128) NOT NULL,
[wait_info] [nvarchar](4000) NULL,
[tran_log_writes] [nvarchar](4000) NULL,
[CPU] [varchar](30) NULL,
[tempdb_allocations] [varchar](30) NULL,
[tempdb_current] [varchar](30) NULL,
[blocking_session_id] [smallint] NULL,
[reads] [varchar](30) NULL,
[writes] [varchar](30) NULL,
[physical_reads] [varchar](30) NULL,
[query_plan] [xml] NULL,
[used_memory] [varchar](30) NULL,
[status] [varchar](30) NOT NULL,
[tran_start_time] [datetime] NULL,
[open_tran_count] [varchar](30) NULL,
[percent_complete] [varchar](30) NULL,
[host_name] [nvarchar](128) NULL,
[database_name] [nvarchar](128) NULL,
[program_name] [nvarchar](128) NULL,
[start_time] [datetime] NOT NULL,
[login_time] [datetime] NULL,
[request_id] [int] NULL,
[collection_time] [datetime] NOT NULL) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
EXEC sp_WhoIsActive
@get_transaction_info = 2,
@get_plans = 1,
@destination_table='#tblWhoIsActive'

SELECT TOP 5
[dd hh:mm:ss.mss],
session_id,
CAST(sql_text as varchar(MAX)) AS sql_text,
login_name,
(REPLACE(tempdb_current,',','')*8)/1024 as tempdb_current_MB,
(REPLACE(tempdb_allocations,',','')*8)/1024 as tempdb_allocations_MB,
CPU,
reads,
writes
INTO #tblWhoIsActive_temp
FROM #tblWhoIsActive
WHERE REPLACE(tempdb_allocations,',','') > 0
ORDER BY tempdb_allocations DESC
IF @@ROWCOUNT = 0
BEGIN
SET @body = N'<head>' + N'<style type="text/css">h2, body {font-family: Arial, verdana;} table{font-size:11px; border-collapse:collapse;} td{background-color:#F1F1F1; border:1px solid black; padding:3px;} th{background-color:#99CCFF;}</style>' +
N'<h2><font color="#0000ff" size="4">Free TempDB space</font></h2>' + N'</head>' + N'<p>' + ' ' + '</p>'+ N'<body>' + N' <hr> ' + N'<h1><font color="#0000ff" size="2">The top 5 TempDB intensive queries currently running are:</font></h1>' +
N' ' + N'<font color="#0000ff" size="2">No queries using TempDB currently running</font>' + N' ' + N' <br></br>' + N'<p>' + ' ' + '</p>'+ N' <hr> ' + N'<h1><font color="#0000ff" size="2">TempDB components size MB:</font></h1>' +
N' ' + N'<table border="1">' + N'<tr><th>PersistedTableSizeMB</th><th>VersionStoreSizeMB</th></tr>' +
CAST ( (
SELECT td = SUM(au.total_pages)*8/1024, '',
td = MAX(A.VersionStoreSizeMB), ''
FROM tempdb.sys.partitions p
INNER JOIN tempdb.sys.allocation_units au
ON p.hobt_id = au.container_id
CROSS APPLY (SELECT cntr_value/1024 AS VersionStoreSizeMB FROM sys.dm_os_performance_counters WHERE counter_name = 'Version Store Size (KB)') AS A
WHERE OBJECT_NAME(p.object_id) not like '#%'
FOR XML PATH('tr'), TYPE )
AS NVARCHAR(MAX) ) +
N'</table>' + N'</body>' ;
END
ELSE
BEGIN
SET @body = N'<head>' + N'<style type="text/css">h2, body {font-family: Arial, verdana;} table{font-size:11px; border-collapse:collapse;} td{background-color:#F1F1F1; border:1px solid black; padding:3px;} th{background-color:#99CCFF;}</style>' +
N'<h2><font color="#0000ff" size="4">Free TempDB space</font></h2>' + N'</head>' + N'<p>' + ' ' + '</p>'+ N'<body>' + N' <hr> ' + N'<h1><font color="#0000ff" size="2">The top 5 tempdb intensive queries currently running are:</font></h1>' +
N' ' + N'<table border="1">' + N'<tr><th>[dd hh:mm:ss.mss]</th><th>session_id</th><th>sql_text</th><th>login_name</th><th>tempdb_allocations_MB</th><th>tempdb_current_MB</th><th>CPU</th><th>reads</th><th>writes</th></tr>' +
CAST ( (
SELECT td = [dd hh:mm:ss.mss], '',
td = session_id, '',
td = CAST(sql_text AS VARCHAR(256)),'',
'',
td = login_name, '',
td = tempdb_allocations_MB, '',
td = tempdb_current_MB, '',
td = CPU, '',
td = reads, '',
td = writes, ''
FROM #tblWhoIsActive_temp
ORDER BY tempdb_allocations_MB DESC
FOR XML PATH('tr'), TYPE )
AS NVARCHAR(MAX) ) +
N'</table>' + N' <br></br>' + N'<p>' + ' ' + '</p>'+ N' <hr> ' + N'<h1><font color="#0000ff" size="2">TempDB components size MB:</font></h1>' + N' ' + N'<table border="1">' +
N'<tr><th>PersistedTableSizeMB</th><th>VersionStoreSizeMB</th></tr>' +
CAST ( (
SELECT
td = SUM(au.total_pages)*8/1024, '',
td = MAX(A.VersionStoreSizeMB), ''
from tempdb.sys.partitions p
INNER JOIN tempdb.sys.allocation_units au
ON p.hobt_id = au.container_id
CROSS APPLY
(SELECT cntr_value/1024 AS VersionStoreSizeMB FROM sys.dm_os_performance_counters WHERE counter_name = 'Version Store Size (KB)') AS A
WHERE object_name(p.object_id) not like '#%'
FOR XML PATH('tr'), TYPE ) AS NVARCHAR(MAX) ) +
N'</table>' + N'</body>'
END

EXEC MSDB.dbo.sp_send_dbmail
@profile_name = 'ProfileName'
,@recipients = 'DBATeam'
,@subject = @subject
,@body = @body
,@body_format = @body_format



The stored procedure is called by an unscheduled SQL Agent Job.























The SQL Agent job is executed by a performance condition alert being triggered within SQL Agent alerts, with the option set to only raise the alert every 5 minutes. This value maybe too high for some people but can be altered on the options page.

























The SQL Agent alert is configured to be triggered when the Free Space falls below a certain value, which I normally set at 50% of the size of tempdb.






















As tempdb size can differ for different instances, i've done a little bit of TSQL trickery to make the script runnable on any instance.


USE [msdb]
GO
DECLARE @PercentToWarn DECIMAL(12,2) = 50
SET @PercentToWarn = @PercentToWarn/100

DECLARE @InstanceName VARCHAR(128) =
(SELECT CASE WHEN SERVERPROPERTY ('InstanceName') IS NULL THEN 'SQLSERVER'
ELSE 'MSSQL$' + CAST(SERVERPROPERTY ('InstanceName') AS VARCHAR(32)) END)

DECLARE @TempWarnSize INT = 
 (SELECT SUM(size)*8 FROM tempdb.sys.database_files WHERE type = 0) * @PercentToWarn
 
DECLARE @Job_id UNIQUEIDENTIFIER = (
 select job_id FROM sysjobs WHERE name = 'zzTempDB_Size_Info')
 
DECLARE @PerfCond VARCHAR(1024) = 
@InstanceName + ':Transactions|Free Space in tempdb (KB)||<|' + CAST(@TempWarnSize AS VARCHAR(132)) + ''

BEGIN
TRY
EXEC msdb.dbo.sp_help_alert 'FreeSpaceInTempdb'
END TRY

BEGIN
CATCH
EXEC msdb.dbo.sp_add_alert
@name=N'FreeSpaceInTempdb',       
@enabled=1,       
@delay_between_responses=300,       
@include_event_description_in=0,      
@performance_condition=@PerfCond,       
@job_id=@Job_id
END CATCH                 
GO


Results 

When tempdb free space drops below the configured value (50% by default although on this instance its configured to 80%), an email will be sent the DBAs.










Further Reading 

Although the tempdb 2005 whitepaper is starting to get a bit old, the details contained within are still largely relevant to subsequent SQL Server versions and is an informative read.

https://technet.microsoft.com/en-gb/library/cc966545.aspx

Also worth watching is a PASS lecture called Inside Tempdb by Bob Ward.

https://www.youtube.com/watch?v=SvseGMobe2w&feature=share&list=PLF80A8A233EE9F22F

Wednesday, 3 February 2016

Recertifying SQL Server 2012 MCSE with Microsoft Virtual Academy

Do people still get certified? I don’t hear much about it in the SQL community these days so I asked my twitter friends.












Nobody replied :-) Maybe thats a sign of peoples interest (or just that I need better friends)

Anyway, I'm still interested and I decided it was time to upgrade my MCSE Data Platform for SQL Server 2012 to 2014. After checking out the Microsoft Learning website (https://www.microsoft.com/en-us/learning/recertification-virtual-academy.aspx), it turns out there’s a new way to get recertified. Although its still possible to take an exam (70-469), there’s now a second option which involves watching a bunch of online videos and taking an assessment after each module. On passing all assessments, sending an email to Microsoft is enough to claim the recertification.

I've had a couple of issues with the exam route for certification over the years. I once booked two exams back to back on a Saturday morning. After turning up at the exam centre, I found it was closed and learned later that it never opened at weekends. Prometric had made some mistake in promoting the exams. I also was never quite sure if I had done enough work to get the 70% pass mark. There were a few times I’ve spent the £100 to book an exam and came out with 60%, needing to retake it some other time. Hopefully, the new module based exam system removes these kind of problems.

The syllabus for the exam is detailed on the the Microsoft website. (https://www.microsoft.com/en-us/learning/recertification-virtual-academy.aspx). As a DBA, I'm interested in option 2...














My initial thoughts on seeing the syllabus were...

...looks like some good things (Azure, Upgrading to 2014, Updating 2014 skills), some “Why does a 2012 MSCE need to do these” things (Database Fundamentals???, Administrating 2012!!!) and some “What the hell does this have to do with DBAing!!!” things (Networking Fundamentals!!!!). Was very disappointed to not see a whole section specifically on Powershell.

Each section is split into a number of modules, which will group a couple of related concepts. For each module, an assessment needs to be passed. For example, in the Database Fundamentals topic, these are the following modules...














...and within the Introduction to Core Database Concepts, theres a video covering three concepts and a five question assessment.










This pattern is followed with all the topics.

I will work through all the topics, updating this post with my opinion on each.


Database Fundamentals

[20160115] Just over one minute into the first module, the following slide is show...


 




...with the presenter saying this topic relates to the MTA exam.

Is this really what a SQL Server 2012 MSCE should be learning to recertify?

Each assessment is pretty simple for an experienced DBA. The final module has a 10 question assessment, with questions of the following calibre...








I didn't even bother watching all the videos in the end.


Microsoft Azure Fundamentals: Storage and Data

[20160120] I was looking forward to this topic and with over 4 hours of videos to watch, was hoping for a lot of content. There were quite a few modules covered, Azure table storage, blob storage, queues, Azure SQL and DocumentDB, with each containing a introduction video and then a “How To” accompaniment. Unfortunately, the “How To” was a bunch of C# code in Visual Studio, not very useful for a DBA. And there were a lot of “How To” videos in the topic so a lot of C#.

The modules followed the same pattern of a video and then assessment. Maybe someone realised these modules were more developer focused as the assessment contained only a single question.

For example, one of the questions in the assessment was this....











not really something a DBA should know, in my opinion.


Querying with Transact-SQL

[20160126] Again, more level 100\200 topics with a 5 question assessment at the end. Although there were a couple of topics that piqued my interest (Using Subqueries and APPLY, Error Handling and Transactions) most were too simple for an experienced DBA to spend time watching (Querying Tables with SELECT, Querying Multiple Tables with Joins), so I just skipped straight to the assessments.


Windows Server Administration Fundamentals

[20160202] A lot of people get into DBA'ing accidentally by being the server admin guy who looks after the database. This wasn't me so my server admin skills are pretty low, hence I was quite interested in a lot of the topics being covered in this module (Managing Storage, Monitoring and Troubleshooting Servers). Unfortunately, these topics are again aimed at 100\200 level and any mid-level or senior DBA should be well aware of the topics covered (RAID levels, using PerfMon)

Shout out to the two guys presenting the videos. They can be pretty cringeworthy at times but at least their style is entertaining and I even occasionally laughed.


Networking Fundamentals and Security Fundamentals
So many three letter acroymns I'll never need to know for work.

Administering Microsoft SQL Server 2012 Jump Start
Although this recertification is for people who have already passed their 2012 exams, I quite enjoyed this recap and was reminded of a couple of areas I need to do some further studying. Would question the reason time was spent on teaching deprecated features such as Profiler and Database Mirroring instead of further time on Extended Events and Availability Groups though.

Same as the other sections, each topic is split into videos of around an hour with a 5 question assessment at the end.

Dont tell Paul Randal but apparently, autoshrink isnt a cardinal sin...














Upgrading to Microsoft SQL Server 2014

[20160522] All the content is very sensible but doesn't really apply solely to 2014. The process would be applicable for upgrading from 2005 to 2008 or 2008 to 2012. 

Updating your Database Management Skills to SQL Server 2014

The first module started promisingly with information on buffer pool extensions, memory optimised tables and enhancements made to columnstore indexes for 2014. Unfortunately, the next four modules cover master data services, data quality services, availability groups and contained databases, which to my knowledge, are all 2012 features which haven't been considerable enhanced with 2014. Very strange to include them. Would've much preferred to see information on the new cardinality estimator, delayed durability and backup and restore enhancements.

The last topic covers SQL Server and the Cloud, which shows how to create and migrate on premise databases to SQL Azure database and SQL VM's created in the cloud. I found this topic to be very informative and would've preferred a more time spent on going into more in depth detail.



Getting the certification

Once all the modules have been completed and the assessments have been passed, an email to microsoft is all thats left before gaining the recertification.

Microsoft require the following information to process the request

  • The name of the certification speciality (for example, MCSE: Communication)
  • Your Microsoft Academy user name
  • Your Microsoft Certification ID (MC ID)
  • A PDF copy of your Microsoft Virtual Academy transcript

The certification name is MCSE: Data Platform , I guessed my user name (my email address) and the MC ID can be retrieved by logging into the recertify page. Finding where to download the PDF copy of the MVA transcript was a little harder though. It turns out the information is under the DASHBOARD option on the topics page.













In the dashboard, hopefully all the modules will be under the courses completed. Unfortunately, if (like me) you have any modules that weren't completely finished, you may have them under courses in progress.










All these courses need to be advanced to 100% which could include re-watching the videos or clicking through the additional information.

Once all the courses have reached 100%, the transcript can be downloaded from the courses completed tab.










Attach the downloaded transcript to an email with the above information, send to certquest@microsoft.com and up to 5 days later you will be recertified. I got my reply within an hour.


When notification is received from Microsoft that the recertification is complete, the MCP Transcript will be updated with a new expiry date for 3 years time for the Microsoft Certified Solutions Expert.










Summary

I was happy to see Microsoft changing the certification process to allow a easier and cheaper way to upgrade. Unfortunately, I cant say I'm that impressed with the result. As a DBA, I use SQL Server every day and wanted to upgrade my 2012 knowledge to 2014. What I got was a lot of very basic database information which wasn't 2014 specific or a lot of totally unnecessary information. I did enjoy the Azure content so all was not lost.

As I said at the start of this blogpost, I dont think people are interested in getting certified anymore, which is a shame. Maybe the option to take the exam would test my database skills (https://www.microsoft.com/en-gb/learning/exam-70-469.aspx) and maybe I will take the exam sometime in the future. But I feel like this new way to get certified has further devalued the certification process.