SQL Rap Contest Results!
Wow! We ended up with 19 SQL rap submissions! The response was more than I could’ve hoped for. Parodies ranged from Coolio to Beyonce, Akon to home-spun rhymes, and everyone single one was awesome. Brent, Ward, and I have closely reviewed each and every submission. We laughed, and then we laughed some more, and now we’re ready to name a winner.
But first… did you know that GoDaddy.com is hiring? I’ve been working for this company for 2 years, and I *love* it. Truly. I can honestly say it’s the best place I’ve ever worked. If you’re looking for a challenging job and a great work environment, go take a look at some of the open positions at GoDaddy.com/Jobs. [/shameless plug]
And now… the winner of the 32GB iPod Touch, generously donated by GoDaddy.com for this silly little contest, is… Steve Jones! Steve’s rap, DBA’s Delight, is set to the tune of ‘Rapper’s Delight’ by The Sugarhill Gang and has so many SQL features dropped it’s almost educational. Almost.
THANK YOU to everyone who submitted a rap! Hopefully you had as much fun writing them as we had reading them. I’ll be following up in the next few days with a full listing of all SQL raps, once I figure out how to organize it! If you’ve posted it to your blog, please leave me a comment with the URL. And if for some reason, you don’t want me to post your submission, that’s okay too, just let me know.
Oh, what’s that? You want to see Steve’s winning entry NOW? Oh, if you insist…
“DBA Delight” by Steve Jones
(This is set to the tune of “Rapper’s Delight” by The Sugarhill Gang. If you’re not familiar with the song, go to Playlist.com and search for it; it really adds to the whole experience!)
Now what you hear is not a parse
I’m rapping to the code
’cause me, my tweeps, and the devs
are gonna try to gen a load.
See I am the D-B-A
and I’d like to say hello
to the devs, the PMs, and the boss
that make me want to explode
But first I gotta, query, query
with intellisense and a brand new de-bug-ger
Say lock, don’t block,
with the hints to make those latches stop
Well so far you’ve seen me code, but I brought 2 men along
And next on the mic is dev Mike
C’mon Mike, show those keys
Check out the C-L-R, and the C-T-E,
and the rest is S-Q-L
you see I go by the link “Code-2-Supreme”
and now I’ll show you why
You see I know my keys
and identities, both char and I-N-T
I got primary and foreign keys
and DDs to back them up.
I got Assemblies, Partitioned entities
And a queue to make to grin
I’ve got a package I can integrate
to find that MAX or MIN!
Master PM, am you on?
It’s now your turn to spin a yarn
Well it’s locks and it’s blocks and it’s mis-matched socks
and the delays don’t stop until I take stock
I’m the PM you hate, when you’re late
I’ve Project and Excel
I’ve got every estimate that you made
Before this project went to hell!
So get to work, and get it done
Server, instance, database, too
I need them all up running, humming along
and returning results so true.
DBA, it’s on you
Show us what you gonna do!
I got a new quad core
sixty-four bit bits
and memory up to the rim
Gonna add some S-S-Ds for speed
and pile on the load for all my sims.
Got Agent jobs, A DR plan,
and procedures for every ‘ject
No access I don’t let you have
and auditing you won’t expect.
Clus-ter-ing, Log shipping,
mirroring across the land
I’ve got Queues in place, just in case
You break some fiber strands
Have you ever went over a friend’s shop to work
and the code just ain’t no good?
The cursors are slow, the procedures long
and a box you wouldn’t patch if you could!
So he asks what to do, to speed things up
and you sit stunned for a sec
The boss wants to help, a little consult
for some work without a spec.
Then you say, that’s it, I got to leave this place,
Don’t care what these people think
I’m just asking for trouble without benefits
and a database on the blink
So you bust out the door, hit the road
go back to your own job
check your server, see green lights
stop that head before it throbs
you text your friend two weeks later
to see how he has been
He says sorry about that job
but DBA, we’re still friends.
PASS Summit 2009
Filed under: PASS, Performance & Tuning, Presentations, Syndication
My abstract for PASS Summit 2009 was accepted! Woot! You may not be able to see it from where you’re sitting, but I’m doing the happy dance.
In case you missed my original post on my abstract submission, here’s what I’ll be presenting on:
Super Bowl, Super Load – A Look at Performance Tuning for VLDB’s
Few DBA’s have the opportunity to experience a real-life load test in their production environment. Michelle Ufford works for GoDaddy.com, a company that has experienced phenomenal success with its Super Bowl ads. These ads are designed to drive traffic to the company’s websites, which puts the database servers under high load. In her presentation, Michelle will explore the performance tuning techniques that have resulted in an 80% reduction in server response times and allowed her VLDB’s to reach rates of 27k transactions per second. Topics will include vertical and horizontal partitioning, bulk operations, table design, and indexing.
Do you read my blog? Do I read yours? Do we exchange weird messages on Twitter? Do you have free cookies? If you’re going to to the PASS Summit and answered “yes” to any of these questions, then I want to meet you! Make sure to say “hi” to me in Seattle.

