SQL Saturday #29 Presentations & Twittering

presentations_2010-03-26.jpg

Tomorrow, I’m presenting a couple of sessions at SQLSaturday #29 in Birmingham, Alabama. Here are the presentation materials I’ll use.

Reaching Out to the Twitterverse

While I was in Seattle last fall for the PASS Community Summit, I saw a couple of presenters effectively reach out to the Twitter community while giving their sessions. They had someone tweet important points for them as they presented their session. Then, as the Twitterverse posted questions in response, the designated liaison would voice them and tweet the presenters answers. It seemed to work out really well.

So, I’m considering trying that for tomorrow’s sessions – if I can find an attendee who doesn’t mind acting as the liaison.

Question: Would that be of interest to you? Would you like to follow some of the sessions for tomorrow’s SQLSaturday via Twitter?

I’ll let you know what the Twitter tag will be if it works out.

I hope to see you there, or at least hear from you via Twitter during the session.

Adding a Column to Every Table

Robot_2010_03_24.jpg

I am Script. I will update your database.

Despite the best laid plans, sometimes circumstances or project scope change and the definition of one or more tables in your database must be altered after they have been created. It’s just a fact of life for a DBA.

Change Happens

Frequently these changes affect more than one database in your environment. The development, test, and eventually even the production databases must have their definitions updated to reflect the newly implemented changes.

For cases like this, I generally prefer to script out the necessary changes rather than using the Management Studio tools. Scripting reduces the likelihood of an unintentionally errant change while updating the 100+ tables in the database. If one database or table is done correctly, you can be assured that the rest are in order as well. That’s not to say you shouldn’t test; you should. But the changes will be much more consistent when they are implemented via a script rather than by hand.

Scripting ALTER TABLE Statements

Recently I was tasked with adding a column to every user table in a database. There were lots of tables in this database and doing it by hand was not a good alternative. Of course if the changes were successful in Dev, they would need to propagated to Test and Production as well. So, I used T-SQL to dynamically create a script for me.

There a number of ways to accomplish this. A cursor or a while loop come to mind. However, since I knew that the new column name did not exist in any of the tables, I could use a shortcut and make use of the sp_msforeachtable system stored procedure. I described its use in a prior blog.

The first step is to use the stored procedure to generate T-SQL code to implement the change. For this example, we want to add a datetime column called Date_Created to each table in the AdventureWorks database. In a new query window, type the following code.

USE AdventureWorks;
EXEC sp_msforeachtable
‘PRINT ”ALTER TABLE ? ADD Date_Created DATETIME DEFAULT GETUTCDATE();”’ ;

When this script is executed, the Messages pane of the query window is filled with a list of DDL (Data Definition Language) statements to implement our change. The output is shown in the following figure.

foreachtable_2010_03_24.jpg

After reviewing these DDL statement to ensure they are indeed what we wish to do, we can then copy and paste them into a query window for execution.

Of course this implementation doesn’t have error handling. If a column by that name already exists, the DDL statement will fail for that table. If you are unsure whether a column already exists, you should use one of the other implementations (cursor, while, etc) so you can check for the presence of the column before issuing the ALTER TABLE statement.

I hope you find this useful. If you have any favorite scripting techniques or comments on this one, please feel free to share in the comments section below.

SQL Server Locking & Block Scripts


A couple of weeks ago, I gave a presentation to the PASS DBA Virtual Chapter on SQL Server Locking & Blocking Made Simple.  The original post had a link to the presentation materials, but I neglected to attach the demo scripts. So, here they are:

To review them, click on the link and open the Microsoft Word document. (For some reason, my blog site won’t allow me to post text files.) Copy and paste the contents of each file into a new query window in SQL Server Management Studio and experiment all you wish. You’ll need the AdventureWorks database; it’s available for download on CodePlex.

If you have any questions or comments, feel free to post them below in the comments section.

Viewing Missing Indexes in Management Studio 2005

phonebook_2010_02_22.jpg

