<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="http://www.simple-talk.com/community/rss.xsl" media="screen"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:wfw="http://wellformedweb.org/CommentAPI/"><channel><title>Simple-Talk</title><link>http://www.simple-talk.com/community/blogs/default.aspx</link><description>.NET, Exchange, SQL Server and Chop Suey</description><dc:language>en-US</dc:language><generator>CommunityServer 2.0 (Build: 60217.2664)</generator><item><title>Getting the URL to the Content Type Hub Programmatically in SharePoint 2010</title><link>http://www.simple-talk.com/community/blogs/damon_armstrong/archive/2012/02/07/105921.aspx</link><pubDate>Tue, 07 Feb 2012 17:23:38 GMT</pubDate><guid isPermaLink="false">f46e5dea-70cd-4a69-a7e1-fd07a313bd4d:105921</guid><dc:creator>Damon</dc:creator><slash:comments>0</slash:comments><description>&lt;p&gt;Many organizations use the content-type hub to manage content-types in their SharePoint 2010 environment.&amp;#160; As a developer in these types of organizations, you may one day find yourself in need of getting the URL of the content type hub programmatically.&amp;#160; Here is a quick snippet that demonstrates how to do it fairly painlessly:&lt;/p&gt;  &lt;p&gt;&lt;code&gt;public static Uri GetContentTypeHubUri(SPSite site)      &lt;br /&gt;{       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; TaxonomySession session = new TaxonomySession(site);       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; return Session.&lt;/code&gt;&lt;code&gt;DefaultSiteCollectionTermStore     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;/code&gt;&lt;code&gt;.ContentTypePublishingHub;     &lt;br /&gt;}&lt;/code&gt;&lt;/p&gt;&lt;img src="http://www.simple-talk.com/community/aggbug.aspx?PostID=105921" width="1" height="1"&gt;</description><category domain="http://www.simple-talk.com/community/blogs/damon_armstrong/archive/category/1009.aspx">.NET Development</category><category domain="http://www.simple-talk.com/community/blogs/damon_armstrong/archive/category/1016.aspx">SharePoint</category></item><item><title>Red Gate and the Community</title><link>http://www.simple-talk.com/community/blogs/redandthecommunity/archive/2012/02/07/105914.aspx</link><pubDate>Tue, 07 Feb 2012 02:14:00 GMT</pubDate><guid isPermaLink="false">f46e5dea-70cd-4a69-a7e1-fd07a313bd4d:105914</guid><dc:creator>RedAndTheCommunity</dc:creator><slash:comments>1</slash:comments><description>&lt;p&gt;I was lucky enough to join the Communities team in April 2011, having worked in the equally awesome (but more number-crunchy), Finance team at Red Gate for about four years before that.&lt;/p&gt;  &lt;p&gt;Being totally passionate about Red Gate, and easily excitable, it seems like the perfect place to be. Not only do I get to talk to people who love Red Gate every day, I get to think up new ways to make them love us even more. &lt;/p&gt;  &lt;p&gt;Red Gate sponsored 178 SQL Server and .NET events and user group meetings in 2011. They ranged from SQL Saturdays and Code Camps to 10 person user group meetings, from California to Krakow. &lt;/p&gt;  &lt;p&gt;We've given away cash, software, Kindles, and of course swag. The Marketing Cupboard is like a wonderland of Red Gate goodies; it is guarded day and night to make sure the greedy Red Gaters don't pilfer the treasure inside. There are Red Gate yo-yos, books, pens, ice scrapers and, over the Holidays, there were some special bears. We had to double the patrols guarding the cupboard to protect them. You can see why:&lt;/p&gt;  &lt;p&gt;&lt;a href="/blogbits/Bear.jpg"&gt;&lt;img src="/blogbits/Bear.jpg"&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;Over the Holidays, we gave funding and special Holiday swag (including the adorable bears), to 10 lucky user groups, who held Christmas parties - doing everything from theatre trips to going to shooting ranges. &lt;/p&gt;  &lt;p&gt;&lt;b&gt;What next?&lt;/b&gt;&lt;/p&gt;  &lt;p&gt;So, what about this year? In 2012 our main aim is to be out there meeting more of you. So get ready to see an army of geeks in red t-shirts at your next event! &lt;/p&gt;  &lt;p&gt;We also want to do more fun things like our Christmas party giveaway.&lt;/p&gt;  &lt;p&gt;&lt;em&gt;&lt;b&gt;What cool ideas do you have for sponsorship in 2012? An Easter Egg hunt with SQL server clues? A coding competition? A duelling contest with a license of SQL Toolbelt for the winner?&lt;/b&gt;&lt;/em&gt;&lt;strong&gt; Let me know. &lt;/strong&gt;&lt;/p&gt;&lt;img src="http://www.simple-talk.com/community/aggbug.aspx?PostID=105914" width="1" height="1"&gt;</description></item><item><title>From nowhere to somewhere in no time at all.</title><link>http://www.simple-talk.com/community/blogs/jonathanallen/archive/2012/02/07/105879.aspx</link><pubDate>Tue, 07 Feb 2012 02:00:00 GMT</pubDate><guid isPermaLink="false">f46e5dea-70cd-4a69-a7e1-fd07a313bd4d:105879</guid><dc:creator>fatherjack</dc:creator><slash:comments>1</slash:comments><description>I am pleased to introduce another guest post from my wife, Annette (@mrs_fatherjack) (this also partially explains the cat picture).  2 years ago I'd never heard of SQL Bits, I wasn't into 'the community' in any way and just plodded along doing what I did, probably not very well.  I was employed as a SQL Developer but in reality for the past few years my role had been primarily management with very little development.  I went to SQL Bits 6 (London) with my husband, Jonathan (@Fatherjack), not really...(&lt;a href="http://www.simple-talk.com/community/blogs/jonathanallen/archive/2012/02/07/105879.aspx"&gt;read more&lt;/a&gt;)&lt;img src="http://www.simple-talk.com/community/aggbug.aspx?PostID=105879" width="1" height="1"&gt;</description><category domain="http://www.simple-talk.com/community/blogs/jonathanallen/archive/category/1041.aspx">Blogging</category><category domain="http://www.simple-talk.com/community/blogs/jonathanallen/archive/category/1049.aspx">SQLBits</category><category domain="http://www.simple-talk.com/community/blogs/jonathanallen/archive/category/1050.aspx">Conferences</category><category domain="http://www.simple-talk.com/community/blogs/jonathanallen/archive/category/1074.aspx">Mrs_FatherJack</category><category domain="http://www.simple-talk.com/community/blogs/jonathanallen/archive/category/1076.aspx">community</category></item><item><title>To Not CI to Eye</title><link>http://www.simple-talk.com/community/blogs/tony_davis/archive/2012/02/03/105828.aspx</link><pubDate>Fri, 03 Feb 2012 11:21:57 GMT</pubDate><guid isPermaLink="false">f46e5dea-70cd-4a69-a7e1-fd07a313bd4d:105828</guid><dc:creator>Tony Davis</dc:creator><slash:comments>6</slash:comments><description>&lt;p&gt;Many developers, including &lt;a href="http://www.simple-talk.com/author/troy-hunt/"&gt;Troy Hunt&lt;/a&gt;, here on Simple-Talk, &lt;a href="http://www.simple-talk.com/sql/sql-tools/the-unnecessary-evil-of-the-shared-development-database/"&gt;have argued persuasively&lt;/a&gt; that each database developer in a team needs to work as sole user of a dedicated database-development environment whilst creating or updating databases. Troy makes a good case, listing several shortcomings of the shared development model: developers are no longer free to experiment and pursue &lt;i&gt;evolutionary design&lt;/i&gt; of the database layer, in the same way as any other component of the application, without unduly interfering with the other developers; without the required discipline of checking in changes for continuous integration, source control for the database is hard to enforce; it's very hard to run reliable tests with data dependencies when everyone is free to change the data structures and data.&lt;/p&gt;  &lt;p&gt;And yet our surveys suggest that around 80% of database development still takes place in a shared environment, and for valid practical reasons. It isn't just about the data, though for enterprise databases, holding perhaps terabytes of data, and with that test data generated by complex ETL processes, it is no trivial task to replicate this environment in each developer's sandbox database. &lt;/p&gt;  &lt;p&gt;Troy's model seemed to assume that developers within the shared model couldn't also access their own sandbox servers, and also that they had no source control. Source Control certainly can be done in the shared model, but just requires more supervision when changes appear that weren't in source control. Many of the consequences he described were due more to this lack of source control, rather than working together on a development server.&lt;/p&gt;  &lt;p&gt;Perhaps the strongest argument for the dedicated model, however, is the need to maintain a constant, stable base against which to develop, in which the DDL code in Source Control is used for Continuous Integration. However, does this CI argument really apply equally to the database as to the application? For any enterprise database of reasonable complexity, the up-front design effort should mitigate the need for continuous evolution of the database design, during development. Also, with many database changes being immediately validated, the value to be gained from dedicated development plus CI, to find out if you broke anything, is surely lessened?&lt;/p&gt;  &lt;p&gt;Could it be that many of the difficulties of integration and deployment that have been so thoroughly documented are more due to poorly thought-out application-interfaces within the database? Integration problems that are due to version differences are far more likely where this has been omitted from the design, and applications have unrestricted access through the database. Are we in danger of trying to change database development practices to try to cure a problem that is far easier to solve by proper system design?&lt;/p&gt;  &lt;p&gt;I'm sure many will disagree; as always I'd love to hear about it.&lt;/p&gt;  &lt;p&gt;Cheers,   &lt;br /&gt;Tony.&lt;/p&gt;&lt;img src="http://www.simple-talk.com/community/aggbug.aspx?PostID=105828" width="1" height="1"&gt;</description></item><item><title>Red Gate does Burns Night 2012</title><link>http://www.simple-talk.com/community/blogs/redwork/archive/2012/02/02/105797.aspx</link><pubDate>Thu, 02 Feb 2012 04:00:00 GMT</pubDate><guid isPermaLink="false">f46e5dea-70cd-4a69-a7e1-fd07a313bd4d:105797</guid><dc:creator>red@work</dc:creator><slash:comments>1</slash:comments><description>&lt;p&gt;Whilst we have our fair share, as a company, of native Scots, somehow none of them managed to attend Red Gate's recent Burns Night celebration. Troublingly, this didn't seem to trouble us. &lt;/p&gt;  &lt;p&gt;A Burns Supper should not, in theory, be hard to organise. We asked our head chef, Big Steve, if he'd put on a bit of haggis and whisky for us. Danielle, a Red Gater with shady connections in such circles, managed to persuade the Cambridge University Ceilidh Band to provide us with a little post-supper dancing. Our very own Brian Harris, Bard of Ayrshire, Scotland's fairest flower (for the evening), would address the haggis. Everything was going swimmingly.&lt;/p&gt;  &lt;p&gt;&lt;a href="/blogbits/redatwork/Red-Gate-does-Burns-Night-2012_988A/christhechef.jpg"&gt;&lt;img title="SONY DSC" border="0" alt="SONY DSC" src="/blogbits/redatwork/Red-Gate-does-Burns-Night-2012_988A/christhechef_thumb.jpg" width="504" height="429" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p align="center"&gt;&lt;strong&gt;Big Steve, Red Gate's resident chef, menaces a haggis.&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;The first hints of disaster became apparent just after lunch on the day itself, when Brian emailed me a full itinerary which laid out all the traditional constituent parts of a well-planned Burns Night supper. All we had was whisky, haggis and an imitation of a Scottish accent which bordered on racism. &lt;/p&gt;  &lt;p&gt;After several hours of frantic scrabbling, the thing began to come together. Big Steve was in calm control of the culinary proceedings, and had sourced us not only a plethora of haggi, but also a litre and a half of Tesco Special Reserve whisky (aged three years), three vegan haggises for those with more delicate constitutions, and a hearty selection of oatcakes. Oatcakes!&lt;/p&gt;  &lt;p&gt;&lt;a href="/blogbits/redatwork/Red-Gate-does-Burns-Night-2012_988A/haggisoatcakesgravy.jpg"&gt;&lt;img title="SONY DSC" border="0" alt="SONY DSC" src="/blogbits/redatwork/Red-Gate-does-Burns-Night-2012_988A/haggisoatcakesgravy_thumb.jpg" width="504" height="339" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p align="center"&gt;&lt;strong&gt;Haggis, oatcakes, whisky gravy. Not bad for a Tuesday at work.&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;We had no piper to pipe in the haggis, so we made a 21&lt;sup&gt;st&lt;/sup&gt; Century improvisation: an MP3 of bagpipe music hooked up to the Red Gate PA system. This had the excellent (but unintended) side effect of annoying Charles Brown, head of the .NET division, who has an apparent horror of bagpipe music. A hand he will come to regret having revealed to me in time, I guarantee. &lt;/p&gt;  &lt;p&gt;What we lacked in authentic Scottish people we made up for in numbers and enthusiasm. Our very own Rabbie Chipperfield, sometime developer, gave the Selkirk Grace. Brian Harris addressed the haggis in his best Scotch burr, a performance which was met with particular puzzlement from some of our European guests. &lt;/p&gt;  &lt;p&gt;With the Tesco Special Reserve whisky safely stowed within, I gave a brief speech to the immortal memory of Burns himself. The lads then toasted the lasses, and the lasses toasted the lads, and we got down to the serious and important business of haggis consumption. The vegan haggis proved overwhelmingly popular, and there was such a glut of the normal stuff that the good people of Red Gate were treated to both chicken stuffed with haggis and "just haggis, suitable for salad" at lunch the following day.&lt;/p&gt;  &lt;p&gt;After the ceremony, those brave souls who had survived the aural and digestive onslaughts of the supper were rewarded with an evening of ceilidh dancing. Och, aye.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Post by Lucy Boyes. Photos by James Billings.&lt;/strong&gt;&lt;/p&gt;&lt;img src="http://www.simple-talk.com/community/aggbug.aspx?PostID=105797" width="1" height="1"&gt;</description></item><item><title>ASP.NET performance: is it all about the database?</title><link>http://www.simple-talk.com/community/blogs/missdotnet/archive/2012/01/25/105667.aspx</link><pubDate>Wed, 25 Jan 2012 07:09:00 GMT</pubDate><guid isPermaLink="false">f46e5dea-70cd-4a69-a7e1-fd07a313bd4d:105667</guid><dc:creator>Michaela Murray</dc:creator><slash:comments>4</slash:comments><description>&lt;p&gt;Developing ASP.NET applications with a data layer, you may be well aware of the pain that performance issues can cause. Perhaps your apps response times drag, connections lag, and the overwhelming user experience is of watching the "page loading" graphic spin endlessly round and round. Sure, your application may be performing poorly. But you don't need a performance profiling tool to fix that, right? What you really need is a better DBA.&lt;/p&gt;
&lt;p&gt;Here's why you might be wrong.&lt;/p&gt;
&lt;h3&gt;Think your ASP.NET applications performance problems all lie in the database? Prove it!&lt;/h3&gt;
&lt;p&gt;Yes, database issues underlie a lot of ASP.NET performance problems. Time spent retrieving data can dwarf the time your application spends executing your code. But that doesn't mean the problem is out of your hands. To begin with, just assuming the problem lies in the database is a quick route to a smug DBA if it later turns out you’re wrong. Far better to know for sure how much of your applications time is spent waiting around for the database to do something, and how many round-trips to and from the database it makes.&lt;/p&gt;
&lt;p&gt;So, how do you know for sure what your application is telling the database to do? If you have a really simple application, and wrote it all yourself, you may genuinely just know. But if your application uses enterprise framework or legacy code, has multiple developers, or has just been sitting around without your attention for a while, reviewing the static source code or stepping through line by line might take too long and fail to show up lurking problems. With a performance profiling tool, on the other hand, you can see exactly what the application does as it runs, pinpoint the calls it makes to the database, and show you at a glance what proportion of your execution time is spent waiting for the database.&lt;/p&gt;
&lt;p&gt;Visualizing all of your applications database interactions gives you a quick, comprehensive view of how your code interacts with the database. If you see you’re telling the database to do something perverse, or inefficient, you can make big performance savings by simplifying and optimizing. You might find that data caching, enabling paging, or making better use of background processing makes the whole thing run faster and more smoothly. Secondly, if your own code really is unimpeachable, a visualization like this gives you the smoking gun to brandish at your DBA.&lt;/p&gt;
&lt;h3&gt;When It’s Not The Database&lt;/h3&gt;
&lt;p&gt;Sometimes you’ll find yourself with a database problem and no one to blame it on. For example, if your applications a custom frontend onto a commercial database, changing the way that database works might be out of your hands. Then you’ll need to look at interfacing with it more efficiently, or concentrate on improvements to your own codes performance.&lt;/p&gt;
&lt;p&gt;Occasionally, and it takes a brave dev to admit this, you may even find that the problem is actually in your code, not in the database.&lt;/p&gt;
&lt;p&gt;In both cases, profiling first lets you find the true culprit – be it the database or the .NET code – and therefore find the best solution. That might mean tweaking a method call, or it might, indeed, mean marching down to the sysadmin basement with the incontrovertible truth in your hands.&lt;/p&gt;
&lt;h3&gt;Further reading&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a target="_blank" href="http://msdn.microsoft.com/en-us/magazine/cc163854.aspx"&gt;10 Tips for Writing High-Performance Web Applications&lt;/a&gt; (MSDN) – Rob Howard’s thorough set of hints and tips, mostly database-related, for souping up your ASP.NET app’s performance.&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.sitepoint.com/aspnet-performance-tips/" target="_blank"&gt;Speed Up Your Site! 8 ASP.NET Performance Tips&lt;/a&gt; – Jeff Atwood and Jon Galloway on stopping your site from chugging.&lt;/li&gt;&lt;/ul&gt;&lt;img src="http://www.simple-talk.com/community/aggbug.aspx?PostID=105667" width="1" height="1"&gt;</description></item><item><title>Inside the ConcurrentCollections: ConcurrentQueue</title><link>http://www.simple-talk.com/community/blogs/simonc/archive/2012/01/24/105658.aspx</link><pubDate>Tue, 24 Jan 2012 22:03:00 GMT</pubDate><guid isPermaLink="false">f46e5dea-70cd-4a69-a7e1-fd07a313bd4d:105658</guid><dc:creator>Simon Cooper</dc:creator><slash:comments>0</slash:comments><description>&lt;p&gt;&lt;code&gt;ConcurrentQueue&lt;/code&gt; is, like &lt;code&gt;ConcurrentStack&lt;/code&gt;, a lockless collection, in that it is implemented without using any locks at all. However, the semantics required for a queue impose a quite different approach; unlike &lt;code&gt;ConcurrentStack&lt;/code&gt;, which has a single point of concurrent contention, a queue can be changed at both the head and tail. This means that at least two variables are involved, most likely more. The simple approach of atomically modifying a single variable won't work here.&lt;/p&gt;

&lt;h4&gt;What does &lt;code&gt;System.Collections.Generic.Queue&lt;/code&gt; do?&lt;/h4&gt;

&lt;p&gt;Well, let's have a look at the non-concurrent queue. This is implemented as a &lt;a href="http://en.wikipedia.org/wiki/Circular_buffer"&gt;circular buffer&lt;/a&gt;. However, this design is very hard to use in a lockless way; when a new item is enqueued and the backing array is full, the array is doubled in size to accommodate the new item.&lt;/p&gt;

&lt;p&gt;To resize the array, the entire contents of the queue has to be read sequentially without using locks and copied into a brand new array by a single thread, during which other threads can enqueue and dequeue items many times. This is very tricky to implement without being subject to race conditions and still ensure high performance.&lt;/p&gt;

&lt;p&gt;So, instead, ConcurrentQueue forgoes the circular buffer, and uses a linear array instead. More specifically, it needs to be a linear array with a (conceptually) infinite capacity - although there will only be a finite number of items stored in the queue, items can be enqueued and dequeued an unlimited number of times. Such an array can't be created as a single object.&lt;/p&gt;

&lt;p&gt;However, you don't need to keep the entire infinite array in memory, you only need the section of the array that is actually storing items. By splitting the array into finite segments you can create and discard segments as items get enqueued and dequeued to the queue. This is what &lt;code&gt;ConcurrentQueue&lt;/code&gt; does.&lt;/p&gt;

&lt;h4&gt;Queue Segments&lt;/h4&gt;

&lt;p&gt;To demonstrate, I'll be using a queue with a segment size of 4. To start off with, three items are enqueued. These are added to the leftmost available slot of the tail segment:&lt;/p&gt;

&lt;img src="/blogbits/simon.cooper/ConcurrentQueue1.png"&gt;

&lt;p&gt;Three more items are then enqueued. A new segment is created and assigned to the tail:&lt;/p&gt;

&lt;img src="/blogbits/simon.cooper/ConcurrentQueue2.png"&gt;

&lt;p&gt;And another three:&lt;/p&gt;

&lt;img src="/blogbits/simon.cooper/ConcurrentQueue3.png"&gt;

&lt;p&gt;Five items are then dequeued from the head. The head segment is now empty, so it is discarded:&lt;/p&gt;

&lt;img src="/blogbits/simon.cooper/ConcurrentQueue4.png"&gt;

&lt;p&gt;Using this method, the illusion of an infinite linear array can be created using a finite number of segments.&lt;/p&gt;

&lt;h4&gt;Achieving thread-safety&lt;/h4&gt;

&lt;p&gt;&lt;code&gt;ConcurrentQueue&lt;/code&gt; uses a segment size of 32, and along with the backing array each segment stores the index items are to be added (&lt;code&gt;m_high&lt;/code&gt;) and where they are to be removed (&lt;code&gt;m_low&lt;/code&gt;):

&lt;/p&gt;&lt;pre&gt;private class Segment {
    volatile T[] m_array;
    volatile int m_high;
    volatile int m_low;
}&lt;/pre&gt;

&lt;p&gt;Thread-safety, in this case, depends on the operation of both enqueuing and dequeuing. So we'll look at the operations in isolation, then put them both together.&lt;/p&gt;

&lt;h4&gt;Enqueuing&lt;/h4&gt;

&lt;p&gt;To enqueue an item, you need to:
&lt;/p&gt;&lt;ol&gt;
&lt;li&gt;Increment the &lt;code&gt;m_high&lt;/code&gt; variable. This is now the index the item should be inserted at.&lt;/li&gt;
&lt;li&gt;Assign the item to the specified slot in &lt;code&gt;m_array&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

The key to this is step 1. If step 1 can be done atomically, returning the new incremented value, that gives each thread trying to enqueue an item at the same time separate slots. Step 2 can then be performed concurrently by each thread without having to worry about conflicts. &lt;code&gt;Interlocked.Increment&lt;/code&gt; performs this increment atomically:&lt;p&gt;&lt;/p&gt;

&lt;pre&gt;public void Enqueue(T item) {
    int insertIndex = Interlocked.Increment(ref m_high);
    m_array[insertIndex] = item;
}&lt;/pre&gt;

&lt;p&gt;That's it! Simple, really...&lt;/p&gt;

&lt;h4&gt;Dequeuing&lt;/h4&gt;
&lt;p&gt;Dequeuing acts in a similar way to enqueuing:

&lt;/p&gt;&lt;ol&gt;
&lt;li&gt;Increment the &lt;code&gt;m_low&lt;/code&gt; variable. The previous index is the index of the item to be dequeued.&lt;/li&gt;
&lt;li&gt;Return the item stored at the specified slot in &lt;code&gt;m_array&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

And, similarly, if each thread trying to dequeue an item can be atomically 'assigned' a slot by performing step 1 using &lt;code&gt;Interlocked.Increment&lt;/code&gt;, then step 2 can be performed concurrently by several threads:

&lt;pre&gt;public T Dequeue() {
    // Increment returns the incremented value of the variable
    int index = Interlocked.Increment(ref m_low);
    return m_array[index-1];
}&lt;/pre&gt;

