Monday, May 9, 2011

T-SQL Tuesday 18: Common Table Expressions AKA CTE’s

T-SQL SQL Tuesday is brought to us this week by Bob Pusateri (blog|@SQLBob).  So Bob what is the topic this month?

Have you ever solved or created a problem by using CTEs? Got a tip, trick, or something nifty to share? I’d love to see your posts about any of the above. Also don’t forget that T-SQL Tuesday is not limited to only T-SQL:
So we aren’t limited to CTE’s but I do enjoy them, so off we go!


HOT FUZZ FIZZ BUZZ


I first learned about Common Table Expressions while studying for the 70-432 exam back in 2007.  They were neat, they were cool.  They have a lot of power when it comes to recursion.  The first time I used them in any practical sense was in a job interview.  I was asked the Fizz Buzz question.

I remembered reading a blog Rob Boek (blog|@robboek) had written about this exact same question, read it here, Fizz Buzz by Rob Boek

I thought it was simple. I thought it was elegant.  It was a great example of Set Based logic.  I was trying to make a good impression, and so I re-created it.  I was honest about it, when asked why I came up with the solution that I had.  It led to a great conversation about how we study as IT professionals, and learn from others.

“So Balls”, you say “We’re going to talk Fizz Buzz?”

Nope but if you’re interested in CTE’s you should stop and go read it, were going to talk about one of my favorite topics Compression.

SIMPLIFY THE COMPLEX


Common Table Expressions can be used as an alias to complex queries.  The example I’m going to work with today is one from the White Paper on Compression, Data Compression: Strategy, Capacity Planning and Best Practices by Sanjay Mishra.  I use some of the Queries from this white paper, to detect Scan and Update Usage Patterns of Indexes, in my Presentation on Page & Row Compression.  If you’re in the Orlando Area you can come see that presentation this Friday at SQL Rally!

The queries look at the sys.dm_db_index_operational_stats DMF to gage the Scan and Update Patterns of Indexes.  This is important when you are determining a Compression Strategy. 

If you have a High Percentage of Updates then you will experience more overhead with Page Compression, than if you had a High Percentage of Scans.  A good example is an OLTP system vs. an OLAP system, Reference Data vs. Data that is constantly in motion.

The queries are not overly complicated, but getting the information you want requires a certain amount of massaging.  A CTE can help this process by providing a wrapper for a very complex query so you can work with the returning data in additional ways.

We’ll start out with our 2 original queries and then move to the CTE that I’ve put together.

Original Query to Detect Scans

SELECT
     so.name AS tableName,
     si.name AS indexName,
     ios.partition_number AS [Partition],
     ios.index_id AS indexID,
     si.type_desc AS indexType,
     (ios.range_scan_count *100.0/(ios.range_scan_count +
     ios.leaf_delete_count + ios.leaf_insert_count + ios.leaf_page_merge_count + ios.leaf_update_count + ios.singleton_lookup_count)) AS percentScan
FROM
     sys.dm_db_index_operational_stats(DB_ID(),NULL,NULL,NULL) ios
     JOIN sys.objects so
     ON so.object_id=ios.object_id
     JOIN sys.indexes si
     ON si.object_id = ios.object_id AND si.index_id = ios.index_id
WHERE
     (ios.range_scan_count + ios.leaf_insert_count + ios.leaf_delete_count + ios.leaf_update_count +ios.leaf_page_merge_count + ios.singleton_lookup_count)!=0
     AND OBJECTPROPERTY(ios.object_id, 'IsUserTable')=1  
ORDER BY
     percentScan;
GO

Original Query to Detect Updates

SELECT
     so.name,
     si.NAME AS [indexName],
     ios.partition_number AS [Partition],
     ios.index_id AS [IndexID],
     si.type_desc AS [IndexType],
     (ios.leaf_update_count *100/(ios.range_scan_count +
     ios.leaf_insert_count +
     ios.leaf_delete_count +
     ios.leaf_update_count +
     ios.leaf_page_merge_count +
     ios.singleton_lookup_count)) AS [Update_Percentage]
