Blog

The Art Of The SQL Server Stored Procedure: Formatting Code

Spaces


First, a list of things that are horrible:

  • Tabs
  • Leading commas
  • All lowercase
  • All uppercase
  • Not putting new things on new lines (from join on where and or order by group by)
  • Not indenting things
  • Leaving AS out of table aliases
  • Leaving out column aliases
  • Top expressions without parentheses
  • Not aligning parentheses

There are others, but I’m tired of thinking about things that are demonstrably wrong to do, like putting ice in scotch or sugar in wine.

Thank you for complying.

Not All Code


When you think about formatting code, you probably think primarily of organizing a single query so that it’s inoffensive to civilized society.

But you should also apply this to your code as a whole, too. People who use words wrong will call this “holistic”.

  • Create all your temporary objects in the same section of code
  • Declare all your variables in the same section of code
  • Set as many of your variables as you can in the same block of code
  • Do as much of your validation in the same section of code as you can

Few things (aside from the list at the beginning of the post) are more grating than seeing random things being created and declared at random points in the code.

It makes things far more difficult to scope, follow, and understand.

I’ll lend some leniency to using SELECT INTO here, because sometimes that’s the best way to get a fully parallel insert.

I’ll also lend some leniency to cursors, because sometimes it’s only sensible to declare them when they’ll be used.

Consistency Is Key


Formatting should follow a consistent set of (my) rules. It is sometimes possible to get used to inferior style choices as long as long as they’re predictable.

What’s impossible to get used to is code formatting that’s constantly changing gears.

There are many ways to format code out there in the world. Some are more acceptable than others.

For example, some companies may shy away from online code formatting tools because who knows who might see the code.

So much valuable intellectual property exists in your “joins” and “column names” and such. Someone else may steal the bright idea to also key on “identifiers”.

I personally use SQL Prompt, because it gets me about 80% of the way to how I want code to look.

While I do wish there were more ways to implement single formatting rules, like changing how columns are aliased from the shabby “column AS new_name” to the correct “new_name = column” format, it’s often trivial to tweak certain things after applying everything.

Thanks for reading!

Going Further


If this is the kind of SQL Server stuff you love learning about, you’ll love my training. I’m offering a 75% discount to my blog readers if you click from here. I’m also available for consulting if you just don’t have time for that, and need to solve database performance problems quickly. You can also get a quick, low cost health check with no phone time required.

The Art Of The SQL Server Stored Procedure: How To Leave Good Comments

Attn Pls.


Most code I look at has been a disaster in the making for many years, worked on by many people who seemed to find one thing that sort of worked, and kept doing it.

I can’t lie: there are areas of my life where I do the same thing. SQL Server is the one area where I confidently know the rules, when I can break them, and explain reasons for both.

It’s not that I don’t make mistakes, it’s just that I learn well from them.

Usually.

There are others things that I’ll do the same way for ages, thinking they’re needlessly complicated, before looking into less needlessly complicated ways of doing them.

What’s shocking is that sometimes there’s no better way of doing things.

Like xquery. What were they thinking?

Find Yourself


Possibly the least helpful, but most humorous, way of leaving comments, is a large block of green text up at the top of a module.

There are all sorts of helpful insights buried in those comments to help me as a consultant understand my audience.

But… even though a lot of changes are described, there are often dozens to hundreds of queries in those stored procedures and function, or the view definition has 50 joins that join to 50 views that have 50 joins in them.

Fixed performance??? Avoided parameter sniffing??? Needed DISTINCT to fix a bug???

WHERE? WHICH QUERY?

SHOW ME TO YOUR MAGICK!

If you use a ticketing system, and there’s an issue number in your comment way up at the top of your stored procedure, add the ticket number in where you changed the code.

If there’s not, make one up. Give me some way to figure out where a change was made.

The only thing more frustrating is seeing some chunk of code quoted out, with no explanation of why it was quoted out.

Explain Yourself


In my stored procedures, I like to quote any code blocks as I go so they’re easier for me to find when I scroll through things.

Not because I can’t read my own code (okay, sometimes I get a lil’ lost), but because there’s often a lot of repetitive code, and it’s usually easier to read plain-English green text when I’m looking for something.

Here’s an example from sp_LogHunter:

enumclaw

This code isn’t hard to understand, but it’s a tiny chunk of code, and pretty easy to miss if I were looking for it.

Leaving little notes about even small sections of code can make life a lot easier for others trying to work for it.

Block It Off


While we’re on the subject, I must beg this of you: USE BLOCK QUOTES

Like I talk about in the post, using the -- method can screw a lot of things up.

Depending on where you get the query from, and where the query originates, the whole query might end up on one line.

