Is a Deprecated feature making my job more difficult?

By definition, a “deprecated” feature refers to a feature or specific function in a piece of software that will be replaced with a newer function/feature or just flat out will be no longer available.

Microsoft is notorious for changing and/or removing features in every version of SQL!  SQL 2014 has an extensive list of deprecated features: https://msdn.microsoft.com/en-us/ms143729.aspx.

The one I found out about today is SET FMTONLY (format only).  This particular setting allows a stored procedure to return the format of the results without actually returning results. This feature has been available since SQL 2005 and apparently will be removed from a future version, to be determined later.

   1: USE AdventureWorks2012;

   2: GO

   3: SET FMTONLY ON;

   4: GO

   5: SELECT * 

   6: FROM HumanResources.Employee;

   7: GO

   8: SET FMTONLY OFF;

   9: GO

In my line of work, I do a lot of SSIS packages that export information to flat files.  And my developers use temp tables religiously.  The problem with this, SSIS packages typically have a problem with resolving the columns of the final result set from a stored procedure when temp tables are used.  The use of SET FMTONLY OFF allows the SSIS package to resolve the stored procedure without attempting get the column definitions first so the statements can complete, which in turn presents the SSIS Data Source with the final column definition.

Beginning in SQL 2012 two new features were debuted to replace FMTONLY setting.

sp_describe_first_result_set Returns the metadata for the first possible result set of the Transact-SQL batch.

   1: sp_describe_first_result_set [ @tsql = ] N'Transact-SQL_batch' 

   2:     [ , [ @params = ] N'parameters' ] 

   3:     [ , [ @browse_information_mode = ] <tinyint> ] ]

sys.dm_exec_describe_first_result_set This dynamic management function takes a Transact-SQL statement as a parameter and describes the metadata of the first result set for the statement

   1: sys.dm_exec_describe_first_result(@tsql, @params, @include_browse_information)

Why 2 you ask?  I have no clue.  These two seem to do the same thing, not sure why two different ways to do the same thing, but I digress…

The point of this article is now when I create a stored procedure with temp tables for an SSIS package, I have to pass the T-SQL statements as a parameter into these function first then execute the T-SQL statements.

Maybe I am too much of a novice, but to take a stored procedure with several hundred lines of code and turn it into a variable @tsql, then pass that variable into a function just to get column definition, then EXEC @tsql sounds more difficult than simply typing SET FMTONLY OFF; Apparently smarter people than me have decided this is the best way to do this.

Of course by accident, I discovered another, almost as simple, solution for SSIS packages and temp tables.  Instead of using a temp table, define a Table Variable at the beginning of the stored procedure.  This @TableVariable will be your final result set, insert records into this table. Using this method, your stored procedure can still use temp tables and have a defined result set for the SSIS data source. 

So, to answer the original question:  Is a deprecated feature making my job more difficult? 

Well, Yes and No.  Yes, because I believe the replacement feature is more difficult to execute and write code for, especially when your stored procedure has multiple statements.  And adding more steps to an already lengthy process is never a good thing. 

And No, because I found a just as easy useable solution with table variables. I just switch # for @ and define my columns.  easy as 1…2…3!

Where is the key to the LOCK?

This past Friday evening, a simple data import process (that has been working for several months), decided to not work correctly.  Because there was no “early warning” type of notifications systems on the SQL 2005 server, the SQL Agent Job was actually running when Monday morning rolled around.

Using Idera’s SQL Check, I quickly noticed that there was a process that had a lock on a table that was causing some MAJOR problems.  Four different SQL processes was waiting on this lock.  And of course my supervisor was getting calls left and right from end users because their applications were not working.

I had to figure out what was going on.  I was able to get a list of processes and which one was causing all the problem with the sp_who2 command.

sp_who2'active'

However, this returned a “bias” HOST NAME.  I am not really sure why. But I confirmed with networking that the returned hostname and IP address do not exist on our network, but that is for another day.

I needed to know an accurate way to get all the information I needed at that moment when a job wrongs long.  This code is probably providing way more information than I really need, but sometimes more is better.  Even though the “host_name” is returning a “bogus” host name; the client_net_address is not!  This valid IP address is very important to locating the culprit machine.