FROM
     sys.dm_db_index_operational_stats(DB_ID(), NULL, NULL, NULL) ios
     JOIN sys.objects so
     ON so.object_id = ios.object_id
     JOIN sys.indexes si
     ON ios.object_id=si.OBJECT_ID AND ios.index_id=si.index_id
WHERE
     (ios.range_scan_count + ios.leaf_insert_count + ios.leaf_delete_count + ios.leaf_update_count + ios.leaf_page_merge_count + ios.singleton_lookup_count) !=0
     AND OBJECTPROPERTY(ios.object_id, 'IsUserTable') =1
ORDER BY
     [Update_Percentage] ASC;
GO

Both of these queries will get you the information you need, but if you want to see the results side by side you would need to perform a Union.  Further manipulation would require you edit both queries, and could get complicated.  This is where our CTE can help simplify things.

We’ll start out with our expression where we set the CTE name, the Data to be returned, and then we define our query.  Final we’ll have a separate select were we can manipulate our CTE and return the data as we see fit.

Our CTE

WITH IndexUsage(tableName, IndexName, [Partition], IndexId, IndexType, Usage, Percentage)
AS (
SELECT
     (ss.name + '.'+ so.name)
     ,si.NAME
     ,ios.partition_number
     ,ios.index_id
     ,si.type_desc
     ,'UPDATES'
     ,(ios.leaf_update_count *100/(ios.range_scan_count +
     ios.leaf_insert_count +
     ios.leaf_delete_count +
     ios.leaf_update_count +
     ios.leaf_page_merge_count +
     ios.singleton_lookup_count))
FROM
     sys.dm_db_index_operational_stats(DB_ID(), NULL, NULL, NULL) ios
     JOIN sys.objects so
     ON so.object_id = ios.object_id
     JOIN sys.indexes si
     ON ios.object_id=si.OBJECT_ID AND ios.index_id=si.index_id
     JOIN sys.schemas ss
     ON so.schema_id=ss.schema_id
WHERE
     (
          ios.range_scan_count +
          ios.leaf_insert_count +
          ios.leaf_delete_count +
          ios.leaf_update_count +
          ios.leaf_page_merge_count +
          ios.singleton_lookup_count) !=0
     AND OBJECTPROPERTY(ios.object_id, 'IsUserTable') =1
UNION All
SELECT
     (ss.name + '.'+ so.name)
     ,si.name
     ,ios.partition_number
     ,ios.index_id
     ,si.type_desc
     ,'SCANS'
     ,(ios.range_scan_count *100.0/(ios.range_scan_count +
     ios.leaf_delete_count +
     ios.leaf_insert_count +
     ios.leaf_page_merge_count +
     ios.leaf_update_count +
     ios.singleton_lookup_count))
FROM
     sys.dm_db_index_operational_stats(DB_ID(),NULL,NULL,NULL) ios
     JOIN sys.objects so
     ON so.object_id=ios.object_id
     JOIN sys.indexes si
     ON si.object_id = ios.object_id AND si.index_id = ios.index_id
     JOIN sys.schemas ss
     ON so.schema_id=ss.schema_id
WHERE
          (ios.range_scan_count +
          ios.leaf_insert_count +
          ios.leaf_delete_count +
          ios.leaf_update_count +
          ios.leaf_page_merge_count +
          ios.singleton_lookup_count)!=0
     AND OBJECTPROPERTY(ios.object_id, 'IsUserTable')=1  
)

SELECT
     iu.tableName
     ,iu.IndexName
     ,iu.IndexType
     ,iu.Usage
     ,iu.Percentage
FROM
     IndexUsage iu
ORDER BY
     iu.tableName
     ,iu.IndexName
     ,iu.Percentage desc
   
   
Despite the complexity of the internal statements, out final select is simple and easy to change and manipulate.

There’s an old phrase, “Work Smarter Not Harder”.  Using CTE’s is a good way to achieve the smarter.  I hope you find this helpful.

Thanks,

Brad

SQL Rally: Business Intelligence Workshop

