August 2009
Mon Tue Wed Thu Fri Sat Sun
« Jul   Sep »
 12
3456789
10111213141516
17181920212223
24252627282930
31  

Month August 2009

text TEXT teXt?

The Problem

A reader ran into a problem on an old post about Automating T-SQL Testing. Thankfully, rather than decide that I’m some useless crank on the internet, this reader took the time to write in to me and tell me about the problem. But, he went one step further: he documented step by step his problem!

The Process

I fired up SSMS and verified his problem (using the thoughtfully provided steps to duplicate). Sure enough, my code didn’t work. Which is odd because I’ve used this very same code to test stored procedures.

At this point, I calmly stood up, walked away from my computer, opened the window, and swore loudly. I then closed the window, walked back to the computer, and sat down. After numerous permutations, I finally searched google in exasperation only to find out it was a capitalization issue (read all about it over here).

Where was this coming from?

The Actual Problem

The GeSHi JavaScript syntax highlighting library was capitalizing the word ‘text’ because it is a datatype in SQL Server. Unfortunately, the text() XML method is lowercase. So, in this isolated incident, my syntax highlighting was causing me problems. The solution was to remove syntax highlighting from that portion of my post and inform the reader of the problem.

What to do?

Well, you need to test things. In this case, though, it was something that I couldn’t effectively test. The developers of the GeSHi plug-in should probably be testing these things (and I’ll be tracking down their info to send them a bug report). The key here is, I guess, to be very very careful. Really I just wanted to share this bug so others don’t get caught by it.

Getting to PASS on the Cheap

The PASS Summit is coming up in a few months and I bet you’re worried about attending. It costs money; I totally understand that. But there are a lot of ways to go for cheap.

  1. Be a speaker – oh, that deadline has come and gone
  2. Be a chapter leader – hrmm… not too many of those, let’s try another one
  3. SPONSORS! – You didn’t think you could get a sponsor for a conference?

Here’s what I mean by a sponsor: Ask your employer to sponsor your trip to the PASS Summit. They aren’t paying for it, they’re sponsoring you.

What You Do For Your Sponsor

You’re asking someone to spend what might initially appear to be a large chunk of money on you.

Wrong.

You’re asking your sponsor to make an investment in your career. But, in addition to this, you’re telling your sponsor that by sending you to the PASS Summit that you are going to be investing back in the company. By sending you to the PASS Summit, they are investing roughly $3,000 on training for you, give or take a few pennies. Sounds like a lot, right? Well, not really. Because, if you think about it, at the PASS Summit you are getting three days of training from the best and the brightest that the SQL Server community and Microsoft have to offer. Nowhere else are you going to have the chance to learn from so many great minds. This opportunity alone would normally cost you an ungodly sum of money. Now, ask yourself: How many people are on my team who could benefit from this knowledge? How many people are on other teams in my organization who could benefit from this knowledge? Let’s say there are 8, including you. What’s 8 x $3,000? $24,000. That’s a lot of money. There’s no way your company could possibly afford to send 8 people to the PASS Summit (bear with me, I’m going somewhere).

Act now and you can get $24,000 worth of training for only $3,000

Act now and you can get $24,000 worth of training for only $3,000

I said something about you investing back in the company, here’s where that comes into play. Take a look at the list of Program Sessions and Spotlight Sessions. There’s a lot in there to learn. More importantly, there’s a lot in there that could benefit your company and your co-workers. Here’s what you do: pick out a two sessions that you want to attend. Write down the title and a quick summary of the abstract but summarize the abstract in a way that shows the value it will add to your current role. Now pick four more sessions that could help your co-workers do their jobs better. Or, if you’re a consultant, you can also pick sessions that can help increase your bill rate (e.g. pick SSIS or BI or DBA sessions if you’re primarily a T-SQL developer). The key here is to show how these sessions are increasing your value to the organization as well as how you can act as a force multiplier for your organization. Remember those force multipliers in old school video games that quadrupled your damage? You want to be that. But helpful instead of destructive. When you show this list of sessions to your boss, be ready to pull out the Ron Popeil schtick.

That’s right, boss! For one easy payment of $3,000 you get $24,000 of value!

How can you possibly deliver this much value? Well, you take copious notes. Take notes in such detail that you could give the presentation. If you don’t think you can do that, talk to the presenter and get their slide deck. Most presenters are more than happy to give you a copy of their slides. Plus, I’m pretty sure they have to make the slides publicly available if they want to present at the PASS Summit. Why are you taking so many notes? Because you’re going to make presentations when you return from the PASS Summit! That’s right, you are going to bring the PASS Summit to your company. You’re going to go to the PASS Summit so you can come back to work and teach everything you learned to your co-workers. Remember how I mentioned that you were investing back in the company? This is how. You’re going to cram your brain with knowledge at the PASS Summit. You’re going to distill that knowledge for when you get back to the office. Then you’re going to deliver training that is specifically tailored to your organization.

