July 2010
Mon Tue Wed Thu Fri Sat Sun
« Jun   Aug »
 1234
567891011
12131415161718
19202122232425
262728293031  

Month July 2010

TFS and You

How many of you are using Visual Studio 2010? How many of you are writing SSIS packages? How many of you are pissed off, irritated, or confused about how you’ll be able to write and version control your SSIS packages (VS 2008) once you’ve upgraded to TFS 2010?

Confused yet? Yeah, so am I.

Let’s backtrack: at work we recently upgraded to VS 2010 and TFS 2010 – this lets everyone on my team take advantage of the database developer edition as well as add a whole slew of automated testing features and doodads. Plus our management can tie in to our tasks

One of the problems that we ran into is connecting to TFS2010 from VS2008. Why would I need to do that? Visual Studio 2010 doesn’t have support for the SQL Server 2008 BI project types yet (SSRS, SSIS, etc). So, in order to work on SSIS packages, I need to keep VS 2008 around.

It’s pretty easy to connect Visual Studio 2008 to TFS 2010. Download this hotfix, install it, and then you’re up and running. That’s really all there is to it.

MSDN 2010 Contest!

Update: The contest is closed. Winners have been announced over here. Thanks for playing.

Who wants an MSDN 2010 subscription?

Due to my over-involvement in the development and database community, Microsoft gave me three MSDN licenses to give away. I’m not sure who I should give them to, so I thought about how to give them away. I originally posted this on Twitter and I got a bajillion responses in a few minutes. I figured that I would normally be incredibly lazy and give it to the first three people. Then I had more thoughts. Then Arnie Rowland messaged me telling me about his great idea: giving them to the unemployed or under-employed.

I think this is a great idea. I don’t want to rip off Arnie’s idea, so I’m not going to.

I have three of these things to give away, so why not mix it up a bit and go in three directions. I’m going to give away the three MSDN subscriptions to the people who email the best description of how they will use the MSDN subscription to help them

  1. further their own career/education
  2. work on an open source project
  3. help them prepare for a new job

It’s all secret this way. Nobody has to know about how much you hate your boss or you want to make an open source porno bit torrent search engine or program some kind of robotic articulated llama comb. Doesn’t matter. Just send your email to 2010msdncontest@facility9.com

Your email MUST contain the phrase “i want some msdn” in the subject line. Otherwise, I’m trashing it. End of story.

Entries are due by Friday, July 9. I’ll judge them on July 10 while I’m recovering from getting a tattoo and then I’ll make the announcement on Monday, July 12.

Using Indexed Views to Replace Triggers

Let’s get this out of the way: I think triggers are cool. I also think triggers have their place, they just need to be used with care. One reason for this is that triggers are synchronous. That is – trigger actions will block a command from returning to the client until the the trigger’s actions have completed.

What’s the solution? Do we run summary jobs on a regular basis? Maybe.

Sometimes summary jobs aren’t enough. Sometimes we have to update summarized data in real time. Let’s break out AdventureWorks and look at an example.

Let’s say we have a report that shows us the total line item sales per customer broken out by year and month.

That’s pretty simple, right?

SELECT  p.BusinessEntityID ,
        p.FirstName ,
        p.LastName ,
        DATEPART(yyyy, soh.OrderDate) AS [Year] ,
        DATEPART(mm, soh.OrderDate) AS [Month] ,
        SUM(sod.LineTotal) AS LineItemTotal
FROM    Person.Person AS p
        INNER JOIN Sales.Customer AS c ON c.PersonID = p.BusinessEntityID
        INNER JOIN Sales.SalesOrderHeader AS soh ON c.CustomerID = soh.CustomerID
        INNER JOIN Sales.SalesOrderDetail AS sod ON soh.SalesOrderID = sod.SalesOrderID
GROUP BY p.BusinessEntityID ,
        p.FirstName ,
        p.LastName ,
        DATEPART(yyyy, soh.OrderDate) ,
        DATEPART(mm, soh.OrderDate)
ORDER BY p.BusinessEntityID ,
        [Year] ,
        [Month] ;

The problem is that this query may use a lot of CPU or disk resources. How can we avoid that? Earlier I mentioned using summary jobs. The problem is that the summary jobs will only run on a schedule and require that we maintain some kind of maintenance history of each row – even if that maintenance history is just a modification timestamp. Wouldn’t it be easier if our summary report just updated itself automagically?

It can! Enter the indexed view.

An indexed view is a regular view that has a clustered index on it. By adding the clustered index the view is persisted to disk. The upside of persisting the indexed view to disk is that there’s an automatic mechanism in place that will update the indexed view. An indexed view must have a unique clustered index so that SQL Server can identify the materialized row that must be updated in response to changes in the underlying data.

CREATE VIEW dbo.my_indexed_view
WITH SCHEMABINDING
AS
  SELECT  p.BusinessEntityID,
          p.FirstName,
          p.LastName,
          DATEPART(yyyy, soh.OrderDate) AS [Year],
          DATEPART(mm, soh.OrderDate) AS [Month],
          SUM(sod.LineTotal) AS LineItemTotal,
          COUNT_BIG(*) AS NumberOfRecords
  FROM    Person.Person AS p
          INNER JOIN Sales.Customer AS c ON c.PersonID = p.BusinessEntityID
          INNER JOIN Sales.SalesOrderHeader AS soh ON c.CustomerID = soh.CustomerID
          INNER JOIN Sales.SalesOrderDetail AS sod ON soh.SalesOrderID = sod.SalesOrderID
  GROUP BY p.BusinessEntityID,
          p.FirstName,
          p.LastName,
          DATEPART(yyyy, soh.OrderDate),
          DATEPART(mm, soh.OrderDate) ;
GO

CREATE UNIQUE CLUSTERED INDEX CX_my_indexed_view ON dbo.my_indexed_view (BusinessEntityID, [Year], [Month]) ;

We could have accomplished this using a summary table and triggers. Triggers are synchronous and updating the summary table will block our data changes from completing. In addition, if we ever want to bypass the trigger from updating (say during a huge data load) we need to disable and then enable the trigger again and then remember to update the summary table. With an indexed view we can just drop the clustered index and then recreate it when we’re done with our load processes.

Note: I can’t take full credit for this question and explanation. A SQL Saturday #42 attendee sent me an email with a question about using indexed views instead of triggers.

This site is protected with Urban Giraffe's plugin 'HTML Purified' and Edward Z. Yang's Powered by HTML Purifier. 401 items have been purified.