If you’ve used SQL Server 2008 Management Studio (SSMS 2008), you may have noticed that Microsoft added a pretty neat little feature when looking at Execution Plans, the Missing Index message. This subtle message may appear when you’re looking at either the Actual or Estimated Query Execution Plan in graphical mode. It can be seen written in green just below the query text.

showplan_xml_2010_02_22_b.jpg

The message tells you that the optimizer would have been able to resolve the query faster if only it had another index. It’s even tells you what that index should be. I’ve heeded its advice on more than one occasion with very good results.

But I’m Running SQL Server 2005

Unfortunately, not everyone has access to SSMS 2008. And Management Studio in SQL Server 2005 (SSMS 2005) doesn’t provide this kind of information – at least not in an automatic and graphical. The image below shows the same query as run in SSMS 2005.

showplan_xml_2010_02_22_c.jpg

You can, however, retrieve the missing index information for a query another way – viewing the Execution Plan as XML.

Viewing the Execution Plan as XML

To view the Execution Plan in XML, open a query window in SSMS 2005 and use the SHOWPLAN_XML option as shown below.

SET SHOWPLAN_XML ON;

Execute the statement to set the option. Setting the SHOWPLAN_XML option causes SQL Server to return the estimated execution plan in XML for subsequent queries on this connection instead of actually executing the queries. For more information about the SET SHOWPLAN_XML statement, visit Books Online.

Once the SHOWPLAN_XML option has been set, “execute” the query whose execution plan you wish analyze. You’ll see something similar to the follow image. Note the SHOWPLAN_XML works best when the output is set to “Result to Grid.”

showplan_xml_2010_02_22_d.jpg

Double click the XML hyperlink to open the execution plan. Scroll down until you see (or search for) the MissingIndexes node. In the example below, there’s a single missing index identified, an index on the phone number. In this case, the optimizer is suggesting that simple, nonclustered index would improve performance. The impact attribute estimates the improvement that adding the index would have. The optimizer may also recommend nonclustered indexes with included columns and composite indexes.

showplan_xml_2010_02_22_e.jpg

Use Your Head

The Missing Index feature in Management Studio can be really nice. It’s another tool available to us as database professionals to help us do our job. However, as helpful as it sometimes can be, it’s no substitute for using your own skills and knowledge when considering which indexes to create, or not create.

Consider what the message recommends in a broader context. What effect will the new index have on inserts and updates? On maintenance plans? Then decide if the index is worthwhile.

Additional Information

To learn more about the Missing Index feature, visit some of these site.

Have you used this feature? Have you found it useful? I’d like to hear you experiences.

Speaking at the Baltimore SQL Server User Group

On Monday, the first of February, 2010, I will be speaking at the Baltimore SQL Server User Group meeting at 7:00 PM EST. My topic will be SQL Server Locking and Blocking Made Simple. In it, I will discuss:

  • The need for locking
  • The consequences of blocking
  • How SQL Server locks resources
  • How blocking affects performance
  • Influencing locks with granularity hints
  • Setting Transaction Isolation Levels

Here is a sample slide from the presentation. You can download the entire presentation here.

During the presentation, I will regularly use the following script to view the locks being held by SQL Server.

–examine the resources
SELECT
resource_type
,(CASE
WHEN resource_type = ‘OBJECT’ THEN object_name(resource_associated_entity_id)
WHEN resource_type IN (‘DATABASE’, ‘FILE’, ‘METADATA’) THEN ‘N/A’
WHEN resource_type IN (‘KEY’, ‘PAGE’, ‘RID’) THEN (
SELECT
object_name(object_id)
FROM
sys.partitions
WHERE
hobt_id=resource_associated_entity_id)
ELSE
‘Undefined’
END) AS resource_name
,request_mode as lock_type
,resource_description
,request_status
,request_session_id
,request_owner_id AS transaction_id
FROM
sys.dm_tran_locks
WHERE
resource_type <> ‘DATABASE’;

I hope you’ll join me there.

If you’re interested in having me speak at your local user group, please send me an email or direct message me in twitter. I’d love to talk with you.

Locking Scripts

Thanks to everyone who attended my TechNet Thrive! and Nashville SQL Server User Group presentations this week! I hope it was worth your while. As promised, here is the presentation.

