Temp Tables vs Table Varibles: The Great Debate

There seems to be a lot of confusion around the differences between  temp tables and table variables (in the classic sense; I'm not talking about in memory table types or anything here). Some people say you should only use table variables. Some people say you should only use temp tables. Most people caution a more nuanced approach. Here I want to cover what I think are the biggest issues in an attempt to shed some light on this surprisingly tricky topic.

Statistics This is usually the most important factor when considering which one to use. It boils down to two facts, and everything else flows from these: Temp Tables maintain statistics, Table Variables do not.

Table Variables Because table variables maintain no statistics, the Query Optimizer always assumes the contain exactly one row. As a result, any joins against a table variable, unless explicitly told to behave otherwise will (probably) alwaysbe a nested loop join.

As long as the number of rows in the table variable are small…

Master Data Services on Windows 10

I just spent several hours trying to figure this out, so I felt it was worth posting here too. If you are installing Master Data Services on Windows 10, there are a bunch of IIS Web Application Requirements you have to satisfy in IIS, or the Master Data Services Configuration Manager will say you're missing all kinds of services and roles.

Most of the documentation relates to using Windows Server, since that's usually where SQL is running. But for a localhost instance you might have for testing, it's probably not. And in my case, it's on Windows 10 homeedition. That last fact is what threw me most because even after enabling all the features I could find on the list in the link above, it still didn't work. That's because by default, you need Windows 10 professional edition to use Windows Authentication, and MDS requires Windows Authentication enabled for IIS to work.

So you can either upgrade to Pro or manually enable that feature through the command line. I kn…

JOINs Using Playing Cards

A few co-workers asked me to explain some of the nuances of different join types (outer joins in particular). I've always reached for Venn diagrams in the past, but I was trying to think of a better way to get the information across. Whether or not I succeeded, I'll let you be the judge. I'm not going to do much in the way of explaining each of the diagrams, but I will label each diagram. I also included a diagram at the end of a common trick for inserting only rows which don't already exist in the target table (using a left outer join, and checking where the right values are null).

Please feel free to use this code and the diagrams if you think they're useful. If you do, it would be nice to credit me with them, but I'm hardly going to get mad if you don't. I'd much rather there just be good training materials out there.
The Code
if object_id('tempdb.dbo.#Cards') is not null drop table #Cards create table #Cards ( NumericValue tinyint not nul…


One of the core ways of making dynamic sql safe is the use of the QUOTENAME() function. QUOTENAME wraps either square brackets (default), double quotes, or single quotes around a provided string. This is crucial for dynamic SQL because if, for example, you need to concatenate a column name, the only way to make it 100% safe is to wrap it in square brackets so it's treated as an identifier. Conceptually the same as doing this:

select [Not A Valid Column] = @@version
Naively you might think then, that if you had a dynamic sql string like this, you would be safe, since you're wrapping brackets around the identifier
declare @ColumnName nvarchar(128) = ''' union all select ''injected code'';--' declare @SQL nvarchar(max) = 'select [' + @ColumnName + '] from sys.columns' select @sql exec (@SQL) /* -- dsql string select [' union all select 'injected code';--] from sys.columns */
And in this example, you are. The …

Yin and Yang of Data Compression

I plan to write about data compression more in the future but for now I just wanted to share a quick diagram I drew up for a colleague.
Any time you're considering data compression on a table, two primary factors come into play. How much will it save you in disk space vs how much I/O will 

On the Y axis, we have the space savings. You might have a table that's 10GB and but after compressing it, its 1GB. You might have another table that's 1TB and compressed it's 700GB. Clearly the first shrinks by a larger percent, but the second saves much more space.
On the X axis, we have table IO. Compressed data has to be decompressed when it's read or modified, and it's all done by the CPU. So the more I/O going on in a compressed table, the more pressure it will put on your CPU.
So how can we understand the diagram, strictly from the standpoint of these two opposing forces?
Tables in the green area you should almost always compress. These are large tables with big spac…

Embrace The Non-DBO Schema

I don't know how it is everywhere, but in my experience, custom schemas (i.e. something other than dbo) have been seldom used, and I think it's a bit of a shame.

First, what's wrong with dbo? Inherently, nothing. But as time passes and databases grow, dbo can become a cluttered place with objects of overlapping interest. Disentangling those objects from one another can be a bit of a pain.
What Do Schemas Address? Schemas can help with several things, but in my mind, they boil down to three big ones:

OrganizationKeeping objects that belong in the same "place" togetherIsolationMaking clear delineations between the responsibilities of the objects in the schemaManagementDifferentiating permissionsBeing able to do operations on a specific subset of objects without having to rely on external documentation or naming conventionsHow Else Can You Achieve Those Benefits? There are really three ways you can achieve the points from the previous section, and they sort of fall al…

Named Constraints on Temp Tables

Momma sed don't name constraints on temp tables. But why?

How SQL Makes Temp Tables Globally Unique

When you first build a temp table, SQL stores the definition of that temp table away  and every subsequent time you create it, it's actually a clone of that one, original table definition. To allow each individual connection to create a clone of the table, it has to do something about the name so that it won't collide with itself. Let's see what that looks like