Having a bunch of double-dash comments makes it really hard to distinguish what’s code, what’s comment, and what’s quoted out code.

Worse, it breaks most every automatic code formatting tool out there.

They can’t figure it out either.

Tidbits


Comments in code are good for all sorts of things. Comments on the internet generally are mistakes and should be ignored.

Leaving comments not only helps others, but can really help you.

Think about how many times you’ve written code with a bunch of BEGIN/END blocks, and you get totally lost in which begin goes with which end and how many ends you need to stop getting an error at the very end of the stored procedure.

Heck, even while writing this post I went through a couple of my bits of code to add better comments in.

Thanks for reading!

Going Further


If this is the kind of SQL Server stuff you love learning about, you’ll love my training. I’m offering a 75% discount to my blog readers if you click from here. I’m also available for consulting if you just don’t have time for that, and need to solve database performance problems quickly. You can also get a quick, low cost health check with no phone time required.

The Art Of The SQL Server Stored Procedure: ANSI/SET Options

Top Down


I start off all of my stored procedures with the following block:

SET ANSI_NULLS ON;
SET ANSI_PADDING ON;
SET ANSI_WARNINGS ON;
SET ARITHABORT ON;
SET CONCAT_NULL_YIELDS_NULL ON;
SET QUOTED_IDENTIFIER ON;
SET NUMERIC_ROUNDABORT OFF;
SET IMPLICIT_TRANSACTIONS OFF;
SET STATISTICS TIME, IO OFF;
GO

This aligns my stored procedures with the necessary settings to accomplish a couple things:

  • Allow the optimizer to use indexed views, filtered indexes, and computed columns
  • Avoid errors when modifying tables involved with indexed views, filtered indexes, and computed columns

Many ORMs mess up with ARITHABORT, and let’s be honest, most of them time ORMs aren’t calling stored procedures.

If you’ve spent some time right-clicking around in SSMS at all, you might have seen how missing index requests and various module templates are generated.

They all start off with enabling ANSI_NULLS and QUOTED_IDENTIFIER, but there are some others that it makes total sense to include.

That’s why I have that list up there.

AS BEGIN


Inside of your stored procedures, you may want to do some other stuff, depending on how you’ll use it.

Inside of a real, production-ready stored procedure, you’ll probably want to do this:

SET NOCOUNT, XACT_ABORT ON;

If your stored procedure are being called by a Java or Python app, you’ll probably want this too:

SET IMPLICIT_TRANSACTIONS OFF;

Because by default, they both use implicit transactions, and you probably don’t want those happening across all the queries in a stored procefure.

That can cause a whole hell of a lot of blocking.

NOCOUNT is of course a good idea to not send additional results back.

XACT_ABORT is a great idea for stored procedures with multiple queries that modify data, because it allows you to roll all of the changes they made back without a TRY/CATCH block surrounding the whole ordeal.

If your query is just reading a bunch of data from different places and there’s nothing to roll back, XACT_ABORT matters not a bit.

Otherwise, use it, because it is wise to do so.

Locally Owned


If you’re writing a stored procedure (like most of my troubleshooting procedures) where you don’t want to:

  • Fail completely if you hit one error
  • Get blocked by all the transient stuff that locks system views and functions
  • Accidentally get query plans for your troubleshooting procedures

You’ll probably want to do something like this:

SET STATISTICS XML OFF;
SET NOCOUNT ON;
SET XACT_ABORT OFF;
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;

That’s what I do inside all of my admin procedures to avoid those things.

Of course, you should not use some of those if you care about:

  • Easily troubleshooting query performance (getting actual execution plans in SSMS)
  • Leaving some changes in place when another part of the procedure fails (XACT_ABORT)
  • Not returning data from potentially dirty reads (READ UNCOMMITTED)

SET NOCOUNT on is still a generally wise idea, regardless of the intent or application of the code.

Deal with it.

Exercise


I’ve been bitten by a lot of different weird things by not doing this stuff in the past.

At one point I had suggested a really helpful filtered index to a client that used Cold Fusion as a front end, which used some weird driver (Adobe, maybe?) that used a bunch of bad ANSI settings.

Implementing the index immediately caused a bunch of queries coming from there to start failing. It was an easy fix — rebuild the index without the filter — tada!

But the better fix was to move the queries to a stored procedure that requested the correct SET options, and re-filter the index.

Consulting life teaches you a lot of weird lessons, probably the first is to be paranoid of everything, and never trust that even the largest companies are doing anything correctly.

In tomorrow’s post, we’ll talk about one of my favorite subjects: helpful and professional (ha ha ha) code comments.

Thanks for reading!