And here’s the script I used to review the locks.

–examine the resources
SELECT
resource_type
,(CASE
WHEN resource_type = ‘OBJECT’ THEN object_name(resource_associated_entity_id)
WHEN resource_type IN (‘DATABASE’, ‘FILE’, ‘METADATA’) THEN ‘N/A’
WHEN resource_type IN (‘KEY’, ‘PAGE’, ‘RID’) THEN (
SELECT
object_name(object_id)
FROM
sys.partitions
WHERE
hobt_id=resource_associated_entity_id)
ELSE
‘Undefined’
END) AS resource_name
,request_mode as lock_type
,resource_description
,request_status
,request_session_id
,request_owner_id AS transaction_id
FROM
sys.dm_tran_locks
WHERE
resource_type <> ‘DATABASE’;

TechNet WebCast: SQL Server Locking & Blocking

Next Monday, I’m presenting a TechNet WebCast for Microsoft Thrive Live! The subject: SQL Server Locking & Blocking Made Simple. Here are the details:

Event Overview

A good working knowledge of how Microsoft SQL Server makes use of locking and transaction isolation levels can help you greatly improve an application’s performance. In this webcast, we explore the SQL Server locking methodology and share techniques for enhancing query response times.

Language(s): English
Product(s): Microsoft SQL Server
Audience(s): IT Generalist
Duration: 60 Minutes
Start Date: Monday, December 07, 2009 9:00 AM Pacific Time (US & Canada)
Event ID: 1032432983

I’d love to have you join me for this free session. Click here to register.

SQL Saturday #21 Orlando Presentation Materials

I’m back in the office now after having a great time in Orlando this past weekend for SQLSaturday #21 in sunny Orlando, Florida! Andy Warren (twitter), Jack Corbett (twitter) and everyone else who had a hand in putting it together did a great job. Their hard work definitely paid off.

The technical content at these kind of events is great! An excellent job was done by all of the speakers that I saw.

But for me the best part of the event is getting to catch up with friends that I only get to see a couple of times a year, meeting Twitter-friends for the first time, and walking around talking with other SQL Server enthusiasts.

With this event, I enjoyed meeting Twitter-friends Jorge Segarra (twitter), Kendal Van Dyke (twitter), and Pam Shaw (twitter), among others for the first time. It was also good to catch up again with Andy Leonard (twitter), Buck Woody (twitter), Kevin Kline (twitter), Jonathan Kehayias (twitter), and so many others. I know I’m leaving many people out, but not intentionally. It’s just that there is so many people to talk with during the event.

Anyway, as promised in my sessions, here are the materials I used. I hope you find them useful and thanks for coming!

  • SQL Server Locking & Blocking Made Simple (presentation)
  • Creating Data-Driven Subscriptions in Reporting Services (presentation)

Generate Lots of Test Data with CROSS JOIN

“Joe Test”

“Joe Test2″

“Joe Test3″

“Arrgh! There has got to be a better way to create some test data!”

Ever had that conversation with yourself? You need to create lots of data to load test an application or to create a demo. But going about it one row at a time is not only slow and tedious, but its results are less than stellar. …Joe Test101.

So, how can you create lots and lots of data without lots and lots of effort? Simple, let SQL do it for you.

Enter the Forgotten Join Type, the CROSS JOIN

Fortunately, SQL Server has a oft forgotten JOIN type that helps for occasions such as this. We’re all pretty familiar with INNER JOIN, LEFT JOIN, and RIGHT JOIN. But do you recall the most famous join type of them all? The CROSS JOIN?

A CROSS JOIN takes each row from the first table and combines it with every row from the second table. This produces a Cartesian product of the two tables.

For example, if my first table has 3 rows of data – Mary, Mark, Luke – and my second table has 2 rows of data – Jones, Smith – the Cartesian product will result in 6 rows of data. Mary Jones, Mary Smith, Mark Jones, Mark Smith, Luke Jones, and Luke Smith