What Your Sponsor Does For You

They write you a check. Seriously, though, this knowledge thing you’re doing isn’t free. Someone has to write a check. By the same token, if you’re sending yourself to the PASS Summit on your own nickel you’re going to attend sessions that you’re interested in. If someone else is sending you, the topic turns to “investment”.

Your sponsor makes an agreement with you: They will pay for airfare, hotel, and the Summit registration costs (hopefully all three, although registration is fine too). In exchange you do everything we talked about above. Their side of things is, frankly, pretty easy: find a couple of grand laying around that they can invest in your career. Money doesn’t grow on trees, but three grand is pretty easy to find.

Keep pushing, you'll get smarter

Keep pushing, you'll get smarter


Sample Letter

Need some ideas on how to put this letter together? I’ve done the basic homework on this one. This sample letter is, in fact, the letter that I’ve sent to my employer asking them to give me money in exchange for my smarts. It also includes the sessions that I want to attend as well as the sessions that I think might be of some use to my co-workers.

Why give away my secret sauce?

  1. It’s not secret
  2. I want you to go to the PASS Summit
  3. I really want you to go to the PASS Summit

Seriously, I want to see as many new faces at the PASS Summit as I can. I want to meet people and learn from them. I want to make new friends. And, frankly, I want you to have a chance to experience everything that the PASS Summit has to offer: sessions, networking, food, vendor swag, all of it. I put the letter together with the help of a few community people because we want to see you at the PASS Summit. The kicker: I don’t get a single cent if you got to the PASS Summit. I just want you to go and have as much fun as I had.

Here’s the Sample PASS Summit ROI document. This is very similar to the document that I sent to my employer.

What if my Sponsor Won’t Cover XYZ?

Let’s say that your sponsor will only cover the registration for the PASS Summit. What are you going to do? There are a lot of ways to get to the Summit for cheap. More importantly, there are a lot of ways that you can stay at the Summit for next to nothing. For the purpose of this example, I’m going to assume you’re arriving on Monday, November 2nd, and flying out on Friday, November 6th. It’s a bit hectic, I know, but it saves on the hotel.

Let’s take a look at flights, first.

Flying to Seattle

Point of Origin Cost
Columbus, OH $194
Chicago, IL (any airport) $309
New York, NY $258
Atlanta, GA $242
Milwaukee, WI $197
Los Angeles, CA $179
Denver, CO $159
Dallas, TX $257
Tampa, FL $238
Ljubljana, Slovenia $1936

I just looked these up on Expedia. So, it’s pretty easy to see that you could get to the PASS Summit for about 300 bucks, max via airplane. Less if you ride a horse. Or maybe more. I don’t know how much travel by horse costs. Point is, you can travel for pretty cheap.

NOM NOM NOM

What about food while you’re at the Summit? Well, I survived last year largely by eating the food provided by the catering folks and then buttering up vendors and getting invited to fancy dinners. It sounds gross, but it’s true: if you butter up vendors you can get invited to dinner. Even if you don’t butter up the vendors, you can still get invited to dinner. Even then, you can still eat for incredibly cheap in Seattle. There are a number of great local restaurants within an easy walk of the convention center. As long as you’re willing to eat breakfast and lunch at the convention center, you could probably get a way with spending no more than $15 a day on food. So that’s 4 days at $15 a day, roughly, which works out to $60.

$300 + $60 = $360, in case you’re keeping track at home.

But Where Will I Sleep?

Park bench? Well, unless you enjoy the homeless chic look of Derelicte and freezing to death on a bench, you probably want something better than a park bench. This is where cheap hotels and your network come into play.

Taking a quick look on expedia (search in Seattle and narrow down the search to “Downtown Seattle”), there are multiple hotels within walking distance of the convention center starting at $80 a night. If you split that with a friend, you’re down to $40 a night. That’s only $160 for all four days that we’re talking about for our hypothetical trip to the PASS Summit. Keep in mind when you’re reviewing your hotel choices that you’re going to be spending about 30 minutes standing up and awake in your room over the entire course of the Summit. The rest of the time you are probably going to be in a session or at some kind of event. The hotel doesn’t need 200 cable channels, a whirlpool, HBO, “magic fingers” or anything like that. Bed + walls = win.

So, now we’re looking at a total price of $300 + $60 + $160 = $520.

Here are some pricing comparisons if you don’t believe me (all prices exclude tax and whatever exorbitant “hotel fee” the city government has decided to levy on us):

Hotel Price per Night With Roommate
Sheraton (Conference hotel) $199 $99.50
The Roosevelt $116 $58
Red Lion Hotel $161 $80.50
Grand Hyatt Seattle $191.00 $95.50

SRSLY?!