Just TWO DAYS until the start of SQL Rally!  I’m going to the Business Intelligence Workshop Pre-Con as my first stop.  I’m as excited as a kid on the 1st day of school!

“Balls”, you say, “Why BI?  Aren’t you a DBA?”

Excellent question Dear Reader.

I’m working on my MCITP: 2008 DBA Certifications and after that I’ll begin work on the DBA developer Certifications.  My goal, for the end of this year, is to have all the pre-qualifications to go for the MCM sometime next year.  So where does BI fit in?

BECOMING MORE INTELLIGENT ABOUT BUSINESS 


Yep I’m a DBA, and it used to be we weren’t so compartmentalized.  It used to be if you were a DBA you were the Developer, the Administrator, and the BI person (and I would bet in some smaller shops that dichotomy probably still exists).  A database, was a database, was a database and that’s all there was to it.  But as the technology has advanced so has the set of skills required to do each job.

I’d like to say I couldn’t Cube my way out of a paper bag.  But this won’t be my first go round with SSAS.  Back in 2008 I had started studying to get my BI certifications for 2005, but life has a way of guiding you and BI was not a place I was supposed to dedicate my focus back then.  I understand the concepts at a 5,000 foot level, but as for applying them I need some work.

So Why BI?  Because our data can tell us a lot of things, and while storing it, maintaining it, and protecting it is important understanding what it can tell us is important as well.  Our data can help us understand trends, patterns, and answers to questions that we might not know existed.  You probably use metrics from your servers to analyze your performance (tracking and trending) .  Well this is doing it with your business data.

KICKING SSAS ONE CUBE AT A TIME


The guys over at Pragmatic Works are the top dogs when it comes to Business Intelligence, and the Pre-Con for SQL Rally get’s you training from not One, not Two, not Three, but FOUR of the top guys in the field today.

Go over to Kendal Van Dyke’s blog  Meet the SQL Rally Pre-Con Presenter’s and read about them, l .  Patrick LeBlanc, Devin Knight, Adam Jorgensen, and Mike Davis are all at the top of this game. 

This is an area where I really want to expand my knowledge and I can’t wait to attend.  I’ll blog about this more in depth on Wednesday night as part of my SQL Rally Day by Day Series. 

I can’t wait get started!  Bring on Wednesday!

Thanks,

Brad


Friday, May 6, 2011

SQL Saturday 74 Round Up

This past Saturday was SQL Saturday 74 in Jacksonville.  And like most great trips it started out with a road trip.  Kendal Van Dyke (blog|@SQLDBA) and I had discussed driving up together, my buddy Dan Taylor (blogY b|@DBABulldog) had decided to join us by mid week, and Karen Lopez (blog|@DataChick) rounded out our cast on Friday.

Dan started his drive at 3:30 in the morning, making it to my house by 4:15, we left around 4:35 to go over to Orlando and pickup Kendal, and then we added Karen to our traveling road show around 6ish.  The road trip was one of the great highlights, that made for a very enjoyable day.  The conversations flowed like hot coffee, and the coffee flowed like......well hot coffee.


Before I knew it we were getting off the exit and heading over to the scenic campus of the University of North Florida.  This wasn't my first time in Jacksonville, but it was the first time I'd been on this University before, Dan had been to this SQL Saturday in the past and was quick to offer up directions of where to go, and at the parking garage, pictured above, we exited the car to make our way down to SQL Saturday! 

PLAMEN RATCHEV: T-SQL ENHANCEMENTS IN DENALI



So I know the Picture is blurry, but I swear this is really him.

DON STEVIC: FUNDAMENTALS OF DBAISM












BEST SWAG EVER!!!











KENDAL VAN DYKE: DR YOUR WANTED IN THE RECOVERY ROOM

at this point I should have taken more photos

LUNCH ON THE LAWN II

KEVIN BOLES: ADVANCED T-SQL SOLUTIONS

BRADLEY BALL: PAGE AND ROW COMPRESSION HOW WHY AND WHEN

BRIAN KNIGHT IRON CHEF JACKSONVILLE BI EDITION