The CROSS JOIN is much maligned. Most everyone who has ever written a SQL statement has accidentally produced a Cartesian product at some point. A query that you expected to return 12 hundred rows produced 12 billion rows. But we can harness that power for good and use it to create lots and lots of test data.

What’s in a Name?

inspector-2009-10-09Where can we get a good, long, list of names to use with our CROSS JOIN? Who captures that kind of information?

The United States Census Bureau, that’s who! Their site has a list of the most popular male, female, and family names. And they make the list available in files for download.

When I last checked, there were a total of 5,494 Given Names and 88,799 Family Names in the three files (the Given Names were broken into two files, male and female).

Creating a Cartesian product of that many names would produce a whopping 487,861,706 unique names (88,799 * 5,494). That’s far more than I typically require for my testing. So, I’ve pruned the list down quite a bit in my environment, down to 2,500.

Using the CROSS JOIN

After importing the files, I used the following script to create my test data.

–clean up the imported names
UPDATE
First_Names
SET
Given_Name = RTRIM(Given_Name)

UPDATE
Last_Names
SET
Family_Name = RTRIM(Family_Name)

–create a very simple customers table
CREATE TABLE Customers
(
Customer_ID INT NOT NULL IDENTITY(1,1)
,Last_Name VARCHAR(20) NOT NULL
,First_Name VARCHAR(20) NOT NULL
,Email_Address VARCHAR(50) NULL
)

–create the test data
INSERT INTO
Customers
(
Last_Name
,First_Name
,Email_Address
)
SELECT
f.Given_Name
,l.Family_Name
,f.Given_Name + ‘.’ + l.Family_Name + ‘@hotmail.com’
FROM
First_Names AS f CROSS JOIN
Last_Names AS l

My new Customers table now has 13,735,000 rows in it. A real business should be so fortunate!

Joe

Running a Server Side Trace

This is part two of three part series on creating, running, and scheduling Server Side Traces in SQL Server. Part I, Scripting Server Side Traces, was posted on August 31, 2009. Part III will be posted soon.

SQL Server Profiler can bring your production server to a screeching halt

In a prior post entitled Scripting Server Side Traces I lauded the laurels of SQL Server Profiler as a wonderful tool to use in development and QA environments to really see what’s happening inside your SQL Server. It’s a great way to shine a spotlight into the nooks and crannies of your database server. But try to use it on a production server and you’re likely to notice some unpleasant performance degradations. My warning to you was to use with caution on production servers. It’s better to use Server Side Traces and I demonstrated how SQL Server Profiler can be used to script out the Server Side Traces for you. If you haven’t already read that blog post, it may be worth while to go back and read it before continuing on with this one.

In this, the second of a three part series on Server Side Traces, we’ll examine the trace script to see what it’s doing. Then I’ll show how you can start and stop Server Side Traces using T-SQL procedures.

Modifying the script

We’ll start with a relatively simple Server Side Trace script that was generated for us by SQL Server Profiler. The script can be seen below. It’s rather long, but we’ll break it down into just a few sections that can be easily digested.

/****************************************************/
/* Created by: SQL Server 2008 Profiler             */
/* Date: 08/27/2009  08:59:12 AM         */
/****************************************************/

–- Create a Queue
declare @rc int
declare @TraceID int
declare @maxfilesize bigint
set @maxfilesize = 500

–- Please replace the text InsertFileNameHere, with an appropriate
–- filename prefixed by a path, e.g., c:\MyFolder\MyTrace. The .trc extension
–- will be appended to the filename automatically. If you are writing from
–- remote server to local drive, please use UNC path and make sure server has
–- write access to your network share

exec @rc = sp_trace_create @TraceID output, 0, N’E:\demo\demotrace2′, @maxfilesize, NULL
if (@rc != 0) goto error

–- Client side File and Table cannot be scripted

