Showing posts with label Jobs. Show all posts
Showing posts with label Jobs. Show all posts

Monday, 27 February 2012

A Script A Day - Day 23 - Find an Object In Job Steps

Today’s script is one which saves me a lot of time on occasion.  On large systems with lets say more than 100 jobs it is esential to manage them properly and the smallest thing like naming conventions help a lot.  So what if you want to check if an object lets say a stored procedure is executed in a job, you aren’t going to search through all 100+ jobs and potentially 1000’s of job steps are you?  Hell No, you use a script, because we don’t like GUI’s ;)

The script below is simple enough just the one join from sysjobs to sysjobsteps and the only thing you need to do is to update the ObjectHere.  It is easy to see that you could use this script to search for any text in a job step not just an object!

/*
      -----------------------------------------------------------------
      Find an Object in Job Steps
      -----------------------------------------------------------------
     
      For more SQL resources, check out SQLServer365.blogspot.co.uk

      -----------------------------------------------------------------

      You may alter this code for your own purposes.
      You may republish altered code as long as you give due credit.
      You must obtain prior permission before blogging this code.
 
      THIS CODE AND INFORMATION ARE PROVIDED "AS IS"
     
      -----------------------------------------------------------------
*/
-- Change database context
USE msdb;
GO

-- Find object in a job step
SELECT
      sj.name,
      sj.[enabled],
      sjs.step_id,
      sjs.step_name,
      sjs.command
FROM    msdb.dbo.sysjobs sj
      INNER JOIN msdb.dbo.sysjobsteps sjs ON sj.job_id = sjs.job_id
WHERE sjs.command LIKE '%ObjectHere%';
GO

Enjoy!

Chris

Wednesday, 11 January 2012

System Stored Procedures

I've been using 4 alerts for corruption now for about 2 years for Errors 823, 824, 825 and 9100.  Basically I would create an operator via SSMS, the four alerts via T-SQL then manually add the operator to the response through SSMS.  Now given that I only did this during the initial server setup I guess I was just lazy and didn't script the whole process.

So I thought being in a new job and wanting to get these alerts set-up across the estate I would create a script to do just that.  In doing so I couldn't remember the table containing the operators was it sys. or dbo. or operators (IntelliSense was also playing up) at this point I gave up and got the text of the system stored procedure msdb.dbo.sp_add_operator from which I found that the table was msdb.dbo.sysoperators.  

This is something I do quite a lot, there are some very knowledgeable people at Microsoft who spend a lot of time writing some fantastic system procedures.  These are worth a look, this time I only learned a table name I was looking for but who knows what I will next time.  The next time you get a few minutes have a nosey you just never know what you will find.

Below is the script I created, the Operator @name, @email_address and Notification @operator_name variables need updating accordingly along with the IF NOT EXISTS check but that is it.  

NOTE - This script is provided as is and has been tested on SQL Server 2005 and SQL Server 2008.  I always recommend running scripts on a non production environment first.

USE [msdb] ;
GO
-- Create the Operator
IF NOT EXISTS ( SELECT  1
                FROM    msdb.dbo.sysoperators
                WHERE   name = '** Operator Here ***' )
    BEGIN
        EXEC msdb.dbo.sp_add_operator @name = N'*** Operator Here ***',
            @enabled = 1, @email_address = N'*** Email Address Here ***'
    END ;
GO

-- Alert 823 - Hard I/O Corruption
IF EXISTS ( SELECT  name
            FROM    msdb.dbo.sysalerts
            WHERE   name = N'823 - Hard I/O Corruption' )
    EXEC msdb.dbo.sp_delete_alert @name = N'823 - Hard I/O Corruption' ;
GO
EXEC msdb.dbo.sp_add_alert @name = N'823 - Hard I/O Corruption',
    @message_id = 823, @severity = 0, @enabled = 1,
    @delay_between_responses = 0, @include_event_description_in = 5,
    @notification_message = N'This is where SQL Server has asked the OS to read the page but it just cant',
    @category_name = N'[Uncategorized]',
    @job_id = N'00000000-0000-0000-0000-000000000000' ;
GO
-- Add Notification
EXEC msdb.dbo.sp_add_notification @alert_name = N'823 - Hard I/O Corruption',
    @operator_name = N'*** Operator Here ***', @notification_method = 1 ;
GO

-- Alert [824 - Soft I/O Corruption]
IF EXISTS ( SELECT  name
            FROM    msdb.dbo.sysalerts
            WHERE   name = N'824 - Soft I/O Corruption' )
    EXEC msdb.dbo.sp_delete_alert @name = N'824 - Soft I/O Corruption' ;
GO
EXEC msdb.dbo.sp_add_alert @name = N'824 - Soft I/O Corruption',
    @message_id = 824, @severity = 0, @enabled = 1,
    @delay_between_responses = 0, @include_event_description_in = 5,
    @notification_message = N'This is where the OS could read the page but SQL Server decided that the page was corrupt - for example with a page checksum failure',
    @category_name = N'[Uncategorized]',
    @job_id = N'00000000-0000-0000-0000-000000000000' ;
GO
-- Add Notification
EXEC msdb.dbo.sp_add_notification @alert_name = N'824 - Soft I/O Corruption',
    @operator_name = N'*** Operator Here ***', @notification_method = 1 ;
GO