That’s right, if you can get your company to foot the bill for the PASS Summit registration, the total cost for you could be as low as $520 if you’re careful about things. With 2 months left until the Summit, that’s a very small amount of money that you need to save between now and then. Don’t get coffee every day, stop renting movies, don’t get another tattoo, stop going out to lunch, do something. There are a lot of ways to save yourself $520 between now and september. Remember, you don’t have to pay for the hotel until you check out, but you do have to find the cash for your airfare.

Round Up

There you have it! If you work with your employer to bring value back from the PASS Summit it becomes a lot easier to justify your attendance. Becoming the trainer not only makes you more valuable through your ability to train your co-workers, but it also increases your ability to communicate clearly and fluently as well as think on your feet. If you think creatively, you can easily find ways to save money at the PASS Summit and make it possible to attend on the cheap. So, remember to ask your employer for money and offer to make a deal and work things out however you can. You never know, they just might give you a big pile of money.

Rate This!

There are a few people out there in the community who speak. You know who you are, I’ve been to your talks.

Sometimes, at a user group meeting there are forms to fill out where you circle a number and hand in the form and potentially win a prize like a license to Red Gate SQL Prompt or a copy of ReSharper. But what happens when people don’t fill them out. Or they come up with a particularly insightful comment after the fact like “ZOMG, your presentation totally saved my ass today! There was so much useful information in your presentation and I was able to use it and fix my production explosion!” Or, heaven forfend, the feedback forms are lost in someone’s car or they get recycled or whatever.

Enter speakerrate.com. I’ve known about speakerrate.com for a while now, but for some reason it’s always slipped my mind. At devLink I told Kevin Kline about it and he immediately added it to his presentation slides.

So, what’s the value? Well, it makes it a bit easier for people to rate at their convenience. Maybe I’m feeling rushed, maybe I’m in a bad mood, maybe I want to think about what the speaker said for a while before I leave a lasting mark on their speaking record. Maybe I want everyone to know that I got absolutely nothing out of this so called advanced presentation. You can do all of those things.

The point is that you’re contributing, for better or for worse, to the long term reputation of a speaker. Everyone can see what you have to say and everyone can see how the audiences respond to the speaker. All in all, everyone wins.

What does this mean for speakers?