–- Set the events
declare @on bit
set @on = 1
exec sp_trace_setevent @TraceID, 27, 7, @on
exec sp_trace_setevent @TraceID, 27, 15, @on
exec sp_trace_setevent @TraceID, 27, 55, @on
exec sp_trace_setevent @TraceID, 27, 8, @on
exec sp_trace_setevent @TraceID, 27, 32, @on
exec sp_trace_setevent @TraceID, 27, 56, @on
exec sp_trace_setevent @TraceID, 27, 64, @on
exec sp_trace_setevent @TraceID, 27, 1, @on
exec sp_trace_setevent @TraceID, 27, 9, @on
exec sp_trace_setevent @TraceID, 27, 41, @on
exec sp_trace_setevent @TraceID, 27, 49, @on
exec sp_trace_setevent @TraceID, 27, 57, @on
exec sp_trace_setevent @TraceID, 27, 2, @on
exec sp_trace_setevent @TraceID, 27, 10, @on
exec sp_trace_setevent @TraceID, 27, 26, @on
exec sp_trace_setevent @TraceID, 27, 58, @on
exec sp_trace_setevent @TraceID, 27, 66, @on
exec sp_trace_setevent @TraceID, 27, 3, @on
exec sp_trace_setevent @TraceID, 27, 11, @on
exec sp_trace_setevent @TraceID, 27, 35, @on
exec sp_trace_setevent @TraceID, 27, 51, @on
exec sp_trace_setevent @TraceID, 27, 4, @on
exec sp_trace_setevent @TraceID, 27, 12, @on
exec sp_trace_setevent @TraceID, 27, 52, @on
exec sp_trace_setevent @TraceID, 27, 60, @on
exec sp_trace_setevent @TraceID, 27, 13, @on
exec sp_trace_setevent @TraceID, 27, 6, @on
exec sp_trace_setevent @TraceID, 27, 14, @on
exec sp_trace_setevent @TraceID, 27, 22, @on
exec sp_trace_setevent @TraceID, 189, 7, @on
exec sp_trace_setevent @TraceID, 189, 15, @on
exec sp_trace_setevent @TraceID, 189, 55, @on
exec sp_trace_setevent @TraceID, 189, 8, @on
exec sp_trace_setevent @TraceID, 189, 32, @on
exec sp_trace_setevent @TraceID, 189, 56, @on
exec sp_trace_setevent @TraceID, 189, 64, @on
exec sp_trace_setevent @TraceID, 189, 1, @on
exec sp_trace_setevent @TraceID, 189, 9, @on
exec sp_trace_setevent @TraceID, 189, 41, @on
exec sp_trace_setevent @TraceID, 189, 49, @on
exec sp_trace_setevent @TraceID, 189, 57, @on
exec sp_trace_setevent @TraceID, 189, 2, @on
exec sp_trace_setevent @TraceID, 189, 10, @on
exec sp_trace_setevent @TraceID, 189, 26, @on
exec sp_trace_setevent @TraceID, 189, 58, @on
exec sp_trace_setevent @TraceID, 189, 66, @on
exec sp_trace_setevent @TraceID, 189, 3, @on
exec sp_trace_setevent @TraceID, 189, 11, @on
exec sp_trace_setevent @TraceID, 189, 35, @on
exec sp_trace_setevent @TraceID, 189, 51, @on
exec sp_trace_setevent @TraceID, 189, 4, @on
exec sp_trace_setevent @TraceID, 189, 12, @on
exec sp_trace_setevent @TraceID, 189, 52, @on
exec sp_trace_setevent @TraceID, 189, 60, @on
exec sp_trace_setevent @TraceID, 189, 13, @on
exec sp_trace_setevent @TraceID, 189, 6, @on
exec sp_trace_setevent @TraceID, 189, 14, @on
exec sp_trace_setevent @TraceID, 189, 22, @on
exec sp_trace_setevent @TraceID, 122, 7, @on
exec sp_trace_setevent @TraceID, 122, 8, @on
exec sp_trace_setevent @TraceID, 122, 64, @on
exec sp_trace_setevent @TraceID, 122, 1, @on
exec sp_trace_setevent @TraceID, 122, 9, @on
exec sp_trace_setevent @TraceID, 122, 25, @on
exec sp_trace_setevent @TraceID, 122, 41, @on
exec sp_trace_setevent @TraceID, 122, 49, @on
exec sp_trace_setevent @TraceID, 122, 2, @on
exec sp_trace_setevent @TraceID, 122, 10, @on
exec sp_trace_setevent @TraceID, 122, 14, @on
exec sp_trace_setevent @TraceID, 122, 22, @on
exec sp_trace_setevent @TraceID, 122, 26, @on
exec sp_trace_setevent @TraceID, 122, 34, @on
exec sp_trace_setevent @TraceID, 122, 50, @on
exec sp_trace_setevent @TraceID, 122, 66, @on
exec sp_trace_setevent @TraceID, 122, 3, @on
exec sp_trace_setevent @TraceID, 122, 11, @on
exec sp_trace_setevent @TraceID, 122, 35, @on
exec sp_trace_setevent @TraceID, 122, 51, @on
exec sp_trace_setevent @TraceID, 122, 4, @on
exec sp_trace_setevent @TraceID, 122, 12, @on
exec sp_trace_setevent @TraceID, 122, 28, @on
exec sp_trace_setevent @TraceID, 122, 60, @on
exec sp_trace_setevent @TraceID, 122, 5, @on
exec sp_trace_setevent @TraceID, 122, 29, @on
exec sp_trace_setevent @TraceID, 10, 15, @on
exec sp_trace_setevent @TraceID, 10, 31, @on
exec sp_trace_setevent @TraceID, 10, 8, @on
exec sp_trace_setevent @TraceID, 10, 48, @on
exec sp_trace_setevent @TraceID, 10, 1, @on
exec sp_trace_setevent @TraceID, 10, 10, @on
exec sp_trace_setevent @TraceID, 10, 34, @on
exec sp_trace_setevent @TraceID, 10, 3, @on
exec sp_trace_setevent @TraceID, 10, 11, @on
exec sp_trace_setevent @TraceID, 10, 35, @on
exec sp_trace_setevent @TraceID, 10, 12, @on
exec sp_trace_setevent @TraceID, 10, 13, @on
exec sp_trace_setevent @TraceID, 10, 14, @on
exec sp_trace_setevent @TraceID, 45, 8, @on
exec sp_trace_setevent @TraceID, 45, 48, @on
exec sp_trace_setevent @TraceID, 45, 1, @on
exec sp_trace_setevent @TraceID, 45, 10, @on
exec sp_trace_setevent @TraceID, 45, 34, @on
exec sp_trace_setevent @TraceID, 45, 3, @on
exec sp_trace_setevent @TraceID, 45, 11, @on
exec sp_trace_setevent @TraceID, 45, 35, @on
exec sp_trace_setevent @TraceID, 45, 12, @on
exec sp_trace_setevent @TraceID, 45, 28, @on
exec sp_trace_setevent @TraceID, 45, 13, @on
exec sp_trace_setevent @TraceID, 45, 14, @on
exec sp_trace_setevent @TraceID, 45, 15, @on
exec sp_trace_setevent @TraceID, 12, 15, @on
exec sp_trace_setevent @TraceID, 12, 31, @on
exec sp_trace_setevent @TraceID, 12, 8, @on
exec sp_trace_setevent @TraceID, 12, 48, @on
exec sp_trace_setevent @TraceID, 12, 1, @on
exec sp_trace_setevent @TraceID, 12, 10, @on
exec sp_trace_setevent @TraceID, 12, 14, @on
exec sp_trace_setevent @TraceID, 12, 3, @on
exec sp_trace_setevent @TraceID, 12, 11, @on
exec sp_trace_setevent @TraceID, 12, 35, @on
exec sp_trace_setevent @TraceID, 12, 12, @on
exec sp_trace_setevent @TraceID, 12, 13, @on