Chainblogging: Deserted Islands Have WiFi?
Jason Massie tagged me in the latest round of ChainBlogging. This one was started by Tim Ford (SQLAgentMan) and asks:
So You’re On A Deserted Island With WiFi and you’re still on the clock at work. Okay, so not a very good situational exercise here, but let’s roll with it; we’ll call it a virtual deserted island. Perhaps what I should simply ask is if you had a month without any walk-up work, no projects due, no performance issues that require you to devote time from anything other than a wishlist of items you’ve been wanting to get accomplished at work but keep getting pulled away from I ask this question: what would be the top items that would get your attention?
Become a BI Jedi Master
I’ve mentioned before on Twitter that I’ve recently accepted a position on the BI team. So it stands to reason that one of my major goals now is to dig into BI. While I can muck my way through as a Padawan, I want to become a true BI Jedi Grand Master. This means not just learning the tools (i.e. BIDS), but learning how to best utilize BI to deliver fast, jaw-dropping BI results. This includes SSAS, MDX, data mining, and anything else BI-related. I want to be able to easily answer the how, what, why, and when. And did I mention I want it to be *fast*?
Service Broker
I’ve played around with this a little bit. For a while, I even toyed with the idea of rolling my own version of replication with Service Broker because of the inability to swap out partitions on a replicated table in SQL 2005. But I still haven’t had a good excuse to build and deploy Service Broker to production, so my experience and understanding is not as high as I’d like it to be.
Upgrade to SQL Server 2008
I’d like to upgrade a couple of our servers to SQL Server 2008 and immediately start applying some of the new functionality. I’d set up Resource Governor to help manage some of those pesky, run-away ad-hoc queries that users like to run. I’d start looking at opportunities to replace old indexes with sexy new filtered indexes, saving space and improving performance. And I’d like to see if MERGE really lives up to the hype in a production environment.
Clean Up My E-mail Inbox
This could take me a month alone. Seriously. Okay, maybe not seriously, but it could at least take a good week.
I’m tagging some of my favorite bloggers:
- Aaron Alton
- Mr. Denny (he dyed his hair blue… how cool is that?!)
- Gail Shaw
East Iowa SQL Saturday – Call for Speakers!
Filed under: Miscellaneous, PASS, Presentations, Syndication
The Call for Speakers is now open for the East Iowa SQL Saturday! This is our first time hosting a SQL Saturday, and there’s a lot of excitement and interest from our local SQL Server folks. There’s some interest from local speakers, but we’ll probably also need to pull in speakers from outside of Cedar Rapids and Iowa City to support the number of tracks and attendees we plan to have.
The event will be held on October 10th, 2009 at the University of Iowa in Iowa City. Special thanks to Russ Allen for his help with securing a location for us!
For those who are not in the immediate area but would be willing to travel, here’s some general travel times from major cities in the area:
- Chicago – 3.5 hours
- Omaha – 3.5 hours
- Milwaukee – 4 hours
- Kansas City – 4.5 hours
- Minneapolis – 5 hours
- St. Louis – 5 hours
- Indianapolis – 6 hours
- Columbus, OH – 9 hours (hint, hint, Jeremiah!)
So if you’re in the general area, please, PLEASE consider speaking at our SQL Saturday. Pretty please with sugar on top.
You can find out a little more information and submit sessions at our SQL Saturday website.
Random Number Generator in T-SQL
Filed under: Performance & Tuning, SQL Tips, Syndication
Ever need to generate a random number in T-SQL? I have, on a couple of different occasions. I’m pretty sure that there’s several different ways of doing this in T-SQL, but here’s what I use:
DECLARE @maxRandomValue TINYINT = 100 , @minRandomValue TINYINT = 0; SELECT CAST(((@maxRandomValue + 1) - @minRandomValue) * RAND() + @minRandomValue AS TINYINT) AS 'randomNumber';
This approach uses the RAND() function to generate a random seed; it also ensures that the value returned is between the specified min and max value. I’ve been using this method in one stored procedure that’s called a couple of hundred times per second, and it seems to perform pretty well.
What method do YOU use to generate a random number? Is it faster than this method?
User Groups Are Like Guilds…
(channeling “Forest Gump”)… you never know what you’re gonna get. Ack! Sorry, I just can’t help myself sometimes. Moving on…
I was recently discussing guilds with my gamer husband and he commented how much running a user group sounds like running a guild. For those of you who aren’t already aware, before I traded my gaming addiction for a SQL one, he and I ran a guild together with around 140 members.