SELECT 
    C.session_id
    ,C.client_net_address
    ,S.host_name
    ,S.Client_version
    ,S.client_interface_name
    ,S.login_name
    ,S.original_login_name
    ,db_name(R.database_id) AS [DB Name]
    ,R.status
    ,R.command
    ,R.blocking_session_id
    ,R.wait_type
    ,R.percent_complete
    ,wait_resource
    ,C.net_transport
    ,C.protocol_type
    ,C.auth_scheme
    ,C.last_read
    ,C.last_write
    ,S.cpu_time
    ,S.memory_usage
    ,(S.total_elapsed_time/1000) AS [Total Sec]
    ,S.lock_timeout
FROM sys.dm_exec_connections AS C
JOIN sys.dm_exec_requests AS R
    ON C.session_id=R.session_id
JOIN sys.dm_exec_sessions AS S
    ON C.session_id=S.session_id
ORDER BY session_id

Using Thomas LaRock’s  HOW TO: Find Currently Running Long SQL Agent Jobs, I setup up a simple 2 step SQL Agent job to check for 1) long running jobs and 2) session information (using the code above).  A simple “save results to txt file” allows me to export the results to and study them later.

USE [msdb]
GO
/****** Object:  Job [job_WH_MonitorDatabase]    Script Date: 10/30/2012 13:57:18 ******/
BEGIN TRANSACTION
DECLARE @ReturnCode INT
SELECT @ReturnCode = 0
/****** Object:  JobCategory [xx] Script Date: 10/30/2012 13:57:18 ******/
IF NOT EXISTS (SELECT name FROM msdb.dbo.syscategories WHERE name=N'xxx' AND category_class=1)
BEGIN
EXEC @ReturnCode = msdb.dbo.sp_add_category @class=N'JOB', @type=N'LOCAL', @name=N'xxx'
IF (@@ERROR <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback

END

DECLARE @jobId BINARY(16)
EXEC @ReturnCode =  msdb.dbo.sp_add_job @job_name=N'job_MonitorDatabase', 
        @enabled=1, 
        @notify_level_eventlog=0, 
        @notify_level_email=2, 
        @notify_level_netsend=0, 
        @notify_level_page=0, 
        @delete_level=0, 
        @description=N'’, 
        @category_name=N'xx', 
        @owner_login_name=N'INFOSYS\xx', 
        @notify_email_operator_name=N'xx', @job_id = @jobId OUTPUT
IF (@@ERROR <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback
/****** Object:  Step [Monitor]    Script Date: 10/30/2012 13:57:18 ******/
EXEC @ReturnCode = msdb.dbo.sp_add_jobstep @job_id=@jobId, @step_name=N'Monitor', 
        @step_id=1, 
        @cmdexec_success_code=0, 
        @on_success_action=3, 
        @on_success_step_id=0, 
        @on_fail_action=2, 
        @on_fail_step_id=0, 
        @retry_attempts=0, 
        @retry_interval=0, 
        @os_run_priority=0, @subsystem=N'TSQL', 
        @command=N'exec usp_LongRunningJobs', 
        @database_name=N'master', 
        @flags=0
IF (@@ERROR <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback
/****** Object:  Step [RecordProcesses]    Script Date: 10/30/2012 13:57:18 ******/
EXEC @ReturnCode = msdb.dbo.sp_add_jobstep @job_id=@jobId, @step_name=N'RecordProcesses', 
        @step_id=2, 
        @cmdexec_success_code=0, 
        @on_success_action=1, 
        @on_success_step_id=0, 
        @on_fail_action=2, 
        @on_fail_step_id=0, 
        @retry_attempts=0, 
        @retry_interval=0, 
        @os_run_priority=0, @subsystem=N'TSQL', 
        @command=N'select
    sysp.spid AS [SPID]
    ,sysp.status AS [Status]
    ,sysp.hostname AS [Host Name]
    ,cn.client_net_address AS [Client IP]
    ,db_name(sysp.dbid) AS [DB Name]
    ,convert(sysname, rtrim(sysp.loginame)) as [Login]
    ,sysp.program_name AS [Program]
    ,sysp.cmd AS [CMD Status]
    ,sysp.cpu AS [CPU usage]
    ,sysp.physical_io [IO]
    ,sysp.blocked AS [Blocked By]
    ,sysp.waitresource AS [Wait Resource]
from master.dbo.sysprocesses AS sysp
INNER JOIN sys.dm_exec_connections AS cn 
    ON sysp.spid=cn.session_ID
WHERE sysp.dbid > 4 AND sysp.cmd <> ''AWAITING COMMAND''
ORDER BY sysp.hostname', 
        @database_name=N'master', 
        @output_file_name=N'F:\SQLAgent_Logs\RunningProcesses.txt', 
        @flags=2
IF (@@ERROR <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback
EXEC @ReturnCode = msdb.dbo.sp_update_job @job_id = @jobId, @start_step_id = 1
IF (@@ERROR <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback
EXEC @ReturnCode = msdb.dbo.sp_add_jobschedule @job_id=@jobId, @name=N'Daily', 
        @enabled=1, 
        @freq_type=4, 
        @freq_interval=1, 
        @freq_subday_type=4, 
        @freq_subday_interval=10, 
        @freq_relative_interval=0, 
        @freq_recurrence_factor=0, 
        @active_start_date=20121030, 
        @active_end_date=99991231, 
        @active_start_time=0, 
        @active_end_time=235959
IF (@@ERROR <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback
EXEC @ReturnCode = msdb.dbo.sp_add_jobserver @job_id = @jobId, @server_name = N'(local)'
IF (@@ERROR <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback
COMMIT TRANSACTION
GOTO EndSave
QuitWithRollback:
    IF (@@TRANCOUNT > 0) ROLLBACK TRANSACTION
EndSave:

Thanks for your time!  I will let you know how it turns out.

Back to the Basics (B2B: Intro)

On occasion, an IT personnel (non-DBA) is tasked with providing SQL support.  Either with installation, upgrading, backups, restores, moving databases or other tasks that normally would not fall under their “job description”.  Trust me I have been there.  We call these “Accidental DBA’s” and sometimes a strange thing happens, the person actually ENJOYS working with MS SQL.  At least that is what happened to me, I was a .NET developer in a corporation with no DBA and over 20 instances of MS SQL in our network.  As the developer, I did create databases, tables, views, etc.; but I didn’t lean SQL management until much later.

So if you are one of those accidental DBAs, where do you find more information on how to do DBA work.  I have always found www.sqlservercentral.com, www.mssqltips.com, and MS MSDN invaluable resources to find answers to questions.  I following some “gurus” of the industry on twitter and their blogs are never boring and always informative.  Some of my personal favorites, to just name a few:

  1. Brad McGehee
  2. Steve Jones
  3. Brent Ozar, PLF (which in reality you get 4, Brent Ozar, Jeremiah Peschka, Kendra Little, Jes Schultz Borland)
  4.  Penal Dave
  5. Thomas LaRock

Every non-DBA needs to know the simple and basic steps to manage MS SQL.  Although I am a fan of GUI interfaces, I will attempt to provide both T-SQL and GUI images to help along.  Yes, I know the evil GUI, most professionals will tell you that knowing and using T-SQL is the only proper way to manage a SQL instance.  However, for those of us that are used to a “point-and-click” environments sometimes learning the point-and-click methods is the quickest and easiest way, especially for those of us who are visual learners.  That being said, I encourage you to always script it out, so you can learn the T-SQL behind the GUI.

During this series I will hope to provide the following information:

  1. How to install SQL; standalone vs. network, there is a difference!
  2. Working with SQL Server Management Studio SSMS
  3. Documentation: Why, I can remember the name of the server? 
  4. Documentation Part 2: Didn’t realize the database was that big.
  5. Maintenance plans (they are not just for backups)
  6. Definition of and creating a Disaster Recovery plan

As of now these are the topic I plan to cover in my Back to Basics series.  Although I reserve the right to edit this, I believe if an “accidental” DBA would learn these, then they could probably drop the “accidental” form their title.

Playing with SQL 2012…(and a rookie mistake)

So I thought I would install SQL 2012 Express with Advanced Services on a Windows 2008 R2 box in the hopes of playing with the new edition and using it as a platform for a new SQL Monitor Solution I am building.

First thing I learned, the hard way, was .NET 3.5 SP1 (which is required for SQL 2012) is not “enabled” by default on Windows 2008. It is installed, but not enabled.  Open System Manager and find “Features”.  Click “Add New Feature” and select .NET 3.5.  This will prompt you to enable IIS and all associated features need to enable .NET 3.5.

Once this pre-requisite was “installed” installation of SQL Express went without a hitch.  I used default settings in most places, except for Service Account information.  I setup a domain service account to run the SQL Services.  All was good.

I then opened SQL Server Configuration Manager to enable TCP/IP connection so I could have remote access.  Except one simple problem, I couldn’t connect.  I double checked all my steps, and still could not connect.  After some “Bing”-ing (I dislike that G company), I realized my “rookie mistake”.  Thanks to this 7 YEAR OLD blog post, realized I forgot to enable SQL Browser.    http://blogs.msdn.com/b/sqlexpress/archive/2005/05/05/415084.aspx

Silly, silly me!