–- Set the Filters
declare @intfilter int
declare @bigintfilter bigint

set @intfilter = 6
exec sp_trace_setfilter @TraceID, 3, 0, 0, @intfilter

set @intfilter = 5
exec sp_trace_setfilter @TraceID, 3, 1, 0, @intfilter

–- Set the trace status to start
exec sp_trace_setstatus @TraceID, 1

–- display trace id for future references
select TraceID=@TraceID
goto finish

error:
select ErrorCode=@rc

finish:
go

Defining variables

The script starts off declaring some variables. You’ll want to make sure that the values you configured in SQL Server Profiler were exported correctly. In particular, make sure the @maxfilesize variable is set to the number of megabytes that you’d like for capture. In the example below, I’ve configured the trace to capture 500 MB of data.

– Create a Queue
declare @rc int
declare @TraceID int
declare @maxfilesize bigint
set @maxfilesize = 500

Creating the trace

The next part of the script creates the trace using the sp_trace_create stored procedure. Here, as the comments indicate, you’ll want to provide the fully qualified path for the output file that you’ll use to store the captured data. In this example, I’m collecting it in a E:\demo\demotrace2.trc. Notice that the trc extension is automatically added for us; you don’t need to include it. If you do, you’ll end up with a file named demotrace2.trc.trc. That’s redundantly redundant.