Not sure what a guild is? Check out the The Guild, a popular, very humorous, and only slightly exaggerated web series.
The more I’ve thought about what my husband said, the more I realized how right he is. Allow me to share my (questionable) thoughts on the subject:
Guild Masters
Some guild masters are great leaders and others are just very dedicated; the same is true with user group leaders. If you spend all day trolling forums and working on maxing your DPS, you’re probably a good gamer but it doesn’t necessarily make you a good guild master. Similarly, being a SQL samurai does not necessarily prepare you to lead a user group. A handful of people are just naturally good leaders; most everyone else has to acquire the skill, often through painful experience. Before starting a guild or user group, you should ask yourself the following questions:
- Are you in the market for an unpaid part-time job?
- Do you like to alphabetize your DVD collection?
- Do you enjoy helping n00bs (junior admins)?
- Have you ever led an anti-social, semi-violent mob before?
If you answered “no” to any of those questions, don’t worry, it doesn’t necessarily mean you should not start your own guild or user group. But you may want to consider first joining an existing group to ensure you’ll enjoy the experience. Either way, you’ll quickly find out how important it is to have…
Officers
You can’t do it alone. Well, you can try, but don’t expect the 40-man heroic raid you scheduled to start on-time or run smoothly. Every guild and group leader needs supportive and dedicated officers. If it’s your first time leading a group, try to recruit someone who has leadership experience but perhaps doesn’t have the time or energy to be El Jefe; this person can be an invaluable resource for you. And if you have run a group before, you still want officers to help distribute the workload. Officers can help with a variety of tasks, from managing supplies to organizing major events. Lastly, they’re also a great point of contact for your…
Guildies
Guildies (members) are the fine men and women who have entrusted you to lead them into battle (provide stimulating meetings). Without them, you would have no guild (user group). They have joined for any number of reasons: some are new to the game and want to learn (junior DBAs), some are interested in meeting new people with similar interests, and others are just there for the free food.
Over time, you’ll find membership waxes and wanes; people switch servers (move to a new city), trade in gaming for a more boring hobby (switch from DBA to sysadmin), or just run out of time in the day. There’s little you can do to change this, so you’ll inevitably have to do some new-member recruitment. However, if you’ve got a good group, you’ll find much of your advertisement is by the word-of-mouth of current members. Still want to recruit new members? Try throwing some big…
Events
Whether it’s an end-of-game dungeon or a SQL Saturday, everyone loves a good event. There’s a couple of things you should be aware of, though. First, always, ALWAYS plan for people to not show. Don’t take it personally; life just happens. I’ve heard that 70% of registrants is a good estimate of how many people will actually show up.
Secondly, while everyone loves to attend events, not many people want to actually help organize one. If you’re lucky enough to get volunteers, treat them very well! You’ll quickly find out a good volunteer is worth his or her weight in…
Loot
Just as dungeon bosses drop loot (prizes) both good and bad, so do sponsors. Very few guildies are motivated solely by loot, and loot is not absolutely necessary for a successful event. Still, everyone likes to win, and there’s really nothing like the joy of rolling a perfect 100 to score that epic dagger (erm… I guess the best translation for this one is having your ticket drawn to win a copy of Quest’s Capacity Manager).
PvP
One of the most popular event types is a PvP (player vs. player) raid. This is where your guildies attack members of opposing factions, just for fun and bragging rights. To help make user groups even more guild-like, I’m currently organizing raids against the local Oracle and mySQL user groups. We hope to use the element of surprise to really lay into ‘em. I’ll let you know how it turns out.
All jokes aside, guilds and user groups may not be _exactly_ the same, but there are certainly a surprising amount of similarities. If nothing else, both definitely involve a lot of time, effort, and dedication, and I think many of the leadership and organizational skills learned in a guild are truly transferable to the “real world.”
Hopefully by now you’re either feeling motivated to start a user group, or you’re off to the store to stock up on Cheetos and Mt. Dew, the sustenance of choice for most gamers, so you can survive the weekend locked in the basement playing PC games. Whatever the case… have fun!
sp_WhoIsActive
Filed under: Miscellaneous, Presentations, Syndication, T-SQL Scripts
For those who attended the webcast I did with Brent Ozar today, “Getting Started With SQL Server Management Studio,” here’s the link to Adam Machanic’s excellent sp_WhoIsActive stored proc:
Thanks for attending!
Webcast Tomorrow!
Filed under: PASS, Presentations, SQL 2008, SQL Tips, Syndication
I’m excited to be doing a webcast tomorrow with the infamous illustrious Brent Ozar for Quest’s Pain-of-the-Week. The title is “Getting Started with SQL Server Management Studio,” and as you’ve probably gathered, it’s pretty entry-level stuff. If you read my blog, then chances are you don’t need to watch this webcast. But if you know anyone who’s trying to learn SQL Server or is trying to make the upgrade from 2000 to 2005/2008, this may be a good webcast for them.
I’ve also got a few other speaking engagements coming up:
June 2nd: Cedar Valley .NET User Group
I’ll be reprising my Iowa Code Camp presentation on “SQL Server for the .NET Developer” for CVINETA. This presentation focuses on what you need to know about good table design, indexing strategies, and fragmentation… you know, what you wish every .NET developer knew about SQL Server.
June 11th: PoTW: Time-Saving SQL Server Management Studio Tips & Tricks
I’ll also be doing this webcast with @BrentO as a follow-up to our webcast tomorrow. It will focus on how to save time and improve your sanity by using some neat little tricks in SSMS 2008.
BOL 2008 Update Released
If you haven’t heard, Microsoft released an update to Books Online for SQL Server 2008 yesterday. You can find the download here:
Overhead in Non-Unique Clustered Indexes
Filed under: Internals, Performance & Tuning, SQL 2008, Syndication
I’ve received a couple of questions regarding my article, Performance Considerations of Data Types, and the overhead associated with non-unique clustered indexes. I started to respond via e-mail, but my response was so long I decided to turn it into a blog post instead.
I should start by clarifying that non-unique clustered indexes do not necessarily consume more space and overhead; it depends on the data stored. If you have duplicate clustered key values, the first instance of the value will be handled as though it were unique. Any subsequent values, however, will incur overhead to manage the uniquifier that SQL Server adds to maintain row uniqueness. This same overhead is also incurred in non-clustered indexes, too, adding to the overall expense of this approach.
I think it helps to actually look at the data, so let’s walk through a few different common scenarios. We’ll create a table with a unique clustered index, a table with a non-unique clustered index but no duplicates, and a table with duplicate key values.
Also, a little warning that I started to write this in SQL Server 2008, and since I’m on a 2008 kick, I decided to leave it that way. You can modify this pretty easily to work in 2005, if necessary.
USE sandbox;Go /* Unique, clustered index, no duplicate values */CREATE TABLE dbo.uniqueClustered( myDate DATE Not Null , myNumber INT Not Null , myColumn CHAR(995) Not Null); CREATE UNIQUE CLUSTERED INDEX CIX_uniqueClustered ON dbo.uniqueClustered(myDate); /* Non-unique clustered index, but no duplicate values */CREATE TABLE dbo.nonUniqueNoDups( myDate DATE Not Null , myNumber INT Not Null , myColumn CHAR(995) Not Null); CREATE CLUSTERED INDEX CIX_nonUniqueNoDups ON dbo.nonUniqueNoDups(myDate); /* Non-unique clustered index, duplicate values */CREATE TABLE dbo.nonUniqueDuplicates( myDate DATE Not Null , myNumber INT Not Null , myColumn CHAR(995) Not Null); CREATE CLUSTERED INDEX CIX_nonUniqueDuplicates ON dbo.nonUniqueDuplicates(myDate);
I’m going to use the date data type in 2008 for my clustered index key. To ensure uniqueness for the first two tables, I’ll iterate through a few years’ worth of dates. This is typical of what you may see in a data mart, where you’d have one record with an aggregation of each day’s data. For the table with duplicate values, I’m going to insert the same date for each row.
/* Populate some test data */SET NOCOUNT ON;DECLARE @myDate DATE = '1990-01-01' , @myNumber INT = 1; WHILE @myDate < '2010-01-01'BEGIN INSERT INTO dbo.uniqueClustered SELECT @myDate, @myNumber, 'data'; INSERT INTO dbo.nonUniqueNoDups SELECT @myDate, @myNumber, 'data'; INSERT INTO dbo.nonUniqueDuplicates SELECT '2009-01-01', @myNumber, 'data'; SELECT @myDate = DATEADD(DAY, 1, @myDate) , @myNumber += 1; END;
After running the above script, each table should have 7,305 records. This is obviously pretty small for a table, but it’ll serve our purposes. Now let’s take a look at the size of our tables:
/* Look at the details of our indexes */ /* Unique, clustered index, no duplicate values */SELECT 'unique' AS 'type', page_count, avg_page_space_used_in_percent, record_count , min_record_size_in_bytes, max_record_size_in_bytesFROM sys.dm_db_index_physical_stats(DB_ID(), OBJECT_ID(N'uniqueClustered'), Null, Null, N'Detailed') WHERE index_level = 0UNION All/* Non-unique clustered index, but no duplicate values */SELECT 'non-unique, no dups', page_count, avg_page_space_used_in_percent, record_count , min_record_size_in_bytes, max_record_size_in_bytesFROM sys.dm_db_index_physical_stats(DB_ID(), OBJECT_ID(N'nonUniqueNoDups'), Null, Null, N'Detailed') WHERE index_level = 0UNION All/* Non-unique clustered index, duplicate values */SELECT 'duplicates', page_count, avg_page_space_used_in_percent, record_count , min_record_size_in_bytes, max_record_size_in_bytesFROM sys.dm_db_index_physical_stats(DB_ID(), OBJECT_ID(N'nonUniqueDuplicates'), Null, Null, N'Detailed') WHERE index_level = 0;
Here’s the results:
type page_count avg_page_space_used_in_percent record_count min_record_size_in_bytes max_record_size_in_bytes------------------- -------------------- ------------------------------ -------------------- ------------------------ ------------------------unique 914 99.8055102545095 7305 1009 1009non-unique, no dups 914 99.8055102545095 7305 1009 1009duplicates 1044 88.066036570299 7305 1009 1017
I want to point out a couple of things. First, there is no difference in the number of pages between the non-unique clustered index with no duplicates ([nonUniqueNoDups]) and the unique clustered index ([uniqueClustered]). The table with duplicate clustered key values, however, requires 14% more pages to store the same amount of data. Secondly, the [max_record_size_in_bytes] of the [nonUniqueDuplicates] table is 8 bytes more than that of the other two. We’ll discuss why in a minute.
Now let’s take a look at the actual data pages. For this, I’m going to use my page internals proc.
Execute dbo.dba_viewPageData_sp @databaseName = 'sandbox' , @tableName = 'sandbox.dbo.uniqueClustered' , @indexName = 'CIX_uniqueClustered';
I’m not going to post the entire results here, but I want to draw your attention to “m_slotCnt = 8″, which is near the top of the page. That means 8 records are stored on this page. Also, when you look near the end of the first record (Slot 0), you should see the following results:
Slot 0 Offset 0x60 Length 1009Record Type = PRIMARY_RECORD Record Attributes = NULL_BITMAP Record Size = 1009Memory Dump @0x00A9C06000000000: 1000ee03 c3150b01 00000064 61746120 †..î.Ã......data [...]000003F0: 00†††††††††††††††††††††††††††††††††††. Slot 0 Column 1 Offset 0x4 Length 3 Length (physical) 3myDate = 1990-01-01 Slot 0 Column 2 Offset 0x7 Length 4 Length (physical) 4myNumber = 1 Slot 0 Column 3 Offset 0xb Length 995 Length (physical) 995myColumn = data
Now let’s look at the table that has a non-unique clustered index but no duplicates:
EXECUTE dbo.dba_viewPageData_sp @databaseName = 'sandbox' , @tableName = 'sandbox.dbo.nonUniqueNoDups' , @indexName = 'CIX_nonUniqueNoDups';
The m_slotCnt count is also 8 for this page. This time, let’s glance at the first and second records (Slot 0 and 1 respectively):
Slot 0 Offset 0x60 Length 1009Record Type = PRIMARY_RECORD Record Attributes = NULL_BITMAP Record Size = 1009Memory Dump @0x62FDC06000000000: 1000ee03 c3150b01 00000064 61746120 †..î.Ã......data [...]000003F0: 00†††††††††††††††††††††††††††††††††††. Slot 0 Column 0 Offset 0x0 Length 4 Length (physical) 0UNIQUIFIER = 0 Slot 0 Column 1 Offset 0x4 Length 3 Length (physical) 3myDate = 1990-01-01 Slot 0 Column 2 Offset 0x7 Length 4 Length (physical) 4myNumber = 1 Slot 0 Column 3 Offset 0xb Length 995 Length (physical) 995myColumn = data Slot 1 Offset 0x451 Length 1009Record Type = PRIMARY_RECORD Record Attributes = NULL_BITMAP Record Size = 1009Memory Dump @0x62FDC451 00000000: 1000ee03 c4150b02 00000064 61746120 †..î.Ä......data [...]000003F0: 00†††††††††††††††††††††††††††††††††††. Slot 1 Column 0 Offset 0x0 Length 4 Length (physical) 0UNIQUIFIER = 0 Slot 1 Column 1 Offset 0x4 Length 3 Length (physical) 3myDate = 1990-01-02 Slot 1 Column 2 Offset 0x7 Length 4 Length (physical) 4myNumber = 2 Slot 1 Column 3 Offset 0xb Length 995 Length (physical) 995myColumn = data
We now see a new addition to the row, “UNIQUIFIER = 0.” This is SQL Server’s way of managing row uniqueness internally. You’ll notice that, because the clustered key values are unique, the UNIQUIFIER is set to 0 and the row size is still 1009; for all intents and purposes, the UNIQUIFIER is not consuming any space.
Update: The DBCC God himself, Paul Randal, explained that non-dupes actually have a NULL UNIQUIFIER, which DBCC PAGE displays as a 0. Thanks for explaining, Paul! I wondered about that but chalked it up to SQL voodoo.
Now let’s look at our final case, a non-unique clustered index with duplicate key values:
EXECUTE dbo.dba_viewPageData_sp @databaseName = 'sandbox' , @tableName = 'sandbox.dbo.nonUniqueDuplicates' , @indexName = 'CIX_nonUniqueDuplicates';
Here’s where things get interesting. The m_slotCnt value is now 7, which means we’re now storing 1 record less per page. Let’s look at the details:
Slot 0 Offset 0x60 Length 1009Record Type = PRIMARY_RECORD Record Attributes = NULL_BITMAP Record Size = 1009Memory Dump @0x00A9C06000000000: 1000ee03 df300b01 00000064 61746120 †..î.ß0.....data [...]000003F0: 00†††††††††††††††††††††††††††††††††††. Slot 0 Column 0 Offset 0x0 Length 4 Length (physical) 0UNIQUIFIER = 0 Slot 0 Column 1 Offset 0x4 Length 3 Length (physical) 3myDate = 2009-01-01 Slot 0 Column 2 Offset 0x7 Length 4 Length (physical) 4myNumber = 1 Slot 0 Column 3 Offset 0xb Length 995 Length (physical) 995myColumn = data Slot 1 Offset 0x451 Length 1017 Record Type = PRIMARY_RECORD Record Attributes = NULL_BITMAP VARIABLE_COLUMNSRecord Size = 1017 Memory Dump @0x00A9C45100000000: 3000ee03 df300b02 00000064 61746120 †0.î.ß0.....data [...]000003F0: 000100f9 03010000 00†††††††††††††††††...ù..... Slot 1 Column 0 Offset 0x3f5 Length 4 Length (physical) 4UNIQUIFIER = 1 Slot 1 Column 1 Offset 0x4 Length 3 Length (physical) 3myDate = 2009-01-01 Slot 1 Column 2 Offset 0x7 Length 4 Length (physical) 4myNumber = 2 Slot 1 Column 3 Offset 0xb Length 995 Length (physical) 995myColumn = data
The first record, Slot 0, looks exactly the same as in the previous table; the UNIQUIFIER is 0 and the row size is 1009. The second record (Slot 1), however, now has a UNIQUIFIER value of 1 and the row size is 1017. If you notice, the “Record Attributes” of Slot 1 are also different, with the addition of “VARIABLE_COLUMNS.” This is because the UNIQUIFIER is stored as a variable column. The extra 8 bytes of overhead break down to 4 bytes to store the UNIQUIFIER, 2 bytes to store the variable column offset, and 2 bytes to store the variable count. The tables we created used all fixed-length columns; you may notice some minor overhead differences if your table already contains variable columns.
To summarize, there is indeed a difference in the page structure between a unique clustered index and a non-unique clustered index; however, there’s only a possible performance and space impact when storing duplicate clustered key values. So there you go, more detail than you ever wanted to know about clustered indexes and uniqueness!