Going Further


If this is the kind of SQL Server stuff you love learning about, you’ll love my training. I’m offering a 75% discount to my blog readers if you click from here. I’m also available for consulting if you just don’t have time for that, and need to solve database performance problems quickly. You can also get a quick, low cost health check with no phone time required.

The Art Of The SQL Server Stored Procedure: What You Need To Know

For Your Eyes Only


I’ve been keeping a mental list of things of things I often have to adjust or fix in stored procedures I work on.

Some of them are a touch pedantic, but the majority of them are lessons and practices I’ve learned (often the hard way) over the years while working on things:

  • Performance tuning
  • Building processes
  • Fixing issues and errors

The thing is, I see the same mistakes over and over again. You probably do too, but you may not know they’re mistakes.

Judging by the code I see, most developers out there don’t.

No offense, it’s just… if all you do is begin a transaction and then try to commit it at the end, with no thought given to error handling or rolling back, what is the point of you?

If you do this, go ahead and tell me why in the comments. I’d love to know.

Anyway.

Table Of Contents


Here’s what I’ll be talking about over the next month or so.

  1.  ANSI/SET options
  2.  Commenting
  3.  Formatting
  4.  Error Handling
  5.  Debugging
  6.  Batching Modifications
  7.  Transactions
  8.  Isolation Levels
  9.  Locking Hints
  10.  Parameter data types
  11.  Table valued parameters/Passing lists
  12.  Conditional logic
  13.  Local variables
  14.  Wrapper stored procedures
  15.  Dynamic sql
  16.  Temporary objects
  17.  Parameter sniffing
  18.  Dynamic searches
  19.  Pagination
  20.  Cursors and Loops

The list might change a little, but it’s the basic outline of what I care to talk about.

Some posts might be shorter than others, because there’s not a lot to say about certain things beyond “this is right, and this is why”.

Hopefully these lessons start to sink in.

Thanks for reading!

Going Further


If this is the kind of SQL Server stuff you love learning about, you’ll love my training. I’m offering a 75% discount to my blog readers if you click from here. I’m also available for consulting if you just don’t have time for that, and need to solve database performance problems quickly. You can also get a quick, low cost health check with no phone time required.

Optimizing SQL Server Query Plans With Eager Index Spools In Them

Optimizing SQL Server Query Plans With Eager Index Spools In Them


 

Going Further


If this is the kind of SQL Server stuff you love learning about, you’ll love my training. I’m offering a 75% discount to my blog readers if you click from here. I’m also available for consulting if you just don’t have time for that, and need to solve database performance problems quickly. You can also get a quick, low cost health check with no phone time required.

Optimizing SQL Server Query Plans With Row Count Spools In Them

Optimizing SQL Server Query Plans With Row Count Spools In Them


 

Going Further


If this is the kind of SQL Server stuff you love learning about, you’ll love my training. I’m offering a 75% discount to my blog readers if you click from here. I’m also available for consulting if you just don’t have time for that, and need to solve database performance problems quickly. You can also get a quick, low cost health check with no phone time required.

Optimizing SQL Server Query Plans With Table Spools In Them

Optimizing SQL Server Query Plans With Table Spools In Them


 

Going Further


If this is the kind of SQL Server stuff you love learning about, you’ll love my training. I’m offering a 75% discount to my blog readers if you click from here. I’m also available for consulting if you just don’t have time for that, and need to solve database performance problems quickly. You can also get a quick, low cost health check with no phone time required.

Optimizing Complex SQL Server Queries By Using Batch Mode

Optimizing Complex SQL Server Queries By Using Batch Mode


 

Going Further


If this is the kind of SQL Server stuff you love learning about, you’ll love my training. I’m offering a 75% discount to my blog readers if you click from here. I’m also available for consulting if you just don’t have time for that, and need to solve database performance problems quickly. You can also get a quick, low cost health check with no phone time required.

Optimizing Common Table Expression Queries In SQL Server

Optimizing Common Table Expression Queries In SQL Server


 

Going Further


If this is the kind of SQL Server stuff you love learning about, you’ll love my training. I’m offering a 75% discount to my blog readers if you click from here. I’m also available for consulting if you just don’t have time for that, and need to solve database performance problems quickly. You can also get a quick, low cost health check with no phone time required.

Optimizing Complex SQL Server Queries

Optimizing Complex SQL Server Queries


 

Going Further


If this is the kind of SQL Server stuff you love learning about, you’ll love my training. I’m offering a 75% discount to my blog readers if you click from here. I’m also available for consulting if you just don’t have time for that, and need to solve database performance problems quickly. You can also get a quick, low cost health check with no phone time required.