&lt;p&gt;But hang on, if we're dequeuing items, we need to check whether the queue is empty first. So checks need to be added to determine when a queue is empty. This depends on the segment state that represents an empty segment. In the case of &lt;code&gt;ConcurrentQueue&lt;/code&gt;, this state is when &lt;code&gt;m_low &amp;gt; m_high&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The exact reasons for this specific state representing an empty segment are a gory implementation detail; if you're wondering the reasons for this, then start by working out exactly what &lt;code&gt;m_high&lt;/code&gt; and &lt;code&gt;m_low&lt;/code&gt; represent.&lt;/em&gt;&lt;/p&gt;

&lt;pre&gt;public bool TryDequeue(out T item) {
    if (m_low &amp;gt; m_high) {
        item = default(T);
        return false;
    }
    
    int index = Interlocked.Increment(ref m_low);
    item = array[index-1];
    return true;
}&lt;/pre&gt;

&lt;p&gt;All good? Well, no. We've actually introduced a subtle race condition. If we've got a queue with one item in it, and two threads trying to dequeue that one item, then if both threads perform the &lt;code&gt;if (m_low &amp;gt; m_high)&lt;/code&gt; check before &lt;code&gt;m_low&lt;/code&gt; has been incremented, one will dequeue the item and one will successfully dequeue on an empty queue.&lt;/p&gt;

&lt;p&gt;In &lt;code&gt;ConcurrentStack&lt;/code&gt;, a similar race condition was solved by using &lt;code&gt;Interlocked.CompareExchange&lt;/code&gt;; taking a snapshot, doing some work, then atomically making that work visible to other threads only if the state is still valid. By judicious use of local variables and loops, we can do the same thing here:

&lt;/p&gt;&lt;pre&gt;public bool TryDequeue(out T item) {
    int index;
    do {
        index = m_low;
        
        // check if the queue is empty
        if (index &amp;gt; m_high) {
            item = default(T);
            return false;
        }
        
        // I think m_low has the same value as index. If it is, replace it with index+1.
        // Return to me what m_low actually was.
        if (Interlocked.CompareExchange(ref m_low, index+1, index) == index) {
            // success - index is now a valid index to dequeue, specific to this thread
            item = m_array[index]
            return true;
        }
        
        // m_low has been changed in the meantime. Go back to the start and try again.
    }
    while (true);
}&lt;/pre&gt;

&lt;p&gt;In this case, &lt;code&gt;CompareExchange&lt;/code&gt; is acting as a conditional Increment.

&lt;/p&gt;&lt;h4&gt;Combining the two&lt;/h4&gt;

&lt;p&gt;This is where it gets complicated. The most obvious issue is another race condition, between enqueuing and dequeuing. To reiterate, the steps performed are:&lt;/p&gt;