Interestingly enough, it makes some aspects of speaking a lot easier. When you’re talking to a user group leader you can give them a link to your SpeakerRate.com page (mine is http://speakerrate.com/peschkaj). This makes it easy for user group leaders and speaker selection committees see what they’re in for. Likewise, it keeps your record public.

It’s even easier to get feedback. Rather than collecting the forms, waiting for someone to process the new email addresses and maybe go through the comments for their own purpose before typing them up and emailing them to you, you can simply put a link at the end of your presentation and ask the audience to visit the site and rate your talk. Sure, it takes a little bit more time but you can also always tell them the honest truth: your boss is going to shove you in a box and shake it up real good unless you have great ratings.

Most important to me is that it’s a constant stream of feedback on how I’m doing as a speaker. I learned that I took a lot of my knowledge for granted. Now I know what I need to do the next time I give this presentation and I’m going to make sure that I do a much better job. Why? Because one of the audience members said that they didn’t understand some concepts that I mentioned without an explanation. I can now tailor the presentation to include more background material or take out some advanced material. The point is that without the feedback, I wouldn’t have known about these comments and I might have continued to give this presentation with too little background information and too much advanced information.

Note I have not been paid for this, I just think it’s a cool idea

SQL Quiz #5: SANs, Sex, and Mirrors

I was actually going to ignore that someone had tagged me in a SQL Quiz. I really was. Then I realized that the someone who tagged me was Thomas W LaRock and that he would probably beat me with a broom handle and pour bacon flavored Jaeger down my throat when I got to the PASS Summit, so I decided I should probably do my best to answer the questions.

Do you feel that you have a reliable SAN solution? If so, what’s the secret?

I have no idea if I have a reliable SAN solution. I think it’s reliable, but I’m basing this on the assumption that it hasn’t failed yet. I have to admit that most of our storage uses a direct attached storage device, which irks me to no end since I only have 16 drives to work with. However, I have it on good authority that our SAN has never caught fire or exploded or spontaneously deleted data… within recent memory. (Using these assumptions, my intestinal tract is currently incredibly reliable since it hasn’t experienced a catastrophic failure since I went to that dodgy Chinese buffet in Dayton.)

Explain Database Mirroring in layman’s terms

No. Oh, there’s Thomas W LaRock with a broom handle… I should probably explain database mirroring.

I had to go look this up. I’m a database developer, we don’t work with these kinds of things on a daily basis, we leave that to the production support DBAs. However, I have it on good authority that database mirroring is a very complicated thing, much like sex, and, much like sex, people lie about how great it is, how much of it they’ve got, and everyone claims they’ve had it working in a 3-way but they can’t actually prove it. Although, looking at Books Online, I could be wrong about that…

Scripting Objects with Magic

You know what, there’s no magic here. However, it’s kinda magic to me since I didn’t write it and reading other people’s code is something that is almost like magic to me. And, I have to admit that I did not write this code. One of my co-workers, Brent Morrow, came up with this solution. Sadly, Brent does not have a blog. Luckily, I do. So now I will share with you Brent’s solution for keeping track of objects to move from one platform to another.

What’s the goal here? Well, let’s say we don’t have VSTS: Database Developer edition. And let’s further posit that we don’t have access to any of the commercially available schema comparison tools. Apart from pen and paper, how shall we keep track of the changes that need to go into production?

Well, we can use SQL Server to keep track of these changes.

The first thing we need is a table to track this:

CREATE TABLE [Debug].[DBObjects]
    (
      [LocalID] [int] IDENTITY(1, 1)
                      NOT NULL,
      [Schema] [nvarchar](128) NOT NULL,
      [Name] [nvarchar](128) NOT NULL,
      [ObjectType] [varchar](30) NOT NULL,
      [RequestedBy] [varchar](30) NULL,
      [RequestedDate] [datetime] NULL,
      [ProductionReady] [bit] NULL,
      [ProductionDate] [smalldatetime] NULL,
      [InProduction] [bit] NULL,
      [Comments] [varchar](2048) NULL,
      CONSTRAINT [PK_DBObjects] PRIMARY KEY CLUSTERED ( [LocalID] ASC )
        WITH ( PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF,
               IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON,
               ALLOW_PAGE_LOCKS = ON ) ON [PRIMARY]
    )
ON  [PRIMARY] ;

So, here are the rules for the table:

  • Schema – this is the object schema. It’s required.
  • Name – the name of the object to be scripted. Also required.
  • ObjectType – the type of object that we’re scripting. This needs to be one of the following values: STORED PROCEDURE, VIEW, FUNCTION. This is required. Spelling is important.
  • RequestedBy – this shows up in the script, but it’s not required.
  • RequestedDate – this also shows up in the script, but it’s not required.
  • ProductionReady – this is required, it needs to be set to 1.
  • ProductionDate – this is optional, it is just the date that something goes/went into production.
  • InProduction – One the object has been moved into production, set this to true (1). If you don’t do this, and ProductionReady is set to true (1), then the object will be scripted the next time that everything is run.
  • Comments – optional comments, these show up in the script.

So, what is the next step? Well, you need a way to script all of this. Basically, the following script will execute against the DBOjects table and will generate a script for all of the objects in the table with ProductionReady set to true and InProduct set to false. Once the script has been run against the new environment, set InProduction to true (or remove the row) and the object won’t be scripted in subsequent runs. If you have more changes, add a new line with a new comment and new request date. Good times, eh?

So, a big thanks to Brent Morrow for sharing this code with the world. If you have questions, comments, concerns, improvements, or just want to share kudos, put them down in the comments or drop me an email and I’ll make sure that Brent knows about it.

---------------------------------------------------------------
-- DEFINITIONS
---------------------------------------------------------------

CREATE TABLE #EntryHold ( [Text] VARCHAR(4000) )

CREATE TABLE #Entry ( [Text] VARCHAR(4000) )

DECLARE @LocalID INT
DECLARE @Schema VARCHAR(50)
DECLARE @Name VARCHAR(100)
DECLARE @ObjectType VARCHAR(100)
DECLARE @ProductionReady BIT
DECLARE @InProduction BIT
DECLARE @RequestedBy VARCHAR(50)
DECLARE @RequestedDate DATETIME
DECLARE @Comments VARCHAR(2000)
DECLARE @Counter TINYINT
DECLARE @Supported BIT

DECLARE [EntryCursor] SCROLL CURSOR
    FOR SELECT  [LocalID],
                [Schema],
                [Name],
                [ObjectType],
                [ProductionReady],
                [InProduction],
                [RequestedBy],
                [RequestedDate],
                [Comments]
        FROM    [Debug].[DBObjects]
        ORDER BY [LocalID]

---------------------------------------------------------------
-- HEADER
---------------------------------------------------------------
OPEN [EntryCursor]

-- STORED PROCEDURES NOT MOVED
INSERT  INTO #Entry
VALUES  (
          '--- OBJECTS NOT BEING MOVED ---'
        )

SET @Counter = 0
WHILE @Counter < 3
    BEGIN
        FETCH FIRST FROM [EntryCursor] INTO @LocalID, @Schema, @Name,
            @ObjectType, @ProductionReady, @InProduction, @RequestedBy,
            @RequestedDate, @Comments

        WHILE @@FETCH_STATUS = 0
            BEGIN
                SET @Supported = CASE WHEN @ObjectType IN ( 'VIEW',
                                                            'STORED PROCEDURE',
                                                            'FUNCTION' )
                                      THEN 1
                                      ELSE 0
                                 END

                IF ( ( @ObjectType = 'VIEW'
                       AND @Counter = 0
                     )
                     OR ( @ObjectType = 'STORED PROCEDURE'
                          AND @Counter = 1
                        )
                     OR ( @ObjectType NOT IN ( 'STORED PROCEDURE', 'VIEW' )
                          AND @Counter = 2
                        )
                   )
                    AND ( @ProductionReady IS NULL
                          OR @ProductionReady = 0
                        )
                    AND ( @InProduction IS NULL
                          OR @InProduction = 0
                        )
                    BEGIN
                        INSERT  INTO #Entry
                        VALUES  (
                                  '--REQUESTOR: ' + @RequestedBy + SPACE(12 - LEN(@RequestedBy))
                                  + 'DATE: ' + CONVERT(VARCHAR, @RequestedDate, 101)
                                  + ' | ' + @ObjectType + ': ' + @Schema + '.'
                                  + @Name
                                )
                        IF @Supported = 1
                            INSERT  INTO #Entry
                            VALUES  (
                                      '--        REASON NOT MOVED:  Not production ready!'
                                    )
                        ELSE
                            INSERT  INTO #Entry
                            VALUES  (
                                      '--        REASON NOT MOVED:  Not Supported!'
                                    )

                        IF ( @Comments IS NOT NULL )
                            INSERT  INTO #Entry
                            VALUES  (
                                      '--        COMMENTS:  ' + @Comments
                                    )
                    END
                FETCH [EntryCursor] INTO @LocalID, @Schema, @Name, @ObjectType,
                    @ProductionReady, @InProduction, @RequestedBy,
                    @RequestedDate, @Comments
            END
        SET @Counter = @Counter + 1
    END
INSERT  INTO #Entry
VALUES  (
          '---------------------------------------------------------------------------------------------------'
        )

INSERT  INTO #Entry
VALUES  (
          '--- OBJECTS READY TO MOVE ---'
        )

SET @Counter = 0
WHILE @Counter < 3
    BEGIN
        FETCH FIRST FROM [EntryCursor] INTO @LocalID, @Schema, @Name,
            @ObjectType, @ProductionReady, @InProduction, @RequestedBy,
            @RequestedDate, @Comments
        WHILE @@FETCH_STATUS = 0
            BEGIN
                IF ( ( @ObjectType = 'VIEW'
                       AND @Counter = 0
                     )
                     OR ( @ObjectType = 'STORED PROCEDURE'
                          AND @Counter = 1
                        )
                     OR ( @ObjectType NOT IN ( 'STORED PROCEDURE', 'VIEW' )
                          AND @Counter = 2
                        )
                   )
                    AND ( @ProductionReady = 1 )
                    AND ( @InProduction IS NULL
                          OR @InProduction = 0
                        )
                    BEGIN
                        INSERT  INTO #Entry
                        VALUES  (
                                  '--REQUESTOR: ' + @RequestedBy + SPACE(12 - LEN(@RequestedBy))
                                  + 'DATE: ' + CONVERT(VARCHAR, @RequestedDate, 101)
                                  + ' | ' + @ObjectType + ': ' + @Schema + '.'
                                  + @Name
                                )
                        IF ( @Comments IS NOT NULL )
                            INSERT  INTO #Entry
                            VALUES  (
                                      '--        COMMENTS:  ' + @Comments
                                    )
                    END
                FETCH [EntryCursor] INTO @LocalID, @Schema, @Name, @ObjectType,
                    @ProductionReady, @InProduction, @RequestedBy,
                    @RequestedDate, @Comments
            END
        SET @Counter = @Counter + 1
    END

INSERT  INTO #Entry
VALUES  (
          '---------------------------------------------------------------------------------------------------'
        )
INSERT  INTO #Entry
VALUES  (
          '--- OBJECT SCRIPTS ---'
        )

---------------------------------------------------------------
-- SCRIPTS THAT ARE PRODUCTION READY
---------------------------------------------------------------
SET @Counter = 0
WHILE @Counter  5
                            BEGIN
                                INSERT  INTO #Entry
                                        SELECT  *
                                        FROM    #EntryHold
                            END
                        ELSE
                            BEGIN
                                INSERT  INTO #Entry
                                VALUES  (
                                          '--' + @ObjectType + ' [' + @Schema
                                          + '].[' + @Name + '] was not found.'
                                        )
                                INSERT  INTO #Entry
                                VALUES  (
                                          '---------------------------------------------------------------------------------------------------'
                                        )
                            END
                        DELETE  FROM #EntryHold
                    END

                FETCH [EntryCursor] INTO @LocalID, @Schema, @Name, @ObjectType,
                    @ProductionReady, @InProduction, @RequestedBy,
                    @RequestedDate, @Comments
            END
        SET @Counter = @Counter + 1
    END

---------------------------------------------------------------
-- SCRIPTS THAT ARE NOT PRODUCTION READY
---------------------------------------------------------------
CREATE TABLE #CommentEntry ( [Text] VARCHAR(4000) )

SET @Counter = 0
WHILE @Counter < 3
    BEGIN
        FETCH FIRST FROM [EntryCursor] INTO @LocalID, @Schema, @Name,
            @ObjectType, @ProductionReady, @InProduction, @RequestedBy,
            @RequestedDate, @Comments

        WHILE @@FETCH_STATUS = 0
            BEGIN
                IF ( ( @ObjectType = 'VIEW'
                       AND @Counter = 0
                     )
                     OR ( @ObjectType = 'STORED PROCEDURE'
                          AND @Counter = 1
                        )
                     OR ( @ObjectType NOT IN ( 'STORED PROCEDURE', 'VIEW' )
                          AND @Counter = 2
                        )
                   )
                    AND ( @ProductionReady IS NULL
                          OR @ProductionReady = 0
                        )
                    AND ( @InProduction IS NULL
                          OR @InProduction = 0
                        )
                    BEGIN
                        INSERT  INTO #CommentEntry
                                EXECUTE
                                       ( 'sp_helptext @objname = ''' + @Schema
                                         + '.' + @Name + ''''
                                       )
                        INSERT  INTO #CommentEntry
                        VALUES  ( 'GO' )
                        INSERT  INTO #CommentEntry
                        VALUES  (
                                  '---------------------------------------------------------------------------------------------------'
                                )
                    END

                FETCH [EntryCursor] INTO @LocalID, @Schema, @Name, @ObjectType,
                    @ProductionReady, @InProduction, @RequestedBy,
                    @RequestedDate, @Comments
            END
        SET @Counter = @Counter + 1
    END

INSERT  INTO #Entry
        SELECT  '--' + [Text]
        FROM    #CommentEntry

DROP TABLE #CommentEntry

CLOSE [EntryCursor]
DEALLOCATE [EntryCursor]

DROP TABLE #EntryHold

SELECT  *
FROM    #Entry
DROP TABLE #ENTRY

AppDev Virtual Chapter and CBusPASS Round Up

A special thanks to Grant Fritchey and Kevin Kline for their recent presentations.

Understanding Execution Plans

Grant Fritchey's Fists of Fury - putting execution plans in their place

Grant Fritchey's Fists of Fury - putting execution plans in their place

Grant Fritchey gave a phenomenal presentation covering more than just the plain basics about execution plans. Rather than focus on the wealth of potential operators that SQL Server can show in an execution plan, Grant focused on reading actual execution plans and showing the most common operations and what they mean. In addition to covering some ideal scenarios, Grant also discussed potential performance bottlenecks, how to investigate these potential bottlenecks, and what to do when they become an actual problem.

Unfortunately, due to technical mishaps (Grant and I both forgetting to start the presentation recording) there is no recording.

FEAR NOT! There will be a repeat of this presentation in October when Grant will be presenting virtually for the CBusPASS group.

End to End Performance Tuning

Kevin Kline happily donated his evening, skipped part of the DevLink keynote and drove me back to my hotel in order to present remotely for CBusPASS. Kevin outlined a performance tuning methodology that works universally across SQL Server 2005 and 2008. Kevin’s presentation, despite some technical hiccups, covered some great ground and reminded me that it’s alwasy best to start at the most basic level (error logs in both Windows and SQL Server) and move through the general layers of the OS, database, and then application while slowly narrowing down towards the specific problem and a working solution.

Bonus Fact: Kevin is red-green color blind.

A Case of Shifting Identity

- Or -
A Brief Foray Into the Realm of IDENTITY Columns

We all know, or should know, when we insert into a table using using SET IDENTITY_INSERT, that the identity value will be reset to the next available value in the sequence. Meaning that the identity value will either be the next value that it was supposed to be (if we filled a gap in the sequence) or the next value larger than the row we’ve just inserted (so if we inserted 100, the next identity will be 101). Right? Well, sort of. Books Online, somewhat confusingly, states that “If the value inserted is larger than the current identity value for the table, SQL Server automatically uses the new inserted value as the current identity value.” Define larger.

In this case, larger actually does mean the next available value in the sequence. Check it:

IF OBJECT_ID('tempdb..#t') IS NOT NULL
  DROP TABLE #t;

CREATE TABLE #t (
  id INT IDENTITY(1,1),
  val VARCHAR(10)
);

INSERT INTO #t VALUES ('a');
INSERT INTO #t VALUES ('b');
INSERT INTO #t VALUES ('c');
INSERT INTO #t VALUES ('d');
INSERT INTO #t VALUES ('e');
INSERT INTO #t VALUES ('f');

SET IDENTITY_INSERT #t ON;

INSERT INTO #t (id, val) VALUES (-1, 'g');

SET IDENTITY_INSERT #t OFF;

INSERT INTO #t VALUES ('h');

SELECT * FROM #t;

“ZOMG, he’s so smart!” I know, that’s totally what you’re saying, right? Well, by using a straightforward example, I’ve gone ahead and proved nothing apart from showing you that I know how to use SET IDENTITY_INSERT and copy/paste.

So, what happens if you want to use a negative identity seed? Technically the numbers are getting smaller, not larger, right?

IF OBJECT_ID('tempdb..#t') IS NOT NULL
  DROP TABLE #t;

CREATE TABLE #t (
  id INT IDENTITY(-1,-1),
  val VARCHAR(10)
);

INSERT INTO #t VALUES ('a');
INSERT INTO #t VALUES ('b');
INSERT INTO #t VALUES ('c');
INSERT INTO #t VALUES ('d');
INSERT INTO #t VALUES ('e');
INSERT INTO #t VALUES ('f');

SET IDENTITY_INSERT #t ON;

INSERT INTO #t (id, val) VALUES (1, 'g');

SET IDENTITY_INSERT #t OFF;

INSERT INTO #t VALUES ('h');

SELECT * FROM #t;

Witchcraft! I made the numbers decrease instead of increase! But then I used good magic to put a positive number in there and then the witches corrupted the sequence and the numbers got smaller again!

Sensibly speaking, though: it works. The identity resumes the normal sequence and order is again restored in the world. Had I inserted -10 instead of 1, the next value inserted into the id column would have been -11. Which makes sense.

Why the linguistic confusion on the part of Books Online? I don’t know. I would hazard a guess and say that it was implied that they meant “larger in relation to the IDENTITY seed that you have set up” (and probably muttered the words “you pedantic toad” under their breath). But rather than explicitly go out on a limb and define such a thing in the documentation for SET IDENTITY_INSERT, they assumed that people would infer the meaning. You know, they assumed that people would make sense.

Why would you ever want to do something silly like this? I have my reasons, but I’m sharing this as a test of the application functionality that I needed and a useful demonstration of how IDENTITY works.

Installing Windows 7

A well-prepared work area

A well-prepared work area

Windows 7 is out. I’m sure a lot of you have gone ahead and installed it already (or at least started the download process), but for those of you who haven’t, I have suffered through a botched installation and I am blogging this from my Windows 7 installation.

I started the process on Saturday at 11am and finally finished up at 6:00PM on Sunday. First off, let me say that my installation process was made difficult by a number of things: installing on a MacBook using BootCamp, installing anti-virus before anything else, and installing from mounted ISO files using unsupported ISO mounting software. Needless to say, I had my work cut out for me.

Let me start out by saying this: prepare yourself. It’s important to carefully plan out anything that could potentially corrupt your data, especially an operation like installing a new operating system. For the record, I never upgrade my operating system. I always back up to external media and repave the OS. I figure that if I’m making the investment in something brand new and fancy I should start with a clean slate.

First draft of the checklist... and some light reading

First draft of the checklist... and some light reading

Before I started my installation, I took a day and I made a checklist.

So, what goes into this whole process? Well, the first thing I did was make a list of all of the software that I have installed. The easiest way to do this is to either open up the Control Panel and look at Add/Remove Programs or else use a program like CCleaner to bring up a list of everything that’s been installed on the computer. Scribble down anything that you actually want to re-install – I say anything that you want to re-install because we all know that our computers get full of junk that we foolishly install thinking that it is going to be useful at some point. Once that list is put together, take a backup of anything that you want to keep around – put it on some DVDs or CDs or a tape or a spare hard drive or a giant pile of AOL floppies – then put them someplace safe, you’ll need it later. Your next step is to find all of your install DVDs and keys. Since you probably have a lot of applications – AIM or Google Talk or whatever – that didn’t come on a DVD, you’ll want to download all of those again as well. Put all of those installers on an external drive or DVD or whatever and keep that safe too.

So, go ahead and re-install Windows, patch the OS, and install any third party drivers. As you’re going through everything that you need to install, do not install any anti-virus software until you’re done with everything else. Why am I saying this? Because anti-virus software can grab a hold of various files during software installation, and the installation process can be horribly, horribly botched. This happened to me and when something gets botched before I have any personal data on the machine I go ahead and start the installation all over again. I lost a lot of time, but at the end of the day I have a working windows installation.

Once everything is completely done, and only then, should you install any kind of system maintenance software like Diskeeper or any kind of anti-virus software. Yeah, it’s good to have anti-virus software on your computer, but at the same time are you really going out there and looking at tons of horrible websites while you’re installing software? Don’t answer that question, just don’t do it.

The key here is to be prepared: make a list, make backups, have your installation media ready, follow your plan. If you run into problems, take notes. If you run into any problems, you can consult your notes, revise the plan, and start over again. If you prepare properly, you shouldn’t run into any mishaps that you can’t recover from.

A Special Note for MacBook Users

For those of you who are using MacBooks and BootCamp, you’ll want to make sure you have your OS X installation DVD handy. The trick is to install the 64-bit drivers (you are using 64-bit Windows, right?) from the command line. Do this: Start -> Run -> cmd. Then navigate to your DVD drive – mine was D:. Once you’re there, do the following:

cd "Boot Camp\Drivers\Apple"
msiexec /i BootCamp64.msi

Windows will pop up some kind of warning about how Apple is going to eat your computer or that the drivers aren’t compatible. You can ignore that and keep on going. The drivers work… for me.

I had a problem with Windows installing some kind of goofy High Definition Audio Device driver that just didn’t work at all. I eventually found a working driver and downloaded it from these guys. This also works. I ran it through my anti-virus software twice, just to be paranoid, and didn’t find any bad things. It appears to work. I watched The Departed last night, I heard swearing, so I think the sound worked.

Links for the Week – 2009.08.07

SQL Server

Commenting Your Code Do it, people. I don’t comment enough of my code, but it’s something I keep in the back of my mind all the time.

Fast Running Totals Solution With Ordered CTE I love Mladen’s solution to this particular problem. I usually would use a nasty self join or some kind of hideous cross join to accomplish this.

Teaser: Left Join..the SQL ego crusher Mmmmm SQL brain teaser.

Development

Software is a Wicked Problem

sqlsharp It’s a port of SQLite to C#. I don’t believe source code has been posted yet, but it’s a great idea for portable development.

TeamReview Ask your co-workers for a code review, and get one, all through VSTS. I’m not a fan of meetings. I hate them. I also hate reading your code. I’d be much happier reading your code from my cube. Now I can.

Stuff & Things

How to Set Someone Straight Correcting people is never easy. Use these four simple steps to lead to success.

title unknown

Teach for America founder on the pointlessness of planning, the importance of saying no, etc. This is interesting because it’s a collection of quotes, but the 37signals folks link back to their own articles. Very interesting stuff.

:::WARNING – RANT:::
Netflix Shares Internal Presentation on Company Culture I was going to try to build an entire blog post out of this. Then I realized it would sound like I rant, so I decided to ran in my weekly link dump instead because it’s my blog and youcantmakemegotobedearlyanymore! So… yeah, anyway. Netflix sounds like an amazing place to work – they do everything they can to let good employees innovate and reward them effectively. For people outside of the consulting world, it doesn’t make sense to hold them to some weird standard of X days of holiday a year. Most of our work is based around meeting goals, not producing sprockets. Does it really matter if I want to take an extra few days off here and there? If I’m a top producer, that should be fine.

The other thing that really struck me about Netflix is how they compensate their employees. They hit a few things on the head that I’ve always agreed with – don’t bonus your employees, pay them. If you tell me, at hiring, that you’ll give me a $5,000 bonus in 6 months, pay me $5,000 more now. I don’t want a bonus. A bonus won’t make the payments on my sweet ride. They also pay their employees what they think they’re worth. Salary negotiations are a game. Playing games with employees that you allegedly trust and who are supposed to trust you is not a good way to conduct business.

Many businesses would do well from reading this slide deck and learning from it.
:::END RANT:::

Upcoming Presentations

There are a few presentations coming up this week.

The first is Grant Fritchey’s presentation on Tuesday 8/11 at 1PM EST: Understanding Execution Plans. Here’s the story:

Attendees will be introduced to the wealth of data contained within the execution plans generated by SQL Server. From the simplest “SELECT *” query to complicated joins, the icons and properties that allow you to understand what is occuring within your query will be explained. You will leave knowing what kinds of execution plans you have available and what they can be used for. You’ll learn about graphical exeuction plans; what do the icons mean and how are they related; how much information is available and how to access and interpret it. All this information will be used to help you understand what’s happening within your queries so that you can identify and fix poor performance in your own environment.

Grant is encouraging questions about execution plans. Also ask him about his robot legs and how they handle sticks. I think you’ll be pleasantly surprised.

Also, Kevin Kline will be presenting, remotely, at CBusPASS (8/13/2009 @ 6:30 PM) on End-to-End Troubleshooting for SQL Server. Kevin will be sharing his wisdom from the devLink conference. Times and LiveMeeting info are on the CBusPASS website. For those in attendance, see if you can spot me. I’ll be in Nashville, stalking Kevin.

Finally on August 26th at noon EST, Janis Griffin will be presenting on Wait-Time Based SQL Server Performance Management for the PASS DBA Virtual Chapter (this is a Live Meeting). Here’s the summary, in case you don’t want to click:

Using Wait Time Analysis and Wait Types is a newer method for tuning SQL Server instances. As a result, there is often confusion on exactly what the data means. The issue typically centers around the fact the wait time data is analyzed at the wrong level or the collected wait time data is not detailed enough. This presentation will focus on these problems and review several real-life case studies of using SQL Server Wait Type data coupled with Wait-Time based performance analysis to solve the most difficult performance related issues.

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