-- Alert Corruption: Read/Retry 825
IF EXISTS ( SELECT  name
            FROM    msdb.dbo.sysalerts
            WHERE   name = N'Corruption: Read/Retry 825' )
    EXEC msdb.dbo.sp_delete_alert @name = N'Corruption: Read/Retry 825' ;
GO
EXEC msdb.dbo.sp_add_alert @name = N'Corruption: Read/Retry 825',
    @message_id = 825, @severity = 0, @enabled = 1,
    @delay_between_responses = 600, @include_event_description_in = 5,
    @notification_message = N'This is where either an 823 or 824 occured, SQL server retried the IO automatically and it succeeded. This error is written to the errorlog only - you need to be aware of these as they''re a sign of your IO subsystem going awry. There''s no way to turn off read-retry and force SQL Server to ''fail-fast'' - whether this behavior is a good or bad thing can be argued both ways - personally I don''t like it',
    @category_name = N'[Uncategorized]',
    @job_id = N'00000000-0000-0000-0000-000000000000' ;
GO
-- Add Notification
EXEC msdb.dbo.sp_add_notification @alert_name = N'Corruption: Read/Retry 825',
    @operator_name = N'*** Operator Here ***', @notification_method = 1 ;
GO

-- Alert Error - 9100 (Index Corruption)
IF EXISTS ( SELECT  name
            FROM    msdb.dbo.sysalerts
            WHERE   name = N'Error - 9100 (Index Corruption)' )
    EXEC msdb.dbo.sp_delete_alert @name = N'Error - 9100 (Index Corruption)' ;
GO
EXEC msdb.dbo.sp_add_alert @name = N'Error - 9100 (Index Corruption)',
    @message_id = 9100, @severity = 0, @enabled = 1,
    @delay_between_responses = 180, @include_event_description_in = 7,
    @category_name = N'[Uncategorized]',
    @job_id = N'00000000-0000-0000-0000-000000000000' ;
GO
-- Add Notification
EXEC msdb.dbo.sp_add_notification @alert_name = N'Error - 9100 (Index Corruption)',
    @operator_name = N'*** Operator Here ***', @notification_method = 1 ;
GO

Enjoy! 

Chris

Wednesday, 4 January 2012

SQL Server Error Logs

I read a blog post this morning on SQLServerCentral by Tim Radney about SQL Server Error Logs.  Tim talks about increasing the number of error logs in SQL Server.  One thing that came to mind to take this one step further and is just as simple to do is to ‘Cycle’ the error log. 
On all of the SQL servers I manage I have a job (the definition for which is below) that cycles the error log at 00:00 daily. 

USE [msdb]
GO
IF  EXISTS (SELECT job_id FROM msdb.dbo.sysjobs_view WHERE name = N'(00:00) Maintenance - CycleErrorLogs')
EXEC msdb.dbo.sp_delete_job @job_name= N'(00:00) Maintenance - CycleErrorLogs', @delete_unused_schedule=1
GO
BEGIN TRANSACTION
DECLARE @ReturnCode INT
SELECT @ReturnCode = 0
IF NOT EXISTS (SELECT name FROM msdb.dbo.syscategories WHERE name=N'[Uncategorized (Local)]' AND category_class=1)
BEGIN
EXEC @ReturnCode = msdb.dbo.sp_add_category @class=N'JOB', @type=N'LOCAL', @name=N'[Uncategorized (Local)]'
IF (@@ERROR <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback
END
DECLARE @jobId BINARY(16)
EXEC @ReturnCode =  msdb.dbo.sp_add_job @job_name=N'(00:00) Maintenance - CycleErrorLogs',
            @enabled=1,
            @notify_level_eventlog=2,
            @notify_level_email=0,
            @notify_level_netsend=0,
            @notify_level_page=0,
            @delete_level=0,
            @description=N'No description available.',
            @category_name=N'[Uncategorized (Local)]',
            @owner_login_name=N'sa', @job_id = @jobId OUTPUT
IF (@@ERROR <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback
EXEC @ReturnCode = msdb.dbo.sp_add_jobstep @job_id=@jobId, @step_name=N'CycleLogs',
            @step_id=1,
            @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=1,
            @os_run_priority=0, @subsystem=N'TSQL',
            @command=N'EXEC sp_cycle_errorlog;
GO',
            @database_name=N'master',
            @flags=0
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=1,
            @freq_subday_interval=0,
            @freq_relative_interval=0,
            @freq_recurrence_factor=0,
            @active_start_date=20060922,
            @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:
GO

It allows me to easily view just one day’s worth of information as and when required.  This is something I have done for years now since I was once unable to view SSMS 2005 because of the sheer size and number of records in it.

Which takes me onto another quick tip and one which I picked up from an old colleague and good friend Chris Taylor http://www.chrisjarrintaylor.co.uk with regard to job names.  The eagle eyed amongst you will have noticed this already but I include the time the job runs in the job name.  I find this incredibly useful as it gives you the ability to see in SSMS when the job runs without viewing the job properties.

In this case I can see that the cycle error log job (00:00) Maintenance – CycleErrorLogs runs at midnight.  This can be easily adapted to (Every 3 Hours) (01:00 Sat) etc. etc. It has helped me and others I work with and have worked with in the past, give it a go and let me know what you think!

Enjoy

Chris