exec @rc = sp_trace_create @TraceID output, 0, N’E:\demo\demotrace2′, @maxfilesize, NULL

The sp_trace_create procedure also accepts some other parameters that are not automatically produced when you export from SQL Server Profiler. For example, you can specify the TRACE_FILE_ROLLOVER option and the @filecount parameter to allow the trace information to span multiple operating system files. Modifying the preceding stored procedure call as shown below would allow the trace to rollover to subsequent files (the second parameter is 2), up to a maximum of five files (the last parameter is 5).

exec @rc = sp_trace_create @TraceID output, 2, N’E:\demo\demotrace2′, @maxfilesize, NULL, 5

You can also specify a time for the trace to end. This is the second to last parameter, which is NULL in the example above.

Notice that the @TraceId parameter is defined as an output parameter. When the sp_trace_create procedure is called, it creates the new trace and returns to us a unique number that we can use to refer to the new trace. We’ll use the @TraceId variable throughout the rest of the script to update the trace properties.

For more information, visit Books Online sp_trace_create.

Specifying the events

The next section of the script defines the events that the trace will capture. The sp_trace_setevent stored procedure is executed repeatedly to define each and every event we’ve asked to see. If you’re monitoring a lot of events, this section is rather tedious to look at. For more information, see sp_trace_setevent in Books Online.

–- Set the events
declare @on bit
set @on = 1
exec sp_trace_setevent @TraceID, 27, 7, @on
exec sp_trace_setevent @TraceID, 27, 15, @on
exec sp_trace_setevent @TraceID, 27, 55, @on

Filtering the events

Filters are set using the sp_trace_setfilter stored procedure in the next section. This is where we can narrow down our trace to just one database or to queries that take longer than some threshold we’ve set. On a SQL Server instance with lots of databases, you’ll definitely want to set some filters. For more information on filtering traces, visit sp_trace_setfilter in Books Online.

– Set the Filters
declare @intfilter int
declare @bigintfilter bigint

set @intfilter = 6
exec sp_trace_setfilter @TraceID, 3, 0, 0, @intfilter

set @intfilter = 5
exec sp_trace_setfilter @TraceID, 3, 1, 0, @intfilter

Starting and stopping the trace

Once the trace has been fully defined within SQL Server, all we have left to do is to start the trace. We do that by setting its status using the sp_trace_setstatus stored procedure.

– Set the trace status to start
exec sp_trace_setstatus @TraceID, 1

There are two parameters that we must supply to the sp_trace_setstatus stored procedure. The first is the trace that we wish to modify; this was the output of the sp_trace_create procedure at the beginning of the script. The second is that status of the trace.

A value of 0 for the status stops the trace. 1 starts the trace. 2 gets rid of the trace from the server. See Books Online for information about the sp_trace_setstatus stored procedure.

Next up: scheduling Server Side Traces

trainschedule_2009-09-14Alright! Now that we have a pretty good understanding of what this script does and how to manually start and stop Server Side Traces, next time we’ll look at ways to automate the trace.  Scheduling the trace will make it easy for us automatically collect data as  at various points throughout the business day and week.  This information will prove invaluable in helping us to benchmark our systems.

Until next time,

Joe

Follow

Get every new post delivered to your Inbox.