THE SQL Server Blog Spot on the Web

Welcome to - The SQL Server blog spot on the web Sign in | |
in Search

Adam Machanic

Adam Machanic, Boston-based SQL Server developer, shares his experiences with programming, monitoring, and performance tuning SQL Server. And the occasional battle with the query optimizer.

  • Query Performance and Parallelism Seminars in Boston and Chicago

    You're a DBA or database developer working on a big (or even big-ish -- doesn't have to be huge) database. Your end-users are doing all sorts of data analysis, and even though you have a pretty beefy server, your queries just don't seem to run as fast as they should.

    The reason (I bet)? Your queries aren't taking full advantage of the CPU power available in today's servers. SQL Server has powerful parallel processing capabilities, but left to its own devices (and defaults) you're never going to see the full potential. Luckily, this can be fixed. You can make your queries much faster. (Often an order of magnitude or more!) And I can show you how.

    Join me in Boston or in Chicago, the Friday before the upcoming SQL Saturday events in those cities, and we'll go deep into parallel processing. You'll learn about Windows server and how it deals with processes and threads, about SQLOS and its thread scheduling internals, how the SQL Server query processor works, and how you can use all of this knowledge to make your queries run faster and your server behave more consistently, even under load.

    These full-day seminars cost only $150 and include lunch, coffee, and a printed course book -- plus a full day of intense content.

    Full information, including an outline and registration details, is available at the links below:

    Hope to see you there!

  • SQLRally Nordic and SQLRally Amsterdam: Wrap Up and Demos

    First and foremost: Huge thanks, and huge apologies, to everyone who attended my sessions at these events. I promised to post materials last week, and there is no good excuse for tardiness. My dog did not eat my computer. I don't have a dog. And if I did, she would far prefer a nice rib eye to a hard chunk of plastic.

    Now, on to the purpose of this post...

    Last week I was lucky enough to have a first visit to each of two amazing cities, Stockholm and Amsterdam. Both cities, as mentioned previously on my blog, hosted SQLRally events, and I did a precon plus two talks at each event.

    The events in both cities were well done and the audiences seemed quite sharp. Very nice events at which to be a speaker! I hope to return to both areas very, very soon. (Hint, hint, event organizers!)

    Precon attendees: You should already know where to get your slides and demos.

    Breakout session attendees: Find the demos for both of my talks attached here.

    Thanks again to everyone who I met and/or taught. It was really a fantastic week. Skål and/or proost -- depending on your disposition!

  • Query Performance Sessions in Stockholm and Amsterdam

    As previously mentioned, I'll be delivering my full-day "No More Guessing" performance troubleshooting seminar at both the Stockholm and Amsterdam SQLRally events. In addition to the seminar, I'll be doing two breakout sessions at each event.

    It's going to be a busy week! But luckily for me, I'm doing the same things in each city:


    Using Your Brain to Beat SQL Server

    This session is a joint effort with one of the world's greatest SQL superheroes, Thomas Kejser. The session is all about query optimizer deficiencies and how to win the battle for excellent performance by applying your own intelligence instead of blindly trusting that SQL Server will do the right thing. I think this is going to be a really fun and useful session.


    Data, Faster: SQL Server Performance Techniques with SQLCLR

    Remember when SQLCLR was first put into SQL Server and everyone was wondering what they should use it for? I found my answer: raw performance. In this session I'll teach you a SQLCLR pattern that can help reduce the run time of your heaviest and most logic-filled queries, often by an order of magnitude or more.


    Looking forward to seeing you in Europe next month!

  • Hey Amsterdam and Stockholm: Just Say No to Guessing About Performance!

    Have SQL Server performance problems? What are you going to look at? Can you quickly isolate the root cause? Or do you ever find yourself stuck, not sure of what to do next?

    That's what the No More Guessing seminar is all about.

    This seminar teaches you to use:

    • Baselining: An analytical methodology based on statistical analysis and evidence rather than graphs and your eyes.
    • Performance counters. The right set of counters to get you where you need to be without being overwhelmed.
    • Wait stats: Including what waits really mean and an extremely in-depth overview of the 15 most common waits you will encounter on real production systems.
    • DMVs: The 15 DMVs that you can use to find out why things are slow on your server right now
    • Query plans: The top things to look for in your biggest, most confusing plans so that you can quickly find the culprit. And, naturally, how to fix the problem.

    All of these techniques will work with any version of SQL Server after 2005, although 2008 and beyond are recommended. (The seminar covers some specific very useful features added in both 2008 and 2012. As soon as 2014 is ready, I look forward to adding some really cool stuff from there as well. SQL Server 2005 just isn't as exciting as it once was.)

    This November I am pleased to be teaching this seminar twice in Europe, at the two SQLRally events:

    I'm also delivering two breakout sessions at each show. More information on those soon.

    Hope to see you in Europe!

  • Next-Level Parallel Plan Forcing: An Alternative to 8649

    "Even experts with decades of SQL Server experience and detailed internal knowledge will want to be careful with this trace flag.  I cannot recommend you use it directly in production unless advised by Microsoft, but you might like to use it on a test system as an extreme last resort, perhaps to generate a plan guide or USE PLAN hint for use in production (after careful review)."

    So wrote Paul White in his often referenced article, "Forcing a Parallel Query Execution Plan." His article focuses on the various reasons that you might not get a parallel query plan, chief among them the optimizer simply not doing a great job with its own cost model. (My session from the 2012 PASS conference, available on YouTube, also discusses the issue in some detail, and from a different perspective. You might want to both watch it and read Paul's article, prior to reading any further here.)

    The trace flag Paul mentions, 8649, is incredibly useful. It allows us to tell the query optimizer to disregard its cost-based comparison of potential serial and parallel versions of our plans, thereby skipping right to the good stuff: a parallel plan (when it's possible to generate one). Alas, the flag is undocumented, unknown, and its full impact difficult to understand. And for those cowboys who are willing to take the plunge and use it in a production environment, there are still other issues lying in wait:

    • This flag is not something you want to enable on a system-wide basis. You can use DBCC TRACEON on a case-by-case basis, but as Paul shows in his post it's much nicer to use the QUERYTRACEON hint. Unfortunately, this hint was, just like the flag, entirely undocumented until only recently. It is now documented only for a very small number of flags; 8649 isn't one of them.
    • Just like DBCC TRACEON, QUERYTRACEON requires significant system-level privileges: system administrator, to be exact. This means that you're forced to either give that permission to all of your users, or do some module signing. Clearly the latter approach is far superior, but it's still a pain.
    • QUERYTRACEON, being a query-level hint, can't be encapsulated in a view or inline table-valued function. So if we want to force these to go parallel, we're pretty much out of luck.

    Clearly, while invaluable for testing, 8649 just isn't the parallel panacea we need.

    Before we get into the details of the solution I'll be presenting here, it’s probably a good idea to do a quick review of the situation.

    Here’s the problem, in brief:


    Big plan, no parallelism. Ouch. Or maybe I should say that more slowly. OOOOOOOOuuuuuuuucccccccchhhhhhhh. Because you’re going to be waiting for quite a while for this plan to finish.

    Why did this happen? We can find out by forcing a parallel version of the plan using 8649 and evaluating the metadata.


    When the query optimizer decides whether or not to select a parallel plan, it first comes up with a serial plan cost, then compares it to the parallel plan cost. If the parallel plan cost is lower, that's the one that gets used. This parallel plan cost is based on the serial cost, but with a few key modifications:

    • CPU costs for each iterator are divided by the degree of parallelism...except when they sit beneath a parallel nested loop. (Except when the input to the parallel nested loop is guaranteed to be one row. That’s a very special parallelism edge case.) Notice the nested loop iterator above? Strike one. (Note: I/O costs aren’t divided by anything.)
    • Sometimes, the parallel plan will have slightly different iterators than the serial version, due to the optimizer doing its job. Notice, above, that the iterator feeding the nested loop has transitioned from a Merge Join to a Hash Match? That’s going to change the cost. In this case, it’s more expensive. Strike two.
    • Parallel iterators are added into the plan as necessary. See that Gather Streams? It’s not free. Strike three.

    Adding all of these modifications together, our parallel plan has a higher cost than our serial plan. Cost is the query optimizer’s way of weighing the relative merits of one plan against another, and just like you might choose the less expensive option at a store, so has the query optimizer. A plan with a cost 10 less than some other plan must perform better, right? Well…no. Not in the real world, and especially not when we're dealing with plans that have estimated costs in the millions.

    Unfortunately, as I mention in the video linked above, the costing model is rather broken. And the workaround I suggest in the video--using a TOP with a variable in conjunction with OPTIMIZE FOR--can work, but it has some problems. The biggest issue, as far as I’m concerned? It requires use of a local variable. Which, just like 8649, means that it can’t be used in a view or inline TVF.

    So what’s a SQL developer to do?

    Recently it hit me. If I could only create a query fragment that had certain properties, I could apply it as needed, just like 8649. Here’s what I set out to create:

    • High CPU cost, low I/O cost. This is key. The query fragment had to be able to benefit from the query optimizer’s math.
    • No variables. See above.
    • A single, self-contained unit. No tables or other outside objects. As much as possible, avoidance of future maintenance issues seemed like a good approach.
    • No impact on estimates in the core parts of the plan. This query fragment had to impact plan selection purely on the basis of cost, and without causing the optimizer to make strange choices about join types, execution order, and so on.

    After quite a bit of trial and error I arrived at my solution, which I encapsulated into the following table-valued function:

    CREATE FUNCTION dbo.make_parallel()
        a(x) AS
                    (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1),
                    (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1),
                    (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1),
                    (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1),
                    (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1),
                    (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1),
                    (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1),
                    (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1),
                    (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1),
                    (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1),
                    (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1),
                    (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1),
                    (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1),
                    (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1),
                    (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1),
                    (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1),
                    (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1),
                    (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1),
                    (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1),
                    (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1),
                    (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1),
                    (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1),
                    (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1),
                    (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1),
                    (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1),
                    (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1),
                    (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1),
                    (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1),
                    (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1),
                    (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1),
                    (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1),
                    (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1),
                    (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1),
                    (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1),
                    (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1),
                    (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1),
                    (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1),
                    (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1),
                    (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1),
                    (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1),
                    (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1),
                    (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1),
                    (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1),
                    (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1),
                    (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1),
                    (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1),
                    (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1),
                    (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1),
                    (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1),
                    (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1),
                    (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1),
                    (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1),
                    (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1),
                    (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1),
                    (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1),
                    (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1),
                    (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1),
                    (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1),
                    (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1),
                    (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1),
                    (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1),
                    (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1),
                    (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1),
                    (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1)
            ) AS a0(x)
        b(x) AS
            SELECT TOP(9223372036854775807)
                a AS a1,
                a AS a2,
                a AS a3,
                a AS a4
                a1.x % 2 = 0
            SUM(b1.x) AS x
            b AS b1
            SUM(b1.x) IS NULL

    What this does: The function starts with a set of 1024 rows, defined in the row value constructor in CTE [a]. This set of rows is cross-joined to itself four times. The resultant Cartesian set contains 1,099,511,627,776 rows, all of which are forced to pass through a Top iterator as well as a Stream Aggregate. This is, naturally, a hugely expensive operation that generates a very high estimated cost.

    Except that in reality there are only 1024 rows. Notice the predicate in CTE [b]: (a1.x % 2 = 0). If you've studied a bit of math you know that 1 divided by 2 has a remainder of 1, not 0. But luckily for us, the query optimizer has no way of evaluating that at compile time. It instead asks its sibling, the query processor, to do that work. The plan involves scanning each of the four cross joined sets for a match, but of course no match is ever found. And since cross joining an empty set to any other set results in an empty set, the query processor has no need to scan any but the first set of rows it encounters. So at run time 1024 rows are touched, and that's that.

    Here's the catch (and it's a good one, for us): Since the query optimizer doesn't know that our predicate will never return true, it also doesn't know how many rows will actually be touched. And it's forced to assume the worst, that the full cross product will be processed. Therefore, this function delivers a rather large cost estimate of just under 1,000,000. (Serial cost; parallel will be less, due to the aforementioned math.) This number, as a cost goal, is somewhat arbitrary. I originally came up with a function that delivered a cost in the billions, but it added a lot of complexity to the query plans I was working with. So I scaled it back a bit. 1,000,000 should be fine in just about every case. The example above is fairly typical; I usually see these cost problems crop up with very small relative differentials between the serial and parallel plan cost. The really important thing is that 100% of the estimated cost from this function is CPU time. That means that we can take full advantage of the way the optimizer works.

    Of course, almost none of the cost is real. This UDF will add a couple of dozen milliseconds to your plan. It will also add around 100ms to the compile time. In my opinion, that doesn’t matter. If you’re playing in the big parallel workload arena you’re not doing thousands of batch requests a second. You’re trying to get your two hour query down to a reasonable amount of time. No one is going to care about a dozen milliseconds.

    This function is also engineered so that the output number of rows is guaranteed to be no greater than one. See that SUM, with no GROUP BY? The query optimizer knows that that can’t return more than one row. And that’s a good thing. It gives us that parallelism edge case I mentioned above. (Nested loop with an input guaranteed to be exactly one row.) Another thing? No rows will ever actually be aggregated in that SUM. Its result will always be NULL. But the query optimizer has no way of knowing that, and it comes up with a plan where the entire backing tree needs to be evaluated. That’s why the HAVING clause is there.

    Using this function is quite simple. You take your query, wrap it in a derived table expression, and CROSS APPLY into it. No correlation required. Let’s pretend that the query we want to force parallel looks something like this:

    FROM TableA AS a
        a.PK = b.PK

    Using the make_parallel function to force this to go parallel is as simple as:

    FROM dbo.make_parallel() AS mp
        FROM TableA AS a
        INNER JOIN TableB AS b ON
            a.PK = b.PK
    ) AS x

    The reason we CROSS APPLY from the function into the query is to keep the high cost on the outer side of any parallel nested loops. This way, the query optimizer’s parallelism math will work it’s magic the right way, yielding the parallel plan we’re after. CROSS APPLY in this case—uncorrelated—can only be optimized as a nested loop itself, and that loop only makes sense if there is at least one row feeding it. Therefore, this query is logically forced to process the TVF first, followed by the inside of table expression [x].

    Note that just as with trace flag 8649, there are a number of parallel inhibitors that are still going to keep this from working. And note that unlike when using the trace flag, the base cost of just under 1,000,000 means that even if you have predicates in certain cases that make a parallel plan less than ideal, you’re still going to get a parallel plan. Using this function is effectively applying a big huge hammer to a problematic nail. Use it with caution, make sure it’s appropriate, and don't bash your thumb.

    So what does a query plan look like, once this has been applied? Here’s the same query from the screen shots above, with the function in play:


    Hopefully (without squinting too much) you can see the key attributes: There is a new subtree on top of the original query. That’s thanks to the TVF. This subtree is evaluated, and feeds the top Distribute Streams iterator, which then feeds the Nested Loops iterator. Since the input to that Distribute Streams is guaranteed to be one row, it uses Broadcast partitioning. But there is no correlation here, so there is really nothing to broadcast; the net effect of this action is to prepare a set of threads to do the work of processing your query in parallel.

    Under the Nested Loops? The same exact plan shape that was produced when I used the trace flag. Same estimates, same iterators, and so on and so forth. The UDF necessarily impacts the plan as a whole, but it works as intended and does not impact any of the parts of the plan we actually care about -- the parts we need to make faster in order to get data to our end users.

    I’m really excited about this technique. It means that I can play fewer games, worry less about privileges and the potentially negative impact of using undocumented hints, and concentrate more on the data I need the query to return than the physical manner in which it’s being processed.

    Bear in mind that there are myriad other problems with SQL Server’s parallel processing capabilities. This technique merely solves one of them, and in all honesty it’s neither the cleanest nor best solution that I can imagine. It’s a start. My hope is that these issues will eventually be addressed by the query optimizer and query processor teams. In the meantime, we as end-users have no choice but to continue to push the product in an effort to get the best possible performance, today, for the queries that we need to run today. Tomorrow, perhaps, will hold a better story.

    Disclaimer: This technique works for me. It may not work for you. It may cause some problem that I haven't yet considered. It may cause your server to literally explode, sending fragments of plastic and metal all over your data center. The function and technique are provided as-is, with no guarantees or warranties, and I take no responsibility for what you do with them. That said, if you DO try this out I'd love to hear about your experience, in the comments section below!


    Special thanks to Gokhan Varol for helping me test this technique.

  • This November, Join Me in Stockholm and Amsterdam

    Late last year, I was invited by Raoul Illyés, a SQL Server MVP from Denmark, to present a precon at the 2013 edition of SQLRally Nordic. I agreed and decided to skip the US PASS Summit this year and instead visit an area of Europe I've never seen before. A bonus came a while later when I learned that there is another SQLRally in Europe that same week: SQLRally Amsterdam. Things worked out in just the right way and today I'm happy to announce that I'll be speaking at both events, back-to-back. Should be quite a week!

    SQLRally Nordic will take place in Stockholm, Sweden, November 4-6.

    SQLRally Amsterdam will be in Amsterdam, naturally. November 6-8.

    Yes, there is a one-day overlap between these two events, and I'll have to leave Sweden a day early to deliver my seminar in Amsterdam. First world problems.

    At both events I'll be delivering my popular No More Guessing! seminar, which teaches a solid and proven performance troubleshooting methodology. I'll be adding some new content and refining some things; watch this space in the coming weeks and months for an updated outline and some information on the newer material.

    Both events are now open for early registration, and both events have an open call for speakers. If you're in Europe, or would like to visit, I highly recommend taking advantage of one or both of these options!

    Look forward to meeting many of you at these events. See you in November!

  • TechEd 2013: Demos for "Data, Faster: Microsoft SQL Server Performance Techniques with SQLCLR"

    Today at TechEd in New Orleans I delivered a breakout session entitled "Data, Faster: Microsoft SQL Server Performance Techniques with SQLCLR."

    This session covered a number of techniques for using SQLCLR as a query tuning tool, especially for big, ugly, and heavily analytical queries.

    Thank you so much for all who attended and took the time to evaluate the session. For those of you who weren't there, the video will (apparently) be posted soon on the link above.

    The full set of demo material is attached to this post. Leave a comment if you have any questions for me.

    Enjoy, and may your queries be ultra-speedy!

  • SQL Saturday #220 (Atlanta): Demos

    Today at SQL Saturday #220 in Atlanta I presented a new brand new session, "SQL Server Query Plan Analysis: The 5 Culprits That Cause 95% of Your Performance Headaches."

    This session is designed to help people quickly analyze query plans and find likely culprits without being query tuning experts; I find that in a huge number of cases the root cause of problems is one of just a few potential situations.

    Thanks to everyone who joined me today for the deliveries! In addition to it being a new session this was also the first time that I've ever been asked to present the same session twice in a single day. So it was quite an experience.

    The demo script is attached. As always, let me know if you have any questions or comments.


  • INSERT SELECT is Broken. Ask Microsoft to Fix It.

    Imagine that you're moving thousands or millions of rows between two tables. Maybe it's between a staging table and a data warehouse in an ETL process. Maybe you're manipulating some data via a temp table as you're preparing lookup data for your OLTP system. Maybe you're preparing data for an end user.

    It doesn't really matter what your use case, because there are so many of them. We, as database developers, spend all day moving data back and forth.

    Unfortunately, sometimes our processes break. It's just a fact of life. Sometimes a bad row will sneak in and will violate a constraint, or won't be implicitly convertable to the target data type, or whatever. It happens all the time, and when it does debugging the problem is excruciatingly painful and overly time-consuming.

    The error messages aren't great, it's often difficult to identify the problem row, and so we wind up manually editing out parts of code and slogging through row after row hoping to find the issue.

    When this happens, the entire INSERT, or UPDATE, or whatever breaks. Even if we would have really liked all of the rows except the single bad row to get through.

    Wouldn't it be nice if there were a better way to tackle this problem?

    Someone named Dan Holmes thought up the perfect solution, and posted a Connect item

    Microsoft, in its infinite wisdom, has responded that this scenario is "not common enough," and has stated that it will be closing the issue. Let's not let that happen.

    If you agree that this is a major concern and that this feature would help you, please click on the link above and vote. Leave a comment, too.

    Thank you.


    Note: This doesn't just apply to INSERT SELECT, but I wanted to get your attention. And if you're reading this, it worked!

  • SQLCLR Performance Session at TechEd US

    I am super-excited to visit New Orleans next month for Microsoft TechEd; it will be my sixth time speaking at the show.

    My session takes an in-depth look at some of the techniques I've developed for using SQLCLR modules -- and some of the great performance gains I've been able to achieve.

    Hope to see you in NOLA! If you're not attending the show, the video will be available on demand a few days after I give the talk.

  • More Fun in Atlanta: Parallelism at SQL Saturday 220

    May 18, SQL Saturday returns yet again to the Atlanta area. At this point I've become a bit of a regular at Atlanta's events; this will be my third one in a row. The team that puts them together is amazing, and produces top quality, super fun and educational days every time. Plus: Taco Mac.

    Friday, May 17, the event is running a few pre-conference seminars, and I'll be delivering one focused on parallelism in SQL Server. This is an updated version of the seminar I delivered at the 2010 PASS conference; you can read Kendra Little's review of that day on her personal blog,

    To get full information on the Atlanta seminar, visit the EventBrite page for the event:

    Any questions? Let me know in the comment section.

    Hope to see you there!

  • Capturing Attention: Writing Great Session Descriptions

    keynote2One of the best ways we can differentiate ourselves and further our careers is to get out of the office… and onto a stage. Presenting can give you name recognition; open doors to new opportunities; help you gain a deeper understanding of technology (teaching a topic often forces you to learn it at a much deeper level); and for many people it's simply a fun and satisfying pastime. Each year there are dozens of speaking opportunities available to you: brown bag talks at your workplace, local user groups, online (virtual) user groups, community events, and conferences, just to name a few.

    Virtually every speaking engagement, no matter how large or small, has something in common: attendees want to know, in advance, what is you're going to be talking about. They want to know whether they should spend their valuable time watching you, watching some other presenter, or perhaps staying at home and catching up on some sleep. And attendees will make this decision based upon an all-important document, the session description.

    I've been speaking publicly and running events for just shy of 10 years now, and in that time I've read thousands of session descriptions. Some were decent, some good or even excellent, and most were very, very bad. I've also seen a lot of potential speakers--many of whom had extremely interesting topics and content--get rejected by events because they made basic mistakes in their session descriptions.

    Writing a great session description is hard work. There's no way around it. But it's work that you need to do if you want to become an accomplished public speaker, especially at competitive events like large conferences. I like to think that I've done pretty well in this area, so in the interest of reading much better descriptions at upcoming shows, I'd like to share what I've learned over time: what matters, and what doesn't, when it comes to describing your sessions.



    To begin with, what is a session description? I struggled with this one a bit; I wanted to talk about abstracts, titles, and levels all in one go. I decided to group them together under the umbrella name "session description." For the rest of this post, when I refer to that term I'm talking about all three parts. When I want to talk about only one of the components, I'll refer to it separately. Let's do that now.

    An abstract is a paragraph that is supposed to describe what you're going to talk about in your session.

    A title is a small number of words that are supposed to describe what you're going to talk about in your session.

    A level is a number that's supposed to help guide who should (and should not) attend your session.

    Another definition is also in order, and that's for the word great, which I've used in the title of this post. Greatness is, naturally, highly subjective. So for the purposes of this post I'll define a great session description as one that, for the correct people, captures their attention, whets their appetite, and makes them actually want to see you talk. That's kind of the point of the whole thing, right?


    enrapturedYour Audience and The Real Goal

    Before you begin working on your session description, it is important to realize what it's going to be used for. Your session description is for attendees. It's for the event organizers. And it's also for you. It has three purposes in life! These are not necessarily conflicting purposes, but you should weigh each of them carefully before writing.

    Attendees will use your session description to decide whether they want to attend your session.

    The organizers will use your session description to decide whether to give you a speaking slot.

    And you can use your session description to set expectations and keep yourself constrained.

    Your session description is, first and foremost, a piece of marketing collateral. You are selling a product: your session. You must first sell it to the organizers. Then you must sell it to attendees. Then you must deliver what you sold. If your text underwhelms you will fail to get the chance to deliver or fail to attract an audience. And if you oversell you will end up creating promises that you can't keep or risk attracting an audience that may not appreciate your work.

    Sales is all about understanding the needs of the people you're selling to, and solving their problem. To sell to the organizers, try to understand the mission of the event and fill appropriate gaps. To sell to attendees, try to understand the audience you're targeting, and write a session description that will help them. These two things are not at all independent of one another. Submit sessions to events that appeal to the attendees you hope to speak to; there is no real benefit in attempting to get yourself booked for inappropriate venues.


    You Are Not Your Audience

    Remember this always: most normal people attend technology events on the premise that doing so will make their lives easier by helping them learn to do their jobs better. Most people who work for a living do not care about technology for the sake of technology. They want to solve problems at work so that they can collect a nice paycheck and enjoy life outside of work. Most people are not at the event because they're ubergeeks. Most speakers are ubergeeks and forget this. If you're reading this you are probably not normal.

    What does this mean for your session? As a presenter, you're much more likely to have a successful run of things if you target the majority of the potential audience, rather than a small niche group. This means helping all of the "normal" people. Don't get me wrong; these may be very technical people who are advanced technology users. But you won't attract them with pure geekery. They don't want to check out your cool technology, no matter how cool it is, just because it's cool. You need to appeal to their sense of purpose.


    Tell a Story

    How do you appeal to your target audience? Easy:

    • Figure out who they are
    • Figure out what problems they need to solve
    • Help them understand that you know who they are
    • Help them understand that you appreciate their problems
    • Help them understand that you can help them solve their problemsdragon

    In other words, relate to your audience, and let your audience know that you relate to them. People like hearing from other people who share similar backgrounds and experiences. And people like hearing stories. Humans have been listening to stories for tens of thousands of years. It's how we're wired. Weave a compelling story and people will want to come and listen to it.

    A great session description is a small story. It's a prelude to the larger story that you'll tell later in your presentation. It's the dust jacket on a great book, or the trailer for a new movie. Each of the three component parts should work together to draw the audience in, get them interested enough to want to keep going, and leave them wondering how the main character is going to escape the fire breathing dragon. A truly great session description will leave each member of your target audience with the understanding that he is the main character, and the fire breathing dragon is the problem he faces at work each week. Accomplish that and audiences won't be able to stay away from your presentation.

    A common question asked by new speakers is "what should I speak about?" (Alternately phrased, "what should I write a session description about?") The answer, truth be told, is that it really doesn't matter. Or at least it shouldn't matter. Choose topics that you know well, are passionate about, solve a problem for you, and, most of all, about which you can tell your story. Chances are excellent that other people out there feel the same way (or your great session description will compel them to feel the same way), and you'll have no trouble finding an audience.


    Your Session Description and the Relative Importance of its Component Parts

    Earlier I introduced the three component parts: The title, the abstract, and the level.

    In theory each of the component parts would be digested together by your audience (attendees, organizers, and/or you) and considered as a single piece of work. In reality that's not what happens. Each of the component parts has its own relative merit, depending on what stage of the game your session description is at.

    Here's how things usually work:

    You, if you're like most speakers I know, will spend some time writing the abstract, then throw in the title, and will hastily tack on the level as an afterthought.

    The organizers will judge you on the title and level (based on what they need for the event) and if sufficiently interested will take some time to read the abstract. Let's assume that 80% of the abstracts get read at this stage.

    The attendees? Depending on the event, many of them will never see your abstract at all, and may not see the level. If you're the only presenter at a user group one evening, most of the attendees will probably at least have the chance to read your abstract. But, you know, TL;DR. People can't be bothered to read a big paragraph full of, like, words.

    The bigger the event, the worse it gets. The majority of attendees decide where to go based on the little printout or booklet they receive when they show up. These usually contain a schedule in a grid format, with only room enough for session titles. Usually levels don't make it to that schedule, and some events don't even include the speakers' names. That means that the entire decision is based on those few words in your title. I would estimate, based on interactions I've had, that only 25% of attendees ever bother reading abstracts.

    The title is the only thing read by everyone, guaranteed. It is, therefore, the most important piece of your session description. The abstract is the next most important, and the level the least important. That said, you should determine the level first. Why? Because the level drives the language used throughout the rest of the description.


    Levels of Confusion

    Session levels are, on the best of days: stressful, vexing, misinterpreted, mostly worthless, improperly used, and entirely subjective. Most attendees don't understand what they mean, most speakers don't understand what they mean, and most event organizers don't leverage them very well. The central problem is that a topic that's really difficult for me ("level 500") may be dead simple for you ("level 100"). So what's the point?

    Session levels don't have to be completely useless. They can help you figure out who your audience is supposed to be, and help you properly target these people by using appropriate language.

    confusedMost events--at least in the Microsoft space--use five levels. 100 is supposed to be for the most basic stuff, and 500 for the most advanced stuff (some events, like Microsoft's TechEd show, max out at level 400). Personally, I compress things down and try to focus on three basic levels:

    Level 1: Material for people who don't know much about what I'm talking about (a.k.a. level 200 or so)
    Level 2: Material for people who've used what I'm talking about but aren't experts (a.k.a. level 300 or so)
    Level 3: Material for people who want in-depth details on what I'm talking about (a.k.a. level 500 or so)

    Each level determines not only the content I'm going to present, but also drives the terminology I'll use in how I describe things.

    Consider a talk on SQL Server AlwaysOn. Both the session description and the presentation itself should be aligned for the audience target.

    At Level 1, the talk would describe the basics, starting with what the terms "high availability" and "disaster recovery" actually mean. Perhaps a brief high-level review of various technologies that solve these problems, and a look at how AlwaysOn tackles some of the key areas. The problem this talk would helping the audience solve is how to make sure that databases and their data are available whenever users need them. The story is a tale about technological advances and how easy it can be to keep the data flowing, even in the face of disaster.

    At Level 2, deeper and more in-depth language would be used. How do "availability groups" work, and what general architectural choices should be made? What are the pros and cons of "synchronous" vs. "asynchronous" commit modes? The problem in this case is understanding the complexity of actually using AlwaysOn. The story is about connecting features and options to real-world use cases.

    At Level 3, focused and specialized language is applied. Both the session description and the talk could reference "listeners," "quorums," "replicas," and so on, without any need for explanation. At this level we're usually targeting fellow ubergeeks, so there may be no real problem we're helping to solve. But--as always--it's very important to tell a story to help engage your audience.

    In each of these cases, the appropriate language should be used in both the title and the abstract as needed. This enables each component part to communicate something about the level to the reader--without the reader ever having to actually read some arbitrary number.


    Designing Your Title

    So you've decided that you want to do a talk on the brand new, supercool, game changing feature that's going to be released next month. We'll pretend that it's called "Hekaton." (Sorry, but it's not really going to be released next month.)

    To recap, the goal of your title is to:

    • Reflect upon the appropriate audience level
    • Draw in the correct audience
    • Create enough excitement to make them want more

    The average session title submitted for SQL Saturday events (based on a quick perusal of the archive) is around 5 to 7 words long, and that's probably not enough. One of the biggest mistakes I see new speakers making is thinking that a short and succinct title is great. So they submit sessions with titles like:

    • "Hekaton in SQL Server v.Next"
    • "Hekaton for OLTP"
    • "Using Hekaton for Faster Transactions"

    The problems abound...

    1. These titles all use a code word, Hekaton, which only certain—and very specific--attendees will actually know. And they're probably not your target audience, because most normal people don't know the term. (Again, "normal" refers to non-ubergeeks, i.e. people who have a life, i.e. the people you probably want to reach.) At the average conference, attendees can sit through maybe five or six talks each day. So committing to a mystery topic? Think about it this way: If you're looking down at your schedule grid and you see one of these sessions, with a term you don't know, and it's up against a session that appears to solve a problem you do have, which option are you going to take?
    2. These titles feel vague and too general. If someone already knows what Hekaton means, chances are good that he won't bother attending these sessions, because he won't be likely to learn anything new. Furthermore, these session titles don't appear to help anyone solve a problem, with the possible exception of the last one. And that one sounds a bit like it's going to be a sales pitch.
    3. These titles are boring. Seriously. I fell asleep while writing them. If your title bores me, chances are good that your talk is going to bore me. And I don't like being bored. No one does.

    So what do we do here?

    First of all, since this is a brand-new feature that still uses a code word, this talk can't possibly be advanced. Even if you've been in a special early adopter program and have in-depth knowledge, there probably won't be an audience for you. So this is going to be a beginner-level talk, and the code word has got to go. Hekaton is an in-memory database solution designed to help speed up transactions. Can you pull a something from that description to explain the feature in just a few words?

    Second, you need to clearly identify the problem you're going to help attendees solve. Which attendees have problems with transactional latency? Probably those with lots and lots of concurrent database users. And it's probably a good idea to help the audience identify itself as it reads your title.

    Third, you need to get these attendees interested enough to either read your abstract or--for the 75% who won't read it--actually show up at your session just on the merits of the title. This means adding a bit of verve: showing some emotion, exposing your excitement, displaying your personality. Something a bit non-technical to indicate that this session isn't going to be nap time.

    Putting it all together, we can come up with some pretty decent titles that do a much better job:

    • "In-Memory Solutions for Massively Concurrent Database Dilemmas"
    • "100,000 Users and Going Strong: In-Memory Transaction Processing Done Right"
    • "From Cessna to F-15: Moving Your Heavy OLTP Workload to Memory and Beyond"

    The code word has been eliminated. The audience can identify itself (those with "massively concurrent" databases, those with lots of users, or those with heavy OLTP workloads; all the same audience, just different ways of addressing them). The titles project a problem and hint at a solution. And each of these titles reads like a human actually put some thought and effort into them. (Well I think so. Nothing like painting a target on my back!)

    The key to all of this? Relate to your prospective attendee. Don't bore them. Help them. And don't be afraid to use a few words to get there.

    As an aside, there's this thing called title case. It's a set of rules for how to capitalize your title, and you should learn it. Failing to properly case your title makes you look like a total amateur.


    Writing Your Abstract

    At this point you've identified your attendee target, established a level, and drawn up one or two potential titles. (Write a few of them if possible; don't constrain yourself!) Now it's time to write the biggest portion of the session description: the paragraph-long abstract.

    First things first. All of the rules already described apply here. Tell a story. Use appropriate language for your audience target. Don't be dull.

    A well written abstract should expand upon, and complete, the narrative that the title started. It's the same message, but you have a lot more room in which to deliver it. When I read an abstract I look for organization, flow, and depth. All things that can help me decide whether the session is worth my time. If your abstract is disorganized, doesn't convey a starting and end point, or isn't at the right level, it's going to translate into the audience thinking the same about your talk.

    The biggest sin when creating an abstract? Failure to even try. I've read countless single-sentence abstracts, especially those submitted to small community events. If you can't spend more than 30 seconds writing your abstract, how can I trust you with 75 minutes of my time?

    Don't do this:

    Attend this talk to learn how to use Integration Services in SQL Server 2012 to help with common ETL tasks.

    Did I mock this up? Kind of. I just grabbed a real SQL Saturday abstract (on a different topic) and changed the words around. So yeah, this is essentially real, and every time I see it I cry a little bit, because no one should have so little enthusiasm about his topic and an expectation that he's going to make any audience care. This abstract probably won't fly at SQL Saturday, and it definitely won't fly at a conference. Just don't do it.storyteller

    So what should you do?

    1. Reflect upon the title. Re-state the problem, but in more words. If possible, refer to the audience. Draw them in.
    2. Describe how what you're going to talk about is going to help address the problem. Give them a hook.
    3. Conclude, re-stating the problem and re-affirming the hypothetical solution. Seal the deal.

    A good abstract should, in my opinion, be at least five or six sentences long. Not too long, mind you--you're not trying to write a book--but long enough to thoroughly set expectations.

    Start by reaffirming that the reader is the correct reader. For a beginner-level SSIS talk similar to the one indicated above, I might begin by describing a familiar scenario:

    You have loads of data sitting in flat files, Access databases, and Excel spreadsheets. How are you going to get it all into one centralized database?

    Now, hopefully, some readers are nodding their heads. They're saying, "you're right, I do have loads of data sitting around in various forms. And I really am having a lot of trouble getting it into the database." Now I've drawn in my target audience. I've reminded them of their problem. And I haven't used any jargon; remember, it's a beginner-level talk.

    Also notice that I am directly addressing the reader ("you"). This is done very much on purpose: I want to reinforce that my talk is for my target audience, and that I'm thinking about and talking to my target audience. I'm not writing this abstract for some random group of people I don't know and don't understand. And it's certainly not for me (or the "royal we"). I'm writing this abstract for a very specific group of people I want to help.

    Next we get into the hook, the section designed to make readers interested in your solution for their problem. The solution, in this case? Integration Services, which, in theory, is a great way to tackle the problem. But why is it great? Tell the reader.

    SQL Server Integration Services (SSIS), first introduced in SQL Server 2005, is a comprehensive tool designed to help ease all of your data loading headaches. In this session you will learn the basics around how SSIS is designed and how to manipulate both the logic and flow of data in your load processes. You will see how simple, yet effective, the SSIS user interface can be, and the ease with which even complex problems can be tackled.

    Now I've answered several questions for the reader:

    • "How am I going to solve my problems?" By using Integration Services.
    • "Well I'm running SQL Server 2008, not 2012. Can I still use it?" Sure you can. It was added to the product way back in 2005.
    • "What are you going to show me?" How to use the Control Flow and Data Flow. Oh wait, I didn't say that in the abstract. That's because it's an abstract for an audience that hasn't used SSIS, and those are jargon terms. Instead I mentioned that you can control logic and flow of data. I didn't even use the term ETL, because I want to target the absolute beginner. Anyone with a basic understanding of databases will understand what I'm getting at. Anyone who is knowledgeable in SSIS is going to read this abstract and immediately know that this talk isn't for them. And that's the goal.
    • "Is it difficult to use?" No, it's "simple, yet effective." I said so right in the abstract!

    In addition to answering these questions, I've kept most of the tone active. Active voice is one of the keys to a great abstract. It tells the reader that there is value to be had here, that this will actually impact his job and his bottom line, and that he shouldn't expect to attend and sit there, mouth agape, drooling and waiting for the bell to ring.

    I could leave the abstract as-is at this point and call it a day. But I like to end on a really positive, upbeat note. I want my reader to walk away excited by the prospect of attending my session. So I seal the deal with a conclusion that restates and ties everything back together.

    There is no reason to allow a data mess to ruin your day; after attending this session you'll have the necessary SSIS knowledge to easily extract data from virtually any source, transform it into whatever shape you need, and quickly load it into the database of your choice.

    If I've done everything right, the target audience member has finished reading and is saying "wow... that's exactly what I want to do."


    What Not To Do in an Abstract

    Over time I've noticed a few things that don't quite work:

    • Bullet points. Bullets are a great way to organize information into small digestible chunks. I've used plenty of them in this post. I'm even using one now to talk about why you shouldn't use bullet points. Oh, the irony. Anyway, the fact is that once you submit your session description for an event, you usually have no control over its formatting. And events botch the formatting all the time. Usually abstracts are compressed down to a single paragraph, so I recommend that you write your abstract as a single paragraph. Bullet points will tend to get rendered into something like this:

    This is my abstract about some cool new technology! I'll be covering such issues as - Using the technology - Installing the technology - Making friends with the technology - Harassing enemies with the technology - Formatting and line breaks using the technology This technology will change your life so attend today!

    • Using your own name in your abstract. Some people like to say things in their abstracts like "In this session Steve will show you why it's great to be a farmer." This works, in very limited cases, but most readers are going to say "Steve? Steve who?" They're going to think you're a deranged egomaniac, and they're not going to want to attend your session. If you've read this far you know that I like to think about the normal people; the ones who aren't plugged in to the community 24x7, because they have something better to do with their time. They probably don't know who you are, even if you include your last name. Sorry.
    • Insulting the reader. Never, ever, ever assume that you're the smartest person in the room, unless you're alone in the room. And be very careful with assumptions about your target audience. Sometimes I'll see abstracts that say something inflammatory, like "if you're a .NET developer creating a data model, you've no doubt screwed up several key aspects." While this may be true in your mind, and might even be true in reality, what you're doing is alienating the reader. A better way to phrase this would be something like "due to various differences between the platforms, .NET developers attempting to create a SQL Server data model may encounter a number of tricky situations." Now the reader can think back, realize that he has hit one or more of these, and become interested in your content. And that's a win.


    speaker_on_stageThe Aftermath

    If you've written your session description with only 15 minutes left before the event closes its submission period, you're pretty much in the same boat as everyone else. Oh, and you're doing it totally wrong.

    The very first thing you should do after you complete your work? Read it yourself. And then read it again. Read it slowly and carefully, word by word. You will find a typo. You will find a grammatical error, or a phrasing problem. If you don't, you're not looking hard enough. And run it through a spell checker. There is nothing that says "careless" more than a glaring error -- and, again, a glaring error in the session description is indicative of lots of glaring errors in the actual talk.

    The next thing you should do is to pass the session description around to some people you trust. Preferably one or two people who are in your target audience, to tell you whether you've created something of interest. Preferably one non-technical person, to screen it for jargon and do a second copy edit. If the non-technical person is just a bit lost, that's okay. If the non-technical person is totally lost, chances are most technical people will be, too. Clean it up.

    If you're writing in English and you're not a native writer, find a native writer and have him proof your work. Neither event organizers nor attendees care about why your abstract is full of grammatical errors. You probably write in English a lot better than I can write in your language, and I have massive respect for you, but you're still out of luck if your work can't be properly understood by English language audiences.

    After that, paste the abstract into the web form, hit Submit, and ... wait.

    Submission for larger events is a painful process. You put your abstract in and sometimes have to endure 90 or more days of wondering before you get your answer. Oftentimes the answer is nothing more than a "yes" or a "no." It's okay to ask for an explanation if you've been rejected, but it's also okay for the event to tell you that they don't have time to provide one. If you're going to start speaking regularly, prep well, build up a nice thick skin, and get ready to endure some rejection. Don't worry. Keep practicing, keep trying, and you'll get there.

    Of course you also have to write the presentation. And as you do so you absolutely must use the session description you wrote. You've set attendee expectations; make sure your actual session will live up to them. Your presentation should cover everything you said you were going to cover and, if your session description was properly worded, not much that you didn't mention. Naturally, writing the session is an entirely different topic for an entirely different blog post.



    A great session description is a short yet compelling story designed for a very specific reader. The reader is the protagonist, his problem is the antagonist, and you are the narrator, helping the reader through his quest for glory. Know your target audience, understand its problems, help solve them, and your session description will be wildly successful. Remember that most readers only look at a very small part of the story, the title, so make sure to spend plenty of time there. And remember to always keep things moving and interesting; there is nothing worse than a boring story.

    I'm sure many of you have opinions that differ from what I've expressed here. I look forward to hearing from you in the comments section below. Likewise, for those of you who have questions I may not have covered above. Finally, I would like to invite readers to post their own abstracts for public criticism. (Constructive!)

    Thank you for reading, and I’ll see you on stage!

  • Itzik Ben-Gan in Atlanta: May 13-17

    This year Data Education is offering a few more classes with Itzik Ben-Gan, the world's foremost T-SQL instructor.

    Our first offering has just been announced: Atlanta, May 13-17.

    Neither Itzik nor his class needs much introduction, but click through for a full outline and other details.

    We think that Atlanta is a great city, with an amazingly vibrant SQL Server community. Hope you'll be able to join us there!


    By the way: if you're joining the class stick around town for a SQL Saturday event that is taking place, coincidentally, on May 18.

  • [New England] SQL Saturday #203: April 5-6, Cambridge MA

    SQL Saturday returns to the Boston area this April, with what is certain to be an exceptional speaker and session lineup. (The actual schedule will be posted soon, but in the meantime you can see the submitted sessions.)

    The free event ($10 if you'd like to eat lunch) will take place on Saturday, April 6. Highly recommended for anyone in the area who is interested in bettering your database skills!

    Friday, April 5, as a lead in to the Saturday event, I'll be delivering my popular full-day "No More Guessing!" seminar. This seminar teaches a solid, proven performance troubleshooting methodology designed to help you quickly find the actual root cause of performance problems. Full information is available on the registration site.

    This seminar has sold out at events like PASS Summit and SQLBits, and it is being offered in Boston at the discounted price, so book early to avoid disappointment.

    Huge thanks to Mike Hillwig for taking the lead on putting together this event. Looking forward to seeing many of you there!

  • [New England] Mark Souza on Big Data and Cloud at NESQL

    This Thursday, January 17, at New England SQL Server we'll be featuring Mark Souza, General Manager of the Data Platform Group at Microsoft. Most of you are probably familiar with that name; he's the guy who founded the CAT team, and he's been in a number of key roles in the SQL Server organization for the past several years.

    Mark's topic for Thursday is Big Data and Cloud at Microsoft. The talk should be an interesting look into how the company is approaching these key areas.

    If you're in New England and aren't already a member of New England SQL Server, you can sign up here. RSVP is required to attend our meetings, and we will send out the invitation e-mail on Tuesday morning.

    Hope to see many of you there!

This Blog


Privacy Statement