&lt;strong&gt;Enqueuing&lt;/strong&gt;:
&lt;ol&gt;
&lt;li&gt;Increment the &lt;code&gt;m_high&lt;/code&gt; variable. This is now the index the item should be inserted at.&lt;/li&gt;
&lt;li&gt;Assign the item to the specified slot in &lt;code&gt;m_array&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;strong&gt;Dequeuing&lt;/strong&gt;:
&lt;ol&gt;
&lt;li&gt;Check if the queue is empty (&lt;code&gt;m_low &amp;gt; m_high&lt;/code&gt;). If it is, return false.&lt;/li&gt;
&lt;li&gt;Increment &lt;code&gt;m_low&lt;/code&gt; (if &lt;code&gt;m_low&lt;/code&gt; hasn't changed) and return the item.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Start with an empty queue. Thread 1 executes step 1 of enqueuing; &lt;code&gt;m_high&lt;/code&gt; is incremented. Thread 2 then tries to dequeue an item; step 1 of dequeuing thinks the queue has items because &lt;code&gt;m_low &amp;lt;= m_high&lt;/code&gt;. Step 2 of dequeuing then executes, and the item dequeued is the null value, because thread 1 hasn't yet assigned the enqueued item to the backing array.&lt;/p&gt;

&lt;p&gt;Hmm, how to solve this? There's more than one variable involved here; the race condition involves the relationship between &lt;em&gt;two&lt;/em&gt; variables, &lt;code&gt;m_high&lt;/code&gt; and &lt;code&gt;m_low&lt;/code&gt;, not a single variable being changed behind the scenes, which was the problem solved previously using &lt;code&gt;CompareExchange&lt;/code&gt; and loops.&lt;/p&gt;

&lt;p&gt;Well, we can't swap round the order of operations for enqueuing, because step 1 is what atomically assigns a slot when several threads are enqueuing items at once.&lt;/p&gt;

&lt;p&gt;What we need is some sort of notification that enqueuing has finished assigned the item to the backing array. Then the dequeuing thread can wait for that notification before dequeuing the item from the queue:&lt;/p&gt;

&lt;strong&gt;Enqueuing&lt;/strong&gt;
&lt;ol&gt;
&lt;li&gt;Increment the &lt;code&gt;m_high&lt;/code&gt; variable. This is now the index the item should be inserted at.&lt;/li&gt;
&lt;li&gt;Assign the item to the specified slot in &lt;code&gt;m_array&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Set state indicating the item at that index has been enqueued.&lt;/li&gt;
&lt;/ol&gt;

&lt;strong&gt;Dequeuing&lt;/strong&gt;:
&lt;ol&gt;
&lt;li&gt;Check if the queue is empty (&lt;code&gt;m_high &amp;gt;= m_low&lt;/code&gt;). If it is, return false.&lt;/li&gt;
&lt;li&gt;Increment &lt;code&gt;m_low&lt;/code&gt; (if &lt;code&gt;m_low&lt;/code&gt; hasn't changed).&lt;/li&gt;
&lt;li&gt;Wait for the state to be set at the index to dequeue.&lt;/li&gt;
&lt;li&gt;Return the item.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This is the role played by the &lt;code&gt;m_state&lt;/code&gt; array in &lt;code&gt;ConcurrentQueue.Segment&lt;/code&gt;. Each segment has an &lt;code&gt;int[] m_state&lt;/code&gt; alongside the &lt;code&gt;T[] m_array&lt;/code&gt;; a 1 in a particular slot indicates the item has been set, and a 0 (the default value) indicates it isn't set. This turns the Enqueue method into this:

&lt;/p&gt;&lt;pre&gt;public void Enqueue(T item) {
    int insertIndex = Interlocked.Increment(ref m_high);
    m_array[insertIndex] = item;
    m_state[insertIndex] = 1;
}&lt;/pre&gt;

and TryDequeue into this:

&lt;pre&gt;public bool TryDequeue(out T item) {
    int index;
    do {
        index = m_low;
        
        if (index &amp;gt; m_high) {
            item = default(T);
            return false;
        }
        
        if (Interlocked.CompareExchange(ref m_low, index+1, index) == index) {
            // busywait until m_state[index] is set
            while (m_state[index] == 0) {}
            
            item = m_array[index]
            return true;
        }
    }
    while (true);
}&lt;/pre&gt;

&lt;p&gt;By marking both &lt;code&gt;m_array&lt;/code&gt; and &lt;code&gt;m_state&lt;/code&gt; as volatile, this stops the JIT reordering accesses to those arrays, ensuring that the invariant implicit in this code (&lt;code&gt;m_state[index] == 1&lt;/code&gt; if and only if &lt;code&gt;m_array[index]&lt;/code&gt; has an item in it) doesn't get broken by the JIT or processors reordering instructions.&lt;/p&gt;

&lt;p&gt;Tweaking the control flow a bit, and sprinkling calls to &lt;code&gt;SpinWait.SpinOnce()&lt;/code&gt; around as the abstraction of a busywait, and you've got the code of the enqueue and dequeue methods of &lt;code&gt;ConcurrentQueue&lt;/code&gt;.

&lt;/p&gt;&lt;h4&gt;Final notes&lt;/h4&gt;

&lt;p&gt;There's a couple of things I need to briefly mention. Firstly, I haven't yet covered growing the queue. Creating new segments when the current segment gets full is largely handled by enqueuing. When an item is added to the last slot in a segment, the Enqueue method creates a new segment and assigns it as the next segment in the queue using the &lt;code&gt;m_next&lt;/code&gt; variable. When the dequeue method reaches the end of the current segment, it waits for the &lt;code&gt;m_next&lt;/code&gt; variable to be set before looking inside that segment to see if there's an item to dequeue.&lt;/p&gt;

&lt;p&gt;Secondly, the eagle-eyed among you might have noticed that dequeued items don't get removed from the backing array; they are still referenced from the array when items are dequeued. I can't see any specific threading reason for this, other than giving one less location for possible threading issues. However, more importantly, this guarantees that the invariant I mentioned above is never be broken, which can be important if you're reasoning about the collection.&lt;/p&gt;

&lt;p&gt;Keeping references around longer than they need isn't so big an issue; the items referenced in the array are dereferenced all together when the containing segment is dereferenced. However it is something to bear in mind if you have large objects referenced in a &lt;code&gt;ConcurrentQueue&lt;/code&gt; for a long time; they might not be garbage collected when they otherwise could be.&lt;/p&gt;

&lt;h4&gt;Concurrent principles&lt;/h4&gt;

&lt;p&gt;So what principles can we extract from this examination of &lt;code&gt;ConcurrentQueue&lt;/code&gt;?&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;h4&gt;Separating threads&lt;/h4&gt;
&lt;p&gt;&lt;code&gt;Increment&lt;/code&gt; and &lt;code&gt;CompareExchange&lt;/code&gt; are used to atomically assign each thread performing an action a separate slot. Each thread can then do work on that slot concurrently without conflicting with each other.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;h4&gt;Invariants&lt;/h4&gt;
&lt;p&gt;An invariant is used to eliminate a race condition between enqueuing and dequeuing, in this case, &lt;code&gt;m_state[index] == 1&lt;/code&gt; iff &lt;code&gt;m_array[index]&lt;/code&gt; has an item in it. This ensures enqueuing and dequeuing on the same slot works as it should. Note that this invariant is maintained even at the cost of keeping things in memory longer than they should.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;h4&gt;&lt;code&gt;volatile&lt;/code&gt; used as a memory barrier&lt;/h4&gt;
&lt;p&gt;Furthermore, &lt;code&gt;volatile&lt;/code&gt; is used to add memory barriers ensuring the JIT doesn't reorder &lt;code&gt;m_state&lt;/code&gt; and &lt;code&gt;m_array&lt;/code&gt; array accesses and inadvertantly break the invariant.&lt;/p&gt;
&lt;/li&gt;&lt;/ol&gt;

&lt;p&gt;Well, that's the core of the &lt;code&gt;ConcurrentQueue&lt;/code&gt; class. I haven't even begun to cover the supporting methods, and glossed over most of the gory details. These I leave for you to explore and figure out. It's time to move on! We finally get some locks involved, and peer under the covers at &lt;code&gt;ConcurrentDictionary&lt;/code&gt;.&lt;/p&gt;&lt;img src="http://www.simple-talk.com/community/aggbug.aspx?PostID=105658" width="1" height="1"&gt;</description><category domain="http://www.simple-talk.com/community/blogs/simonc/archive/category/1093.aspx">Inside the Concurrent Collections</category></item><item><title>Can desktop software be Lean?</title><link>http://www.simple-talk.com/community/blogs/ben_c/archive/2012/01/24/105648.aspx</link><pubDate>Tue, 24 Jan 2012 16:21:01 GMT</pubDate><guid isPermaLink="false">f46e5dea-70cd-4a69-a7e1-fd07a313bd4d:105648</guid><dc:creator>benc</dc:creator><slash:comments>0</slash:comments><description>&lt;p&gt;Eric Ries and the &lt;a href="http://theleanstartup.com/"&gt;Lean Startup&lt;/a&gt; movement seem to have become the hottest trend since Agile. The &lt;a href="http://www.ft.com/cms/s/2/8a022f32-de33-11e0-9fb7-00144feabdc0.html#axzz1kHsHPm3k"&gt;Financial Times&lt;/a&gt; already ranks Ries' book alongside Clay Christensen's &lt;em&gt;Innovator's Dilemma&lt;/em&gt; and Geoffrey Moore's &lt;em&gt;Crossing the Chasm&lt;/em&gt; for changing the way we think about innovation and entrepreneurship.&lt;/p&gt;  &lt;p&gt;While the book includes "Startup" in the title, and startups are where the ideas were first formulated, its principles are applicable to almost anyone building something new; including point releases of a desktop application!&lt;/p&gt;  &lt;p&gt;At the heart of the movement is the concept of the "build-measure-learn" feedback loop.&lt;/p&gt;  &lt;p&gt;Ries argues that in order to improve a product you need to track the effect of changes you make to your application. If you're not measuring these changes then you have no idea whether you're actually improving the product. Increasing sales might be attributable to better marketing and not a better product. In fact, unless you measure what you're doing you might actually be making your product worse, not better. It's fairly obvious when you think about it; by being more scientific, formulating hypotheses and running experiments we can eliminate a lot of the opinion and guesswork that can lead a project to ruin.&lt;/p&gt;  &lt;p&gt;The Lean Startup movement, borrowing from the Toyota Way, also encourages us to work in smaller batch sizes because "finding out sooner is much better than finding out later". The shorter the feedback cycle the quicker you can adapt. The risk of spending six months working on a feature that nobody wants can be completely eliminated.&lt;/p&gt;  &lt;p&gt;Many website and web applications have already taken the principle of smaller batch sizes to its logical conclusion and have adopted continuous deployment. Releasing new updates everyday takes discipline, especially with regard to testing, but is not uncommon. Well-established analytics solutions make tracking improvement simple.&lt;/p&gt;  &lt;p&gt;By contrast, adopting build-measure-learn for desktop applications is much harder.&lt;/p&gt;  &lt;p&gt;The tools for tracking feature usage of desktop apps are less well-established, so measuring improvements is much harder. Worse still are the deployment issues. Whereas a website can be updated by rolling out the latest build to a single server, for a desktop application to be updated every client needs to be upgraded.&lt;/p&gt;  &lt;p&gt;As the end user of the application has to do this themselves, it is impractical to release at anywhere near the same rate. Asking them to update on even a weekly basis results in disgruntled users (iTunes) and a proliferation of versions when they fail to upgrade.&lt;/p&gt;  &lt;p&gt;Instead of employing a continuous release cycle, most desktop vendors seem to have resigned themselves to the status quo: release cycles measured in quarters not days, imprecise usage data, and long spells of coding in the dark.&lt;/p&gt;  &lt;p&gt;If we're lucky, we try to validate what we're doing with UX tests and beta programs but this is imprecise compared to the web's best practices. &lt;/p&gt;  &lt;p&gt;This doesn't have to be the case. With Chrome, Google completely eliminated the pain of updating. As a result they are able to release as regularly as they like, and this has helped give them a major edge in the browser wars. Dropbox, another big name, have also been silently updating for years.&lt;/p&gt;  &lt;p&gt;Implementing a comparable system, even using Google's Omaha framework, isn't easy though.&lt;/p&gt;  &lt;p&gt;That's why at Red Gate, we're currently trying to build &lt;a href="http://quietdeploy.com"&gt;a service that lets developers silently update their application&lt;/a&gt;. We want desktop developers to enjoy all the same advantages as those who code for web. Desktop software shouldn't become a second class citizen just because it's too slow to adapt.&lt;/p&gt;  &lt;p&gt;&lt;a href="http://quietdeploy.com"&gt;&lt;img alt="Quiet Deploy" src="http://www.simple-talk.com/blogbits/benc/quietdeploy.png" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;We're currently trying to get as much feedback as possible, so if you're interested in learning more please check out &lt;a href="http://quietdeploy.com"&gt;Quiet Deploy&lt;/a&gt; or leave a comment below! We'd love to talk to you.&lt;/p&gt;  &lt;p&gt;* We're also expanding our desktop analytics effort. If you're interested in learning how people are using your desktop app visit &lt;a href="http://applicationmetrics.com"&gt;Application Metrics&lt;/a&gt;.&lt;/p&gt;&lt;img src="http://www.simple-talk.com/community/aggbug.aspx?PostID=105648" width="1" height="1"&gt;</description></item><item><title>Educational Programming</title><link>http://www.simple-talk.com/community/blogs/daveconvery/archive/2012/01/20/105562.aspx</link><pubDate>Fri, 20 Jan 2012 13:50:00 GMT</pubDate><guid isPermaLink="false">f46e5dea-70cd-4a69-a7e1-fd07a313bd4d:105562</guid><dc:creator>Dave Convery</dc:creator><slash:comments>8</slash:comments><description>&lt;p&gt;At last, we’ve woken up to the worrying fact that there just aren’t enough good programmers to go around. Instead of aiming to get a generation of students interested in building their own software, education has instead been compelled by successive governments to focus on word processing, presentation graphics, and stultifying vocational work geared to office skills. Something needs to change; the good news is that change may have already started.&lt;/p&gt;
&lt;p&gt;Thankfully the current UK government, who were previously expected to be more likely to make Latin compulsory, have listened to cries from industry and done away with rigidly-specified ICT lessons, to replace them with an ‘open-source’ curriculum that returns to schools the decision of what to teach.&lt;/p&gt;
&lt;p&gt;Joel Spolsky &lt;a target="_blank" href="http://www.joelonsoftware.com/items/2012/01/13.html"&gt;recently wrote&lt;/a&gt; about a New York school that he’s supporting – one that will focus on finding students with a passion for coding and nurture them, rather than skimming off the kids with the best grades for a subject that they don’t necessarily have any affinity for. If successful, there are plans to roll this model out further. Schools everywhere already have valuable support from organisations like MIT, who have created an excellent resource in their &lt;a target="_blank" href="http://scratch.mit.edu/"&gt;Scratch programming language&lt;/a&gt;, and &lt;a target="_blank" href="http://www.sqlpass.org/"&gt;PASS&lt;/a&gt;, whose 
volunteers have been working to engage with students.&lt;/p&gt;
&lt;p&gt;There are initiatives in hardware like the &lt;a target="_blank" href="http://www.raspberrypi.org/"&gt;Raspberry Pi&lt;/a&gt;, a tiny, powerful and ultra-cheap Linux box that’s designed to lower the barrier to entry for kids to get started with programming. More importantly, it opens the way to genuinely experimental programming, the sort of thing that produced so many of the great hobbyist programmers of the 80s and 90s. It plugs directly into a TV, and supports USB inputs so that it allows anyone to get set up for very little outlay (the highest-spec version of the machine costs only $35), which will hopefully also make it attractive to schools that would otherwise struggle to buy much dedicated programming hardware.&lt;/p&gt;
&lt;p&gt;Beyond the obvious benefit to the students, these initiatives could well help the software industry itself. By getting kids interested in programming at a younger age, we may at last reverse the growing  gender gap in future by reducing the perception of programming as being a masculine discipline (something &lt;a target="_blank" href="http://www.womenintechnology.org/content.asp?contentid=79"&gt;Girls in Technology&lt;/a&gt; are already doing good work on). And of course employers would love increased competition for good jobs.&lt;/p&gt;
&lt;p&gt;It’s not all good news though, as a drought of great programmers also means a drought of qualified, passionate teachers. Even with the current, much more limited ICT classes, it’s estimated that, in the UK, &lt;a href="http://www.edge-online.com/news/only-third-ict-teachers-are-qualified-study"&gt;only 30% of the teachers&lt;/a&gt; responsible for these classes actually have direct, relevant education in what they’re teaching. There are many lucrative careers open to good coders, and this is especially the case with the more mathematically-minded where their skills are in demand for the huge amounts of data wrangling needed in the financial sector. It’s not easy to persuade someone that, after some very expensive years at college, they should head into a relatively low-paid line of work, no matter how ‘rewarding’ it might be.&lt;/p&gt;
&lt;p&gt;What languages do you think we should be teaching kids? How should we do it? How would you persuade great programmers to pass on their skills and enthusiasm to the next generation by teaching programming?&lt;/p&gt;&lt;img src="http://www.simple-talk.com/community/aggbug.aspx?PostID=105562" width="1" height="1"&gt;</description></item><item><title>It always works on my machine.</title><link>http://www.simple-talk.com/community/blogs/brian_donahue/archive/2012/01/18/105522.aspx</link><pubDate>Wed, 18 Jan 2012 10:17:00 GMT</pubDate><guid isPermaLink="false">f46e5dea-70cd-4a69-a7e1-fd07a313bd4d:105522</guid><dc:creator>Brian Donahue</dc:creator><slash:comments>2</slash:comments><description>Probably the most common question that the Red Gate developer tools support gets is "Does your X work with Y?" where X is your bit of software and Y is a bit of software made by a different company. This is probably the least answerable question in the known universe.

Start with the obvious - "Does X work?" - full stop. Because with millions of possible configurations in Windows, it's entirely possible that it won't "work" at all. But I can personally guarantee you that it "works on my machine"!

Second of all, what does "work" mean? Several things that come to mind:
&lt;ul&gt;&lt;li&gt;Can X and Y peacefully coexist on the same computer?
&lt;li&gt;Does X extend the functionality of Y?
&lt;li&gt;Is X a replacement for Y?
&lt;li&gt;Can the output from X be processed by Y?
&lt;li&gt;Does the new version of Y cause the old version of X to fail? 
&lt;li&gt;If I run X and Y at the same time, will it Div/0 and open a hole in the universe?
&lt;/ul&gt;

Finally, as I already mentioned, the question could be about &lt;b&gt;F&lt;/b&gt;ear, &lt;b&gt;U&lt;/b&gt;ncertainty, and &lt;b&gt;D&lt;/b&gt;oubt. 
For instance, if a new version of Microsoft .NET Framework comes out, there is a doubt that your program will not function correctly with it. I've heard of a dutiful network administrator mass-emailing every vendor he has bought any software from when a new version of SQL Server is on the horizon - "Does X work with the new version of SQL Server"?

I believe it's a bit lazy to ask a question this way and you may not get the answer you expect, unless you are perhaps more specific about the particular functionality you are interested in.&lt;img src="http://www.simple-talk.com/community/aggbug.aspx?PostID=105522" width="1" height="1"&gt;</description></item><item><title>Inside Red Gate - Experimental Results</title><link>http://www.simple-talk.com/community/blogs/simonc/archive/2012/01/17/105506.aspx</link><pubDate>Tue, 17 Jan 2012 17:16:00 GMT</pubDate><guid isPermaLink="false">f46e5dea-70cd-4a69-a7e1-fd07a313bd4d:105506</guid><dc:creator>Simon Cooper</dc:creator><slash:comments>0</slash:comments><description>&lt;p&gt;As a brief interlude from my Concurrent Collections series, I thought I would give an roundup of how the lean startup experiments have been progressing. As you can expect, there's been some good aspects and some bad aspects.&lt;/p&gt;

&lt;h4&gt;The experiments so far&lt;/h4&gt;
&lt;p&gt;After lots of discussions, arguments, posing and ruling out hypotheses, we came up with two 'starter' hypotheses we could test fairly easily:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Customers don't agree to send data on how they use SmartAssembly; which features they use, the versions of .NET they have installed, etc, because the consent dialog doesn't make it clear the data is all anonymous and aggregated.
&lt;p&gt;This is a prequisite for further experimentation. SmartAssembly isn't a webapp, with google analytics and web logs telling us everything. In order to conduct experiments on SmartAssembly, we need to know how customers are using it once it is installed on their machines, and they need to confirm it's ok for us to collect that data. Our current acceptance rate for usage reporting on SmartAssembly itself is quite low, so we needed to improve this for future experiments.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;Customers aren't using feature usage reporting and error reporting within their own applications because those options are swamped amongst all the obfuscation options.&lt;/li&gt;
&lt;/ol&gt;

&lt;h4&gt;Experiment 1&lt;/h4&gt;
&lt;p&gt;&lt;strong&gt;Hypothesis:&lt;/strong&gt; Customers don't agree to send data on how they use SmartAssembly because the dialog asking for consent doesn't make it clear the data is all anonymous&lt;/p&gt;
&lt;p&gt;The experiment for this is pretty obvious - improve the wording on the consent dialog. This change was applied to SmartAssembly 6.5. We would compare signup rates with 6.2 to see what effect, if any, this change would have.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Result:&lt;/strong&gt; Inconclusive&lt;/p&gt;
&lt;p&gt;We found after 6.5 had been released that we weren't collecting the right data from our download and install process to be able to accurately calculate an acceptance percentage. One of the quirks of the existing feature usage instrumentation is that the answer users give to the consent dialog is used for all future versions of the product with the same major version.&lt;/p&gt;
&lt;p&gt;Since 6.5 is a minor version upgrade from 6.2, this means we couldn't differentiate between an existing customer downloading to upgrade from &amp;lt;6.2 to 6.5 (who wouldn't be presented with the new consent dialog), and a new user downloading for the first time. The data we collected couldn't be interpreted one way or the other; there were too many other variables.&lt;/p&gt;

&lt;h4&gt;Experiment 2&lt;/h4&gt;
&lt;p&gt;&lt;strong&gt;Hypothesis:&lt;/strong&gt; Customers aren't using feature usage reporting and error reporting within their own applications because those options are swamped amongst all the obfuscation options&lt;/p&gt;
&lt;p&gt;To perform this experiment, we produced a version of SmartAssembly that only had merging, signing, feature usage and error reporting available. We only wanted to present this version to customers whom we knew were downloading SmartAssembly for the error and/or feature usage reporting. The only place we could reasonably guarantee this was a reporting-specific landing page. So, the download link on that page would be A/B tested between the reporting-only and standard version of SmartAssembly.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Result:&lt;/strong&gt; Not enough data&lt;/p&gt;
&lt;p&gt;Our limited scope for this test - one specific landing page amongst the many pages on SmartAssembly where customers could download - meant we got very few people downloading the reporting-only version of SmartAssembly; not enough for any conclusion to be drawn one way or the other.&lt;/p&gt;
&lt;p&gt;We had also added a 'cop-out' link on the download page so people could guarantee to get the standard version, if they did happen to download the reporting-only version and wonder where all the obfuscation went. We suspect a lot of users clicked this link; unfortunately, it was untracked, so we don't really know.&lt;/p&gt;

&lt;h4&gt;It's not all bad news...&lt;/h4&gt;
&lt;p&gt;So, the first experiments we performed didn't really work. However, that doesn't mean they weren't useful. We worked through a lot of the infrastructure issues that restricted our experimentation, and, most importantly, we learnt things:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Make sure you know what the experiment is for, and what data you will collect to validate or refute your hypotheses. Check the data you will be collecting will make sense.&lt;/li&gt;
&lt;li&gt;For an A/B test, ensure you will have a sensible number of users on both sides to able to draw conclusions.&lt;/li&gt;
&lt;li&gt;Don't allow users to opt-out of experimental builds, even if it's not marketed as an 'experimental' version. Don't blur the boundaries of experimental and non-experimental builds.&lt;/li&gt;
&lt;/ol&gt;

&lt;h4&gt;So what now?&lt;/h4&gt;
&lt;p&gt;We've decided we're going down the wrong route. We shouldn't be trying to target existing users of SmartAssembly, who are looking primarily for an obfuscation tool, we need to target new users. We've decided to pivot and create a new product, a new website, and a new analytics platform. If you're interested, there are samples of the kind of data you could have on your applications at &lt;a href="http://www.applicationmetrics.com"&gt;http://www.applicationmetrics.com&lt;/a&gt;, as well as a sign up to receive more information and take part in our experiments.&lt;/p&gt;&lt;img src="http://www.simple-talk.com/community/aggbug.aspx?PostID=105506" width="1" height="1"&gt;</description><category domain="http://www.simple-talk.com/community/blogs/simonc/archive/category/1079.aspx">Inside Red Gate</category></item><item><title>A new toy - .NET Demon</title><link>http://www.simple-talk.com/community/blogs/alex/archive/2012/01/16/105463.aspx</link><pubDate>Mon, 16 Jan 2012 16:17:00 GMT</pubDate><guid isPermaLink="false">f46e5dea-70cd-4a69-a7e1-fd07a313bd4d:105463</guid><dc:creator>Alex.Davies</dc:creator><slash:comments>0</slash:comments><description>&lt;p&gt;I'd like to present a new tool for .NET Developers that we've been cooking up in the Red Gate .NET team. It's only a beta at the moment, but it works for most people.&lt;/p&gt;  &lt;p&gt;&lt;a href="http://www.red-gate.com/products/dotnet-development/dotnet-demon/"&gt;.NET Demon Beta&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;It's a Visual Studio extension that cuts the time you spend waiting to find whether your code is right. It does this by:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Continuous testing (running your NUnit tests as you type)&lt;/li&gt;    &lt;li&gt;Continuous compilation (so you can start running instantly because your code is already compiled)&lt;/li&gt;    &lt;li&gt;Inline code coverage (so you know which tests are covering the code you're editing, and if they start failing)&lt;/li&gt;    &lt;li&gt;Continuous save (so you don't have to press ctrl-S ever again)&lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Let me know what you think of it!&lt;/p&gt;&lt;img src="http://www.simple-talk.com/community/aggbug.aspx?PostID=105463" width="1" height="1"&gt;</description></item><item><title>5 reasons why I almost loved WPF</title><link>http://www.simple-talk.com/community/blogs/richard/archive/2012/01/13/105406.aspx</link><pubDate>Fri, 13 Jan 2012 01:14:00 GMT</pubDate><guid isPermaLink="false">f46e5dea-70cd-4a69-a7e1-fd07a313bd4d:105406</guid><dc:creator>Richard Mitchell</dc:creator><slash:comments>0</slash:comments><description>Before you read this you should probably read my original post 5 Reasons why I hate WPF. Also "Qwertie" wrote a nice article detail about his overview of why WPF sucks.  1 - Binding  There is something so nice about setting a button to be enabled or not enabled based on a property in the view. All the enabling and disabling is handled for you (more or less). I find that using MVVM helps in many ways to separate UI logic from UI appearance. Something I've always found difficult when writing WinForms...(&lt;a href="http://www.simple-talk.com/community/blogs/richard/archive/2012/01/13/105406.aspx"&gt;read more&lt;/a&gt;)&lt;img src="http://www.simple-talk.com/community/aggbug.aspx?PostID=105406" width="1" height="1"&gt;</description></item><item><title>Inside the Concurrent Collections: ConcurrentStack</title><link>http://www.simple-talk.com/community/blogs/simonc/archive/2012/01/12/105370.aspx</link><pubDate>Thu, 12 Jan 2012 12:35:00 GMT</pubDate><guid isPermaLink="false">f46e5dea-70cd-4a69-a7e1-fd07a313bd4d:105370</guid><dc:creator>Simon Cooper</dc:creator><slash:comments>2</slash:comments><description>&lt;p&gt;The first concurrent collection we'll look at is &lt;code&gt;ConcurrentStack&lt;/code&gt;. This is conceptually the same as &lt;code&gt;System.Collections.Generic.Stack&lt;/code&gt;, but is geared towards occasional concurrent modifications.&lt;/p&gt;

&lt;p&gt;Now, in these posts I won't be looking to explain what every method does; just like my other explorations of various collection types, I'll be concentrating on the core implementation and concepts used by the collections, and glossing over the more sordid implementation details and scaffolding required to support an &lt;code&gt;ICollection&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;So, without further ado, let's get started:&lt;/p&gt;

&lt;h4&gt;ConcurrentStack&lt;/h4&gt;
&lt;p&gt;There are three basic operations you can perform on a stack:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;Push&lt;/code&gt;: Push a new value onto the top of the stack&lt;/li&gt;
&lt;li&gt;&lt;code&gt;TryPeek&lt;/code&gt;: Peeking at the top value. In &lt;code&gt;ConcurrentStack&lt;/code&gt;, this is quite a simple method.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;TryPop&lt;/code&gt;: Popping the top value off the stack&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;ConcurrentStack supplements these with &lt;code&gt;PushRange&lt;/code&gt; and &lt;code&gt;TryPopRange&lt;/code&gt; for pushing and popping an array of values, &lt;code&gt;ToArray&lt;/code&gt;, and the standard &lt;code&gt;ICollection&lt;/code&gt; methods.&lt;/p&gt;

&lt;p&gt;The stack is implemented as a singly-linked list, with nodes represented by the &lt;code&gt;ConcurrentStack&amp;lt;T&amp;gt;.Node&lt;/code&gt; private class:
&lt;/p&gt;&lt;pre&gt;private class Node {
    internal T m_Value;
    internal Node m_Next;
}&lt;/pre&gt;
&lt;p&gt;The top of the stack is referenced by the volatile &lt;code&gt;m_head&lt;/code&gt; variable. An empty stack is represented by a null value in &lt;code&gt;m_head&lt;/code&gt;. For example, if you push the integers 1, 2 and 3 onto the stack in that order, the nodes will look like this:&lt;/p&gt;

&lt;img src="/blogbits/simon.cooper/ConcurrentStack1.png"&gt;

&lt;p&gt;If you then pop a single value off the stack, &lt;code&gt;m_head&lt;/code&gt; will point at the '2' node.&lt;/p&gt;

&lt;h4&gt;Pushing values&lt;/h4&gt;
&lt;p&gt;So, there are three operations required to push a new value onto the stack:
&lt;/p&gt;&lt;ol&gt;
&lt;li&gt;Create a new &lt;code&gt;Node&lt;/code&gt; object to hold the new value&lt;/li&gt;
&lt;li&gt;Setting the node's &lt;code&gt;m_next&lt;/code&gt; variable to point to the current head node&lt;/li&gt;
&lt;li&gt;Changing &lt;code&gt;m_head&lt;/code&gt; to point to the newly-created node.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;And, straight away, we've got the possibility of a race condition. Say Thread 1 is pushing the value '4' onto the stack. It's just executed step 2:&lt;/p&gt;

&lt;img src="/blogbits/simon.cooper/ConcurrentStack4.png"&gt;

&lt;p&gt;Now, Thread 2 is scheduled on the CPU and is pushing the value '5'. Thread 2 executes steps 1, 2 and 3:&lt;/p&gt;

&lt;img src="/blogbits/simon.cooper/ConcurrentStack5.png"&gt;

&lt;p&gt;Thread 1 then executes step 3:&lt;/p&gt;

&lt;img src="/blogbits/simon.cooper/ConcurrentStack6.png"&gt;

&lt;p&gt;The node successfully pushed by Thread 2 has disappeared from the stack.&lt;/p&gt;

&lt;p&gt;So, what we want to do is perform step 3 &lt;em&gt;only if the head hasn't changed in the meantime&lt;/em&gt;. If it has been changed, then go back to step 2 to use the updated head node as the value of &lt;code&gt;m_next&lt;/code&gt;. Furthermore, this all has to be done atomically so other threads can't see the intermediate state.&lt;/p&gt;

&lt;p&gt;This is where &lt;code&gt;Interlocked.CompareExchange&lt;/code&gt; comes into play. If you recall my previous post, &lt;code&gt;CompareExchange&lt;/code&gt; performs the following as an atomic operation:
&lt;/p&gt;&lt;pre&gt;public static T CompareExchange&amp;lt;T&amp;gt;(ref T location, T value, T comparand)
  where T : class {
    T origValue = location;
    if (location == comparand)
        location = value;
    return origValue;
}&lt;/pre&gt;
Or, in words:
&lt;p&gt;I think &lt;code&gt;location&lt;/code&gt; has the same value as &lt;code&gt;comparand&lt;/code&gt;. If it is, replace it with &lt;code&gt;value&lt;/code&gt;. Return me what &lt;code&gt;location&lt;/code&gt; actually is.&lt;/p&gt;

&lt;p&gt;This allows us to do the 'check and assign a new head, else try again' operation atomically, like so:&lt;/p&gt;
&lt;pre&gt;public void Push(T item) {
    Node node = new Node(item);
    do {
        node.m_next = m_head;
    }
    while (Interlocked.CompareExchange(ref m_head, node, node.m_next) != node.m_next);
}&lt;/pre&gt;
&lt;p&gt;Or, as words:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Create a new node&lt;/li&gt;
&lt;li&gt;Set the node's next field to the current head&lt;/li&gt;
&lt;li&gt;atomically{I think the current head is the value of the node's next field. If it is, replace it with the new node}. If the head was't actually the same as the next field, go back to 2.&lt;/li&gt;
&lt;/ol&gt;

&lt;img src="/blogbits/simon.cooper/ConcurrentStack3.png"&gt;

&lt;p&gt;This has eliminated the race condition we had between steps 2 and 3. Only if the head hasn't been changed is the new node pushed onto the stack as the new head. This loop repeats until &lt;code&gt;CompareExchange&lt;/code&gt; successfully sets the head to the new node.&lt;/p&gt;

&lt;p&gt;This can easily be generalised to a range of values in &lt;code&gt;PushRange&lt;/code&gt; - we can simply change step 1 to construct the list of nodes holding the values being pushed, then using the &lt;code&gt;m_next&lt;/code&gt; field of the tail node, and the top node as the new head, like so:&lt;/p&gt;

&lt;img src="/blogbits/simon.cooper/ConcurrentStack2.png"&gt;

&lt;p&gt;So that's pushing values onto the stack. What about removing them?&lt;/p&gt;

&lt;h4&gt;Popping values&lt;/h4&gt;
&lt;p&gt;As you can expect, popping items from the stack can be done in a similar way to pushing them:
&lt;/p&gt;&lt;pre&gt;Node topNode;
do {
    topNode = m_head;
}
while (Interlocked.CompareExchange(ref m_head, m_head.m_next, topNode) != topNode);&lt;/pre&gt;

&lt;p&gt;However, it's not quite so simple as that. For one thing, the stack may be empty, so &lt;code&gt;m_head&lt;/code&gt; might be null. For another, you need to be able to pop several items off the stack as a single atomic operation, which requires navigating several &lt;code&gt;m_next&lt;/code&gt; references at once. We need to be slightly more clever about it.&lt;/p&gt;

&lt;p&gt;Let's cover checking for an empty stack first. Checking for null is easy, right? &lt;code&gt;if (m_head == null) return false;&lt;/code&gt; So we put this at the start of the pop method:
&lt;/p&gt;&lt;pre&gt;public bool TryPop(out T item) {
    if (m_head == null) {
        item = default(T);
        return false;
    }

    Node topNode;
    do {
        topNode = m_head;
    }
    while (Interlocked.CompareExchange(ref m_head, m_head.m_next, topNode) != topNode);
    
    item = topNode.m_value;
    return true;
}&lt;/pre&gt;
&lt;p&gt;However, again, we've got a race condition. The null check only happens once. If another thread were to empty the stack while the current thread is inside the while loop, this leaves us with a &lt;code&gt;NullReferenceException&lt;/code&gt; lying in wait when we try and get &lt;code&gt;m_head.m_next&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The simple way to fix this is to do the null check inside the loop, eliminating the race condition:&lt;/p&gt;
&lt;pre&gt;public bool TryPop(out T item) {
    Node topNode;
    do {
        topNode = m_head;
        
        if (topNode == null) {
            item = default(T);
            return false;
        }
    }
    while (Interlocked.CompareExchange(ref m_head, m_head.m_next, topNode) != topNode);
    
    item = topNode.m_value;
    return true;
}&lt;/pre&gt;

&lt;p&gt;Sorted. So, what about popping multiple values off the stack? Again, like the null check, this has to be performed inside the while loop using the 'snapshot' of the head we've taken in &lt;code&gt;topNode&lt;/code&gt;:

&lt;/p&gt;&lt;pre&gt;public int TryPopRange(T[] items, int count) {
    int i;
    Node topNode;
    do {
        topNode = m_head;
        Node curNode = topNode;
        i=0;

        while (i&amp;lt;count &amp;amp;&amp;amp; curNode != null) {
            items[i] = curNode.m_value;
            curNode = curNode.m_next;
            i++;
        }
    }
    while (Interlocked.CompareExchange(ref m_head, curNode, topNode) != topNode);
    
    return i;
}&lt;/pre&gt;

&lt;p&gt;In fact, this idea of taking the current head, doing some work on it, then atomically swapping it if it hasn't been changed in the meantime can be generalised:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Take an atomic snapshot of the current state&lt;/li&gt;
&lt;li&gt;Do some work on the snapshot locally to the current thread&lt;/li&gt;
&lt;li&gt;Atomically make the work visible to all other threads, if the snapshot you took is still a valid representation of the state&lt;/li&gt;
&lt;li&gt;If it isn't, go back to the start and try again&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This is, at its core, how &lt;code&gt;ConcurrentStack&lt;/code&gt; works.&lt;/p&gt;

&lt;h4&gt;Performing atomic operations&lt;/h4&gt;
&lt;p&gt;So, what underlying aspects of the system let us perform these operations atomically?
&lt;/p&gt;&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Object references are atomic&lt;/strong&gt;&lt;br&gt;
This lets us take an atomic snapshot of the current state simply by storing the value of &lt;code&gt;m_head&lt;/code&gt; in a local variable; &lt;code&gt;m_head&lt;/code&gt; will always be pointing at a valid node (or null), it won't be 'half-changed'.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;Interlocked.CompareExchange&lt;/code&gt; is atomic&lt;/strong&gt;&lt;br&gt;
This ensures the state-check-and-switch won't be afflicted by race conditions with other threads.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;m_head&lt;/code&gt; is a volatile variable&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;m_head&lt;/code&gt; is marked as &lt;code&gt;volatile&lt;/code&gt;. This means that any changes to that variable by one thread are instantly visible to all other threads on the system; there's no caching to get in the way. Any threads that are attempting to modify &lt;code&gt;m_head&lt;/code&gt; will be forced to try again, and they won't overwrite the changes already made.&lt;/li&gt;
&lt;/ol&gt;

&lt;h4&gt;Gory implementation details&lt;/h4&gt;
&lt;p&gt;Now, I said at the start that I wouldn't be covering gory implementation details of these collections. However, in this case, there are some important considerations.&lt;/p&gt;

&lt;p&gt;If you decompile &lt;code&gt;ConcurrentStack&lt;/code&gt;, you'll notice there's a &lt;code&gt;Push&lt;/code&gt; method and a &lt;code&gt;PushCore&lt;/code&gt; method (similarly for &lt;code&gt;TryPop&lt;/code&gt; and &lt;code&gt;TryPopRange&lt;/code&gt;). This is a small but significant performance detail; &lt;code&gt;ConcurrentStack&lt;/code&gt; assumes there aren't going to be any thread collisions. The public methods all optimistically attempt to perform the operation once. Only if another thread gets in the way do the corresponding Core methods get executed. It is these that contain the full loop logic, along with calls to &lt;code&gt;SpinWait.SpinOnce&lt;/code&gt; to try and get the other threads out of the way before they try again.&lt;/p&gt;

&lt;p&gt;In fact, &lt;code&gt;TryPopCore&lt;/code&gt; goes one step further, and implements a randomised &lt;a href="http://en.wikipedia.org/wiki/Exponential_backoff"&gt;exponential backoff&lt;/a&gt; to reduce the chances of several threads all waiting the same amount of time. It does mean that, although &lt;code&gt;ConcurrentStack&lt;/code&gt; is lockless, and so eliminates the risk of deadlock, the performance will suffer if there are many threads all modifying the stack at the same time, as each method will have to try several times before its operation succeeds.&lt;/p&gt;

&lt;p&gt;That's the essence of how &lt;code&gt;ConcurrentStack&lt;/code&gt; is implemented. Next time, I'll take a look at the second lockless concurrent collection, &lt;code&gt;ConcurrentQueue&lt;/code&gt;, which goes about achieving thread-safety in quite a different way.&lt;/p&gt;

&lt;h4&gt;Footnote&lt;/h4&gt;
&lt;p&gt;I'm now on twitter! If you want to get in touch, comment on the series, or suggest other things I could look at, my username is &lt;a href="https://twitter.com/#%21/simonmcooper"&gt;@simonmcooper&lt;/a&gt;&lt;/p&gt;&lt;img src="http://www.simple-talk.com/community/aggbug.aspx?PostID=105370" width="1" height="1"&gt;</description><category domain="http://www.simple-talk.com/community/blogs/simonc/archive/category/1093.aspx">Inside the Concurrent Collections</category></item><item><title>Indexing - take the hint and leave it to the experts</title><link>http://www.simple-talk.com/community/blogs/jonathanallen/archive/2012/01/10/105306.aspx</link><pubDate>Tue, 10 Jan 2012 07:00:00 GMT</pubDate><guid isPermaLink="false">f46e5dea-70cd-4a69-a7e1-fd07a313bd4d:105306</guid><dc:creator>fatherjack</dc:creator><slash:comments>8</slash:comments><description>The most common T-SQL command in use has to be the SELECT statement, it is the bedrock of any SQL Professional's day. Sometimes it's used to snatch some data from a table or two while some quick investigation is done, other times it is at the heart of a stored procedure or view that will inform business decisions for coming months or even years.  The latter purpose means you should spend some time making sure it is as efficient as possible. Not endless hours to save a millisecond or two (I mentioned...(&lt;a href="http://www.simple-talk.com/community/blogs/jonathanallen/archive/2012/01/10/105306.aspx"&gt;read more&lt;/a&gt;)&lt;img src="http://www.simple-talk.com/community/aggbug.aspx?PostID=105306" width="1" height="1"&gt;</description><category domain="http://www.simple-talk.com/community/blogs/jonathanallen/archive/category/1040.aspx">How To</category><category domain="http://www.simple-talk.com/community/blogs/jonathanallen/archive/category/1048.aspx">Tips and Tricks</category><category domain="http://www.simple-talk.com/community/blogs/jonathanallen/archive/category/1066.aspx">TSQL</category></item><item><title>Retrieving Passwords from Managed Accounts in SharePoint 2010 for C#</title><link>http://www.simple-talk.com/community/blogs/damon_armstrong/archive/2012/01/06/105198.aspx</link><pubDate>Fri, 06 Jan 2012 15:17:00 GMT</pubDate><guid isPermaLink="false">f46e5dea-70cd-4a69-a7e1-fd07a313bd4d:105198</guid><dc:creator>Damon</dc:creator><slash:comments>0</slash:comments><description>&lt;p&gt;I was looking for a way to retrieve a password from a managed account when I ran into a post titled &lt;a href="http://www.sharepointlonghorn.com/Lists/Posts/Post.aspx?ID=11"&gt;How to: Get Your Managed Account Passwords When They are Changed Automatically by SharePoint 2010&lt;/a&gt; by Jason Himmelstein.  It was written for PowerShell and I needed in C#, so I figured I would post the converted code in case anyone was looking for the same thing.  You will need to have the following using statements:&lt;/p&gt; &lt;code&gt;using System.Runtime.InteropServices;    &lt;br /&gt;using Microsoft.SharePoint.Administration; &lt;/code&gt;  &lt;p&gt;Then you can use the following code to retrieve the managed password:&lt;/p&gt;  &lt;p&gt;&lt;code&gt;var managedAccounts = new SPFarmManagedAccountCollection(SPFarm.Local);     &lt;br /&gt;&lt;/code&gt;&lt;code&gt;foreach (SPManagedAccount managedAccount in managedAccounts)      &lt;br /&gt;{  &lt;br /&gt;  var securePassword = (SPEncryptedString)managedAccount      &lt;br /&gt;&lt;/code&gt;&lt;code&gt;    .GetType()     &lt;br /&gt;    .GetField("m_Password",  &lt;br /&gt;      System.Reflection.BindingFlags.GetField |      &lt;br /&gt;      System.Reflection.BindingFlags.Instance |      &lt;br /&gt;      System.Reflection.BindingFlags.NonPublic)       &lt;br /&gt;    .GetValue(managedAccount);       &lt;br /&gt;      &lt;br /&gt;  var intptr = System.IntPtr.Zero;       &lt;br /&gt;  var unmanagedString = Marshal.      &lt;br /&gt;    SecureStringToGlobalAllocUnicode(securePassword.SecureStringValue);      &lt;br /&gt;&lt;/code&gt;&lt;code&gt;     &lt;br /&gt;  var unsecureString = Marshal.PtrToStringUni(unmanagedString);      &lt;br /&gt;  Marshal.ZeroFreeGlobalAllocUnicode(unmanagedString);  &lt;br /&gt;      &lt;br /&gt;&lt;/code&gt;&lt;code&gt;  //Do something with unsecureString      &lt;br /&gt;} &lt;/code&gt;&lt;/p&gt;  &lt;p&gt;One caveat to this is that you must be running as a Farm Administrator for the code to succeed.  Otherwise you will get an error about accessing the registry.  It is also relying on reflection to retrieve a non-public internal field, so as my friend Jeff Burt was quick to point out, Microsoft could change it at any time and break this code.  Probably not good for production code.&lt;/p&gt;&lt;img src="http://www.simple-talk.com/community/aggbug.aspx?PostID=105198" width="1" height="1"&gt;</description><category domain="http://www.simple-talk.com/community/blogs/damon_armstrong/archive/category/1009.aspx">.NET Development</category><category domain="http://www.simple-talk.com/community/blogs/damon_armstrong/archive/category/1016.aspx">SharePoint</category></item><item><title>SQL Server's Big Red Buttons</title><link>http://www.simple-talk.com/community/blogs/tony_davis/archive/2012/01/06/105192.aspx</link><pubDate>Fri, 06 Jan 2012 12:24:00 GMT</pubDate><guid isPermaLink="false">f46e5dea-70cd-4a69-a7e1-fd07a313bd4d:105192</guid><dc:creator>Tony Davis</dc:creator><slash:comments>7</slash:comments><description>&lt;p&gt;One of the most reassuring aspects of watching a vintage James Bond film is the comfort of knowing that, just when there seems no further hope that the villain's plans for world domination will be thwarted, Bond will glance up at the wall and notice a big red button. Instantly, he knows that all he has to do is press it and the villain's lair will self-destruct messily, with plenty of pyrotechnics, and armed men being tossed into the air like rag dolls.&lt;/p&gt;  &lt;p&gt;Of course, you have to wonder why the technologists who built the lair put that big red button on the wall. It seems to be an irresistible urge, and one to which the creators of SQL Server are not immune, as &lt;a href="https://twitter.com/#!/SQLPoolBoy"&gt;@SQLPoolBoy&lt;/a&gt; noted last week in one of his tweets...&lt;/p&gt;  &lt;p&gt;        "&lt;em&gt;Looking at a database that has 99% fragmentation across the board. The cause, AutoShrink&lt;/em&gt;"&lt;/p&gt;  &lt;p&gt;...a database brought to its knees by some poor soul who had accidentally hit one of SQL Server's big red buttons. &lt;/p&gt;  &lt;p&gt;You have to feel sorry for anyone who accidentally accepts the default database sizing and auto-growth settings, or turns on AutoShrink, or accidentally creates a collation conflict, or falls foul of any other of a host of 'Red Button' actions that can eventually lead to metaphorical pyrotechnics and DBAs being tossed in the air like dolls.&lt;/p&gt;  &lt;p&gt;SQL Server makes it very easy to tweak its various database- and server-level settings and so it's easy for inconsistency to creep in between database and servers, and it's easy for someone to unwittingly hit one of the red buttons. However, for the DBA managing tens of servers, it's not necessarily easy to find out which buttons have been pressed where, or to find best practice advice on how some of these settings really should be configured for each environment.&lt;/p&gt;  &lt;p&gt;However, help in various forms is slowly emerging. Brent Ozar has made publicly available his &lt;a href="http://www.brentozar.com/sql/blitz-minute-sql-server-takeovers/"&gt;SQL Server Blitz&lt;/a&gt; script, which helps you verify some of the absolute fundamentals (Are backups being taken? Are DBCC checks being run?), and then seeks out a few of the more common red buttons, which may need deactivating.&lt;/p&gt;  &lt;p&gt;Then there is also &lt;a href="http://sqlcop.lessthandot.com/detectedissues.php"&gt;SQLCop&lt;/a&gt;, a free community tool for "&lt;i&gt;detecting common problems with database configurations and TSQL code&lt;/i&gt;". Named after a similar .NET tool (&lt;a href="http://msdn.microsoft.com/en-us/library/bb429476(v=VS.80).aspx"&gt;FxCop&lt;/a&gt;), it's broader in scope than the Blitz script, checking everything from configuration settings, to fragmented indexes, to missing Foreign Keys, to "code smells" in stored procedures. Red Gate has done some work with the makers of this tool, in incorporating some of their tests into the &lt;a href="http://www.red-gate.com/products/sql-development/sql-test/"&gt;SQLTest&lt;/a&gt; tool, the idea being that the final step to resolving such problems may be automated testing. &lt;/p&gt;  &lt;p&gt;However, there is still much work to be done. What are your favorite "Red Button" actions in SQL Server? What is the best way to find and deactivate them before they cause havoc in your Server and databases?&lt;/p&gt;  &lt;p&gt;Cheers,&lt;/p&gt;  &lt;p&gt;Tony.&lt;/p&gt;&lt;img src="http://www.simple-talk.com/community/aggbug.aspx?PostID=105192" width="1" height="1"&gt;</description></item><item><title>Inside the Concurrent Collections</title><link>http://www.simple-talk.com/community/blogs/simonc/archive/2012/01/05/105166.aspx</link><pubDate>Thu, 05 Jan 2012 14:41:00 GMT</pubDate><guid isPermaLink="false">f46e5dea-70cd-4a69-a7e1-fd07a313bd4d:105166</guid><dc:creator>Simon Cooper</dc:creator><slash:comments>0</slash:comments><description>&lt;p&gt;The concurrent collections, located in the &lt;code&gt;System.Collections.Concurrent&lt;/code&gt; namespace, were introduced in .NET 4 as thread-safe collections that could be used without locking, and there are plenty of posts and articles out on the interwebs giving an overview of the collections and how to use them.&lt;/p&gt;
&lt;p&gt;Instead, I'll be focusing these posts on how the concurrent collections are implemented; how they achieve thread-safety and the principles behind their implementation. Not only because I find that sort of thing quite interesting, but also to give you ideas about how you might use these principles in your own code.&lt;/p&gt;
&lt;p&gt;Note however, that writing bulletproof thread-safe collections is &lt;em&gt;hard&lt;/em&gt;. &lt;em&gt;Really&lt;/em&gt; hard. Think carefully about somehow using one of the existing collections before trying to write or adapt your own.&lt;/p&gt;

&lt;h4&gt;What is a 'thread-safe' collection?&lt;/h4&gt;
&lt;p&gt;First of all, we need to understand what we mean by 'thread-safe'. Well, let's start with the repository of all human knowledge - &lt;a href="http://en.wikipedia.org/wiki/Thread_safety"&gt;wikipedia&lt;/a&gt;:
&lt;/p&gt;&lt;blockquote&gt;A piece of code is thread-safe if it only manipulates shared data structures in a manner that guarantees safe execution by multiple threads at the same time&lt;/blockquote&gt;
OK, well, as an example, if &lt;code&gt;m_Collection&lt;/code&gt; is some sort of 'thread-safe' &lt;code&gt;ICollection&lt;/code&gt;, what will the result of these two threads running concurrently do?&lt;p&gt;&lt;/p&gt;
&lt;table&gt;
    &lt;tr&gt;
        &lt;th&gt;Thread 1&lt;/th&gt;
        &lt;th&gt;Thread 2&lt;/th&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td&gt;&lt;pre&gt;m_Collection.Add(m_Item);&lt;/pre&gt;&lt;/td&gt;
        &lt;td&gt;&lt;pre&gt;bool removed = m_Collection.Remove(m_Item);&lt;/pre&gt;&lt;/td&gt;
    &lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;The answer depends on exactly which order Thread 1 and Thread 2 run with respect to each other. So, whether &lt;code&gt;m_Item&lt;/code&gt; is in &lt;code&gt;m_Collection&lt;/code&gt; after these two threads have run depends entirely on the whim of the operating system. Thread 2 could try and remove an item that's not in the collection, setting &lt;code&gt;removed&lt;/code&gt; to false, then Thread 1 adds the item to the collection. Or Thread 1 could run first, adding the item, which is then immediately removed by Thread 2, setting &lt;code&gt;removed&lt;/code&gt; to true. Thread 1 could then merrily carry on executing, assuming &lt;code&gt;m_Item&lt;/code&gt; is in &lt;code&gt;m_Collection&lt;/code&gt;, not knowing it's been immediately removed by Thread 2.&lt;/p&gt;
&lt;p&gt;That, however, is an implementation detail of whoever wrote the code for Thread 1 and Thread 2. The important thing is that, after these two threads have run the above code in some order, &lt;code&gt;m_Collection&lt;/code&gt; will either have the item in it, or not; it won't be in some corrupted half-state where some internal datastructures think it has the item and some don't, so that (for example) &lt;code&gt;m_Collection.Contains(m_Item)&lt;/code&gt; returns false but the enumerator still returns the item. So, I propose that this is what is meant by a thread-safe collection:
&lt;/p&gt;&lt;blockquote&gt;A thread-safe collection is one that can be modified by multiple threads at the same time without corrupting itself.&lt;/blockquote&gt;&lt;p&gt;&lt;/p&gt;

&lt;h4&gt;Achieving concurrency&lt;/h4&gt;
&lt;p&gt;There is a very simple way of writing a thread-safe collection - implement &lt;code&gt;ICollection&amp;lt;T&amp;gt;&lt;/code&gt; by wrapping a &lt;code&gt;List&amp;lt;T&amp;gt;&lt;/code&gt; that locks the backing list object on every method call (if you're unclear about what locks are, I'll be covering them below). This means that only one thread can access and modify the backing list at once; thread-safety is therefore maintained. However, this isn't a very good solution; many threads could be blocked by one costly list resize operation. This solution doesn't have very good concurrency.&lt;/p&gt;
&lt;p&gt;Ideally, we want collections that don't keep threads waiting. As we'll see, two of the collections (ConcurrentStack and ConcurrentQueue) achieve thread-safety using no locks at all, and the other collections minimise the chances of two threads blocking on the same lock.

&lt;/p&gt;&lt;h4&gt;Locking and synchronization primitives&lt;/h4&gt;
&lt;p&gt;You can't just create a lockless thread-safe datastructure out of nowhere, you need some underlying support from the hardware, operating system and runtime to achieve this. Before we look at the collections themselves, we need to understand these primitives and what guarantees they provide.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Atomic types&lt;/strong&gt;
&lt;p&gt;Some types in .NET are specified as being 'atomic'. That is, if you change the value of a variable of an atomic type, it is guaranteed to appear to change value instantaneously; another thread won't be able to see the variable 'half-changed'. Object references and primitive types of 4 bytes or shorter are always atomic (ints, chars, booleans, floats etc), but 8-byte primitives are only atomic when running on a 64-bit process. The atomicity of object references is especially important to lockless collections, as we'll see in later posts.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Volatile variables&lt;/strong&gt;
&lt;p&gt;I discussed volatility in a &lt;a href="/community/blogs/simonc/archive/2010/11/24/95830.aspx"&gt;previous post&lt;/a&gt;. To recap, marking a variable as volatile means that:
&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;The JIT compiler won't cache the variable in a cpu register; it will always read and write to it using the original memory location. This is important when multiple threads are changing a variable at the same time, so that any changes made to the variable in one thread are immediately picked up by other threads.&lt;/li&gt;
&lt;li&gt;A read or write to a volatile location introduces a memory barrier at that point, so that other reads and writes won't be reordered with respect to each other. This is important later on, as we'll see.&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Locks&lt;/strong&gt;
&lt;p&gt;Mutual-exclusion locks are one of the more basic synchronization primitives. Each object has a lock associated with it, and by locking on an object you only allow one thread to have 'ownership' of that lock at a time. This allows only one thread to execute the section of code protected by that lock at a time.&lt;/p&gt;
&lt;p&gt;When the currently executing thread 'releases' the lock, another thread (and only one other thread) is then allowed to take control of the lock and execute the protected code. Any other threads waiting to take the lock are blocked and cannot continue executing until it is their turn to take the lock.&lt;/p&gt;
&lt;p&gt;C# has special syntax for locking on an object:&lt;/p&gt;
&lt;pre&gt;private readonly object m_LockObj = new object();

public void SynchronizedMethod() {
    lock (m_LockObj) {
        // protected code
     }
}&lt;/pre&gt;
C# actually compiles this method to something like this:
&lt;pre&gt;public void SynchronizedMethod() {
    bool lockTaken = false;
    object lockObj = m_LockObj;
    
    try {
        System.Threading.Monitor.Enter(lockObj, ref lockTaken);
        // protected code
    }
    finally {
        if (lockTaken)
            System.Threading.Monitor.Exit(lockObj);
    }
}&lt;/pre&gt;
&lt;p&gt;This uses the &lt;a href="http://msdn.microsoft.com/en-us/library/x090d6tf.aspx"&gt;&lt;code&gt;System.Threading.Monitor&lt;/code&gt;&lt;/a&gt; class to implement the lock. The call to &lt;code&gt;Monitor.Enter&lt;/code&gt; blocks the thread until it can take control of the lock, and the lock is released by &lt;code&gt;Monitor.Exit&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;System.Threading.Interlocked&lt;/code&gt;&lt;/strong&gt;
&lt;p&gt;&lt;code&gt;Interlocked&lt;/code&gt; provides various methods for performing operations that wouldn't normally be atomic in an atomic fashion. For example, &lt;a href="http://msdn.microsoft.com/en-us/library/system.threading.interlocked.read.aspx"&gt;&lt;code&gt;Interlocked.Read&lt;/code&gt;&lt;/a&gt; allows an 8-byte &lt;code&gt;long&lt;/code&gt; to be read as an atomic operation (remember, 8-byte primitives are only atomic on 64-bit processes), &lt;a href="http://msdn.microsoft.com/en-us/library/system.threading.interlocked.add.aspx"&gt;&lt;code&gt;Interlocked.Add&lt;/code&gt;&lt;/a&gt; allows you to perform &lt;code&gt;a = a + b&lt;/code&gt; (aka &lt;code&gt;a+=b&lt;/code&gt;) atomically, &lt;a href="http://msdn.microsoft.com/en-us/library/system.threading.interlocked.decrement.aspx"&gt;&lt;code&gt;Interlocked.Decrement&lt;/code&gt;&lt;/a&gt; performs &lt;code&gt;a = a - 1&lt;/code&gt; (aka &lt;code&gt;--a&lt;/code&gt;) atomically, etc.&lt;/p&gt;
&lt;p&gt;The most important of these is &lt;a href="http://msdn.microsoft.com/en-us/library/4wx2c0dx.aspx"&gt;&lt;code&gt;Interlocked.CompareExchange&lt;/code&gt;&lt;/a&gt;. This family of methods performs the following operation atomically (using the generic overload as an example):&lt;/p&gt;
&lt;pre&gt;public static T CompareExchange&amp;lt;T&amp;gt;(ref T location, T value, T comparand)
  where T : class {
    T originalValue = location;
    if (location == comparand)
        location = value;
    return originalValue;
}&lt;/pre&gt;
&lt;p&gt;This might not seem like a particularly useful atomic operation, but it is crucial to the lockless collections, as we'll see.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;System.Threading.SpinWait&lt;/code&gt;&lt;/strong&gt;
&lt;p&gt;Introduced in .NET 4, this structure encapsulates the idea of a 'spinwait':
&lt;/p&gt;&lt;pre&gt;while (!variableThatShouldBeTrueToContinue) {}&lt;/pre&gt;
&lt;p&gt;This keeps the thread continually spinning round the while loop, repeatedly checking whether another thread has set &lt;code&gt;variableThatShouldBeTrueToContinue&lt;/code&gt; to true. However, performing such a spinwait gives no guarantees that the thread that is meant to set &lt;code&gt;variableThatShouldBeTrueToContinue&lt;/code&gt; will be given the chance to execute; the operating system could, if it wishes, simply keep on executing the spinwait and not switch to other threads that actually change this variable.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;System.Threading.SpinWait&lt;/code&gt; gets round this problem by, as well as simply spinning, occasionally calling &lt;code&gt;Thread.Sleep&lt;/code&gt; and &lt;code&gt;Thread.Yield&lt;/code&gt;. This will respectively encourage and force the operating system to execute other threads, giving a chance for the spinning condition to be satisfied.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h4&gt;Using the concurrent collections&lt;/h4&gt;
&lt;p&gt;At this point it's also worth pointing out that using a thread-safe collection will not make the rest of your code thread-safe and free of race conditions; it is not a panacea. As in the example at the top of this post, using a thread-safe collection does not stop a race condition between adding and removing the same item from the collection. Using a thread-safe collection simply means you have one less thing to worry about when writing threaded code. You still have the rest of your code to worry about!&lt;/p&gt;

&lt;p&gt;That's it for introductions; in the &lt;a href="/community/blogs/simonc/archive/2012/01/12/105370.aspx"&gt;next post&lt;/a&gt;, we'll look at the simplest of the concurrent collections, &lt;code&gt;ConcurrentStack&lt;/code&gt;.&lt;/p&gt;&lt;img src="http://www.simple-talk.com/community/aggbug.aspx?PostID=105166" width="1" height="1"&gt;</description><category domain="http://www.simple-talk.com/community/blogs/simonc/archive/category/1093.aspx">Inside the Concurrent Collections</category></item><item><title>Using XML to pass lists as parameters in SQL Server </title><link>http://www.simple-talk.com/community/blogs/philfactor/archive/2012/01/05/105167.aspx</link><pubDate>Thu, 05 Jan 2012 02:32:00 GMT</pubDate><guid isPermaLink="false">f46e5dea-70cd-4a69-a7e1-fd07a313bd4d:105167</guid><dc:creator>Phil Factor</dc:creator><slash:comments>10</slash:comments><description>&lt;blockquote&gt;&lt;p&gt;&lt;i&gt;(Updated 14th Jan 2012, and again &lt;/i&gt;&lt;i&gt;26th Jan 2012)&lt;/i&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;Every so often, the question comes up on forums of how to pass a list as a parameter to a SQL
 procedure or function.  There was a time 
that I used to love this question because one could spread so much happiness and gratitude by showing how to parse a comma-delimited 
list into a table. Jeff Moden has probably won the laurels for the ultimate list-parsing TSQL function, the amazing ‘&lt;span&gt;DelimitedSplit8K&lt;/span&gt;’.
&lt;span&gt;&lt;a href="http://www.sommarskog.se/index.html"&gt;Erland Sommarskog&lt;/a&gt; has 
permanently nailed the topic with&lt;/span&gt; a very complete coverage of the various methods for using lists in SQL Server&lt;span&gt; on his website..&lt;/span&gt; With Table-Valued parameters, of course, the necessity for having any lists 
in SQL Server is enormously reduced, though it still crops up. &lt;/p&gt;
&lt;p&gt;Element-based XML seems, on the surface, to provide a built-in way of handling lists as parameters. No need for all 
those ancillary functions for splitting lists into tables, one might think. Yes, indeed, but be careful of the XQuery 
syntax that you use, as we'll see.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;Let’s just take the very simplest example of taking a list of integers and turning it into a table 
of integers. One can use a simple element-based XML list based on a fragment like this…&lt;br&gt;&lt;br&gt;
&lt;font face="'Courier New', Courier, monospace" size="2"&gt;
&lt;span&gt;&lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&lt;/span&gt;&lt;font color="blue" face="Courier New"&gt;DECLARE&lt;/font&gt; @XMLlist &lt;font color="blue" face="Courier New"&gt;XML&lt;/font&gt;&lt;span&gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&lt;/span&gt;&lt;font color="blue" face="Courier New"&gt;SELECT&lt;/font&gt;&lt;span&gt;&amp;nbsp; &lt;/span&gt;@XMLList
&lt;font color="gray" face="Courier New"&gt;=&lt;/font&gt; &lt;font color="red" face="Courier New"&gt;
'&amp;lt;list&amp;gt;&amp;lt;i&amp;gt;2&amp;lt;/i&amp;gt;&amp;lt;i&amp;gt;4&amp;lt;/i&amp;gt;&amp;lt;i&amp;gt;6&amp;lt;/i&amp;gt;&amp;lt;i&amp;gt;8&amp;lt;/i&amp;gt;&amp;lt;i&amp;gt;10&amp;lt;/i&amp;gt;&amp;lt;i&amp;gt;15&amp;lt;/i&amp;gt;&amp;lt;i&amp;gt;17&amp;lt;/i&amp;gt;&amp;lt;i&amp;gt;21&amp;lt;/i&amp;gt;&amp;lt;/list&amp;gt;'&lt;/font&gt;&lt;/span&gt;&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;…to give a table like this ..&lt;/p&gt;
&lt;p&gt;&lt;font face="'Courier New', Courier, monospace" size="2"&gt;
&lt;span&gt;IDs&lt;/span&gt;&lt;br&gt;&lt;span&gt;-----------&lt;/span&gt;&lt;br&gt;
&lt;span&gt;2&lt;/span&gt;&lt;br&gt;
&lt;span&gt;4&lt;/span&gt;&lt;br&gt;
&lt;span&gt;6&lt;/span&gt;&lt;br&gt;
&lt;span&gt;8&lt;/span&gt;&lt;br&gt;
&lt;span&gt;10&lt;/span&gt;&lt;br&gt;
&lt;span&gt;15&lt;/span&gt;&lt;br&gt;
&lt;span&gt;17&lt;/span&gt;&lt;br&gt;
&lt;span&gt;21&lt;/span&gt;&lt;br&gt;
&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;br&gt;
&lt;span&gt;(8 row(s) affected)&lt;/span&gt;&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;..by using this TSQL expression&lt;/p&gt;
&lt;p&gt; &lt;font color="black" face="'Courier New', Courier, monospace" size="2"&gt;  &lt;span&gt;&amp;nbsp; &lt;/span&gt;
&lt;font color="blue" face="Courier New"&gt;SELECT&lt;/font&gt; x&lt;font color="gray" face="Courier New"&gt;.&lt;/font&gt;y&lt;font color="gray" face="Courier New"&gt;.&lt;/font&gt;value&lt;font color="gray" face="Courier New"&gt;(&lt;/font&gt;&lt;font color="red" face="Courier New"&gt;'.'&lt;/font&gt;&lt;font color="gray" face="Courier New"&gt;,&lt;/font&gt;&lt;font color="red" face="Courier New"&gt;'int'&lt;/font&gt;&lt;font color="gray" face="Courier New"&gt;)&lt;/font&gt;
&lt;font color="blue" face="Courier New"&gt;AS&lt;/font&gt; IDs&lt;span&gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&lt;/span&gt;&lt;font color="blue" face="Courier New"&gt;FROM&lt;/font&gt; @XMLList&lt;font color="gray" face="Courier New"&gt;.&lt;/font&gt;nodes&lt;font color="gray" face="Courier New"&gt;(&lt;/font&gt;&lt;font color="red" face="Courier New"&gt;'/list/i'&lt;/font&gt;&lt;font color="gray" face="Courier New"&gt;)&lt;/font&gt;
&lt;font color="blue" face="Courier New"&gt;AS&lt;/font&gt; x&lt;font color="blue" face="Courier New"&gt; &lt;/font&gt;&lt;font color="gray" face="Courier New"&gt;(&lt;/font&gt; y
&lt;font color="gray" face="Courier New"&gt;)&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;It isn’t as intuitive as a simple comma-delimited list to be sure, but it is bearable. In small 
doses, this shredding of element-based XML lists works fine, but,&amp;lt;added 26th January&amp;gt; using this particular syntax for getting the value of the element &amp;lt;/added 26th January&amp;gt; one soon notices the sigh from the server as the length of the list 
starts to increases into four figures. Try it on a list of a hundred thousand integers and you’ll have time to eat a 
sandwich. &lt;/p&gt;
&lt;p&gt;OK. Let’s do a few measurements and do a graph.&lt;/p&gt;
&lt;p&gt;
&lt;img src="/blogbits/philf/TheFirstGraph.jpg" border="0" height="437" width="602"&gt;&lt;/p&gt;
&lt;p&gt;Jeff Moden’s Split function, scales beautifully as shown by the red line, and it is difficult to 
measure it, it is so quick. The XML eShred technique by contrast, using the element-based list, and this XQuery syntax, exhibits horrible scaling. This sort of
 curve is enough to strike terror into the developer. Just as a comparison, I did 
the process of taking a list and turning it into a table by creating a VALUES expression from the list. Even this took 
longer than Jeff’s function, presumably because of the overhead of compiling the expression. Of course, the comparison 
is rather unfair because this third approach , the ‘Using Values Script’ approach, does no validation, but still one 
wonders what on earth the XML expression is DOING all that time. It must be gazing out the window, reading the paper and 
scratching itself, one assumes. No. Actually, the CPU is warming up on the task, so it involves frantic activity.&lt;/p&gt;
&lt;p&gt;
&lt;img src="/blogbits/philf/TheSecondGraph.jpg" border="0" height="436" width="601"&gt;&lt;/p&gt;
&lt;p&gt;Operations involving XML can be startlingly fast in SQL Server, but this particular critter seems startlingly slow 
once one gets to a three-figure number in the list that you’re turning into a relation that can then be used in SQL 
Expressions. Imagine this getting loose in a production system when someone starts passing more values in the list and 
the database suddenly slows down. How would you track the problem down?&lt;/p&gt;
&lt;p&gt;&amp;lt;added 26th January&amp;gt;The big problem here is one of the expression. As pointed out by a reader of the blog, if you modify the expression slightly to&lt;/p&gt;&lt;p&gt; &lt;font color="black" face="'Courier New', Courier, monospace" size="2"&gt;  &lt;span&gt;&amp;nbsp; &lt;/span&gt;
&lt;font color="blue" face="Courier New"&gt;SELECT&lt;/font&gt; x&lt;font color="gray" face="Courier New"&gt;.&lt;/font&gt;y&lt;font color="gray" face="Courier New"&gt;.&lt;/font&gt;value&lt;font color="gray" face="Courier New"&gt;(&lt;/font&gt;&lt;font color="red" face="Courier New"&gt;'.'&lt;/font&gt;&lt;font color="gray" face="Courier New"&gt;,&lt;/font&gt;&lt;font color="red" face="Courier New"&gt;'int'&lt;/font&gt;&lt;font color="gray" face="Courier New"&gt;)&lt;/font&gt;
&lt;font color="blue" face="Courier New"&gt;AS&lt;/font&gt; IDs&lt;span&gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&lt;/span&gt;&lt;font color="blue" face="Courier New"&gt;FROM&lt;/font&gt; @XMLList&lt;font color="gray" face="Courier New"&gt;.&lt;/font&gt;nodes&lt;font color="gray" face="Courier New"&gt;(&lt;/font&gt;&lt;font color="red" face="Courier New"&gt;'/list/i/text()'&lt;/font&gt;&lt;font color="gray" face="Courier New"&gt;)&lt;/font&gt;
&lt;font color="blue" face="Courier New"&gt;AS&lt;/font&gt; x&lt;font color="blue" face="Courier New"&gt; &lt;/font&gt;&lt;font color="gray" face="Courier New"&gt;(&lt;/font&gt; y
&lt;font color="gray" face="Courier New"&gt;)&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p&gt;The shredding suddenly goes like a rocket&amp;lt;/added 26th January&amp;gt;.&lt;br&gt;&lt;/p&gt;&lt;p&gt;There is a second, and more wordy version of the simple XML list, The attribute-based list. Here&lt;/p&gt;
&lt;p&gt;&lt;font face="'Courier New', Courier, monospace" size="2"&gt;
&lt;font color="blue"&gt;&amp;nbsp;&amp;nbsp; DECLARE &lt;/font&gt;&lt;font color="#434343"&gt;@XMLlist &lt;/font&gt;&lt;font color="blue"&gt;XML&lt;br&gt;&amp;nbsp;&amp;nbsp; SELECT&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#434343"&gt;@XMLList &lt;/font&gt;&lt;font color="blue"&gt;= &lt;/font&gt;&lt;font color="red"&gt;'&amp;lt;list&amp;gt;&amp;lt;y i="2" /&amp;gt;&amp;lt;y i="4" /&amp;gt;&amp;lt;y i="6" /&amp;gt;&amp;lt;y i="8" /&amp;gt;&amp;lt;y i="10" /&amp;gt;&amp;lt;y i="15" /&amp;gt;&amp;lt;y i="17" /&amp;gt;&amp;lt;y i="21" /&amp;gt;&amp;lt;/list&amp;gt;'&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;…to give exactly the same table  ..&lt;/p&gt;
&lt;p&gt;&lt;font face="'Courier New', Courier, monospace" size="2"&gt;
&lt;span&gt;IDs&lt;/span&gt;&lt;br&gt;&lt;span&gt;-----------&lt;/span&gt;&lt;br&gt;
&lt;span&gt;2&lt;/span&gt;&lt;br&gt;
&lt;span&gt;4&lt;/span&gt;&lt;br&gt;
&lt;span&gt;6&lt;/span&gt;&lt;br&gt;
&lt;span&gt;8&lt;/span&gt;&lt;br&gt;
&lt;span&gt;10&lt;/span&gt;&lt;br&gt;
&lt;span&gt;15&lt;/span&gt;&lt;br&gt;
&lt;span&gt;17&lt;/span&gt;&lt;br&gt;
&lt;span&gt;21&lt;/span&gt;&lt;br&gt;
&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;br&gt;
&lt;span&gt;(8 row(s) affected)&lt;/span&gt;&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;by using a very similar syntax like this...&lt;/p&gt;
&lt;p&gt;&lt;font face="'Courier New', Courier, monospace" size="2"&gt;&lt;font color="blue"&gt;&amp;nbsp;&amp;nbsp; SELECT &lt;/font&gt;&lt;font color="black"&gt;x.y.value&lt;/font&gt;&lt;font color="gray"&gt;(&lt;/font&gt;&lt;font color="red"&gt;'@i'&lt;/font&gt;&lt;font color="gray"&gt;,&lt;/font&gt;&lt;font color="red"&gt;'int'&lt;/font&gt;&lt;font color="gray"&gt;)&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/font&gt;&lt;font color="blue"&gt;FROM &lt;/font&gt;&lt;font color="#434343"&gt;@XMLList&lt;/font&gt;&lt;font color="black"&gt;.nodes&lt;/font&gt;&lt;font color="gray"&gt;(&lt;/font&gt;&lt;font color="red"&gt;'list/y'&lt;/font&gt;&lt;font color="gray"&gt;) &lt;/font&gt;&lt;font color="blue"&gt;AS &lt;/font&gt;&lt;font color="black"&gt;x&lt;/font&gt;&lt;font color="gray"&gt;( &lt;/font&gt;&lt;font color="black"&gt;y &lt;/font&gt;&lt;font color="gray"&gt;)&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;'Eh? What difference could this make?', you're wondering. Well, rather a lot, it turns out. Thanks to a reader comment on the first version of this blog 
by &lt;b&gt;wBob&lt;/b&gt;, 
we can reveal that this version scales as well as Jeff's amazing 'split' function. I must admit to being rather 
surprised at the difference in performance of the two. By using the Attribute-based list, or the modified XQuery expression,&amp;nbsp; you can cheerfully pass lists 
of substantial length to procedures without worrying, it seems. It reminded me of an argument I had some years ago with 
a distinguished Database Developer who was advising us all not to use XML-based lists because of their performance 
problems. I'd been using attribute-based&amp;nbsp; lists simply because I copied Bob Beauchamin's example code in 'The 
Book', and hadn't hit any problem. We couldn't convince each other. Perhaps we'd hit this performance difference. &lt;/p&gt;
&lt;p&gt;&amp;lt;added 26th January&amp;gt;We can even improve on this. as Sviridov Konstantin has pointed out, you can tweak it to the point that it goes 
around twice the speed of Jeff's TSQL split function by using syntax like this...&lt;/p&gt;
&lt;p&gt;&lt;font face="'Courier New', Courier, monospace" size="2"&gt;&lt;font color="blue"&gt;&amp;nbsp;&amp;nbsp; SELECT &lt;/font&gt;&lt;font color="black"&gt;x.y.value&lt;/font&gt;&lt;font color="gray"&gt;(&lt;/font&gt;&lt;font color="red"&gt;'.'&lt;/font&gt;&lt;font color="gray"&gt;,&lt;/font&gt;&lt;font color="red"&gt;'int'&lt;/font&gt;&lt;font color="gray"&gt;)&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/font&gt;&lt;font color="blue"&gt;FROM &lt;/font&gt;&lt;font color="#434343"&gt;@XMLList&lt;/font&gt;&lt;font color="black"&gt;.nodes&lt;/font&gt;&lt;font color="gray"&gt;(&lt;/font&gt;&lt;font color="red"&gt;'list/y/@i'&lt;/font&gt;&lt;font color="gray"&gt;) &lt;/font&gt;&lt;font color="blue"&gt;AS &lt;/font&gt;&lt;font color="black"&gt;x&lt;/font&gt;&lt;font color="gray"&gt;( &lt;/font&gt;&lt;font color="black"&gt;y &lt;/font&gt;&lt;font color="gray"&gt;)&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;Which will give a performance comparison with the the TSQL split function. These modified XML shreds must be the fastest non-CLR 
method of&amp;nbsp; transferring list-based data as a variable in SQL. &lt;/p&gt;
&lt;p&gt;&lt;img src="/blogbits/philf/FinalShootout.jpg"&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/added 26th January&amp;gt;XML in 
SQL Server seems to remind me of the old poem by Henry Wadsworth Longfellow. (1807-1882)&lt;/p&gt;
&lt;blockquote&gt;There was a little girl, who had a little curl&lt;br&gt;Right in the middle of her forehead,&lt;br&gt;And 
when she was good, she was very, very good,&lt;br&gt;But when she was bad she was horrid.'.&lt;/blockquote&gt;
&lt;p&gt;Just as a comparison, here is the horrid XML performing against the first attribute-based XML Shred, and the TSQL split function&lt;/p&gt;
&lt;p&gt;&lt;img src="/blogbits/philf/TheThirdGraph.jpg"&gt;&lt;/p&gt;
&lt;p&gt;As always, one should measure everything you can, and take nothing for granted if you have to 
deliver a scalable application. &lt;/p&gt;
&lt;p&gt;Here is the simple code I used to do the metrics. The results were simply pasted into excel and 
graphed. &lt;/p&gt;
&lt;p&gt;&lt;font color="black" face="'Courier New', Courier, monospace" size="2"&gt; 
&lt;font color="green"&gt;--in order to record the timings, we prepare a log.&lt;br&gt;&lt;/font&gt;&lt;font color="blue"&gt;DECLARE &lt;/font&gt;&lt;font color="#434343"&gt;@log &lt;/font&gt;&lt;font color="blue"&gt;TABLE &lt;/font&gt;&lt;font color="gray"&gt;(&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="black"&gt;Log_Id &lt;/font&gt;&lt;font color="blue"&gt;INT &lt;/font&gt;&lt;font color="#434343"&gt;IDENTITY&lt;/font&gt;&lt;font color="gray"&gt;(&lt;/font&gt;&lt;font color="black"&gt;1&lt;/font&gt;&lt;font color="gray"&gt;, &lt;/font&gt;&lt;font color="black"&gt;1&lt;/font&gt;&lt;font color="gray"&gt;),&lt;/font&gt;&lt;font color="black"&gt;TheeVent &lt;/font&gt;&lt;font color="blue"&gt;VARCHAR&lt;/font&gt;&lt;font color="gray"&gt;( &lt;/font&gt;&lt;font color="black"&gt;2000 &lt;/font&gt;&lt;font color="gray"&gt;),&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="black"&gt;[Values] &lt;/font&gt;&lt;font color="blue"&gt;INT&lt;/font&gt;&lt;font color="gray"&gt;, &lt;/font&gt;&lt;font color="black"&gt;CPU &lt;/font&gt;&lt;font color="blue"&gt;FLOAT DEFAULT&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#434343"&gt;@@CPU_BUSY&lt;/font&gt;&lt;font color="gray"&gt;,&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="black"&gt;DateAndTime &lt;/font&gt;&lt;font color="blue"&gt;DATETIME DEFAULT &lt;/font&gt;&lt;font color="magenta"&gt;GETDATE&lt;/font&gt;&lt;font color="gray"&gt;()) ;&lt;br&gt;&lt;/font&gt;&lt;font color="green"&gt;--define working variables&lt;br&gt;&lt;/font&gt;&lt;font color="blue"&gt;DECLARE &lt;/font&gt;&lt;font color="#434343"&gt;@List &lt;/font&gt;&lt;font color="blue"&gt;VARCHAR&lt;/font&gt;&lt;font color="gray"&gt;(&lt;/font&gt;&lt;font color="magenta"&gt;MAX&lt;/font&gt;&lt;font color="gray"&gt;),&lt;/font&gt;&lt;font color="#434343"&gt;@XMLList &lt;/font&gt;&lt;font color="blue"&gt;XML&lt;/font&gt;&lt;font color="gray"&gt;,&lt;/font&gt;&lt;font color="#434343"&gt;@AttributeBasedXMLList &lt;/font&gt;&lt;font color="blue"&gt;XML&lt;/font&gt;&lt;font color="gray"&gt;,&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#434343"&gt;@buildScript &lt;/font&gt;&lt;font color="blue"&gt;VARCHAR&lt;/font&gt;&lt;font color="gray"&gt;(&lt;/font&gt;&lt;font color="magenta"&gt;MAX&lt;/font&gt;&lt;font color="gray"&gt;), &lt;/font&gt;&lt;font color="#434343"&gt;@XMLbuildScript &lt;/font&gt;&lt;font color="blue"&gt;NVARCHAR&lt;/font&gt;&lt;font color="gray"&gt;(&lt;/font&gt;&lt;font color="magenta"&gt;MAX&lt;/font&gt;&lt;font color="gray"&gt;),&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#434343"&gt;@ii &lt;/font&gt;&lt;font color="blue"&gt;INT&lt;/font&gt;&lt;font color="gray"&gt;, &lt;/font&gt;&lt;font color="#434343"&gt;@Values &lt;/font&gt;&lt;font color="blue"&gt;INT&lt;/font&gt;&lt;font color="gray"&gt;;&lt;br&gt;&lt;/font&gt;&lt;font color="green"&gt;--and table variables to receive the results/relations&lt;br&gt;&lt;/font&gt;&lt;font color="blue"&gt;DECLARE &lt;/font&gt;&lt;font color="#434343"&gt;@ByteBucket &lt;/font&gt;&lt;font color="blue"&gt;TABLE &lt;/font&gt;&lt;font color="gray"&gt;(&lt;/font&gt;&lt;font color="black"&gt;TheNumeral &lt;/font&gt;&lt;font color="blue"&gt;INT&lt;/font&gt;&lt;font color="gray"&gt;)&lt;br&gt;&lt;/font&gt;&lt;font color="blue"&gt;DECLARE &lt;/font&gt;&lt;font color="#434343"&gt;@ByteBucket2 &lt;/font&gt;&lt;font color="blue"&gt;TABLE &lt;/font&gt;&lt;font color="gray"&gt;(&lt;/font&gt;&lt;font color="black"&gt;TheNumeral &lt;/font&gt;&lt;font color="blue"&gt;INT&lt;/font&gt;&lt;font color="gray"&gt;)&lt;br&gt;&lt;/font&gt;&lt;font color="blue"&gt;DECLARE &lt;/font&gt;&lt;font color="#434343"&gt;@ByteBucket3 &lt;/font&gt;&lt;font color="blue"&gt;TABLE &lt;/font&gt;&lt;font color="gray"&gt;(&lt;/font&gt;&lt;font color="black"&gt;TheNumeral &lt;/font&gt;&lt;font color="blue"&gt;INT&lt;/font&gt;&lt;font color="gray"&gt;)&lt;br&gt;&lt;/font&gt;&lt;font color="blue"&gt;DECLARE &lt;/font&gt;&lt;font color="#434343"&gt;@ByteBucket4 &lt;/font&gt;&lt;font color="blue"&gt;TABLE &lt;/font&gt;&lt;font color="gray"&gt;(&lt;/font&gt;&lt;font color="black"&gt;TheNumeral &lt;/font&gt;&lt;font color="blue"&gt;INT&lt;/font&gt;&lt;font color="gray"&gt;)&lt;br&gt;&lt;/font&gt;&lt;font color="blue"&gt;DECLARE &lt;/font&gt;&lt;font color="#434343"&gt;@ByteBucket5 &lt;/font&gt;&lt;font color="blue"&gt;TABLE &lt;/font&gt;&lt;font color="gray"&gt;(&lt;/font&gt;&lt;font color="black"&gt;TheNumeral &lt;/font&gt;&lt;font color="blue"&gt;INT&lt;/font&gt;&lt;font color="gray"&gt;)&lt;br&gt;&lt;/font&gt;&lt;font color="blue"&gt;DECLARE &lt;/font&gt;&lt;font color="#434343"&gt;@ByteBucket6 &lt;/font&gt;&lt;font color="blue"&gt;TABLE &lt;/font&gt;&lt;font color="gray"&gt;(&lt;/font&gt;&lt;font color="black"&gt;TheNumeral &lt;/font&gt;&lt;font color="blue"&gt;INT&lt;/font&gt;&lt;font color="gray"&gt;)&lt;br&gt;&lt;/font&gt;&lt;font color="blue"&gt;SET NOCOUNT ON&lt;br&gt;SELECT &lt;/font&gt;&lt;font color="#434343"&gt;@Values&lt;/font&gt;&lt;font color="blue"&gt;=&lt;/font&gt;&lt;font color="black"&gt;1 &lt;/font&gt;&lt;font color="green"&gt;--start with one item in the list&lt;br&gt;&lt;/font&gt;&lt;font color="blue"&gt;WHILE &lt;/font&gt;&lt;font color="#434343"&gt;@Values&lt;/font&gt;&lt;font color="gray"&gt;&amp;lt;&lt;/font&gt;&lt;font color="black"&gt;&lt;/font&gt;&lt;font color="blue"&gt;=&lt;/font&gt;&lt;font color="black"&gt;3000&lt;br&gt;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="blue"&gt;BEGIN&lt;br&gt;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="green"&gt;--build up the list with random integers&lt;br&gt;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="blue"&gt;SELECT &lt;/font&gt;&lt;font color="#434343"&gt;@List&lt;/font&gt;&lt;font color="blue"&gt;=&lt;/font&gt;&lt;font color="red"&gt;'1'&lt;/font&gt;&lt;font color="gray"&gt;,&lt;/font&gt;&lt;font color="#434343"&gt;@ii&lt;/font&gt;&lt;font color="blue"&gt;=&lt;/font&gt;&lt;font color="#434343"&gt;@Values&lt;br&gt;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="blue"&gt;WHILE &lt;/font&gt;&lt;font color="#434343"&gt;@ii&lt;/font&gt;&lt;font color="gray"&gt;&amp;gt;&lt;/font&gt;&lt;font color="black"&gt;1&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="blue"&gt;BEGIN&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;SELECT &lt;/font&gt;&lt;font color="#434343"&gt;@List&lt;/font&gt;&lt;font color="blue"&gt;=&lt;/font&gt;&lt;font color="#434343"&gt;@List&lt;/font&gt;&lt;font color="gray"&gt;+&lt;/font&gt;&lt;font color="red"&gt;','&lt;/font&gt;&lt;font color="gray"&gt;+&lt;/font&gt;&lt;font color="magenta"&gt;CONVERT&lt;/font&gt;&lt;font color="gray"&gt;(&lt;/font&gt;&lt;font color="blue"&gt;VARCHAR&lt;/font&gt;&lt;font color="gray"&gt;(&lt;/font&gt;&lt;font color="black"&gt;3&lt;/font&gt;&lt;font color="gray"&gt;),&lt;/font&gt;&lt;font color="magenta"&gt;CONVERT&lt;/font&gt;&lt;font color="gray"&gt;(&lt;/font&gt;&lt;font color="blue"&gt;INT&lt;/font&gt;&lt;font color="gray"&gt;,&lt;/font&gt;&lt;font color="magenta"&gt;RAND&lt;/font&gt;&lt;font color="gray"&gt;()*&lt;/font&gt;&lt;font color="black"&gt;100&lt;/font&gt;&lt;font color="gray"&gt;))&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="blue"&gt;SELECT &lt;/font&gt;&lt;font color="#434343"&gt;@ii&lt;/font&gt;&lt;font color="blue"&gt;=&lt;/font&gt;&lt;font color="#434343"&gt;@ii&lt;/font&gt;&lt;font color="gray"&gt;-&lt;/font&gt;&lt;font color="black"&gt;1 &lt;/font&gt;&lt;font color="green"&gt;--&amp;nbsp;&amp;nbsp;.. to the required length&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="blue"&gt;END&lt;br&gt;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="green"&gt;--and pre-prepare the XML List and VALUES script&lt;br&gt;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="blue"&gt;SELECT &lt;/font&gt;&lt;font color="#434343"&gt;@XMLList&lt;/font&gt;&lt;font color="blue"&gt;=&lt;/font&gt;&lt;font color="red"&gt;'&amp;lt;list&amp;gt;&amp;lt;i&amp;gt;'&lt;/font&gt;&lt;font color="gray"&gt;+&lt;/font&gt;&lt;font color="magenta"&gt;REPLACE&lt;/font&gt;&lt;font color="gray"&gt;(&lt;/font&gt;&lt;font color="#434343"&gt;@List&lt;/font&gt;&lt;font color="gray"&gt;,&lt;/font&gt;&lt;font color="red"&gt;','&lt;/font&gt;&lt;font color="gray"&gt;,&lt;/font&gt;&lt;font color="red"&gt;'&amp;lt;/i&amp;gt;&amp;lt;i&amp;gt;'&lt;/font&gt;&lt;font color="gray"&gt;)+&lt;/font&gt;&lt;font color="red"&gt;'&amp;lt;/i&amp;gt;&amp;lt;/list&amp;gt;'&lt;br&gt;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="blue"&gt;SELECT &lt;/font&gt;&lt;font color="#434343"&gt;@BuildScript&lt;/font&gt;&lt;font color="blue"&gt;=&lt;/font&gt;&lt;font color="red"&gt;'SELECT x FROM (values ('&lt;/font&gt;&lt;font color="gray"&gt;+&lt;/font&gt;&lt;font color="magenta"&gt;REPLACE&lt;/font&gt;&lt;font color="gray"&gt;(&lt;/font&gt;&lt;font color="#434343"&gt;@List&lt;/font&gt;&lt;font color="gray"&gt;,&lt;/font&gt;&lt;font color="red"&gt;','&lt;/font&gt;&lt;font color="gray"&gt;,&lt;/font&gt;&lt;font color="red"&gt;'),('&lt;/font&gt;&lt;font color="gray"&gt;)+&lt;/font&gt;&lt;font color="red"&gt;'))d(x)'&lt;br&gt;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="green"&gt;--and pre-prepare the XML List and VALUES script&amp;nbsp;&amp;nbsp;&lt;br&gt;&lt;/font&gt;&lt;font color="blue"&gt;SELECT &lt;/font&gt;&lt;font color="#434343"&gt;@XMLBuildScript&lt;/font&gt;&lt;font color="blue"&gt;=&lt;/font&gt;&lt;font color="red"&gt;'SELECT @AttributeBasedXMLList = ( SELECT x AS "@x" FROM (values ('&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="gray"&gt;+&lt;/font&gt;&lt;font color="magenta"&gt;REPLACE&lt;/font&gt;&lt;font color="gray"&gt;(&lt;/font&gt;&lt;font color="#434343"&gt;@List&lt;/font&gt;&lt;font color="gray"&gt;,&lt;/font&gt;&lt;font color="red"&gt;','&lt;/font&gt;&lt;font color="gray"&gt;,&lt;/font&gt;&lt;font color="red"&gt;'),('&lt;/font&gt;&lt;font color="gray"&gt;)+&lt;/font&gt;&lt;font color="red"&gt;'))d(x) FOR XML PATH(''y''), ROOT(''root''), TYPE )'&lt;br&gt;&lt;/font&gt;&lt;font color="blue"&gt;EXEC &lt;/font&gt;&lt;font color="darkred"&gt;sp_executesql &lt;/font&gt;&lt;font color="#434343"&gt;@XMLBuildScript&lt;/font&gt;&lt;font color="gray"&gt;, &lt;/font&gt;&lt;font color="red"&gt;N'@AttributeBasedXMLList XML OUT'&lt;/font&gt;&lt;font color="gray"&gt;,&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#434343"&gt;@AttributeBasedXMLList &lt;/font&gt;&lt;font color="black"&gt;OUT&lt;br&gt;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="green"&gt;--try doing the delimited list function&lt;br&gt;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="blue"&gt;INSERT INTO &lt;/font&gt;&lt;font color="#434343"&gt;@log &lt;/font&gt;&lt;font color="gray"&gt;(&lt;/font&gt;&lt;font color="black"&gt;TheEvent&lt;/font&gt;&lt;font color="gray"&gt;, &lt;/font&gt;&lt;font color="black"&gt;[Values]&lt;/font&gt;&lt;font color="gray"&gt;) &lt;/font&gt;&lt;font color="blue"&gt;SELECT &lt;/font&gt;&lt;font color="red"&gt;'Using Split function'&lt;/font&gt;&lt;font color="gray"&gt;,&lt;/font&gt;&lt;font color="#434343"&gt;@Values&lt;br&gt;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="blue"&gt;INSERT INTO &lt;/font&gt;&lt;font color="#434343"&gt;@ByteBucket &lt;/font&gt;&lt;font color="gray"&gt;(&lt;/font&gt;&lt;font color="black"&gt;TheNumeral&lt;/font&gt;&lt;font color="gray"&gt;)&lt;br&gt;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="blue"&gt;SELECT &lt;/font&gt;&lt;font color="black"&gt;item &lt;/font&gt;&lt;font color="blue"&gt;FROM &lt;/font&gt;&lt;font color="black"&gt;dbo.DelimitedSplit8K &lt;/font&gt;&lt;font color="gray"&gt;(&lt;/font&gt;&lt;font color="#434343"&gt;@list&lt;/font&gt;&lt;font color="gray"&gt;,&lt;/font&gt;&lt;font color="red"&gt;','&lt;/font&gt;&lt;font color="gray"&gt;)&lt;br&gt;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="green"&gt;--use the XML Shred trick&lt;br&gt;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="blue"&gt;INSERT INTO &lt;/font&gt;&lt;font color="#434343"&gt;@log &lt;/font&gt;&lt;font color="gray"&gt;(&lt;/font&gt;&lt;font color="black"&gt;TheEvent&lt;/font&gt;&lt;font color="gray"&gt;, &lt;/font&gt;&lt;font color="black"&gt;[Values]&lt;/font&gt;&lt;font color="gray"&gt;) &lt;/font&gt;&lt;font color="blue"&gt;SELECT &lt;/font&gt;&lt;font color="red"&gt;'Element-based XML'&lt;/font&gt;&lt;font color="gray"&gt;,&lt;/font&gt;&lt;font color="#434343"&gt;@Values&lt;br&gt;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="blue"&gt;INSERT INTO &lt;/font&gt;&lt;font color="#434343"&gt;@ByteBucket2 &lt;/font&gt;&lt;font color="gray"&gt;(&lt;/font&gt;&lt;font color="black"&gt;TheNumeral&lt;/font&gt;&lt;font color="gray"&gt;)&lt;br&gt;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="blue"&gt;SELECT &lt;/font&gt;&lt;font color="black"&gt;x.y.value&lt;/font&gt;&lt;font color="gray"&gt;(&lt;/font&gt;&lt;font color="red"&gt;'.'&lt;/font&gt;&lt;font color="gray"&gt;,&lt;/font&gt;&lt;font color="red"&gt;'int'&lt;/font&gt;&lt;font color="gray"&gt;) &lt;/font&gt;&lt;font color="blue"&gt;AS &lt;/font&gt;&lt;font color="black"&gt;IDs&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/font&gt;&lt;font color="blue"&gt;FROM &lt;/font&gt;&lt;font color="#434343"&gt;@XMLList&lt;/font&gt;&lt;font color="black"&gt;.nodes&lt;/font&gt;&lt;font color="gray"&gt;(&lt;/font&gt;&lt;font color="red"&gt;'/list/i'&lt;/font&gt;&lt;font color="gray"&gt;) &lt;/font&gt;&lt;font color="blue"&gt;AS &lt;/font&gt;&lt;font color="black"&gt;x &lt;/font&gt;&lt;font color="gray"&gt;( &lt;/font&gt;&lt;font color="black"&gt;y &lt;/font&gt;&lt;font color="gray"&gt;)&lt;br&gt;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="green"&gt;--use the XML Shred trick&lt;br&gt;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="blue"&gt;INSERT INTO &lt;/font&gt;&lt;font color="#434343"&gt;@log &lt;/font&gt;&lt;font color="gray"&gt;(&lt;/font&gt;&lt;font color="black"&gt;TheEvent&lt;/font&gt;&lt;font color="gray"&gt;, &lt;/font&gt;&lt;font color="black"&gt;[Values]&lt;/font&gt;&lt;font color="gray"&gt;) &lt;/font&gt;&lt;font color="blue"&gt;SELECT &lt;/font&gt;&lt;font color="red"&gt;'Element-based XML (text())'&lt;/font&gt;&lt;font color="gray"&gt;,&lt;/font&gt;&lt;font color="#434343"&gt;@Values&lt;br&gt;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="blue"&gt;INSERT INTO &lt;/font&gt;&lt;font color="#434343"&gt;@ByteBucket6 &lt;/font&gt;&lt;font color="gray"&gt;(&lt;/font&gt;&lt;font color="black"&gt;TheNumeral&lt;/font&gt;&lt;font color="gray"&gt;)&lt;br&gt;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="blue"&gt;SELECT &lt;/font&gt;&lt;font color="black"&gt;x.y.value&lt;/font&gt;&lt;font color="gray"&gt;(&lt;/font&gt;&lt;font color="red"&gt;'.'&lt;/font&gt;&lt;font color="gray"&gt;,&lt;/font&gt;&lt;font color="red"&gt;'int'&lt;/font&gt;&lt;font color="gray"&gt;) &lt;/font&gt;&lt;font color="blue"&gt;AS &lt;/font&gt;&lt;font color="black"&gt;IDs&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/font&gt;&lt;font color="blue"&gt;FROM &lt;/font&gt;&lt;font color="#434343"&gt;@XMLList&lt;/font&gt;&lt;font color="black"&gt;.nodes&lt;/font&gt;&lt;font color="gray"&gt;(&lt;/font&gt;&lt;font color="red"&gt;'/list/i/text()'&lt;/font&gt;&lt;font color="gray"&gt;) &lt;/font&gt;&lt;font color="blue"&gt;AS &lt;/font&gt;&lt;font color="black"&gt;x &lt;/font&gt;&lt;font color="gray"&gt;( &lt;/font&gt;&lt;font color="black"&gt;y &lt;/font&gt;&lt;font color="gray"&gt;)&lt;br&gt;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="green"&gt;--try the VALUES method&lt;br&gt;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="blue"&gt;INSERT INTO &lt;/font&gt;&lt;font color="#434343"&gt;@log &lt;/font&gt;&lt;font color="gray"&gt;(&lt;/font&gt;&lt;font color="black"&gt;TheEvent&lt;/font&gt;&lt;font color="gray"&gt;, &lt;/font&gt;&lt;font color="black"&gt;[Values]&lt;/font&gt;&lt;font color="gray"&gt;) &lt;/font&gt;&lt;font color="blue"&gt;SELECT &lt;/font&gt;&lt;font color="red"&gt;'Using Values script'&lt;/font&gt;&lt;font color="gray"&gt;,&lt;/font&gt;&lt;font color="#434343"&gt;@Values&lt;br&gt;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="blue"&gt;INSERT INTO &lt;/font&gt;&lt;font color="#434343"&gt;@ByteBucket3 &lt;/font&gt;&lt;font color="gray"&gt;(&lt;/font&gt;&lt;font color="black"&gt;TheNumeral&lt;/font&gt;&lt;font color="gray"&gt;)&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="blue"&gt;EXECUTE &lt;/font&gt;&lt;font color="gray"&gt;(&lt;/font&gt;&lt;font color="#434343"&gt;@BuildScript&lt;/font&gt;&lt;font color="gray"&gt;)&lt;br&gt;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="green"&gt;--use the XML Shred trick&lt;br&gt;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="blue"&gt;INSERT INTO &lt;/font&gt;&lt;font color="#434343"&gt;@log &lt;/font&gt;&lt;font color="gray"&gt;(&lt;/font&gt;&lt;font color="black"&gt;TheEvent&lt;/font&gt;&lt;font color="gray"&gt;, &lt;/font&gt;&lt;font color="black"&gt;[Values]&lt;/font&gt;&lt;font color="gray"&gt;) &lt;/font&gt;&lt;font color="blue"&gt;SELECT &lt;/font&gt;&lt;font color="red"&gt;'Attribute-based XML'&lt;/font&gt;&lt;font color="gray"&gt;,&lt;/font&gt;&lt;font color="#434343"&gt;@Values&lt;br&gt;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="blue"&gt;INSERT INTO &lt;/font&gt;&lt;font color="#434343"&gt;@ByteBucket4 &lt;/font&gt;&lt;font color="gray"&gt;(&lt;/font&gt;&lt;font color="black"&gt;TheNumeral&lt;/font&gt;&lt;font color="gray"&gt;)&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="blue"&gt;SELECT &lt;/font&gt;&lt;font color="black"&gt;x.y.value&lt;/font&gt;&lt;font color="gray"&gt;(&lt;/font&gt;&lt;font color="red"&gt;'@x'&lt;/font&gt;&lt;font color="gray"&gt;,&lt;/font&gt;&lt;font color="red"&gt;'int'&lt;/font&gt;&lt;font color="gray"&gt;)&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/font&gt;&lt;font color="blue"&gt;FROM &lt;/font&gt;&lt;font color="#434343"&gt;@AttributeBasedXMLList&lt;/font&gt;&lt;font color="black"&gt;.nodes&lt;/font&gt;&lt;font color="gray"&gt;(&lt;/font&gt;&lt;font color="red"&gt;'root/y'&lt;/font&gt;&lt;font color="gray"&gt;) &lt;/font&gt;&lt;font color="blue"&gt;AS &lt;/font&gt;&lt;font color="black"&gt;x&lt;/font&gt;&lt;font color="gray"&gt;(&lt;/font&gt;&lt;font color="black"&gt;y&lt;/font&gt;&lt;font color="gray"&gt;)&lt;br&gt;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="blue"&gt;INSERT INTO &lt;/font&gt;&lt;font color="#434343"&gt;@log &lt;/font&gt;&lt;font color="gray"&gt;(&lt;/font&gt;&lt;font color="black"&gt;TheEvent&lt;/font&gt;&lt;font color="gray"&gt;, &lt;/font&gt;&lt;font color="black"&gt;[Values]&lt;/font&gt;&lt;font color="gray"&gt;) &lt;/font&gt;&lt;font color="blue"&gt;SELECT &lt;/font&gt;&lt;font color="red"&gt;'finished'&lt;/font&gt;&lt;font color="gray"&gt;,&lt;/font&gt;&lt;font color="#434343"&gt;@Values&lt;br&gt;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="green"&gt;--use the XML Shred trick&lt;br&gt;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="blue"&gt;INSERT INTO &lt;/font&gt;&lt;font color="#434343"&gt;@log &lt;/font&gt;&lt;font color="gray"&gt;(&lt;/font&gt;&lt;font color="black"&gt;TheEvent&lt;/font&gt;&lt;font color="gray"&gt;, &lt;/font&gt;&lt;font color="black"&gt;[Values]&lt;/font&gt;&lt;font color="gray"&gt;) &lt;/font&gt;&lt;font color="blue"&gt;SELECT &lt;/font&gt;&lt;font color="red"&gt;'Attribute-based XML (@)'&lt;/font&gt;&lt;font color="gray"&gt;,&lt;/font&gt;&lt;font color="#434343"&gt;@Values&lt;br&gt;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="blue"&gt;INSERT INTO &lt;/font&gt;&lt;font color="#434343"&gt;@ByteBucket5 &lt;/font&gt;&lt;font color="gray"&gt;(&lt;/font&gt;&lt;font color="black"&gt;TheNumeral&lt;/font&gt;&lt;font color="gray"&gt;)&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="blue"&gt;SELECT &lt;/font&gt;&lt;font color="black"&gt;x.y.value&lt;/font&gt;&lt;font color="gray"&gt;(&lt;/font&gt;&lt;font color="red"&gt;'.'&lt;/font&gt;&lt;font color="gray"&gt;,&lt;/font&gt;&lt;font color="red"&gt;'int'&lt;/font&gt;&lt;font color="gray"&gt;)&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/font&gt;&lt;font color="blue"&gt;FROM &lt;/font&gt;&lt;font color="#434343"&gt;@AttributeBasedXMLList&lt;/font&gt;&lt;font color="black"&gt;.nodes&lt;/font&gt;&lt;font color="gray"&gt;(&lt;/font&gt;&lt;font color="red"&gt;'root/y/@x'&lt;/font&gt;&lt;font color="gray"&gt;) &lt;/font&gt;&lt;font color="blue"&gt;AS &lt;/font&gt;&lt;font color="black"&gt;x&lt;/font&gt;&lt;font color="gray"&gt;(&lt;/font&gt;&lt;font color="black"&gt;y&lt;/font&gt;&lt;font color="gray"&gt;)&lt;br&gt;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="blue"&gt;INSERT INTO &lt;/font&gt;&lt;font color="#434343"&gt;@log &lt;/font&gt;&lt;font color="gray"&gt;(&lt;/font&gt;&lt;font color="black"&gt;TheEvent&lt;/font&gt;&lt;font color="gray"&gt;, &lt;/font&gt;&lt;font color="black"&gt;[Values]&lt;/font&gt;&lt;font color="gray"&gt;) &lt;/font&gt;&lt;font color="blue"&gt;SELECT &lt;/font&gt;&lt;font color="red"&gt;'finished'&lt;/font&gt;&lt;font color="gray"&gt;,&lt;/font&gt;&lt;font color="#434343"&gt;@Values&lt;br&gt;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="blue"&gt;SELECT &lt;/font&gt;&lt;font color="#434343"&gt;@Values&lt;/font&gt;&lt;font color="blue"&gt;=&lt;/font&gt;&lt;font color="#434343"&gt;@Values&lt;/font&gt;&lt;font color="gray"&gt;+&lt;/font&gt;&lt;font color="black"&gt;100&lt;br&gt;&lt;/font&gt;&lt;font color="blue"&gt;END&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br&gt;&lt;br&gt;&lt;/font&gt;&lt;font color="green"&gt;--Yes, we need to check that they all agree!&lt;br&gt;&lt;/font&gt;&lt;font color="blue"&gt;SELECT &lt;/font&gt;&lt;font color="magenta"&gt;COUNT&lt;/font&gt;&lt;font color="gray"&gt;(*), &lt;/font&gt;&lt;font color="magenta"&gt;SUM&lt;/font&gt;&lt;font color="gray"&gt;(&lt;/font&gt;&lt;font color="black"&gt;TheNumeral&lt;/font&gt;&lt;font color="gray"&gt;) &lt;/font&gt;&lt;font color="blue"&gt;FROM &lt;/font&gt;&lt;font color="#434343"&gt;@ByteBucket&lt;br&gt;&lt;/font&gt;&lt;font color="blue"&gt;UNION &lt;/font&gt;&lt;font color="gray"&gt;ALL&lt;br&gt;&lt;/font&gt;&lt;font color="blue"&gt;SELECT &lt;/font&gt;&lt;font color="magenta"&gt;COUNT&lt;/font&gt;&lt;font color="gray"&gt;(*), &lt;/font&gt;&lt;font color="magenta"&gt;SUM&lt;/font&gt;&lt;font color="gray"&gt;(&lt;/font&gt;&lt;font color="black"&gt;TheNumeral&lt;/font&gt;&lt;font color="gray"&gt;) &lt;/font&gt;&lt;font color="blue"&gt;FROM &lt;/font&gt;&lt;font color="#434343"&gt;@ByteBucket2&lt;br&gt;&lt;/font&gt;&lt;font color="blue"&gt;UNION &lt;/font&gt;&lt;font color="gray"&gt;ALL&lt;br&gt;&lt;/font&gt;&lt;font color="blue"&gt;SELECT &lt;/font&gt;&lt;font color="magenta"&gt;COUNT&lt;/font&gt;&lt;font color="gray"&gt;(*), &lt;/font&gt;&lt;font color="magenta"&gt;SUM&lt;/font&gt;&lt;font color="gray"&gt;(&lt;/font&gt;&lt;font color="black"&gt;TheNumeral&lt;/font&gt;&lt;font color="gray"&gt;) &lt;/font&gt;&lt;font color="blue"&gt;FROM &lt;/font&gt;&lt;font color="#434343"&gt;@ByteBucket3&lt;br&gt;&lt;/font&gt;&lt;font color="blue"&gt;UNION &lt;/font&gt;&lt;font color="gray"&gt;ALL&lt;br&gt;&lt;/font&gt;&lt;font color="blue"&gt;SELECT &lt;/font&gt;&lt;font color="magenta"&gt;COUNT&lt;/font&gt;&lt;font color="gray"&gt;(*), &lt;/font&gt;&lt;font color="magenta"&gt;SUM&lt;/font&gt;&lt;font color="gray"&gt;(&lt;/font&gt;&lt;font color="black"&gt;TheNumeral&lt;/font&gt;&lt;font color="gray"&gt;) &lt;/font&gt;&lt;font color="blue"&gt;FROM &lt;/font&gt;&lt;font color="#434343"&gt;@ByteBucket4&lt;br&gt;&lt;/font&gt;&lt;font color="blue"&gt;UNION &lt;/font&gt;&lt;font color="gray"&gt;ALL&lt;br&gt;&lt;/font&gt;&lt;font color="blue"&gt;SELECT &lt;/font&gt;&lt;font color="magenta"&gt;COUNT&lt;/font&gt;&lt;font color="gray"&gt;(*), &lt;/font&gt;&lt;font color="magenta"&gt;SUM&lt;/font&gt;&lt;font color="gray"&gt;(&lt;/font&gt;&lt;font color="black"&gt;TheNumeral&lt;/font&gt;&lt;font color="gray"&gt;) &lt;/font&gt;&lt;font color="blue"&gt;FROM &lt;/font&gt;&lt;font color="#434343"&gt;@ByteBucket5&lt;br&gt;&lt;/font&gt;&lt;font color="blue"&gt;UNION &lt;/font&gt;&lt;font color="gray"&gt;ALL&lt;br&gt;&lt;/font&gt;&lt;font color="blue"&gt;SELECT &lt;/font&gt;&lt;font color="magenta"&gt;COUNT&lt;/font&gt;&lt;font color="gray"&gt;(*), &lt;/font&gt;&lt;font color="magenta"&gt;SUM&lt;/font&gt;&lt;font color="gray"&gt;(&lt;/font&gt;&lt;font color="black"&gt;TheNumeral&lt;/font&gt;&lt;font color="gray"&gt;) &lt;/font&gt;&lt;font color="blue"&gt;FROM &lt;/font&gt;&lt;font color="#434343"&gt;@ByteBucket6&lt;br&gt;&lt;br&gt;&lt;/font&gt;&lt;font color="blue"&gt;SELECT&lt;br&gt;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="black"&gt;TheStart.[Values]&lt;/font&gt;&lt;font color="gray"&gt;,&lt;br&gt;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="magenta"&gt;MAX&lt;/font&gt;&lt;font color="gray"&gt;(&lt;/font&gt;&lt;font color="magenta"&gt;CASE &lt;/font&gt;&lt;font color="blue"&gt;WHEN &lt;/font&gt;&lt;font color="black"&gt;TheStart.TheeVent &lt;/font&gt;&lt;font color="blue"&gt;=&lt;/font&gt;&lt;font color="red"&gt;'Using Split function'&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/font&gt;&lt;font color="blue"&gt;THEN &lt;/font&gt;&lt;font color="magenta"&gt;DATEDIFF&lt;/font&gt;&lt;font color="gray"&gt;( &lt;/font&gt;&lt;font color="black"&gt;ms&lt;/font&gt;&lt;font color="gray"&gt;, &lt;/font&gt;&lt;font color="black"&gt;TheStart.DateAndTime&lt;/font&gt;&lt;font color="gray"&gt;, &lt;/font&gt;&lt;font color="black"&gt;Theend.DateAndTime &lt;/font&gt;&lt;font color="gray"&gt;)&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/font&gt;&lt;font color="blue"&gt;ELSE &lt;/font&gt;&lt;font color="black"&gt;0&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="blue"&gt;END&lt;/font&gt;&lt;font color="gray"&gt;) &lt;/font&gt;&lt;font color="blue"&gt;AS &lt;/font&gt;&lt;font color="black"&gt;[Using Split function]&lt;/font&gt;&lt;font color="gray"&gt;,&lt;br&gt;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="magenta"&gt;MAX&lt;/font&gt;&lt;font color="gray"&gt;(&lt;/font&gt;&lt;font color="magenta"&gt;CASE &lt;/font&gt;&lt;font color="blue"&gt;WHEN &lt;/font&gt;&lt;font color="black"&gt;TheStart.TheeVent &lt;/font&gt;&lt;font color="blue"&gt;=&lt;/font&gt;&lt;font color="red"&gt;'Element-based XML'&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/font&gt;&lt;font color="blue"&gt;THEN &lt;/font&gt;&lt;font color="magenta"&gt;DATEDIFF&lt;/font&gt;&lt;font color="gray"&gt;( &lt;/font&gt;&lt;font color="black"&gt;ms&lt;/font&gt;&lt;font color="gray"&gt;, &lt;/font&gt;&lt;font color="black"&gt;TheStart.DateAnddTime&lt;/font&gt;&lt;font color="gray"&gt;, &lt;/font&gt;&lt;font color="black"&gt;Theend.DateAndTime &lt;/font&gt;&lt;font color="gray"&gt;)&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/font&gt;&lt;font color="blue"&gt;ELSE &lt;/font&gt;&lt;font color="black"&gt;0&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="blue"&gt;END&lt;/font&gt;&lt;font color="gray"&gt;) &lt;/font&gt;&lt;font color="blue"&gt;AS &lt;/font&gt;&lt;font color="black"&gt;[Element-based XML]&lt;/font&gt;&lt;font color="gray"&gt;,&lt;br&gt;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="magenta"&gt;MAX&lt;/font&gt;&lt;font color="gray"&gt;(&lt;/font&gt;&lt;font color="magenta"&gt;CASE &lt;/font&gt;&lt;font color="blue"&gt;WHEN &lt;/font&gt;&lt;font color="black"&gt;TheStart.TheeVent &lt;/font&gt;&lt;font color="blue"&gt;=&lt;/font&gt;&lt;font color="red"&gt;'Using Values script'&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/font&gt;&lt;font color="blue"&gt;THEN &lt;/font&gt;&lt;font color="magenta"&gt;DATEDIFF&lt;/font&gt;&lt;font color="gray"&gt;( &lt;/font&gt;&lt;font color="black"&gt;ms&lt;/font&gt;&lt;font color="gray"&gt;, &lt;/font&gt;&lt;font color="black"&gt;TheStart.DateAndTime&lt;/font&gt;&lt;font color="gray"&gt;, &lt;/font&gt;&lt;font color="black"&gt;Theend.DateAndTime &lt;/font&gt;&lt;font color="gray"&gt;)&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/font&gt;&lt;font color="blue"&gt;ELSE &lt;/font&gt;&lt;font color="black"&gt;0&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="blue"&gt;END&lt;/font&gt;&lt;font color="gray"&gt;) &lt;/font&gt;&lt;font color="blue"&gt;AS &lt;/font&gt;&lt;font color="black"&gt;[Using Values script]&lt;/font&gt;&lt;font color="gray"&gt;,&lt;br&gt;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="magenta"&gt;MAX&lt;/font&gt;&lt;font color="gray"&gt;(&lt;/font&gt;&lt;font color="magenta"&gt;CASE &lt;/font&gt;&lt;font color="blue"&gt;WHEN &lt;/font&gt;&lt;font color="black"&gt;TheStart.TheeVent &lt;/font&gt;&lt;font color="blue"&gt;=&lt;/font&gt;&lt;font color="red"&gt;'Attribute-based XML'&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/font&gt;&lt;font color="blue"&gt;THEN &lt;/font&gt;&lt;font color="magenta"&gt;DATEDIFF&lt;/font&gt;&lt;font color="gray"&gt;( &lt;/font&gt;&lt;font color="black"&gt;ms&lt;/font&gt;&lt;font color="gray"&gt;, &lt;/font&gt;&lt;font color="black"&gt;TheStart.DateAndTime&lt;/font&gt;&lt;font color="gray"&gt;, &lt;/font&gt;&lt;font color="black"&gt;Theend.DateAndTime &lt;/font&gt;&lt;font color="gray"&gt;)&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/font&gt;&lt;font color="blue"&gt;ELSE &lt;/font&gt;&lt;font color="black"&gt;0&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="blue"&gt;END&lt;/font&gt;&lt;font color="gray"&gt;) &lt;/font&gt;&lt;font color="blue"&gt;AS &lt;/font&gt;&lt;font color="black"&gt;[XML Attributes]&lt;/font&gt;&lt;font color="gray"&gt;,&lt;/font&gt;&lt;font color="green"&gt;*/&lt;br&gt;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="magenta"&gt;MAX&lt;/font&gt;&lt;font color="gray"&gt;(&lt;/font&gt;&lt;font color="magenta"&gt;CASE &lt;/font&gt;&lt;font color="blue"&gt;WHEN &lt;/font&gt;&lt;font color="black"&gt;TheStart.TheeVent &lt;/font&gt;&lt;font color="blue"&gt;=&lt;/font&gt;&lt;font color="red"&gt;'Element-based XML (text())'&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/font&gt;&lt;font color="blue"&gt;THEN &lt;/font&gt;&lt;font color="magenta"&gt;DATEDIFF&lt;/font&gt;&lt;font color="gray"&gt;( &lt;/font&gt;&lt;font color="black"&gt;ms&lt;/font&gt;&lt;font color="gray"&gt;, &lt;/font&gt;&lt;font color="black"&gt;TheStart.DateAndTime&lt;/font&gt;&lt;font color="gray"&gt;, &lt;/font&gt;&lt;font color="black"&gt;Theend.DateAndTime &lt;/font&gt;&lt;font color="gray"&gt;)&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/font&gt;&lt;font color="blue"&gt;ELSE &lt;/font&gt;&lt;font color="black"&gt;0&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="blue"&gt;END&lt;/font&gt;&lt;font color="gray"&gt;) &lt;/font&gt;&lt;font color="blue"&gt;AS &lt;/font&gt;&lt;font color="black"&gt;[Element-based XML (text())]&lt;/font&gt;&lt;font color="gray"&gt;,&lt;br&gt;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="magenta"&gt;MAX&lt;/font&gt;&lt;font color="gray"&gt;(&lt;/font&gt;&lt;font color="magenta"&gt;CASE &lt;/font&gt;&lt;font color="blue"&gt;WHEN &lt;/font&gt;&lt;font color="black"&gt;TheStart.TheeVent &lt;/font&gt;&lt;font color="blue"&gt;=&lt;/font&gt;&lt;font color="red"&gt;'Attribute-based XML (@)'&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/font&gt;&lt;font color="blue"&gt;THEN &lt;/font&gt;&lt;font color="magenta"&gt;DATEDIFF&lt;/font&gt;&lt;font color="gray"&gt;( &lt;/font&gt;&lt;font color="black"&gt;ms&lt;/font&gt;&lt;font color="gray"&gt;, &lt;/font&gt;&lt;font color="black"&gt;TheStart.DateAndTime&lt;/font&gt;&lt;font color="gray"&gt;, &lt;/font&gt;&lt;font color="black"&gt;Theend.DateAndTime &lt;/font&gt;&lt;font color="gray"&gt;)&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/font&gt;&lt;font color="blue"&gt;ELSE &lt;/font&gt;&lt;font color="black"&gt;0&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="blue"&gt;END&lt;/font&gt;&lt;font color="gray"&gt;) &lt;/font&gt;&lt;font color="blue"&gt;AS &lt;/font&gt;&lt;font color="black"&gt;[Attribute-based XML (@)]&lt;br&gt;&lt;/font&gt;&lt;font color="blue"&gt;FROM&amp;nbsp;&amp;nbsp; &lt;/font&gt;&lt;font color="#434343"&gt;@log &lt;/font&gt;&lt;font color="black"&gt;TheStart&lt;br&gt;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="blue"&gt;INNER JOIN &lt;/font&gt;&lt;font color="#434343"&gt;@log &lt;/font&gt;&lt;font color="black"&gt;Theend&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="blue"&gt;ON &lt;/font&gt;&lt;font color="black"&gt;Theend.Log_Id &lt;/font&gt;&lt;font color="blue"&gt;= &lt;/font&gt;&lt;font color="black"&gt;TheStart.Log_Id &lt;/font&gt;&lt;font color="gray"&gt;+ &lt;/font&gt;&lt;font color="black"&gt;1&lt;br&gt;&lt;/font&gt;&lt;font color="blue"&gt;WHERE &lt;/font&gt;&lt;font color="black"&gt;TheStart.TheEvent&lt;/font&gt;&lt;font color="gray"&gt;&amp;lt;&lt;/font&gt;&lt;font color="black"&gt;&lt;/font&gt;&lt;font color="gray"&gt;&amp;gt;&lt;/font&gt;&lt;font color="red"&gt;'finished'&lt;br&gt;&lt;/font&gt;&lt;font color="blue"&gt;GROUP BY &lt;/font&gt;&lt;font color="black"&gt;TheStart.[Values]&lt;/font&gt;&lt;font color="gray"&gt;;&lt;br&gt;&lt;br&gt;&lt;/font&gt;&lt;font color="blue"&gt;SELECT&lt;br&gt;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="black"&gt;TheStart.[Values]&lt;/font&gt;&lt;font color="gray"&gt;,&lt;br&gt;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="magenta"&gt;MAX&lt;/font&gt;&lt;font color="gray"&gt;(&lt;/font&gt;&lt;font color="magenta"&gt;CASE &lt;/font&gt;&lt;font color="blue"&gt;WHEN &lt;/font&gt;&lt;font color="black"&gt;TheStart.TheeVent &lt;/font&gt;&lt;font color="blue"&gt;=&lt;/font&gt;&lt;font color="red"&gt;'Using Split function'&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/font&gt;&lt;font color="blue"&gt;THEN &lt;/font&gt;&lt;font color="black"&gt;theEnd.cpu&lt;/font&gt;&lt;font color="gray"&gt;-&lt;/font&gt;&lt;font color="black"&gt;TheStart.cpu&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/font&gt;&lt;font color="blue"&gt;ELSE &lt;/font&gt;&lt;font color="black"&gt;0&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/font&gt;&lt;font color="blue"&gt;END&lt;/font&gt;&lt;font color="gray"&gt;) &lt;/font&gt;&lt;font color="blue"&gt;AS &lt;/font&gt;&lt;font color="black"&gt;[Using Split function]&lt;/font&gt;&lt;font color="gray"&gt;,&lt;br&gt;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="magenta"&gt;MAX&lt;/font&gt;&lt;font color="gray"&gt;(&lt;/font&gt;&lt;font color="magenta"&gt;CASE &lt;/font&gt;&lt;font color="blue"&gt;WHEN &lt;/font&gt;&lt;font color="black"&gt;TheStart.TheeVent &lt;/font&gt;&lt;font color="blue"&gt;=&lt;/font&gt;&lt;font color="red"&gt;'Element-based XML'&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/font&gt;&lt;font color="blue"&gt;THEN &lt;/font&gt;&lt;font color="black"&gt;theEnd.cpu&lt;/font&gt;&lt;font color="gray"&gt;-&lt;/font&gt;&lt;font color="black"&gt;TheStart.cpu&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/font&gt;&lt;font color="blue"&gt;ELSE &lt;/font&gt;&lt;font color="black"&gt;0&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="blue"&gt;END&lt;/font&gt;&lt;font color="gray"&gt;) &lt;/font&gt;&lt;font color="blue"&gt;AS &lt;/font&gt;&lt;font color="black"&gt;[Element-based XML]&lt;/font&gt;&lt;font color="gray"&gt;,&lt;br&gt;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="magenta"&gt;MAX&lt;/font&gt;&lt;font color="gray"&gt;(&lt;/font&gt;&lt;font color="magenta"&gt;CASE &lt;/font&gt;&lt;font color="blue"&gt;WHEN &lt;/font&gt;&lt;font color="black"&gt;TheStart.TheeVent &lt;/font&gt;&lt;font color="blue"&gt;=&lt;/font&gt;&lt;font color="red"&gt;'Using Values script'&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/font&gt;&lt;font color="blue"&gt;THEN &lt;/font&gt;&lt;font color="black"&gt;theEnd.cpu&lt;/font&gt;&lt;font color="gray"&gt;-&lt;/font&gt;&lt;font color="black"&gt;TheStart.cpu&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/font&gt;&lt;font color="blue"&gt;ELSE &lt;/font&gt;&lt;font color="black"&gt;0&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="blue"&gt;END&lt;/font&gt;&lt;font color="gray"&gt;) &lt;/font&gt;&lt;font color="blue"&gt;AS &lt;/font&gt;&lt;font color="black"&gt;[Using Values script]&lt;/font&gt;&lt;font color="gray"&gt;,&lt;br&gt;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="magenta"&gt;MAX&lt;/font&gt;&lt;font color="gray"&gt;(&lt;/font&gt;&lt;font color="magenta"&gt;CASE &lt;/font&gt;&lt;font color="blue"&gt;WHEN &lt;/font&gt;&lt;font color="black"&gt;TheStart.TheeVent &lt;/font&gt;&lt;font color="blue"&gt;=&lt;/font&gt;&lt;font color="red"&gt;'Attribute-based XML'&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/font&gt;&lt;font color="blue"&gt;THEN &lt;/font&gt;&lt;font color="black"&gt;theEnd.cpu&lt;/font&gt;&lt;font color="gray"&gt;-&lt;/font&gt;&lt;font color="black"&gt;TheStart.cpu&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/font&gt;&lt;font color="blue"&gt;ELSE &lt;/font&gt;&lt;font color="black"&gt;0&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="blue"&gt;END&lt;/font&gt;&lt;font color="gray"&gt;) &lt;/font&gt;&lt;font color="blue"&gt;AS &lt;/font&gt;&lt;font color="black"&gt;[XML Attributes]&lt;/font&gt;&lt;font color="gray"&gt;,&lt;br&gt;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="magenta"&gt;MAX&lt;/font&gt;&lt;font color="gray"&gt;(&lt;/font&gt;&lt;font color="magenta"&gt;CASE &lt;/font&gt;&lt;font color="blue"&gt;WHEN &lt;/font&gt;&lt;font color="black"&gt;TheStart.TheeVent &lt;/font&gt;&lt;font color="blue"&gt;=&lt;/font&gt;&lt;font color="red"&gt;'Element-based XML (text())'&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/font&gt;&lt;font color="blue"&gt;THEN &lt;/font&gt;&lt;font color="black"&gt;theEnd.cpu&lt;/font&gt;&lt;font color="gray"&gt;-&lt;/font&gt;&lt;font color="black"&gt;TheStart.cpu&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/font&gt;&lt;font color="blue"&gt;ELSE &lt;/font&gt;&lt;font color="black"&gt;0&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="blue"&gt;END&lt;/font&gt;&lt;font color="gray"&gt;) &lt;/font&gt;&lt;font color="blue"&gt;AS &lt;/font&gt;&lt;font color="black"&gt;[Element-based XML (text())]&lt;/font&gt;&lt;font color="gray"&gt;,&lt;br&gt;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="magenta"&gt;MAX&lt;/font&gt;&lt;font color="gray"&gt;(&lt;/font&gt;&lt;font color="magenta"&gt;CASE &lt;/font&gt;&lt;font color="blue"&gt;WHEN &lt;/font&gt;&lt;font color="black"&gt;TheStart.TheeVent &lt;/font&gt;&lt;font color="blue"&gt;=&lt;/font&gt;&lt;font color="red"&gt;'Attribute-based XML (@)'&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/font&gt;&lt;font color="blue"&gt;THEN &lt;/font&gt;&lt;font color="black"&gt;theEnd.cpu&lt;/font&gt;&lt;font color="gray"&gt;-&lt;/font&gt;&lt;font color="black"&gt;TheStart.cpu&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/font&gt;&lt;font color="blue"&gt;ELSE &lt;/font&gt;&lt;font color="black"&gt;0&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="blue"&gt;END&lt;/font&gt;&lt;font color="gray"&gt;) &lt;/font&gt;&lt;font color="blue"&gt;AS &lt;/font&gt;&lt;font color="black"&gt;[Attribute-based XML (@)]&lt;br&gt;&lt;/font&gt;&lt;font color="blue"&gt;FROM&amp;nbsp;&amp;nbsp; &lt;/font&gt;&lt;font color="#434343"&gt;@log &lt;/font&gt;&lt;font color="black"&gt;TheStart&lt;br&gt;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="blue"&gt;INNER JOIN &lt;/font&gt;&lt;font color="#434343"&gt;@log &lt;/font&gt;&lt;font color="black"&gt;Theend&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="blue"&gt;ON &lt;/font&gt;&lt;font color="black"&gt;Theend.Log_Id &lt;/font&gt;&lt;font color="blue"&gt;= &lt;/font&gt;&lt;font color="black"&gt;TheStart.Log_Id &lt;/font&gt;&lt;font color="gray"&gt;+ &lt;/font&gt;&lt;font color="black"&gt;1&lt;br&gt;&lt;/font&gt;&lt;font color="blue"&gt;WHERE &lt;/font&gt;&lt;font color="black"&gt;TheStart.TheEvent&lt;/font&gt;&lt;font color="gray"&gt;&amp;lt;&lt;/font&gt;&lt;font color="black"&gt;&lt;/font&gt;&lt;font color="gray"&gt;&amp;gt; &lt;/font&gt;&lt;font color="red"&gt;'finished'&lt;br&gt;&lt;/font&gt;&lt;font color="blue"&gt;GROUP BY &lt;/font&gt;&lt;font color="black"&gt;TheStart.[Values]&lt;/font&gt;&lt;font color="gray"&gt;;&lt;br&gt;&lt;br&gt;&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;








&lt;p&gt;&lt;/p&gt;&lt;img src="http://www.simple-talk.com/community/aggbug.aspx?PostID=105167" width="1" height="1"&gt;</description></item><item><title>New Year resolution: A better diet and some home cooking</title><link>http://www.simple-talk.com/community/blogs/jonathanallen/archive/2012/01/02/105074.aspx</link><pubDate>Mon, 02 Jan 2012 03:00:00 GMT</pubDate><guid isPermaLink="false">f46e5dea-70cd-4a69-a7e1-fd07a313bd4d:105074</guid><dc:creator>fatherjack</dc:creator><slash:comments>0</slash:comments><description>Many people reflect on their diet at this time of year and decide to make changes and I would suggest that all DBAs should do the same. This is not because I think any DBA is over-weight (although I'd like to be a bit lighter than I am) but because they should be considering what their SQL Servers are having to consume and how that is affecting their health and performance.  Just like a human that eats too many take-away burgers a server that is working with poor TSQL will become slow to respond...(&lt;a href="http://www.simple-talk.com/community/blogs/jonathanallen/archive/2012/01/02/105074.aspx"&gt;read more&lt;/a&gt;)&lt;img src="http://www.simple-talk.com/community/aggbug.aspx?PostID=105074" width="1" height="1"&gt;</description><category domain="http://www.simple-talk.com/community/blogs/jonathanallen/archive/category/1040.aspx">How To</category><category domain="http://www.simple-talk.com/community/blogs/jonathanallen/archive/category/1048.aspx">Tips and Tricks</category><category domain="http://www.simple-talk.com/community/blogs/jonathanallen/archive/category/1049.aspx">SQLBits</category><category domain="http://www.simple-talk.com/community/blogs/jonathanallen/archive/category/1066.aspx">TSQL</category><category domain="http://www.simple-talk.com/community/blogs/jonathanallen/archive/category/1076.aspx">community</category><category domain="http://www.simple-talk.com/community/blogs/jonathanallen/archive/category/1090.aspx">SQL Relay</category><category domain="http://www.simple-talk.com/community/blogs/jonathanallen/archive/category/1091.aspx">DBA</category></item><item><title>Anatomy of a .NET Assembly - Type forwards</title><link>http://www.simple-talk.com/community/blogs/simonc/archive/2011/12/23/104984.aspx</link><pubDate>Fri, 23 Dec 2011 14:02:00 GMT</pubDate><guid isPermaLink="false">f46e5dea-70cd-4a69-a7e1-fd07a313bd4d:104984</guid><dc:creator>Simon Cooper</dc:creator><slash:comments>0</slash:comments><description>&lt;p&gt;If you've ever had a poke around System.dll or System.Core.dll in Reflector, you may have noticed &lt;code&gt;TypeForwardedToAttributes&lt;/code&gt; applied to the assembly:

&lt;/p&gt;&lt;pre&gt;[assembly: TypeForwardedTo(typeof(Lazy&amp;lt;&amp;gt;))]
[assembly: TypeForwardedTo(typeof(LazyThreadSafetyMode))]
[assembly: TypeForwardedTo(typeof(Action))]
[assembly: TypeForwardedTo(typeof(Action&amp;lt;,&amp;gt;))]
[assembly: TypeForwardedTo(typeof(Action&amp;lt;,,&amp;gt;))]
[assembly: TypeForwardedTo(typeof(Action&amp;lt;,,,&amp;gt;))]&lt;/pre&gt;

This post has a look at what these are, and how they're implemented.

&lt;h4&gt;Type forwards&lt;/h4&gt;
&lt;p&gt;&lt;code&gt;TypeForwardedToAttribute&lt;/code&gt; is part of a feature introduced in .NET 2 - &lt;a href="http://msdn.microsoft.com/en-us/library/ms404275.aspx"&gt;Type forwarding&lt;/a&gt;. As the documentation says, this is a feature that allows a type to be moved to a different assembly without having to recompile assemblies using that type. This is used extensively by the class libraries when types were moved from System.Core.dll to mscorlib.dll between .NET 3.5 and 4, allowing assemblies compiled against .NET 2 and 3.5 to run on the .NET 4 framework as-is, without having to be recompiled.&lt;/p&gt;

&lt;p&gt;However, if you think about it, this is much more than a simple attribute; this is a core change to the CLR type resolution mechanism. Every type that is resolved in an assembly first has to check for the existance of a type forward indicating the type has been moved somewhere else.&lt;/p&gt;
&lt;p&gt;This isn't something that can easily be represented in a simple attribute; &lt;code&gt;TypeForwardedToAttribute&lt;/code&gt; is actually an example of a &lt;a href="/community/blogs/simonc/archive/2010/11/30/95936.aspx"&gt;pseudo custom attribute&lt;/a&gt;.&lt;/p&gt;

&lt;h4&gt;ExportedType&lt;/h4&gt;
&lt;p&gt;First, a bit of background. The &lt;code&gt;ExportedType&lt;/code&gt; metadata table was originally designed to be used in multi-module assemblies as part of the 'public contract' of an assembly; the manifest module for the assembly would contain an entry in &lt;code&gt;ExportedType&lt;/code&gt; for every public type defined in other modules, comprising&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;TypeName&lt;/code&gt; &amp;amp; &lt;code&gt;TypeNamespace&lt;/code&gt;: the exported type's full name&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Implementation&lt;/code&gt;: the module (or nested &lt;code&gt;ExportedType&lt;/code&gt;) the type can be found.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;TypeDefId&lt;/code&gt;: the index within the &lt;code&gt;TypeDef&lt;/code&gt; table in the module the type is located.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This allows any tool referencing the multi-module assembly to only need to look in the manifest module to find every public type defined in the assembly and where it can be found; it doesn't have to scan every module comprising the assembly.&lt;/p&gt;
&lt;p&gt;When .NET 2 came along, &lt;code&gt;ExportedType&lt;/code&gt; was repurposed to store type forwards as well. If &lt;code&gt;Implementation&lt;/code&gt; is a reference to an assembly rather than a module, then that assembly is the new location of the type named by &lt;code&gt;TypeName&lt;/code&gt; and &lt;code&gt;TypeNamespace&lt;/code&gt; (type forwards don't allow you to change the type name or namespace).&lt;/p&gt;

&lt;p&gt;So, when the C# compiler sees a type forward in System.Core.dll specified by the attribute
&lt;/p&gt;&lt;pre&gt;[assembly: TypeForwardedTo(typeof(Action))]&lt;/pre&gt;
the &lt;code&gt;Action&lt;/code&gt; type is resolved using the normal C# type resolution rules to &lt;code&gt;[mscorlib]System.Action&lt;/code&gt;, and the compiler generates an entry in &lt;code&gt;ExportedType&lt;/code&gt; like so:
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;TypeName&lt;/code&gt;: &lt;code&gt;Action&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;TypeNamespace&lt;/code&gt;: &lt;code&gt;System&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Implementation&lt;/code&gt;: assembly reference to &lt;code&gt;mscorlib&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;TypeDefId&lt;/code&gt;: 0 (type forwards don't use this field)&lt;/li&gt;
&lt;/ul&gt;
this entry is then followed by the core CLR type resolution mechanism so that any references to &lt;code&gt;[System.Core]System.Action&lt;/code&gt; are transparently redirected to &lt;code&gt;[mscorlib]System.Action&lt;/code&gt; at runtime; assemblies using the forwarded type don't have to be recompiled.&lt;p&gt;&lt;/p&gt;

&lt;h4&gt;TypeForwardedFrom&lt;/h4&gt;
&lt;p&gt;Finally, &lt;code&gt;TypeForwardedFromAttribute&lt;/code&gt; is the counterpart to &lt;code&gt;TypeForwardedToAttribute&lt;/code&gt;; it specifies the assembly a type has been forwarded from (using an assembly name string, rather than a direct metadata assembly reference). However, unlike &lt;code&gt;TypeForwardedTo&lt;/code&gt;, this is a normal attribute, has no effect on CLR type resolution, and exists primarily for bookkeeping purposes.&lt;/p&gt;

&lt;p&gt;Type forwards may seem like a niche feature aimed at library writers, but they are invaluable in the right circumstances. In the BCL, they allow programs compiled against the .NET 2 and 3.5 frameworks to run on the .NET 4 framework without needing to be recompiled.&lt;/p&gt;&lt;img src="http://www.simple-talk.com/community/aggbug.aspx?PostID=104984" width="1" height="1"&gt;</description><category domain="http://www.simple-talk.com/community/blogs/simonc/archive/category/1070.aspx">Anatomy of a .NET Assembly</category></item><item><title>Continuous profiling for websites</title><link>http://www.simple-talk.com/community/blogs/jamesgilmore/archive/2011/12/20/104902.aspx</link><pubDate>Tue, 20 Dec 2011 14:08:00 GMT</pubDate><guid isPermaLink="false">f46e5dea-70cd-4a69-a7e1-fd07a313bd4d:104902</guid><dc:creator>jamesg</dc:creator><slash:comments>0</slash:comments><description>&lt;p&gt;&lt;i&gt;The .NET division at Red Gate have been working on a new way of profiling ASP.NET applications.&lt;/i&gt;&lt;/p&gt;
&lt;p&gt;Traditional profiling tools live on the developer's workstation and run in short bursts while the developer wrestles with a particular performance problem. If you’re a web developer, you’ll start and stop WebDev or IIS Express, or maybe a local installation of IIS, as part of an edit-&amp;gt;compile-&amp;gt;deploy-&amp;gt;profile cycle. These profilers give you a source code view of where time is being spent, generally with method-level timings. But collecting the data in bursts this way can be cumbersome, and continuous monitoring tools, of the kind sysadmins currently use, seldom give you much detail about which part of the code is performing badly.&lt;/p&gt;
&lt;p&gt;Another problem when profiling ASP.NET is that when something runs slowly the developer has to recreate the issue locally; attaching to a process on a running production server may be impossible, and restarting it to hook in a profiler is seldom permitted (or wise). Even getting access to a test machine can sometimes be problematic. Worse, these issues are rarely reproducible in a simple way – the website slows to a crawl, the administrator restarts IIS, everything is fine…and many of the clues required to fix the issue have been destroyed.&lt;/p&gt;
&lt;p&gt;We wanted to make a tool to solve these problems: an "always-on" method-level profiler that runs as part of IIS and automatically records call-stack data for any application pools, giving you quick and easy access to the results. With continuous profiling, you can collect information at (and before) the point of failure, an approach much likelier to lead to a successful fix. Continuous profiling on your development machine gets less cumbersome, as edit-&amp;gt;compile-&amp;gt;deploy-&amp;gt;profile becomes simply edit-&amp;gt;compile-&amp;gt;deploy. And you get real performance data throughout.&lt;/p&gt;
&lt;h1&gt;How does it work and what will it do to my system?&lt;/h1&gt;
&lt;p&gt;At first I was slightly daunted by the prospect of testing something that would live inside IIS – it felt like being asked to test the software for a pacemaker – but in fact the continuous profiler is a lot less invasive than standard profilers. It’s pretty much a passive listener, there’s no clever rewriting of IL or function detours, or anything that actually modifies the website under test. That’s not to say it’s perfect yet – it’s running in the IIS process, it’s unmanaged code (as profilers have to be, to sit outside the CLR), and it’s very, very new. On the other hand, our internal web team have been running it for several weeks on their test servers and it’s easy to disable from the IIS control panel.&lt;/p&gt;
&lt;p&gt;Continuous profiling works by installing an IIS module that loads before the CLR. .NET is then configured to load the profiler DLL (or ‘core’) into w3wp.exe before the profiled website begins to execute. Our DLL can then record results for our web UI to read and display.&lt;/p&gt;
&lt;h2&gt;Will it make everything slow?&lt;/h2&gt;
&lt;p&gt;ANTS Performance Profiler will automatically hide insignificant methods (defined in terms of the number of instructions and amount of branching they contain, and the contribution they make to the total time), and we’re continuing to tune performance as we develop the tool. We’re currently exploring ways to reduce this even more, like functionality that lets you exclude high-overhead methods from profiling, for example. Meanwhile, you can expect your website to be perfectly usable while it’s being profiled, although overhead can vary depending on the nature of the site. Unsurprisingly, something held together with JavaScript will take less of a hit than something more traditionally server-side.&lt;/p&gt;
&lt;h2&gt;What can I expect to see?&lt;/h2&gt;
&lt;p&gt;The interface is designed to help you find and explore performance bottlenecks quickly. At the top there’s a zoomable timeline with a graph of CPU usage and underneath there’s another timeline showing all the available data. When a region of time is selected, the main body of the webpage will display an expandable call-tree showing the time spent in each method, the cumulative time spent with all children of that method, and the hit count. If you’ve used Red Gate’s ANTS Performance Profiler before, the layout will be very familiar.
Not all the planned features are complete yet – you can pick up our nightly builds to get new functionality as we release it!&lt;/p&gt;
&lt;p&gt;&lt;img src="/blogbits/net/JamesGblog.jpg"&gt;&lt;/p&gt;
&lt;h2&gt;Where do I get it?&lt;/h2&gt;
&lt;p&gt;The Early Access Program is now open. To participate, just download a build from
&lt;a href="http://help.red-gate.com/help/ANTSPerformanceProfiler/download_eap.html"&gt;http://help.red-gate.com/help/ANTSPerformanceProfiler/download_eap.html&lt;/a&gt;, and let us know what you think. We look forward to hearing your comments.&lt;/p&gt;&lt;img src="http://www.simple-talk.com/community/aggbug.aspx?PostID=104902" width="1" height="1"&gt;</description></item><item><title>What Counts For A DBA: Humbug!</title><link>http://www.simple-talk.com/community/blogs/drsql/archive/2011/12/20/104884.aspx</link><pubDate>Tue, 20 Dec 2011 06:00:00 GMT</pubDate><guid isPermaLink="false">f46e5dea-70cd-4a69-a7e1-fd07a313bd4d:104884</guid><dc:creator>drsql</dc:creator><slash:comments>0</slash:comments><description>&lt;DIV&gt;&lt;SPAN&gt;If you have seen the movie ‘The Christmas Carol’, you will remember that the evil bank owner Ebenezer Scrooge is not a proponent of the holiday season, claiming Christmas to be "a poor excuse for picking a man's pocket every twenty-fifth of December" and doesn't even want his employee Bob Cratchet to miss work on Christmas Day; work that involves foreclosing on his customers who no doubt spent their money on the holiday merriment instead of the mortgage. If you are unfamiliar with the story, I won't spoil how it happens, but in the end, not surprisingly, his heart softens to the ordeal, gives Bob the day off and a big raise. However, even Scrooge 2.0's head would have exploded at how much time his employee would be spending on the festivities nowadays.&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN&gt;&amp;nbsp;&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/DIV&gt;
&lt;P&gt;&lt;SPAN&gt;During the holiday season (more or less all of December and a bit of the surrounding months), the productivity of the average worker falls off to dangerously anemic levels. Preparations for parties, travel, shopping, office decorating, gift exchanging, vacations, team volunteering outings for Toys for Tots/Rescue Mission etc. and other seasonal activities encroach heavily upon the employee's attention.&lt;SPAN&gt;&amp;nbsp; &lt;/SPAN&gt;Most companies are complicit with this, organizing several holiday parties (team, department, division, company, SQL User Group), and in some companies this means that employees come back to work the next day a bit tired, or worst case, don't come to work the next due to what is claimed to be a mysterious fruitcake related illness (&lt;/SPAN&gt;&lt;A href="http://stevecla.posterous.com/how-drunk-can-you-get-at-your-office-xmas-par"&gt;&lt;SPAN&gt;&lt;FONT color=#0000ff&gt;we know the truth though)&lt;/FONT&gt;&lt;/SPAN&gt;&lt;/A&gt;&lt;SPAN&gt;. With productivity so low, many employees save up their vacation and take most of the month of December off in order to escape the frustration of getting work done in December, thereby multiplying the effect.&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN&gt;&amp;nbsp;&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&lt;SPAN&gt;However, all of these lazy employees, like me, for instance, are not my focus today. Rather, I wish to send a love letter of sorts to the excellent DBAs and consultants who tirelessly support the work that developers like myself have created and forced them to support, regardless of whether Charlie Brown is on TV or not.&lt;SPAN&gt;&amp;nbsp; &lt;/SPAN&gt;Many production DBAs will have to work the holidays, or for the case of the &lt;/SPAN&gt;&lt;A href="/community/blogs/drsql/archive/2011/11/13/104324.aspx"&gt;&lt;SPAN&gt;&lt;FONT color=#0000ff&gt;observant&lt;/FONT&gt;&lt;/SPAN&gt;&lt;/A&gt;&lt;SPAN&gt; DBA, carry around electronic leashes to be available in case their monitoring software determines there is cause for concern (day or night.) For many there will be issues. As each year passes, we get more and more electronic devices being used around the word that require the Internet to operate twenty four hours a day, since Christmas Day in one part of the word is Christmas Eve in another, and just another work day for still more parts of the world.&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN&gt;&amp;nbsp;&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&lt;SPAN&gt;So during this holiday season, when you are leaned back in your favorite sitting place with your bowl of gingerbread cookies and a glass of eggnog (more nog than egg, naturally), with &lt;SPAN&gt;&amp;nbsp;&lt;/SPAN&gt;your new Internet connected phone, tablet, MP3 player, laptop computer, DVR, Internet radio, WiFi Router, TV Remote Control, TV, and &lt;/SPAN&gt;&lt;A href="http://norman.shoso.com/index.php?entry=entry071223-220541"&gt;&lt;SPAN&gt;&lt;FONT color=#0000ff&gt;Toaster&lt;/FONT&gt;&lt;/SPAN&gt;&lt;/A&gt;&lt;SPAN&gt; humming along simultaneously, remember to take a few minutes to think about the production support staff, (especially our beloved DBAs!)&lt;SPAN&gt;&amp;nbsp; &lt;/SPAN&gt;and what they go through when they are the only person available to solve a problem for tens of thousands of customers that will either be the next repeat customer, or the next negative reviewers, all based on just how well they handle the issues that we developers left them. So whether or not the DBA likes it, on Christmas morning they may have to say "humbug!" to the figgy pudding (whatever the heck that is) or perhaps their child's first holiday to diagnose an issue that may have just needed an index that should have been caught in development or testing (by me, no doubt).&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN&gt;&amp;nbsp;&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&lt;SPAN&gt;Happy Holidays to all, and to all a good database design!&lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&lt;SPAN&gt;&lt;/SPAN&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&lt;SPAN&gt;As an added bonus, enjoy the following festive picture by Andrea Benedtti (&lt;A href="http://twitter.com/anbenedetti"&gt;anbenedetti on twitter&lt;/A&gt;), a SQL Server MVP from Italy by running the following SQL Server 2008+ code... &lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&lt;IMG src="http://a.yfrog.com/img738/6813/uvas.png"&gt;&lt;BR&gt;&lt;FONT size=2 face=Arial&gt;Christmas Tree Drawn Using SQL Server Spatial Types&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;SPAN&gt;&lt;FONT size=1 face="Courier New"&gt;/*&lt;BR&gt;********************&lt;BR&gt;Happy SQL Christmas!&lt;BR&gt;********************&lt;BR&gt;Andrea Benedetti, SQL Server MVP&lt;BR&gt;Twitter: @anbenedetti&lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=1 face="Courier New"&gt;*/&lt;BR&gt;&lt;/FONT&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&lt;SPAN&gt;&lt;FONT size=1 face="Courier New"&gt;SET NOCOUNT ON;&lt;BR&gt;/* please choose the level of the tree... :-) */&lt;BR&gt;DECLARE @level smallint = 10;&lt;BR&gt;&lt;BR&gt;DECLARE @i tinyint = 1;&lt;BR&gt;DECLARE @Offset smallint = 10;&lt;BR&gt;DECLARE @x1 smallint = 100;&lt;BR&gt;DECLARE @y1 smallint = 100;&lt;BR&gt;DECLARE @x2 smallint = 150;&lt;BR&gt;DECLARE @y2 smallint = 100;&lt;BR&gt;DECLARE @x3 smallint = 125;&lt;BR&gt;DECLARE @y3 smallint = 115;&lt;BR&gt;DECLARE @x4 smallint = 100;&lt;BR&gt;DECLARE @y4 smallint = 100;&lt;BR&gt;DECLARE @Tree TABLE( Id tinyint IDENTITY(1 , 1) , &lt;BR&gt;Triangle geometry );&lt;BR&gt;DECLARE @Palline TABLE( Id tinyint IDENTITY(1 , 1) , &lt;BR&gt;Ball geometry ); &lt;BR&gt;WHILE @i &amp;lt;= @level&lt;BR&gt;BEGIN&lt;BR&gt;INSERT INTO @Tree( Triangle )&lt;BR&gt;VALUES( geometry::STGeomFromText( 'POLYGON ((' + CAST(@x1 AS varchar( 5 )) + ' ' + CAST(@y1 AS varchar( 5 )) + ',' + CAST(@x2 AS varchar( 5 )) + ' ' + CAST(@y2 AS varchar( 5 )) + ',' + CAST(@x3 AS varchar( 5 )) + ' ' + CAST(@y3 AS varchar( 5 )) + ',' + CAST(@x4 AS varchar( 5 )) + ' ' + CAST(@y4 AS varchar( 5 )) + '))' , 0 ));&lt;BR&gt;INSERT INTO @Palline( Ball )&lt;BR&gt;VALUES( geometry::STGeomFromText( 'POINT(' + CAST(@x1 AS varchar( 5 )) + ' ' + CAST(@y1 AS varchar( 5 )) + ')' , 0 ));&lt;BR&gt;INSERT INTO @Palline( Ball )&lt;BR&gt;VALUES( geometry::STGeomFromText( 'POINT(' + CAST(@x2 AS varchar( 5 )) + ' ' + CAST(@y2 AS varchar( 5 )) + ')' , 0 ));&lt;BR&gt;INSERT INTO @Palline( Ball )&lt;BR&gt;VALUES( geometry::STGeomFromText( 'POINT(' + CAST(@x3 AS varchar( 5 )) + ' ' + CAST(@y3 AS varchar( 5 )) + ')' , 0 ));&lt;BR&gt;&lt;BR&gt;SET @x1-=@Offset;&lt;BR&gt;SET @x2+=@Offset;&lt;BR&gt;SET @x4-=@Offset;&lt;BR&gt;SET @y1-=@Offset;&lt;BR&gt;SET @y2-=@Offset;&lt;BR&gt;SET @y3-=@Offset;&lt;BR&gt;SET @y4-=@Offset;&lt;BR&gt;SET @i+=1;&lt;BR&gt;END;&lt;BR&gt;SET @x1 = @x3 - @Offset;&lt;BR&gt;SET @x2 = @x3 + @Offset;&lt;BR&gt;SET @x3 = @x3 + @Offset;&lt;BR&gt;SET @x4 = @x2;&lt;BR&gt;&lt;BR&gt;INSERT INTO @Tree( Triangle )&lt;BR&gt;VALUES( geometry::STGeomFromText( 'POLYGON ((' + CAST(@x1 AS varchar( 5 )) + ' ' + CAST(@y1 AS varchar( 5 )) + ',' + CAST(@x2 AS varchar( 5 )) + ' ' + CAST(@y2 AS varchar( 5 )) + ',' + CAST(@x2 AS varchar( 5 )) + ' ' + CAST(@y3 AS varchar( 5 )) + ',' + CAST(@x1 AS varchar( 5 )) + ' ' + CAST(@y3 AS varchar( 5 )) + ',' + CAST(@x1 AS varchar( 5 )) + ' ' + CAST(@y1 AS varchar( 5 )) + '))' , 0 ));&lt;BR&gt;&lt;BR&gt;SELECT Triangle&lt;BR&gt;FROM @Tree&lt;BR&gt;UNION ALL&lt;BR&gt;SELECT Ball.STBuffer( 3 )&lt;BR&gt;FROM @Palline;&lt;/FONT&gt;&lt;BR&gt;&lt;/P&gt;&lt;/SPAN&gt;&lt;img src="http://www.simple-talk.com/community/aggbug.aspx?PostID=104884" width="1" height="1"&gt;</description></item><item><title>A suitable present, whatever one's past</title><link>http://www.simple-talk.com/community/blogs/tony_davis/archive/2011/12/15/104830.aspx</link><pubDate>Thu, 15 Dec 2011 17:32:47 GMT</pubDate><guid isPermaLink="false">f46e5dea-70cd-4a69-a7e1-fd07a313bd4d:104830</guid><dc:creator>Tony Davis</dc:creator><slash:comments>14</slash:comments><description>&lt;p&gt;Even DBAs have devoted aunts. They are probably also oblivious to the mental anguish they cause to their relatives in the run-up to Christmas. What would be a suitable gift for someone so deeply in the grip of technophilia that they can tell you the difference between ten apparently identical brands of Smartphone, and have a couple of them stuffed in their pockets? Who then use them to discuss with colleagues the finer points of query-plan caching or buffer-chaining?&lt;/p&gt;  &lt;p&gt;I've got it you cry.some amusing, techno-gadgets! Something they'd want to keep with them, at their desk at work, and maybe be reminded of the source of the gift. We've all seen them: the &lt;a href="http://www.firebox.com/product/1179/USB-Lava-Lamp"&gt;USB lava lamps&lt;/a&gt;, a &lt;a href="http://www.thinkgeek.com/computing/thumb-drives-storage/e659/?srp=34"&gt;Voltron USB drive&lt;/a&gt;, a &lt;a href="http://www.thinkgeek.com/computing/usb-gadgets/cf6d/?srp=13"&gt;USB-heated blanket&lt;/a&gt;, and &lt;a href="http://www.thinkgeek.com/homeoffice/supplies/ebcc/"&gt;toast hand warmers&lt;/a&gt;. No; this stuff might have some value to the type of geek that holes up in a drafty basement, secretly inventing new programming languages, or trying to break the latest record for overclocking a CPU. Many DBAs, however, would open the parcel with a frozen rictus of a smile, a gurgle of feigned delight.&lt;/p&gt;  &lt;p&gt;A bit more imagination is required. So, here is an idea: a &lt;b&gt;USB Home Brew kit&lt;/b&gt;. Plug it into your server or laptop and, with a bit of control software, you can keep the fermentation temperature at a steady 68F, and watch proudly as the brew progresses. Plus, the gentle bubbles of fermentation coupled with the faint odour of malt will be more satisfying, and relaxing, than any lava lamp.&lt;/p&gt;  &lt;p&gt;Could I be wrong? I encourage you to submit your ideas for the most delightful, but yet-to-be-manufactured, Christmas gift for IT professionals. The winner will receive one each of every gift linked in this blog (or equivalent value voucher). Three runners up will receive a gift each.&lt;/p&gt;  &lt;p&gt;Since this is my final Simple-Talk editorial of 2011, I would like to thank everyone for their support over the year, and to wish you all a happy festive season and 2012. I will probably be back in the New Year, depending on how well my new USB Home Brew business takes off.&lt;/p&gt;  &lt;p&gt;Cheers,&lt;/p&gt;  &lt;p&gt;Tony.&lt;/p&gt;&lt;img src="http://www.simple-talk.com/community/aggbug.aspx?PostID=104830" width="1" height="1"&gt;</description></item><item><title>What Counts For a DBA: Practicality</title><link>http://www.simple-talk.com/community/blogs/drsql/archive/2011/12/15/104823.aspx</link><pubDate>Thu, 15 Dec 2011 09:56:00 GMT</pubDate><guid isPermaLink="false">f46e5dea-70cd-4a69-a7e1-fd07a313bd4d:104823</guid><dc:creator>drsql</dc:creator><slash:comments>7</slash:comments><description>&lt;P class=STHeading1&gt;As a data architect, and writer on the same subject, I am completely entrenched in learning and applying the discipline of normalization. When I set my course down the road of great database design, my motto is "&lt;I&gt;Fifth Normal Form or bust&lt;/I&gt;", even if it takes months to finish the design for just a few tables (and, of course, to make sure every table and column is meticulously named). Not much gives me greater pleasure than the beauty of a database that has been honed to a high degree of normalized perfection and that, to the amazement of the many detractors and doubters, also performs magnificently.&lt;o:p&gt;&lt;/o:p&gt;&lt;/P&gt;
&lt;P class=MsoNormal&gt;If this sounds like one of Lewis Carroll's stories, there is good reason for it. The reality is that I don't live in Wonderland, and rarely get time to design anything, much less everything, in meticulous detail. My average project tends to fall into one of two categories&lt;o:p&gt;&lt;/o:p&gt;&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;
&lt;DIV class=STBullet1CxSpFirst&gt;&lt;SPAN class=STBold&gt;&lt;I&gt;&lt;STRONG&gt;The Surprise Project&lt;/STRONG&gt;&lt;/I&gt;&lt;/SPAN&gt; – about 30 seconds after you fall asleep for the night, a mobile device starts dancing to that catchy ringtone that was annoying &lt;A href="/community/blogs/drsql/archive/2011/04/01/101030.aspx"&gt;&lt;FONT color=#0000ff&gt;10 years ago&lt;/FONT&gt;&lt;/A&gt;. Something has failed and it is time to fix it. As long as the problem wasn't caused by you, this can be the most rewarding times of your career, as you put on your Superman Underoos and save the day.&lt;o:p&gt;&lt;/o:p&gt;&lt;/DIV&gt;&lt;/LI&gt;
&lt;LI&gt;
&lt;DIV class=STBullet1CxSpLast&gt;&lt;B&gt;&lt;I&gt;The Incredibly Urgent Project&lt;/I&gt;&lt;/B&gt; – after months of furtive meetings between various marketing and project managers, over the need for some innovative new campaign, advertising scheme, or product line, a decision has finally been made to go ahead. And they need the project to start…&lt;I&gt;immediately&lt;/I&gt;! And the delivery date is…&lt;I&gt;as soon as possible&lt;/I&gt;!&lt;o:p&gt;&lt;/o:p&gt;&lt;/DIV&gt;&lt;/LI&gt;&lt;/UL&gt;
&lt;P class=MsoNormal&gt;My normal workday, as a result, most closely resembles a typical episode of the TV show, Junkyard Wars…"&lt;EM&gt;Contestants, you have just 10 hours to build a fully-working dragster from the contents of this junkyard."&lt;/EM&gt; My favorite team welded together an old motorcycle and a rusty golf cart and went flying down the track. Their solution would never work long enough to survive the complete drag racing season, but it survived 2 trips down the eighth mile. They knew for how long their solution would be used, but most software built like this, with a planned expiration date, usually last years longer than expected.&lt;/P&gt;
&lt;P class=MsoNormal&gt;&lt;o:p&gt;&lt;/o:p&gt; &lt;/P&gt;
&lt;P class=MsoNormal&gt;Many project are like this; get it done quick. The best theoretical solutions need not be posited; your deep and hard-won knowledge of advanced "internals" is of little good to you here. Practical is what is required. When a manager says "as soon as possible", they don't mean "&lt;I&gt;as soon as you can reasonably arrive at the optimum database design and then build a proper solution with stringent application of sound programming principles&lt;/I&gt;". They mean "&lt;I&gt;why haven't you got something to show me, already?&lt;/I&gt;"&lt;/P&gt;
&lt;P class=MsoNormal&gt;&lt;o:p&gt;&lt;/o:p&gt; &lt;/P&gt;
&lt;P class=MsoNormal&gt;The oft-heard battle cry from management is that "Better is the enemy of good enough"; true, but in the wrong hands, very dangerous. Too often, the definition of "good enough" is taken to mean something works to the point that the manager can check a box, no matter the implications to the future user or maintenance workers.&lt;/P&gt;
&lt;P class=MsoNormal&gt;&lt;o:p&gt;&lt;/o:p&gt; &lt;/P&gt;
&lt;P class=MsoNormal&gt;Does this mean that all of your &lt;A href="/community/blogs/drsql/archive/2011/07/12/102328.aspx"&gt;&lt;FONT color=#0000ff&gt;training&lt;/FONT&gt;&lt;/A&gt;, all of your dedication to doing your job the right way, is useless? Not at all; in fact, it is going to be more necessary than ever. Just because your solutions need to be devised with practicality and timeliness as a priority, it doesn't mean that you can actually do things poorly or technical debt will pile up like dirty clothes in a dorm room. It does mean, however, that you need to stop aiming for perfection and start shooting for "good enough", but where good enough implies a practical solution that adopts at least the basic software engineering principles, and a solution that you are comfortable releasing to the users, even in the knowledge that an even better solution was just out of reach.&lt;/P&gt;
&lt;P class=MsoNormal&gt;&lt;o:p&gt;&lt;/o:p&gt; &lt;/P&gt;
&lt;P class=MsoNormal&gt;Almost every solution that is created according to a definition of practical that means "delivered tomorrow" is doomed to be a &lt;A href="/community/blogs/drsql/archive/2011/04/16/101261.aspx"&gt;&lt;FONT color=#0000ff&gt;lesson&lt;/FONT&gt;&lt;/A&gt; for the next project; when practical means "as good as practically possible", everything will usually be alright.&lt;o:p&gt;&lt;/o:p&gt;&lt;/P&gt;&lt;img src="http://www.simple-talk.com/community/aggbug.aspx?PostID=104823" width="1" height="1"&gt;</description></item></channel></rss>
