<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="http://blogs.msdn.com/utility/FeedStylesheets/atom.xsl" media="screen"?><feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en-US"><title type="html">Isaac @ MSDN</title><subtitle type="html" /><id>http://blogs.msdn.com/b/isaac/atom.aspx</id><link rel="alternate" type="text/html" href="http://blogs.msdn.com/b/isaac/" /><link rel="self" type="application/atom+xml" href="http://blogs.msdn.com/b/isaac/atom.aspx" /><generator uri="http://telligent.com" version="5.6.583.21163">Telligent Community 5.6.583.21163 (Build: 5.6.583.21163)</generator><updated>2008-10-09T16:49:27Z</updated><entry><title>StreamInsight 2012 on Academy Live</title><link rel="alternate" type="text/html" href="http://blogs.msdn.com/b/isaac/archive/2012/03/08/streaminsight-2012-on-academy-live.aspx" /><id>http://blogs.msdn.com/b/isaac/archive/2012/03/08/streaminsight-2012-on-academy-live.aspx</id><published>2012-03-08T10:30:00Z</published><updated>2012-03-08T10:30:00Z</updated><content type="html">&lt;p&gt;Hi Folks,&lt;/p&gt;
&lt;p&gt;As part of the SQL Server 2012 launch, I've contributed a presentation on StreamInsight 2.0, which is available either on &lt;a title="TechNet" href="http://technet.microsoft.com/en-us/edge/Video/hh858466"&gt;TechNet &lt;/a&gt;or the &lt;a title="Academy Live" href="https://www.microsoftvirtualacademy.com/tracks/breakthrough-insights-using-microsoft-sql-server-2012-scalable-data-warehouse"&gt;Microsoft Virtual Academy&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;You can get the code associated with the video here &lt;a href="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-55-34-AcadLive2012Demo/2703.Demo.zip"&gt;code&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Enjoy!&lt;br /&gt;-Isaac&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=10263746" width="1" height="1"&gt;</content><author><name>Isaac Kunen</name><uri>http://blogs.msdn.com/isaackunen_4000_stdin.org/ProfileUrlRedirect.ashx</uri></author></entry><entry><title>Map Projections</title><link rel="alternate" type="text/html" href="http://blogs.msdn.com/b/isaac/archive/2011/11/14/map-projections.aspx" /><id>http://blogs.msdn.com/b/isaac/archive/2011/11/14/map-projections.aspx</id><published>2011-11-14T18:43:25Z</published><updated>2011-11-14T18:43:25Z</updated><content type="html">&lt;p&gt;&lt;a href="http://xkcd.com/977/"&gt;Cute!&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;Although I’m guessing that people who really are into maps have a slightly higher view of Mercator than he implies.&lt;/p&gt;  &lt;p&gt;Cheers,   &lt;br /&gt;-Isaac&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=10236922" width="1" height="1"&gt;</content><author><name>Isaac Kunen</name><uri>http://blogs.msdn.com/isaackunen_4000_stdin.org/ProfileUrlRedirect.ashx</uri></author></entry><entry><title>PASS Wrap-Up</title><link rel="alternate" type="text/html" href="http://blogs.msdn.com/b/isaac/archive/2011/10/17/pass-wrap-up.aspx" /><id>http://blogs.msdn.com/b/isaac/archive/2011/10/17/pass-wrap-up.aspx</id><published>2011-10-17T20:46:24Z</published><updated>2011-10-17T20:46:24Z</updated><content type="html">&lt;p&gt;Hi Folks,&lt;/p&gt;  &lt;p&gt;I just wrapped up my &lt;a href="http://www.sqlpass.org/summit/2011/Speakers/CallForSpeakers/SessionDetail.aspx?sid=1911"&gt;talk&lt;/a&gt; the &lt;a href="http://www.sqlpass.org/summit/2011/"&gt;2011 PASS Summit&lt;/a&gt;. Here are a few quick thoughts:&lt;/p&gt;  &lt;p&gt;StreamInsight seems like a technology that could benefit a large number of customers, for a large number of scenarios. But relatively few people even know what SI can do. So although the title of my talks was, “What’s new in Microsoft StreamInsight?”, I turned it into more of a dev-ish, “What the Heck is StreamInsight?” This &lt;em&gt;seemed&lt;/em&gt; successful: people seemed attentive; I got a lot of good questions; very few people waked out—all good signs. I’ll see what the session feedback looks like, and if you have any comments, please paste them here or shoot me an email. I’ll be talking again at &lt;a href="http://devconnections.com/shows/fall2011/default.aspx?s=179"&gt;Connections&lt;/a&gt;, and want to use all the feedback I can to refine that talk.&lt;/p&gt;  &lt;p&gt;I promised folks at the talk that I’d post my code. I’ve cleaned it up a little—added comments and some copyright info to save myself from our legal department—but it really is the code I used during the talk. Hopefully both of these will show up with &lt;a href="http://www.sqlpass.org/summit/2011/Speakers/CallForSpeakers/SessionDetail.aspx?sid=1911"&gt;the talk&lt;/a&gt; on the PASS website, but you can also download my code &lt;a href="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-55-34-PASS2011Demo/1665.PASS-Demo.zip"&gt;here&lt;/a&gt;.&lt;/p&gt;  &lt;p&gt;One final thought: I’ve underestimated how hard it would be to get back in the blogging groove. But I’ll keep trying.&lt;/p&gt;  &lt;p&gt;Cheers,    &lt;br /&gt;-Isaac&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=10226631" width="1" height="1"&gt;</content><author><name>Isaac Kunen</name><uri>http://blogs.msdn.com/isaackunen_4000_stdin.org/ProfileUrlRedirect.ashx</uri></author><category term="streaminsight" scheme="http://blogs.msdn.com/b/isaac/archive/tags/streaminsight/" /></entry><entry><title>Alastair on Spatiotemporal with StreamInsight</title><link rel="alternate" type="text/html" href="http://blogs.msdn.com/b/isaac/archive/2011/08/05/alastair-on-spatiotemporal-with-streaminsight.aspx" /><id>http://blogs.msdn.com/b/isaac/archive/2011/08/05/alastair-on-spatiotemporal-with-streaminsight.aspx</id><published>2011-08-05T18:16:00Z</published><updated>2011-08-05T18:16:00Z</updated><content type="html">&lt;p&gt;Alastair Aitchison has &lt;a href="http://alastaira.wordpress.com/2011/07/31/spatio-temporal-event-processing-with-streaminsight-sql-server-denali-and-bing-maps-part-1/"&gt;started a series&lt;/a&gt; on doing spatiotemporal analysis using StreamInsight and the SQL Server spatial library over on his &lt;a href="http://alastaira.wordpress.com/"&gt;blog&lt;/a&gt;. I&amp;rsquo;ll certainly be watching how he makes out.&lt;/p&gt;
&lt;p&gt;To answer one question he asks in his post: StreamInsight doesn&amp;rsquo;t &lt;em&gt;require &lt;/em&gt;SQL Server Compact, but if you use it for you use it for your &lt;a href="http://msdn.microsoft.com/en-us/library/ff518478.aspx"&gt;metadata provider&lt;/a&gt;, then the server metadata (applications, queries, and the like) will be persisted across restarts. This is required if you want to use &lt;a href="http://blogs.msdn.com/b/isaac/archive/2011/07/25/introducing-checkpointing-in-streaminsight-1-2.aspx"&gt;resiliency&lt;/a&gt; for fairly obvious reasons.&lt;/p&gt;
&lt;p&gt;Cheers, &lt;br /&gt;-Isaac&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=10193231" width="1" height="1"&gt;</content><author><name>Isaac Kunen</name><uri>http://blogs.msdn.com/isaackunen_4000_stdin.org/ProfileUrlRedirect.ashx</uri></author><category term="spatial" scheme="http://blogs.msdn.com/b/isaac/archive/tags/spatial/" /><category term="streaminsight" scheme="http://blogs.msdn.com/b/isaac/archive/tags/streaminsight/" /><category term="spatiotemporal" scheme="http://blogs.msdn.com/b/isaac/archive/tags/spatiotemporal/" /></entry><entry><title>Introducing Checkpointing in StreamInsight 1.2</title><link rel="alternate" type="text/html" href="http://blogs.msdn.com/b/isaac/archive/2011/07/25/introducing-checkpointing-in-streaminsight-1-2.aspx" /><id>http://blogs.msdn.com/b/isaac/archive/2011/07/25/introducing-checkpointing-in-streaminsight-1-2.aspx</id><published>2011-07-25T07:00:00Z</published><updated>2011-07-25T07:00:00Z</updated><content type="html">&lt;p&gt;Hi Folks,&lt;/p&gt;
&lt;p&gt;As I mentioned some a few posts ago, I recently made a move to the StreamInsight team. Well, we&amp;rsquo;ve just released the new version, StreamInsight 1.2, so it&amp;rsquo;s time to start talking about what we&amp;rsquo;ve been up to.&lt;/p&gt;
&lt;p&gt;One of the big features in the new version is resiliency, which helps you build highly available systems that use StreamInsight. This post gives a high-level, no-code overview of what this functionality does and how it can be used. More detailed posts will follow.&lt;/p&gt;
&lt;p&gt;To motivate the feature, consider a few use cases:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;You have a query that consumes sensor data&amp;mdash;say the temperature of a machine&amp;mdash;and computes the average temperature over the last day. It&amp;rsquo;s not the end of the world if StreamInsight were to miss a few minutes of data: the missed events will likely have little impact on the overall average. But if these missed events were caused by an outage, you do care (a) that your app comes back up quickly, (b) that you don&amp;rsquo;t lose the substantial state that was built up for the aggregation, and (c) that the results you get when SI comes back up are &lt;em&gt;close &lt;/em&gt;to what you would have gotten had SI not gone down.&lt;/li&gt;
&lt;/ol&gt;&lt;ol start="2"&gt;
&lt;li&gt;You have a query that consumes Twitter data and sends you email every time someone mentions &lt;a href="http://en.wikipedia.org/wiki/Justin_bieber"&gt;Justin Bieber&lt;/a&gt;. For this query, you have the same requirement (a) for speedy recovery as above, but (b) and (c) are no longer sufficient: you really don&amp;rsquo;t want to miss an important alert should StreamInsight go down. On the other hand, you don't mind getting duplicate alerts. I.e., you want the &lt;em&gt;same&lt;/em&gt; events you would have gotten without the outage&amp;mdash;perhaps with some duplicates.&lt;/li&gt;
&lt;/ol&gt;&lt;ol start="3"&gt;
&lt;li&gt;You have a query that consumes stock price data, and produces trade events based on some secret algorithm. Now you have all of the requirements from the Bieber-bot&amp;mdash;fast recovery, equivalent events&amp;mdash;but now it could be catastrophic if you got duplicate trades. I.e., you want completely equivalent outputs whether or not there was an outage.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The form of resiliency introduced in StreamInsight 1.2 allows SI to take and restore checkpoints. A checkpoint is a serialized form of all of the internal state SI keeps for a query. When SI restarts, it will automatically restart a previously-running query and restore its state from the checkpoint, effectively putting the query at a known point when the checkpoint was taken.&lt;/p&gt;
&lt;p&gt;You can control when checkpoints are taken: take them more frequently and you&amp;rsquo;ll lose less in a crash; take them less frequently and you&amp;rsquo;ll keep the impact on the system low. Let&amp;rsquo;s consider how this would be used in our first use case:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Your query is happily chugging along, and you&amp;rsquo;re asking the system to take a checkpoint every five minutes. At some time&amp;mdash;say 12:59&amp;mdash;some &lt;a href="http://smurfs.wikia.com/wiki/Clumsy_Smurf"&gt;doofus&lt;/a&gt; trips on the power cord of the machine and brings it down. Realizing what he&amp;rsquo;s done, he plugs it back in and restarts everything. At 1:05 everything&amp;rsquo;s ready and he restarts StreamInsight, which reads back the latest checkpoint from 12:55 and is ready to start accepting events again at 1:07. &lt;br /&gt; &lt;br /&gt;In this case, SI was down from 12:59 to 1:07, and all events that should have been received during this time were lost. In addition, all events received between 12:55 and 12:59 were effectively lost as well, since they weren&amp;rsquo;t recorded in the last checkpoint before the system went down. These lost input events may cause missed output events, and can also affect aggregate results that overlap the outage. Still, you&amp;rsquo;re happy because the system is back up, you&amp;rsquo;ve only lost 12 minutes of data, and your long-term aggregates are roughly intact.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Perhaps all of this is fine for a silly temperature reading, but what if someone were to tweet a Bieber sighting during the outage? To avoid missing this critical information, StreamInsight needs some help: something needs to keep track of the events that occurred during the outage, as well as those that occurred before the outage but after the last checkpoint, and be ready to send them along when SI comes back up.&lt;/p&gt;
&lt;p&gt;That something is the input adapter&amp;mdash;or more properly, whatever the input adapter is connected to. In other words, there has to be a component sitting in front of StreamInsight that keeps track of recent events and can replay them for SI. And this component has to be independent and highly available as well.&lt;/p&gt;
&lt;p&gt;If we have this in place, we&amp;rsquo;re ready to tackle our second use case:&lt;/p&gt;
&lt;ol start="2"&gt;
&lt;li&gt;Your query is happily Biebering along, taking checkpoints every minute, but you have a historian sitting in front of your query. This historian is pulling tweets from Twitter and persisting them before sending them on to StreamInsight. As before, our doofus trips over the cable at 12:59 and restarts StreamInsight at 1:05. But now as part of its recovery routine, SI will ask its input adapter to replay the event it&amp;rsquo;s missed and the historian will guarantee that SI will see all that it has missed since 12:55 when it took its last checkpoint. &lt;br /&gt; &lt;br /&gt;And this is great: StreamInsight came back, and you haven&amp;rsquo;t missed a thing. But you notice something funny: the report of Justin&amp;rsquo;s new coif that issued at 12:57 came through twice. Once before the outage, and once after. Why? Because SI forgot that it issued that event before the outage, and when the events replayed, it got issued again.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;And that&amp;rsquo;s not bad. Unless events have consequences&amp;mdash;which is certainly the case with stock trades. To eliminate these duplicates, StreamInsight needs a little more help, this time on the output. As SI produces events, the output adapter&amp;mdash;again, more properly, whatever the output adapter is connected to&amp;mdash;has to remember them.&lt;/p&gt;
&lt;p&gt;When StreamInsight comes back up after an outage, it will essentially tell its output adapters the last time it remembers. It also guarantees that every event that it produced after that time will be produced again. Since the output adapter knows what these events were, it can remove the duplicates when it sees them instead of acting on them. And this is what we need in our third use case:&lt;/p&gt;
&lt;ol start="3"&gt;
&lt;li lt="" li=""&gt;Your query is happily trading away, taking checkpoints every minute. You also have a historian in front of the query recoding stock prices, and a historian on the end recording trades. As before our doofus&amp;mdash;who we have somehow failed to fire&amp;mdash;trips over the cable at 12:59 and restarts things at 1:05. During recovery, StreamInsight gets the input to replay all stock info since 12:55, so no input is missed. It also notifies its output that all trades that happened between 12:55 and the outage will be sent again, so when the duplicate trades are issued, the output adapter just drops them on the floor. &lt;br /&gt; &lt;br /&gt;And now we have full stream equivalence. You don&amp;rsquo;t miss a trade, and you don&amp;rsquo;t get any duplicates.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Hopefully this gives a feel of what&amp;rsquo;s possible with checkpointing. I&amp;rsquo;ll have more to say on specifics over the next few weeks. In the meantime, be sure to pick up &lt;a href="http://www.microsoft.com/download/en/details.aspx?id=26720"&gt;the release&lt;/a&gt;&amp;nbsp;and take a look at the &lt;a href="http://msdn.microsoft.com/en-us/library/ee828711.aspx"&gt;documentation&lt;/a&gt;. And there&amp;rsquo;s a full end-to-end demo available on &lt;a href="http://streaminsight.codeplex.com/releases/view/46435"&gt;CodePlex&lt;/a&gt; as well.&lt;/p&gt;
&lt;p&gt;Cheers, &lt;br /&gt;-Isaac&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=10185585" width="1" height="1"&gt;</content><author><name>Isaac Kunen</name><uri>http://blogs.msdn.com/isaackunen_4000_stdin.org/ProfileUrlRedirect.ashx</uri></author><category term="streaminsight" scheme="http://blogs.msdn.com/b/isaac/archive/tags/streaminsight/" /><category term="resiliency" scheme="http://blogs.msdn.com/b/isaac/archive/tags/resiliency/" /><category term="checkpointing" scheme="http://blogs.msdn.com/b/isaac/archive/tags/checkpointing/" /></entry><entry><title>Collation Hell</title><link rel="alternate" type="text/html" href="http://blogs.msdn.com/b/isaac/archive/2011/05/05/collation-hell.aspx" /><id>http://blogs.msdn.com/b/isaac/archive/2011/05/05/collation-hell.aspx</id><published>2011-05-05T16:00:00Z</published><updated>2011-05-05T16:00:00Z</updated><content type="html">&lt;p&gt;Hi Folks,&lt;/p&gt; &lt;p&gt;I’m going to pick up from &lt;a href="http://blogs.msdn.com/b/isaac/archive/2011/04/20/the-database-shuffle.aspx"&gt;last time&lt;/a&gt; and discuss another major problem with moving databases from one place to another: collations. Some people will have never run into collation issues because they have a consistent collation across all of their environments: they have the same collation on all of their instances, and all databases share that same collation as well.&lt;/p&gt; &lt;p&gt;Others are not so lucky.&lt;/p&gt; &lt;p&gt;Let me illustrate the problem with a few concrete examples. The most common example people encounter involves mismatches between their database collation and the collation used by tempdb. For the purposes of this post, we’ll assume that the tempdb collation is the same as the instance collation. This is not strictly true, but is almost always the case.&lt;/p&gt; &lt;p&gt;Here’s the typical way this rears its ugly head. A developer creates a table and a temp table, and joins the two:&lt;/p&gt;&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;CREATE TABLE &lt;/span&gt;&lt;span style="color: teal"&gt;foo &lt;/span&gt;&lt;span style="color: gray"&gt;(&lt;/span&gt;&lt;span style="color: teal"&gt;x &lt;/span&gt;&lt;span style="color: blue"&gt;varchar&lt;/span&gt;&lt;span style="color: gray"&gt;(&lt;/span&gt;100&lt;span style="color: gray"&gt;))
&lt;/span&gt;&lt;span style="color: blue"&gt;GO
CREATE TABLE &lt;/span&gt;&lt;span style="color: teal"&gt;#bar &lt;/span&gt;&lt;span style="color: gray"&gt;(&lt;/span&gt;&lt;span style="color: teal"&gt;y &lt;/span&gt;&lt;span style="color: blue"&gt;varchar&lt;/span&gt;&lt;span style="color: gray"&gt;(&lt;/span&gt;100&lt;span style="color: gray"&gt;))
&lt;/span&gt;&lt;span style="color: blue"&gt;GO

&lt;/span&gt;&lt;span style="color: green"&gt;-- ...

&lt;/span&gt;&lt;span style="color: blue"&gt;SELECT &lt;/span&gt;&lt;span style="color: teal"&gt;foo&lt;/span&gt;&lt;span style="color: gray"&gt;.&lt;/span&gt;&lt;span style="color: teal"&gt;x&lt;/span&gt;&lt;span style="color: gray"&gt;, &lt;/span&gt;&lt;span style="color: teal"&gt;#bar&lt;/span&gt;&lt;span style="color: gray"&gt;.&lt;/span&gt;&lt;span style="color: teal"&gt;y
&lt;/span&gt;&lt;span style="color: blue"&gt;FROM &lt;/span&gt;&lt;span style="color: teal"&gt;foo &lt;/span&gt;&lt;span style="color: gray"&gt;JOIN &lt;/span&gt;&lt;span style="color: teal"&gt;#bar &lt;/span&gt;&lt;span style="color: blue"&gt;ON &lt;/span&gt;&lt;span style="color: teal"&gt;foo&lt;/span&gt;&lt;span style="color: gray"&gt;.&lt;/span&gt;&lt;span style="color: teal"&gt;x &lt;/span&gt;&lt;span style="color: gray"&gt;= &lt;/span&gt;&lt;span style="color: teal"&gt;#bar&lt;/span&gt;&lt;span style="color: gray"&gt;.&lt;/span&gt;&lt;span style="color: teal"&gt;y&lt;/span&gt;&lt;span style="color: teal"&gt;&lt;/pre&gt;&lt;/span&gt;
&lt;p&gt;When the developer created this, the instance and database had the same collation, say SQL_Latin1_General_CP1_CI_AS. But at some later point, an administrator moved the database to a new instance with a different collation. It doesn’t matter what collation this is, but for purposes of this example, let’s say it was Turkish_100_CI_AI. Now when we create the temp table and perform the join, things don’t go so well:&lt;/p&gt;&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;CREATE TABLE &lt;/span&gt;&lt;span style="color: teal"&gt;#bar &lt;/span&gt;&lt;span style="color: gray"&gt;(&lt;/span&gt;&lt;span style="color: teal"&gt;y &lt;/span&gt;&lt;span style="color: blue"&gt;varchar&lt;/span&gt;&lt;span style="color: gray"&gt;(&lt;/span&gt;100&lt;span style="color: gray"&gt;))
&lt;/span&gt;&lt;span style="color: blue"&gt;GO

&lt;/span&gt;&lt;span style="color: green"&gt;-- ...

&lt;/span&gt;&lt;span style="color: blue"&gt;SELECT &lt;/span&gt;&lt;span style="color: teal"&gt;foo&lt;/span&gt;&lt;span style="color: gray"&gt;.&lt;/span&gt;&lt;span style="color: teal"&gt;x&lt;/span&gt;&lt;span style="color: gray"&gt;, &lt;/span&gt;&lt;span style="color: teal"&gt;#bar&lt;/span&gt;&lt;span style="color: gray"&gt;.&lt;/span&gt;&lt;span style="color: teal"&gt;y
&lt;/span&gt;&lt;span style="color: blue"&gt;FROM &lt;/span&gt;&lt;span style="color: teal"&gt;foo &lt;/span&gt;&lt;span style="color: gray"&gt;JOIN &lt;/span&gt;&lt;span style="color: teal"&gt;#bar &lt;/span&gt;&lt;span style="color: blue"&gt;ON &lt;/span&gt;&lt;span style="color: teal"&gt;foo&lt;/span&gt;&lt;span style="color: gray"&gt;.&lt;/span&gt;&lt;span style="color: teal"&gt;x &lt;/span&gt;&lt;span style="color: gray"&gt;= &lt;/span&gt;&lt;span style="color: teal"&gt;#bar&lt;/span&gt;&lt;span style="color: gray"&gt;.&lt;/span&gt;&lt;span style="color: teal"&gt;y
&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;This results in:&lt;/p&gt;&lt;pre class="code"&gt;Msg 468, Level 16, State 9, Line 5
Cannot resolve the collation conflict between "Turkish_100_CI_AI" and &lt;br&gt;   "SQL_Latin1_General_CP1_CI_AS" in the equal to operation.&lt;/pre&gt;
&lt;p&gt;To get around this, the developer has to rewrite things slightly:&lt;/p&gt;&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;CREATE TABLE &lt;/span&gt;&lt;span style="color: teal"&gt;#bar &lt;/span&gt;&lt;span style="color: gray"&gt;(&lt;/span&gt;&lt;span style="color: teal"&gt;y &lt;/span&gt;&lt;span style="color: blue"&gt;varchar&lt;/span&gt;&lt;span style="color: gray"&gt;(&lt;/span&gt;100&lt;span style="color: gray"&gt;) &lt;/span&gt;&lt;span style="color: blue"&gt;COLLATE &lt;/span&gt;&lt;span style="color: teal"&gt;DATABASE_DEFAULT&lt;/span&gt;&lt;span style="color: gray"&gt;)
&lt;/span&gt;&lt;span style="color: blue"&gt;GO

 &lt;/span&gt;&lt;span style="color: green"&gt;-- ...

&lt;/span&gt;&lt;span style="color: blue"&gt;SELECT &lt;/span&gt;&lt;span style="color: teal"&gt;foo&lt;/span&gt;&lt;span style="color: gray"&gt;.&lt;/span&gt;&lt;span style="color: teal"&gt;x&lt;/span&gt;&lt;span style="color: gray"&gt;, &lt;/span&gt;&lt;span style="color: teal"&gt;#bar&lt;/span&gt;&lt;span style="color: gray"&gt;.&lt;/span&gt;&lt;span style="color: teal"&gt;y
&lt;/span&gt;&lt;span style="color: blue"&gt;FROM &lt;/span&gt;&lt;span style="color: teal"&gt;foo &lt;/span&gt;&lt;span style="color: gray"&gt;JOIN &lt;/span&gt;&lt;span style="color: teal"&gt;#bar &lt;/span&gt;&lt;span style="color: blue"&gt;ON &lt;/span&gt;&lt;span style="color: teal"&gt;foo&lt;/span&gt;&lt;span style="color: gray"&gt;.&lt;/span&gt;&lt;span style="color: teal"&gt;x &lt;/span&gt;&lt;span style="color: gray"&gt;= &lt;/span&gt;&lt;span style="color: teal"&gt;#bar&lt;/span&gt;&lt;span style="color: gray"&gt;.&lt;/span&gt;&lt;span style="color: teal"&gt;y&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;Now things work as we’d like: the COLLATE DATABASE_DEFAULT statement ensures that the collation used for the data in the temp table will match the database, regardless of the instance collation. But it’s unlikely that the developer would have proactively done this, and it’s a pain to do in any case.&lt;/p&gt;
&lt;p&gt;This example is fairly common. I want to emphasize that the next example is not: I have never seen or heard of this happening in the wild; the example was invented by one of our developers to illustrate what &lt;em&gt;could&lt;/em&gt; go wrong. I would be very interested to hear if this has ever occurred for real.&lt;/p&gt;
&lt;p&gt;Alright: let’s blow something up! &lt;/p&gt;
&lt;p&gt;I am going to generate some collation-dependent behavior that manifests in a very bad way. To do this, I first need to identify some collation-dependent behavior, and for this example, I’m going to exploit a difference between Latin1_General and Turkish collations. I’ve chosen this because it’s kind of fun, but you can engineer similar behavior just case sensitivity. Also, to understand what’s going on, remember that variable binding is done using the instance collation. I.e., unlike most languages where there is only one way for variables to bind, in T-SQL you can change this by changing the instance collation.&lt;/p&gt;
&lt;p&gt;So let’s play with the Turkish “I”. Imagine I have variables named @I and @İ. (Note that the first one is a usual “I”, but the second one has a dot.) These are different variables in both Latin1_General and Turkish collations. But what happens if I refer to @i (a little “i” with a dot) and my instance collation is case insensitive? It depends:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;In Latin1_General, @i binds to @I.&lt;/li&gt;
&lt;li&gt;In Turkish, @i binds to @İ.&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;My next step is to amplify this difference a bit:&lt;/p&gt;&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;CREATE FUNCTION &lt;/span&gt;&lt;span style="color: teal"&gt;snafu &lt;/span&gt;&lt;span style="color: gray"&gt;(&lt;/span&gt;&lt;span style="color: teal"&gt;@x &lt;/span&gt;&lt;span style="color: blue"&gt;int&lt;/span&gt;&lt;span style="color: gray"&gt;) &lt;/span&gt;&lt;span style="color: blue"&gt;RETURNS int
WITH SCHEMABINDING
AS
BEGIN
    DECLARE &lt;/span&gt;&lt;span style="color: teal"&gt;@I &lt;/span&gt;&lt;span style="color: blue"&gt;int &lt;/span&gt;&lt;span style="color: gray"&gt;= &lt;/span&gt;1
    &lt;span style="color: blue"&gt;DECLARE &lt;/span&gt;&lt;span style="color: teal"&gt;@İ &lt;/span&gt;&lt;span style="color: blue"&gt;int &lt;/span&gt;&lt;span style="color: gray"&gt;= &lt;/span&gt;2
    &lt;span style="color: blue"&gt;RETURN &lt;/span&gt;&lt;span style="color: teal"&gt;@i &lt;/span&gt;&lt;span style="color: gray"&gt;* &lt;/span&gt;&lt;span style="color: teal"&gt;@x
&lt;/span&gt;&lt;span style="color: blue"&gt;END&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;This function exhibits behavior that is sensitive to the instance collation. On an instance with a case-insensitive Latin1_General collation, it’s the identity function on integers: for each input @x, it just returns @x times one. But on an instance with a case-insensitive Turkish collation, it doubles its input.&lt;/p&gt;
&lt;p&gt;Now we can do something truly horrible. Imagine that we have our database on an instance with a Latin1_General collation, and we create:&lt;/p&gt;&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;CREATE TABLE &lt;/span&gt;&lt;span style="color: teal"&gt;baz &lt;/span&gt;&lt;span style="color: gray"&gt;(&lt;/span&gt;&lt;span style="color: teal"&gt;a &lt;/span&gt;&lt;span style="color: blue"&gt;int&lt;/span&gt;&lt;span style="color: gray"&gt;, &lt;/span&gt;&lt;span style="color: teal"&gt;b &lt;/span&gt;&lt;span style="color: blue"&gt;as &lt;/span&gt;&lt;span style="color: teal"&gt;dbo&lt;/span&gt;&lt;span style="color: gray"&gt;.&lt;/span&gt;&lt;span style="color: teal"&gt;snafu&lt;/span&gt;&lt;span style="color: gray"&gt;(&lt;/span&gt;&lt;span style="color: teal"&gt;a&lt;/span&gt;&lt;span style="color: gray"&gt;) &lt;span style="color: blue"&gt;PERSISTED&lt;/span&gt;)
&lt;/span&gt;&lt;span style="color: blue"&gt;GO
&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;If we insert a few values and try a couple simple commands:&lt;/p&gt;&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;INSERT INTO &lt;/span&gt;&lt;span style="color: teal"&gt;baz &lt;/span&gt;&lt;span style="color: blue"&gt;VALUES &lt;/span&gt;&lt;span style="color: gray"&gt;(&lt;/span&gt;1&lt;span style="color: gray"&gt;), (&lt;/span&gt;2&lt;span style="color: gray"&gt;), (&lt;/span&gt;3&lt;span style="color: gray"&gt;)
&lt;/span&gt;&lt;span style="color: blue"&gt;GO

SELECT &lt;/span&gt;&lt;span style="color: teal"&gt;a&lt;/span&gt;&lt;span style="color: gray"&gt;, &lt;/span&gt;&lt;span style="color: teal"&gt;b
&lt;/span&gt;&lt;span style="color: blue"&gt;FROM &lt;/span&gt;&lt;span style="color: teal"&gt;baz
&lt;/span&gt;&lt;span style="color: blue"&gt;GO
&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;&lt;span style="color: blue"&gt;DBCC &lt;/span&gt;&lt;span style="color: teal"&gt;CHECKTABLE &lt;/span&gt;&lt;span style="color: gray"&gt;(&lt;/span&gt;&lt;span style="color: teal"&gt;baz&lt;/span&gt;&lt;span style="color: gray"&gt;)&lt;br&gt;&lt;/span&gt;&lt;span style="color: blue"&gt;GO&lt;br&gt;&lt;/p&gt;&lt;/span&gt;
&lt;p&gt;We get back:&lt;/p&gt;&lt;pre class="code"&gt;a           b
----------- -----------
1           1
2           2
3           3

(3 row(s) affected)

DBCC results for 'baz'.
There are 3 rows in 1 pages for object "baz".
DBCC execution completed. If DBCC printed error messages, &lt;br&gt;   contact your system administrator.&lt;br&gt;&lt;/pre&gt;
&lt;p&gt;Everything looks fine. But now if we move the database to our Turkish instance and rerun the DBCC we get:&lt;/p&gt;&lt;pre class="code"&gt;Msg 2537, Level 16, State 106, Line 1
Table error: object ID 885578193, index ID 0, partition ID 72057594039173120, &lt;br&gt;   alloc unit ID 72057594043498496 (type In-row data), page (1:223), row 0. &lt;br&gt;   The record check (valid computed column) failed. The values are 2 and 0.
Msg 2537, Level 16, State 106, Line 1
Table error: object ID 885578193, index ID 0, partition ID 72057594039173120,&lt;br&gt;   alloc unit ID 72057594043498496 (type In-row data), page (1:223), row 1.&lt;br&gt;   The record check (valid computed column) failed. The values are 2 and 0.
Msg 2537, Level 16, State 106, Line 1
Table error: object ID 885578193, index ID 0, partition ID 72057594039173120, &lt;br&gt;   alloc unit ID 72057594043498496 (type In-row data), page (1:223), row 2. &lt;br&gt;   The record check (valid computed column) failed. The values are 2 and 0.
DBCC results for 'baz'.
There are 3 rows in 1 pages for object "baz".
CHECKTABLE found 0 allocation errors and 3 consistency errors in table 'baz' &lt;br&gt;   (object ID 885578193).
repair_allow_data_loss is the minimum repair level for the errors found by &lt;br&gt;   DBCC CHECKTABLE (foo.dbo.baz).
DBCC execution completed. If DBCC printed error messages, contact your system &lt;br&gt;   administrator.&lt;/pre&gt;
&lt;p&gt;Ack! Our table is corrupted! What’s going on? We’ve persisted values of a function that exhibits a dependency on the instance collation, and these values are no longer valid on the new instance. We can illustrate this another way by inserting the same values again and looking at the result:&lt;/p&gt;&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;INSERT INTO &lt;/span&gt;&lt;span style="color: teal"&gt;baz &lt;/span&gt;&lt;span style="color: blue"&gt;VALUES &lt;/span&gt;&lt;span style="color: gray"&gt;(&lt;/span&gt;1&lt;span style="color: gray"&gt;), (&lt;/span&gt;2&lt;span style="color: gray"&gt;), (&lt;/span&gt;3&lt;span style="color: gray"&gt;)
&lt;/span&gt;&lt;span style="color: blue"&gt;GO

SELECT &lt;/span&gt;&lt;span style="color: teal"&gt;a&lt;/span&gt;&lt;span style="color: gray"&gt;, &lt;/span&gt;&lt;span style="color: teal"&gt;b
&lt;/span&gt;&lt;span style="color: blue"&gt;FROM &lt;/span&gt;&lt;span style="color: teal"&gt;baz
&lt;/span&gt;&lt;span style="color: blue"&gt;GO
&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;a&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; b&lt;br&gt;----------- -----------&lt;br&gt;1&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 1&lt;br&gt;2&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 2&lt;br&gt;3&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 3&lt;br&gt;1&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 2&lt;br&gt;2&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 4&lt;br&gt;3&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 6&lt;/p&gt;
&lt;p&gt;(6 row(s) affected)&lt;/p&gt;
&lt;p&gt;The values in column b should be dependent solely on those in column a. They aren’t.&lt;/p&gt;
&lt;p&gt;The takeaway from this nightmare is that databases in SQL Server exhibit a strong dependency on the instance collation. There are other instance-level settings that have similar bindings, but collations are probably the most pervasive.&lt;/p&gt;
&lt;p&gt;As with authentication, we’ve addressed this with &lt;a href="http://msdn.microsoft.com/en-us/library/ff929071%28SQL.110%29.aspx"&gt;contained databases&lt;/a&gt;. But before moving on to solutions, I want to step back and frame this problem a bit more generally. And that will be my next post.&lt;/p&gt;
&lt;p&gt;Cheers,&lt;br&gt;-Isaac&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=10161434" width="1" height="1"&gt;</content><author><name>Isaac Kunen</name><uri>http://blogs.msdn.com/isaackunen_4000_stdin.org/ProfileUrlRedirect.ashx</uri></author></entry><entry><title>The Database Shuffle</title><link rel="alternate" type="text/html" href="http://blogs.msdn.com/b/isaac/archive/2011/04/20/the-database-shuffle.aspx" /><id>http://blogs.msdn.com/b/isaac/archive/2011/04/20/the-database-shuffle.aspx</id><published>2011-04-20T16:56:00Z</published><updated>2011-04-20T16:56:00Z</updated><content type="html">&lt;p&gt;Hi Folks,&lt;/p&gt;
&lt;p&gt;As I mentioned in my &lt;a href="http://blogs.msdn.com/b/isaac/archive/2011/03/31/it-s-alive.aspx"&gt;previous post&lt;/a&gt;, I recently moved from my old home in the SQL Server engine to the &lt;a href="http://www.microsoft.com/sqlserver/2008/en/us/R2-complex-event.aspx"&gt;StreamInsight&lt;/a&gt; team. As I continue to ramp up here, I want to take a few posts to talk about what I was working on back in the engine: the &lt;a href="http://msdn.microsoft.com/en-us/library/ff929071%28SQL.110%29.aspx"&gt;contained database&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;To illustrate the problem contained databases are intended to solve, let&amp;rsquo;s consider a simple scenario: I take a database &lt;em&gt;D&lt;/em&gt; that lives on server &lt;em&gt;S&lt;/em&gt;, detach it, and attach it to server &lt;em&gt;T&lt;/em&gt;:&lt;/p&gt;
&lt;p&gt;&lt;a href="http://blogs.msdn.com/cfs-file.ashx/__key/CommunityServer-Blogs-Components-WeblogFiles/00-00-00-55-34-metablogapi/7737.image_5F00_2AB0EED7.png"&gt;&lt;img height="128" width="290" src="http://blogs.msdn.com/cfs-file.ashx/__key/CommunityServer-Blogs-Components-WeblogFiles/00-00-00-55-34-metablogapi/7713.image_5F00_thumb_5F00_7A59F453.png" alt="image" border="0" title="image" style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: block; float: none; margin-left: auto; border-top: 0px; margin-right: auto; border-right: 0px; padding-top: 0px" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;This is one example of database movement, but there are many movement scenarios&amp;mdash;recovery, upgrade, load balancing, consolidation, moves to production&amp;mdash;and many movement techniques&amp;mdash;backup/restore, detach/attach, mirroring. But how well do these techniques satisfy the scenarios?&lt;/p&gt;
&lt;p&gt;In a word: poorly. As an illustrative example, let&amp;rsquo;s take a look at what happens with authentication. &lt;/p&gt;
&lt;p&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/bb510418.aspx"&gt;SQL Server security&lt;/a&gt; is a little complex, but for our purposes it&amp;rsquo;s enough to consider two core artifacts: &lt;em&gt;logins &lt;/em&gt;and &lt;em&gt;users.&lt;/em&gt; Logins are instance-level objects (stored in master) and users are database-level objects (stored in the user database). Each of these are responsible for &lt;em&gt;authorization&lt;/em&gt; in their respective domains, i.e., used to grant permissions at the instance and at the database respectively. But only logins are used for &lt;em&gt;authentication.&lt;/em&gt; So in order to even log on to the server you have to have a login. &lt;/p&gt;
&lt;p&gt;Users and logins are associated with each other through a matching identifier called a &lt;em&gt;SID&lt;/em&gt;, and in order for a person to connect to and use a database, he must have a user in the target database and matching login on the instance. And here&amp;rsquo;s where our problem comes from: while users are stored in and move with the database, logins are not and do not. They&amp;rsquo;re left behind:&lt;/p&gt;
&lt;p&gt;&lt;a href="http://blogs.msdn.com/cfs-file.ashx/__key/CommunityServer-Blogs-Components-WeblogFiles/00-00-00-55-34-metablogapi/4111.image_5F00_454D6523.png"&gt;&lt;img height="128" width="445" src="http://blogs.msdn.com/cfs-file.ashx/__key/CommunityServer-Blogs-Components-WeblogFiles/00-00-00-55-34-metablogapi/1462.image_5F00_thumb_5F00_1A08CE1C.png" alt="image" border="0" title="image" style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: block; float: none; margin-left: auto; border-top: 0px; margin-right: auto; border-right: 0px; padding-top: 0px" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The result of this is that someone who could connect to &lt;em&gt;D &lt;/em&gt;when it lived on &lt;em&gt;S&lt;/em&gt; may no longer be able to do so when it moves to &lt;em&gt;T&lt;/em&gt; because their login is missing. This is reparable, of course: you just need to &lt;em&gt;manually&lt;/em&gt; add the required logins to the new instance. It&amp;rsquo;s also not easily automatable, since the target instance may already have a different login with the same name, which would cause a collision.&lt;/p&gt;
&lt;p&gt;Were this only a problem for logins, we&amp;rsquo;d have one nit to work around. But of course it isn&amp;rsquo;t. The same applies to any other server-scoped object on which the database depends: agent jobs, error messages, linked servers, etc.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m going to blow my punch line here: we solved &lt;span style="text-decoration: line-through;"&gt;this&lt;/span&gt; the authentication problem with contained databases. But before moving on to the details, I&amp;rsquo;m going to touch on some more subtle problems. In particular, collations. Stay tuned.&lt;/p&gt;
&lt;p&gt;Cheers, &lt;br /&gt;-Isaac&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=10156294" width="1" height="1"&gt;</content><author><name>Isaac Kunen</name><uri>http://blogs.msdn.com/isaackunen_4000_stdin.org/ProfileUrlRedirect.ashx</uri></author><category term="sql server" scheme="http://blogs.msdn.com/b/isaac/archive/tags/sql+server/" /><category term="contained databases" scheme="http://blogs.msdn.com/b/isaac/archive/tags/contained+databases/" /></entry><entry><title>It’s Alive!</title><link rel="alternate" type="text/html" href="http://blogs.msdn.com/b/isaac/archive/2011/03/31/it-s-alive.aspx" /><id>http://blogs.msdn.com/b/isaac/archive/2011/03/31/it-s-alive.aspx</id><published>2011-03-30T23:46:13Z</published><updated>2011-03-30T23:46:13Z</updated><content type="html">&lt;p&gt;Hi Folks,&lt;/p&gt;  &lt;p&gt;Many years ago I kicked up this blog. It started with a trickle of general posts on SQL Server programmability topics. As our spatial support took off, it was quickly consumed by spatial-related posts.&lt;/p&gt;  &lt;p&gt;And then it languished…&lt;/p&gt;  &lt;p&gt;…and now its back. Let me quickly explain via a quick Q&amp;amp;A with myself:&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Where did you go?&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;Through the 2008 release, I was the program manager for spatial. I led spatial projects, thought spatial thoughts, and dreamt spatial… well only occasionally. In any case, as we ramped up the next release, I started working on what we now call “&lt;a href="http://msdn.microsoft.com/en-us/library/ff929071%28SQL.110%29.aspx"&gt;contained databases&lt;/a&gt;”. Since these weren’t public yet, I couldn’t say too much to say about them. And since I wasn’t involved so much in spatial, I didn’t have so much to say there, either.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Why are you back?&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;After spending six years in the SQL Server engine, I’ve taken a new job. I am now a program manager with &lt;a href="http://www.microsoft.com/sqlserver/2008/en/us/R2-complex-event.aspx"&gt;StreamInsight&lt;/a&gt;. And with this new adventure comes a renewed vigor on the blogging front.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;What is this blog about now?&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;Since most of what I’m working on is centered around StreamInsight, StreamInsight would be a good guess. I’ll probably have a thing or two to say about contained databases as well. And heck, I may even do some spatial.&lt;/p&gt;  &lt;p&gt;Stick around and we’ll find out.&lt;/p&gt;  &lt;p&gt;Cheers,   &lt;br /&gt;-Isaac&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=10147979" width="1" height="1"&gt;</content><author><name>Isaac Kunen</name><uri>http://blogs.msdn.com/isaackunen_4000_stdin.org/ProfileUrlRedirect.ashx</uri></author><category term="housekeeping" scheme="http://blogs.msdn.com/b/isaac/archive/tags/housekeeping/" /></entry><entry><title>Filter: One Odd Duck</title><link rel="alternate" type="text/html" href="http://blogs.msdn.com/b/isaac/archive/2010/03/04/filter-one-odd-duck.aspx" /><id>http://blogs.msdn.com/b/isaac/archive/2010/03/04/filter-one-odd-duck.aspx</id><published>2010-03-04T15:57:00Z</published><updated>2010-03-04T15:57:00Z</updated><content type="html">&lt;p&gt;Hi Folks,
&lt;/p&gt;&lt;p&gt;Over at his &lt;a href="http://blog.jordogskog.no/2010/02/27/strange-behavior-by-design-of-the-spatial-function-filter-in-sql-server-2008/"&gt;&lt;span style="color:#669966; text-decoration:underline"&gt;blog&lt;/span&gt;&lt;/a&gt;, Nicklas Avéns questions the behavior of Filter. He's right: Filter is a little odd. It is also very much by design. 
&lt;/p&gt;&lt;p&gt;Before we look at filter, let's review the data flow for a typical spatial query. A spatial selection generally has two internal components: a primary filter, which is designed to be fast, but which may produce extra results; and a secondary filter, which is slower, but only works to remove the false positives passed by the primary filter. 
&lt;/p&gt;&lt;p&gt;The primary filter is accomplished by using the spatial index. The secondary filter requires calls to actual geometry routines, and will be much more expensive. But the secondary filter also guarantees index-independent—and geometrically correct—results.
&lt;/p&gt;&lt;p&gt;Without an index, most operations will just skip the primary filter. The result is slow, but returns the same results as the full primary–secondary pathway.
&lt;/p&gt;&lt;p&gt;Filter is designed for a pretty common, but somewhat odd use case. Imagine that you want to display a portion of a map: you want to retrieve from the database those objects that would show on the map, but if you happen to retrieve a few extras you don't care—they'll just fall off the display.
&lt;/p&gt;&lt;p&gt;In other words, false positives are okay. In fact, they're often preferred, because the overall performance is can be much better if you can skip the expensive geometry operations and instead render some additional objects.
&lt;/p&gt;&lt;p&gt;So we added Filter, which simply skips the secondary filter and gives you the quick index-only results.
&lt;/p&gt;&lt;p&gt;But what if you don't have an index? We had two choices, either (a) return an error, or (b) revert to STIntersects. Note that both of these options have index-dependent behavior: that ship sailed when we decided to skip the secondary filter.
&lt;/p&gt;&lt;p&gt;We chose to allow the operation, but revert to STIntersects in the non-indexed case. This gives us &lt;em&gt;clear&lt;/em&gt; semantics: the correct results are always a subset of what we return. It's true that for SQL Server, these are somewhat &lt;em&gt;odd &lt;/em&gt;semantics, since they are index-dependent.
&lt;/p&gt;&lt;p&gt;But this is the &lt;em&gt;only &lt;/em&gt;place in spatial where we have such behavior. If you want consistent results regardless of index, use STIntersects or any of the other methods we provide. If your use case fits the one I described above, you may very well want Filter.
&lt;/p&gt;&lt;p&gt;Call it useful, call it odd. Call it Filter.
&lt;/p&gt;&lt;p&gt;Cheers,&lt;br/&gt;-Isaac&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9972910" width="1" height="1"&gt;</content><author><name>Isaac Kunen</name><uri>http://blogs.msdn.com/isaackunen_4000_stdin.org/ProfileUrlRedirect.ashx</uri></author></entry><entry><title>Spatial Data Type Structure</title><link rel="alternate" type="text/html" href="http://blogs.msdn.com/b/isaac/archive/2009/08/10/spatial-data-type-structure.aspx" /><id>http://blogs.msdn.com/b/isaac/archive/2009/08/10/spatial-data-type-structure.aspx</id><published>2009-08-10T19:38:25Z</published><updated>2009-08-10T19:38:25Z</updated><content type="html">&lt;p&gt;Hi Folks,&lt;/p&gt;  &lt;p&gt;As part of a &lt;a href="http://msdn.microsoft.com/en-us/library/ee209073.aspx"&gt;larger effort&lt;/a&gt; to document our protocols, SQL Server has just released &lt;a href="http://msdn.microsoft.com/en-us/library/ee320529.aspx"&gt;documentation&lt;/a&gt; on the structure of our spatial types.&amp;#160; The document is also available in &lt;a href="http://download.microsoft.com/download/7/9/3/79326E29-1E2E-45EE-AA73-74043587B17D/%5BMS-SSCLRT%5D.pdf"&gt;PDF&lt;/a&gt;.&amp;#160; Note that all of this is preliminary, and while I doubt it will change much, it could.&amp;#160; I had very little to do with this effort; you have &lt;a href="http://blogs.msdn.com/edkatibah"&gt;Ed&lt;/a&gt; to thank.&lt;/p&gt;  &lt;p&gt;It turns out that this structure is pretty simple, and there are folks out there who have fairly easily reverse-engineered it.&amp;#160; Now that we’re publishing the structure, let me make one very specific warning: if you are going to play around with the binary format, &lt;em&gt;do not set the valid bit (v) unless you’re absolutely sure the object is valid.&lt;/em&gt;&lt;/p&gt;  &lt;p&gt;Setting this should not cause SQL Server itself any problems: you won’t crash anything.&amp;#160; We just can’t guarantee that you’ll get the most predictable results.&amp;#160; And things get very difficult to fix.&lt;/p&gt;  &lt;p&gt;Let’s work an example.&amp;#160; Consider the following linestring: LINESTRING (0 0, 10 0, 5 0, 10 0).&amp;#160; This is clearly invalid according to the OGC, since it overlaps itself.&amp;#160; We can put this into a geometry element and play with it:&lt;/p&gt;  &lt;blockquote&gt;   &lt;div class="csharpcode"&gt;     &lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;declare&lt;/span&gt; @g geometry = &lt;span class="str"&gt;'LINESTRING (0 0, 10 0, 5 0, 10 0)'&lt;/span&gt;&lt;/pre&gt;

    &lt;pre&gt;&lt;span class="kwrd"&gt;select&lt;/span&gt; @g.STIsValid()            &lt;span class="rem"&gt;-- 0&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;select&lt;/span&gt; @g.MakeValid().STLength() &lt;span class="rem"&gt;-- 10&lt;/span&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/blockquote&gt;
&lt;style type="text/css"&gt;

















.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/style&gt;

&lt;p&gt;We can’t run the STLength() without first making the object valid or we’ll get an error.&amp;#160; We can now pull out the binary version of this to play with:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;div class="csharpcode"&gt;
    &lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;select&lt;/span&gt; @g&lt;/pre&gt;
  &lt;/div&gt;
&lt;/blockquote&gt;
&lt;style type="text/css"&gt;











.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/style&gt;

&lt;p&gt;And we get:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;div class="csharpcode"&gt;
    &lt;pre class="alt"&gt;0x0000000001&lt;font style="background-color: yellow"&gt;00&lt;/font&gt;040000000000000000000000000000000000000000000000000024400000000000000000000000000000144000000000000000000000000000002440000000000000000001000000010000000001000000FFFFFFFF0000000002&lt;/pre&gt;
  &lt;/div&gt;
&lt;/blockquote&gt;
&lt;style type="text/css"&gt;











.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/style&gt;

&lt;p&gt;We’re particularly interested in the highlighted byte, which contains a number of flags, all currently false.&amp;#160; Most of these aren’t particularly dangerous to play with.&amp;#160; For example, the lowest-order bit tells SQL Server that the item contains Z values.&amp;#160; If you flip it, you’ll just end up with an error, since the data that follows doesn’t actually contain any Z values:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;div class="csharpcode"&gt;
    &lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;declare&lt;/span&gt; @g geometry = 0x0000000001&lt;font style="background-color: yellow"&gt;01&lt;/font&gt;040000000000000000000000000000000000000000000000000024400000000000000000000000000000144000000000000000000000000000002440000000000000000001000000010000000001000000FFFFFFFF0000000002&lt;/pre&gt;

    &lt;pre&gt;&amp;#160;&lt;/pre&gt;

    &lt;pre class="alt"&gt;Msg 6522, &lt;span class="kwrd"&gt;Level&lt;/span&gt; 16, &lt;span class="kwrd"&gt;State&lt;/span&gt; 1, Line 1&lt;/pre&gt;

    &lt;pre&gt;A .NET Framework error occurred during execution of user-defined routine or aggregate &amp;quot;geometry&amp;quot;: &lt;/pre&gt;

    &lt;pre class="alt"&gt;System.IO.EndOfStreamException: Unable to read beyond the end of the stream.&lt;/pre&gt;
  &lt;/div&gt;
&lt;/blockquote&gt;
&lt;style type="text/css"&gt;












.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/style&gt;

&lt;p&gt;The valid bit, the third-least significant, is a little touchy, though.&amp;#160; Let’s see what happens if we flip that on our instance and run a few operations:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;div class="csharpcode"&gt;
    &lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;declare&lt;/span&gt; @g geometry = 0x0000000001&lt;font style="background-color: yellow"&gt;04&lt;/font&gt;040000000000000000000000000000000000000000000000000024400000000000000000000000000000144000000000000000000000000000002440000000000000000001000000010000000001000000FFFFFFFF0000000002&lt;/pre&gt;

    &lt;pre&gt;&lt;span class="kwrd"&gt;select&lt;/span&gt; @g.STIsValid()  &lt;span class="rem"&gt;-- 1&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;select&lt;/span&gt; @g.STLength()   &lt;span class="rem"&gt;-- 20&lt;/span&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/blockquote&gt;
&lt;style type="text/css"&gt;










.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/style&gt;

&lt;p&gt;What’s happening?&amp;#160; First, the system is trusting the bit and telling us that the instance is valid.&amp;#160; This shouldn’t be too surprising: the bit was added so that we wouldn’t have to perform an expensive check every time we check the validity, and we’re using the optimization.&lt;/p&gt;

&lt;p&gt;Second, the result of the STLength() operation is a bit odd.&amp;#160; It’s calculating the length used to draw the invalid object, not the length of the object itself.&lt;/p&gt;

&lt;p&gt;Okay, you say: let’s make this instance valid and see if we can fix things:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;div class="csharpcode"&gt;
    &lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;declare&lt;/span&gt; @h geometry = @g.MakeValid()&lt;/pre&gt;

    &lt;pre&gt;&lt;span class="kwrd"&gt;select&lt;/span&gt; @h.STLength()  &lt;span class="rem"&gt;-- 20&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;select&lt;/span&gt; @h.ToString()  &lt;span class="rem"&gt;-- LINESTRING (0 0, 10 0, 5 0, 10 0)&lt;span&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/blockquote&gt;
&lt;style type="text/css"&gt;







.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/style&gt;

&lt;p&gt;Ack!&amp;#160; We’re trapped.&amp;#160; MakeValid() tries to preserve the input geometry whenever possible, and therefore refuses to touch a valid instance.&amp;#160; Our instance isn’t actually valid, but we said it was.&lt;/p&gt;

&lt;p&gt;So if you’re creating a geometry from scratch, how are you to know how to set this bit?&amp;#160; That is, how on Earth do you figure out if an instance is valid?&amp;#160; Unless you’re absolutely sure, let the system do it for you: tell SQL that it isn’t valid and then run MakeValid().&amp;#160; Unlike setting the value true, there’s absolutely no harm in doing this—other than perf.&amp;#160; In fact, when MakeValid() sees an object that isn’t marked as valid, it will first check to see if the instance is valid.&amp;#160; If it is, MakeValid() won’t muck with the data, but will just flip the bit to true.&lt;/p&gt;

&lt;p&gt;And keep in mind that although you &lt;em&gt;can &lt;/em&gt;play with these structures, most of the time you shouldn’t need to.&amp;#160; Use the built-in methods, and use the &lt;a href="http://blogs.msdn.com/isaac/archive/2008/05/30/our-upcoming-builder-api.aspx"&gt;builder/sink API&lt;/a&gt; if you need to do something fancy.&amp;#160; As always, there are plenty of examples on the &lt;a href="http://www.codeplex.com/sqlspatialtools/"&gt;SQL Server Spatial Tools&lt;/a&gt; CodePlex project.&lt;/p&gt;

&lt;p&gt;Cheers, 
  &lt;br /&gt;-Isaac&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9863347" width="1" height="1"&gt;</content><author><name>Isaac Kunen</name><uri>http://blogs.msdn.com/isaackunen_4000_stdin.org/ProfileUrlRedirect.ashx</uri></author></entry><entry><title>The Sphere is Finite</title><link rel="alternate" type="text/html" href="http://blogs.msdn.com/b/isaac/archive/2009/07/09/the-sphere-is-finite.aspx" /><id>http://blogs.msdn.com/b/isaac/archive/2009/07/09/the-sphere-is-finite.aspx</id><published>2009-07-09T20:18:20Z</published><updated>2009-07-09T20:18:20Z</updated><content type="html">&lt;p&gt;Hi Folks,&lt;/p&gt;  &lt;p&gt;The title of this post states the obvious: the area of a sphere is finite.&amp;#160; We even have a nice formula for it, 4πr&lt;sup&gt;2&lt;/sup&gt;.&amp;#160; The same is true for an ellipsoid, which is just a sat-upon sphere, although computing the area gets more &lt;a href="http://mathworld.wolfram.com/Ellipsoid.html"&gt;complicated&lt;/a&gt;.&lt;/p&gt;  &lt;p&gt;But the plane is infinite.&amp;#160; If we combine this with the fact that the OGC (implicitly) assumes that all geometry objects have a finite area, then any OGC-valid geometry has exactly one reasonable interpretation.&amp;#160; If I ask you to fill in this polygon:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://blogs.msdn.com/blogfiles/isaac/WindowsLiveWriter/TheSpherehasaFiniteArea_BBED/image_2.png"&gt;&lt;img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="image" border="0" alt="image" src="http://blogs.msdn.com/blogfiles/isaac/WindowsLiveWriter/TheSpherehasaFiniteArea_BBED/image_thumb.png" width="262" height="263" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;You have only one reasonable choice:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://blogs.msdn.com/blogfiles/isaac/WindowsLiveWriter/TheSpherehasaFiniteArea_BBED/image_4.png"&gt;&lt;img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="image" border="0" alt="image" src="http://blogs.msdn.com/blogfiles/isaac/WindowsLiveWriter/TheSpherehasaFiniteArea_BBED/image_thumb_1.png" width="263" height="264" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;Not:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://blogs.msdn.com/blogfiles/isaac/WindowsLiveWriter/TheSpherehasaFiniteArea_BBED/image_8.png"&gt;&lt;img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="image" border="0" alt="image" src="http://blogs.msdn.com/blogfiles/isaac/WindowsLiveWriter/TheSpherehasaFiniteArea_BBED/image_thumb_3.png" width="264" height="265" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;You can’t reasonably give me the latter one, since it would have an infinite area.&lt;/p&gt;  &lt;p&gt;But since the sphere already has a finite area, a ring like this on the sphere just cuts it into two finite areas.&amp;#160; So if I ask you to fill in this box:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://blogs.msdn.com/blogfiles/isaac/WindowsLiveWriter/TheSpherehasaFiniteArea_BBED/image_10.png"&gt;&lt;img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="image" border="0" alt="image" src="http://blogs.msdn.com/blogfiles/isaac/WindowsLiveWriter/TheSpherehasaFiniteArea_BBED/image_thumb_4.png" width="374" height="367" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;You have a problem, since you don’t know for sure what I mean: do I want you to fill the portion containing the United States, or the part containing the rest of the world?&amp;#160; The request is underspecified.&lt;/p&gt;  &lt;p&gt;We fix this by using orientation, which I’ll discuss next time.&lt;/p&gt;  &lt;p&gt;Cheers,   &lt;br /&gt;-Isaac&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9827198" width="1" height="1"&gt;</content><author><name>Isaac Kunen</name><uri>http://blogs.msdn.com/isaackunen_4000_stdin.org/ProfileUrlRedirect.ashx</uri></author></entry><entry><title>New Stuff in SQL Spatial Tools</title><link rel="alternate" type="text/html" href="http://blogs.msdn.com/b/isaac/archive/2009/06/02/new-stuff-in-sql-spatial-tools.aspx" /><id>http://blogs.msdn.com/b/isaac/archive/2009/06/02/new-stuff-in-sql-spatial-tools.aspx</id><published>2009-06-02T23:40:19Z</published><updated>2009-06-02T23:40:19Z</updated><content type="html">&lt;p&gt;Hi Folks,&lt;/p&gt;  &lt;p&gt;Marko Tintor from our Serbia team just dropped some new functionality into the &lt;a href="http://sqlspatialtools.codeplex.com/"&gt;SQL Server Spatial Tools&lt;/a&gt; project on CodePlex:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;A method for testing whether a geography instance is valid. &lt;/li&gt;    &lt;li&gt;Better: a method for creating a valid geography from invalid input.&amp;#160; How this works deserves a post on of its own, but it basically uses the technique I suggested in &lt;a href="http://social.msdn.microsoft.com/Forums/en-US/sqlspatial/thread/d0964a39-e402-4dd5-bf78-3701eb68268e"&gt;this forum thread&lt;/a&gt;. &lt;/li&gt;    &lt;li&gt;Methods for creating convex hulls in geography. &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Enjoy!    &lt;br /&gt;-Isaac&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9686784" width="1" height="1"&gt;</content><author><name>Isaac Kunen</name><uri>http://blogs.msdn.com/isaackunen_4000_stdin.org/ProfileUrlRedirect.ashx</uri></author></entry><entry><title>The Plane, the Sphere, and the Ellipsoid</title><link rel="alternate" type="text/html" href="http://blogs.msdn.com/b/isaac/archive/2009/06/01/the-plane-the-sphere-and-the-ellipsoid.aspx" /><id>http://blogs.msdn.com/b/isaac/archive/2009/06/01/the-plane-the-sphere-and-the-ellipsoid.aspx</id><published>2009-06-02T00:00:00Z</published><updated>2009-06-02T00:00:00Z</updated><content type="html">&lt;p&gt;Hi Folks,&lt;/p&gt;  &lt;p&gt;We all know that the sphere isn’t the plane, and that an ellipsoid is different as well, but I don’t know if everyone has given so much thought to the practical effects of these differences.&lt;/p&gt;  &lt;p&gt;And so I thought it might be a nice idea to catalog some of the interesting things that change when we move from a flat to round model—and it also makes a nice new series for the blog.&amp;nbsp; My planned agenda is:&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;&lt;a href="http://blogs.msdn.com/isaac/archive/2008/05/03/edges-on-the-globe.aspx" mce_href="http://blogs.msdn.com/isaac/archive/2008/05/03/edges-on-the-globe.aspx"&gt;Edges on the Ellipsoid aren’t Obvious&lt;/a&gt; &lt;/li&gt;    &lt;li&gt;&lt;a href="http://blogs.msdn.com/isaac/archive/2009/07/09/the-sphere-is-finite.aspx" mce_href="http://blogs.msdn.com/isaac/archive/2009/07/09/the-sphere-is-finite.aspx"&gt;The Sphere is Finite&lt;/a&gt;… &lt;/li&gt;    &lt;li&gt;… So Orientation Matters on the Sphere… &lt;/li&gt;    &lt;li&gt;…And yet, Maybe not so Much &lt;/li&gt;    &lt;li&gt;Some Sensible Concepts Are Nonsense on the Sphere &lt;/li&gt;    &lt;li&gt;Bounding Boxes on the Sphere are Strange &lt;/li&gt;    &lt;li&gt;Funny Things Happen to Convex Polygons &lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;I’ll keep this list up to date with links as they bake.&amp;nbsp; &lt;/p&gt;  &lt;p&gt;As you can see, I get off easy on the first post: I wrote it some time ago.&amp;nbsp; I’ve also started to &lt;a href="http://blogs.msdn.com/isaac/archive/2007/10/29/geography-and-ring-orientation.aspx" mce_href="http://blogs.msdn.com/isaac/archive/2007/10/29/geography-and-ring-orientation.aspx"&gt;touch on&lt;/a&gt; the next few topics, but I think there’s more to say.&amp;nbsp; I’ll be scrounging some material from my PDC talk last year, but there should be some new goodies as well.&lt;/p&gt;  &lt;p&gt;Cheers,    &lt;br&gt;-Isaac&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9682191" width="1" height="1"&gt;</content><author><name>Isaac Kunen</name><uri>http://blogs.msdn.com/isaackunen_4000_stdin.org/ProfileUrlRedirect.ashx</uri></author></entry><entry><title>SQL Server Spatial Indexing</title><link rel="alternate" type="text/html" href="http://blogs.msdn.com/b/isaac/archive/2009/05/28/sql-server-spatial-indexing.aspx" /><id>http://blogs.msdn.com/b/isaac/archive/2009/05/28/sql-server-spatial-indexing.aspx</id><published>2009-05-28T17:58:49Z</published><updated>2009-05-28T17:58:49Z</updated><content type="html">&lt;p&gt;Hi Folks,&lt;/p&gt;  &lt;p&gt;This post contains no new information; it’s just a rollup of links to spatial indexing posts I’ve made.&amp;#160; If you want to know more about spatial indexing, these are the ones to read.&lt;/p&gt;  &lt;p&gt;In order:&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;&lt;a href="http://blogs.msdn.com/isaac/archive/2007/11/24/spatial-indexing-part-1-why-a-spatial-index.aspx"&gt;Why a Spatial Index?&lt;/a&gt;&lt;/li&gt;    &lt;li&gt;&lt;a href="http://blogs.msdn.com/isaac/archive/2007/11/27/spatial-indexing-part-2-a-simple-spatial-indexing-scheme.aspx"&gt;A Simple Spatial Indexing Scheme&lt;/a&gt;&lt;/li&gt;    &lt;li&gt;&lt;a href="http://blogs.msdn.com/isaac/archive/2007/12/01/spatial-indexing-part-3-faster-primary-filtering.aspx"&gt;Faster Primary Filtering&lt;/a&gt;&lt;/li&gt;    &lt;li&gt;&lt;a href="http://blogs.msdn.com/isaac/archive/2008/02/05/picking-up-on-indexing-moving-beyond-the-simple-grid.aspx"&gt;Picking up on Indexing: Moving Beyond the Simple Grid&lt;/a&gt;&lt;/li&gt;    &lt;li&gt;&lt;a href="http://blogs.msdn.com/isaac/archive/2008/03/01/basic-multi-level-grids.aspx"&gt;Basic Multi-Level Grids&lt;/a&gt;&lt;/li&gt;    &lt;li&gt;&lt;a href="http://blogs.msdn.com/isaac/archive/2008/04/08/more-on-the-multi-level-grid.aspx"&gt;More on the Multi-Level Grid&lt;/a&gt;&lt;/li&gt;    &lt;li&gt;&lt;a href="http://blogs.msdn.com/isaac/archive/2008/08/29/is-my-spatial-index-being-used.aspx"&gt;Is my spatial index being used?&lt;/a&gt;&lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;Hmm… it looks like I never got around to the specific of the geography index.&amp;#160; It’s in the queue now.&lt;/p&gt;  &lt;p&gt;Cheers,   &lt;br /&gt;-Isaac&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9647392" width="1" height="1"&gt;</content><author><name>Isaac Kunen</name><uri>http://blogs.msdn.com/isaackunen_4000_stdin.org/ProfileUrlRedirect.ashx</uri></author></entry><entry><title>London Spatial Event</title><link rel="alternate" type="text/html" href="http://blogs.msdn.com/b/isaac/archive/2009/04/09/london-spatial-event.aspx" /><id>http://blogs.msdn.com/b/isaac/archive/2009/04/09/london-spatial-event.aspx</id><published>2009-04-09T19:09:28Z</published><updated>2009-04-09T19:09:28Z</updated><content type="html">&lt;p&gt;&lt;a href="http://www.sqlblogcasts.com/blogs/simons/"&gt;Simon Sabin&lt;/a&gt; asked me to pass along information about a &lt;em&gt;free&lt;/em&gt; spatial event that he and &lt;a href="http://johanneskebeck.spaces.live.com/"&gt;Johannes Kebeck&lt;/a&gt; are holding in London on the 16th.&amp;#160; It looks like they’ll be covering a bunch of hot SQL Server Spatial topics: how to get your data in to SQL, how to get your data out and visualize it, and how to make best use of spatial indexes.&lt;/p&gt;  &lt;p&gt;Actually, they’re holding it twice: once in the &lt;a href="http://sqlserverfaq.com/events/154/Using-Spatial-Data-in-SQL-Server-and-Virtual-Earth-Afternoon.aspx"&gt;afternoon&lt;/a&gt;, and again in the &lt;a href="http://sqlserverfaq.com/events/155/Using-Spatial-Data-in-SQL-Server-and-Virtual-Earth-Evening-Event.aspx"&gt;evening&lt;/a&gt;.&amp;#160; Follow those links to sign up.&lt;/p&gt;  &lt;p&gt;It looks like it should be a good meeting.&lt;/p&gt;  &lt;p&gt;Cheers,   &lt;br /&gt;-Isaac&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9540564" width="1" height="1"&gt;</content><author><name>Isaac Kunen</name><uri>http://blogs.msdn.com/isaackunen_4000_stdin.org/ProfileUrlRedirect.ashx</uri></author></entry><entry><title>The Spatial Library without the Server: Bug and Workaround</title><link rel="alternate" type="text/html" href="http://blogs.msdn.com/b/isaac/archive/2009/02/24/the-spatial-library-without-the-server-bug-and-workaround.aspx" /><id>http://blogs.msdn.com/b/isaac/archive/2009/02/24/the-spatial-library-without-the-server-bug-and-workaround.aspx</id><published>2009-02-24T04:40:20Z</published><updated>2009-02-24T04:40:20Z</updated><content type="html">&lt;p&gt;Hi Folks,&lt;/p&gt;  &lt;p&gt;&lt;a href="http://jasonfollas.com/blog/archive/2009/02/21/knowledge-4.aspx"&gt;Jason Follas&lt;/a&gt; recently ran across a &lt;a href="https://connect.microsoft.com/SQLServer/feedback/ViewFeedback.aspx?FeedbackID=355402&amp;amp;wa=wsignin1.0"&gt;lingering issue&lt;/a&gt; when using our spatial library without the server.&amp;#160; I mistakenly thought the fix had been shipped, but for now it remains.&lt;/p&gt;  &lt;p&gt;The background is that the spatial library consists of a managed part and a native part.&amp;#160; Roughly, the core geometry library resides in the native code, and everything else is in the managed layer.&amp;#160; The native code requires the C++ runtime libraries.&amp;#160; This is installed with SQL Server, so everything works fine if you install SQL.&amp;#160; &lt;/p&gt;  &lt;p&gt;The redistributable version we ship as part of the &lt;a href="http://www.microsoft.com/downloads/details.aspx?FamilyID=228de03f-3b5a-428a-923f-58a033d316e1&amp;amp;DisplayLang=en"&gt;feature pack&lt;/a&gt;&amp;#160;&lt;em&gt;should &lt;/em&gt;redistribute the runtime as well, but it doesn’t.&amp;#160; That’s the bug.&amp;#160; So, if you install the library on a machine without the runtime, then it will fail.&lt;/p&gt;  &lt;p&gt;The workaround is simple: install &lt;a href="http://www.microsoft.com/downloads/details.aspx?FamilyID=A5C84275-3B97-4AB7-A40D-3802B2AF5FC2&amp;amp;displaylang=en"&gt;the runtime&lt;/a&gt; manually.&amp;#160; Annoying, but effective.&amp;#160; You’ll also be fine if you install another package—like the SQL Native Client—that includes the runtime, but unless you also want that component, I’d stick with the stand-alone install.&lt;/p&gt;  &lt;p&gt;SP1 for SQL Server 2008 is coming up, but unfortunately, we’ve missed the cutoff to get this in.&amp;#160; We’ll try to get this into the next service pack, but that will take some time.&amp;#160; In the meantime, you’ll have to use this workaround.&amp;#160; I’ll try to get an official KB article published on this as well.&lt;/p&gt;  &lt;p&gt;So, apologies for the inconvenience.&amp;#160; And thanks to Jason for raising the issue.&lt;/p&gt;  &lt;p&gt;Cheers,   &lt;br /&gt;-Isaac&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9442022" width="1" height="1"&gt;</content><author><name>Isaac Kunen</name><uri>http://blogs.msdn.com/isaackunen_4000_stdin.org/ProfileUrlRedirect.ashx</uri></author></entry><entry><title>The Geography Hemisphere Limitation</title><link rel="alternate" type="text/html" href="http://blogs.msdn.com/b/isaac/archive/2009/02/06/the-geography-hemisphere-limitation.aspx" /><id>http://blogs.msdn.com/b/isaac/archive/2009/02/06/the-geography-hemisphere-limitation.aspx</id><published>2009-02-06T22:08:46Z</published><updated>2009-02-06T22:08:46Z</updated><content type="html">&lt;p&gt;Hi Folks,&lt;/p&gt;  &lt;p&gt;It occurs to me that I haven’t posted anything about the hemisphere limitation for the SQL Server geography type.&amp;#160; This limitation is a little confusing, and could probably use some clarification.&lt;/p&gt;  &lt;p&gt;It also occurs to me that I haven’t posted anything in a while—let’s rectify both of these.&lt;/p&gt;  &lt;p&gt;We usually express SQL Server’s limitation by saying that no object can exceed a hemisphere.&amp;#160; But which hemisphere?&amp;#160; Does this mean that objects cannot cross the equator?&amp;#160; The international date line?&amp;#160; The truth: neither.&amp;#160; We can, in fact, generate objects that cross the equator:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;&lt;font face="Consolas"&gt;POLYGON ((-145 -45, -55 -45, -55 45, -145 45, -145 -45))&lt;/font&gt;&lt;/p&gt;    &lt;p&gt;&lt;a href="http://blogs.msdn.com/blogfiles/isaac/WindowsLiveWriter/TheGeographyHemisphereLimitation_7200/image_2.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" src="http://blogs.msdn.com/blogfiles/isaac/WindowsLiveWriter/TheGeographyHemisphereLimitation_7200/image_thumb.png" width="520" height="262" /&gt;&lt;/a&gt; &lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;Or the date line:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;&lt;font face="Consolas"&gt;POLYGON ((135 0, -135 0, -135 90, 135 90, 135 0))&lt;/font&gt;&lt;/p&gt;    &lt;p&gt;&lt;a href="http://blogs.msdn.com/blogfiles/isaac/WindowsLiveWriter/TheGeographyHemisphereLimitation_7200/image_4.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" src="http://blogs.msdn.com/blogfiles/isaac/WindowsLiveWriter/TheGeographyHemisphereLimitation_7200/image_thumb_1.png" width="520" height="260" /&gt;&lt;/a&gt; &lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;Or the poles:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;&lt;font face="Consolas"&gt;POLYGON ((0 45, 90 45, 180 45, 270 45, 0 45))&lt;/font&gt;&lt;/p&gt;    &lt;p&gt;&lt;a href="http://blogs.msdn.com/blogfiles/isaac/WindowsLiveWriter/TheGeographyHemisphereLimitation_7200/image_6.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" src="http://blogs.msdn.com/blogfiles/isaac/WindowsLiveWriter/TheGeographyHemisphereLimitation_7200/image_thumb_2.png" width="520" height="257" /&gt;&lt;/a&gt; &lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;This illustrates that it is not objects in certain positions that are disallowed.&amp;#160; Rather, &lt;em&gt;large &lt;/em&gt;objects are disallowed: if an object spans more than half the globe, SQL Server will complain.&amp;#160; So while a polygon that sits slightly inside of a hemisphere is fine:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;&lt;font face="Consolas"&gt;POLYGON ((0 1, 90 1, 180 1, 270 1, 0 1))&lt;/font&gt;&lt;/p&gt;    &lt;p&gt;&lt;a href="http://blogs.msdn.com/blogfiles/isaac/WindowsLiveWriter/TheGeographyHemisphereLimitation_7200/image_8.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" src="http://blogs.msdn.com/blogfiles/isaac/WindowsLiveWriter/TheGeographyHemisphereLimitation_7200/image_thumb_3.png" width="520" height="260" /&gt;&lt;/a&gt; &lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;One that is slightly larger causes problems:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;&lt;font face="Consolas"&gt;POLYGON ((0 -1, 90 -1, 180 -1, 270 -1, 0 -1))&lt;/font&gt;&lt;/p&gt;    &lt;p&gt;&lt;font color="#ff0000"&gt;Msg 6522, Level 16, State 1, Line 1        &lt;br /&gt;A .NET Framework error occurred during execution of user-defined routine or aggregate &amp;quot;geography&amp;quot;:         &lt;br /&gt;Microsoft.SqlServer.Types.GLArgumentException: 24205: The specified input does not represent a valid geography instance because it exceeds a single hemisphere. Each geography instance must fit inside a single hemisphere. A common reason for this error is that a polygon has the wrong ring orientation.         &lt;br /&gt;Microsoft.SqlServer.Types.GLArgumentException:         &lt;br /&gt;&amp;#160;&amp;#160; at Microsoft.SqlServer.Types.GLNativeMethods.ThrowExceptionForHr(GL_HResult errorCode)         &lt;br /&gt;&amp;#160;&amp;#160; at Microsoft.SqlServer.Types.GLNativeMethods.GeodeticIsValid(GeoData g)         &lt;br /&gt;&amp;#160;&amp;#160; at Microsoft.SqlServer.Types.SqlGeography.IsValidExpensive()         &lt;br /&gt;&amp;#160;&amp;#160; at Microsoft.SqlServer.Types.SqlGeography.ConstructGeographyFromUserInput(GeoData g, Int32 srid)         &lt;br /&gt;&amp;#160;&amp;#160; at Microsoft.SqlServer.Types.SqlGeography.GeographyFromText(OpenGisType type, SqlChars taggedText, Int32 srid)         &lt;br /&gt;&amp;#160;&amp;#160; at Microsoft.SqlServer.Types.SqlGeography.STGeomFromText(SqlChars geometryTaggedText, Int32 srid)         &lt;br /&gt;&amp;#160;&amp;#160; at Microsoft.SqlServer.Types.SqlGeography.Parse(SqlString s)         &lt;br /&gt;.&lt;/font&gt;&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;We can dig a little deeper.&amp;#160; When SQL Server sees a geography instance, it computes a &lt;em&gt;bounding cap &lt;/em&gt;for it.&amp;#160; This is very much like a bounding box on the plane, but is defined by a center point and an angle.&amp;#160; We can actually find the bounding cap for an object using the EnvelopeCenter() and EnvelopeAngle() methods on geography.&amp;#160; Using these, we can plot the cap.&amp;#160; For example:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;&lt;font face="Consolas"&gt;POLYGON ((-50 -10, 50 -10, 50 10, -50 10, -50 -10))&lt;/font&gt;&lt;/p&gt;    &lt;p&gt;&lt;a href="http://blogs.msdn.com/blogfiles/isaac/WindowsLiveWriter/TheGeographyHemisphereLimitation_7200/image_10.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" src="http://blogs.msdn.com/blogfiles/isaac/WindowsLiveWriter/TheGeographyHemisphereLimitation_7200/image_thumb_4.png" width="520" height="257" /&gt;&lt;/a&gt; &lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;If the cap angle exceeds 90 degrees, then the object exceeds a hemisphere.&amp;#160; The cap computed above has an angle of 50.7 degrees.&lt;/p&gt;  &lt;p&gt;But there is some subtlety in how SQL Server determines this cap.&amp;#160; The angle is relatively simple: it is the maximum angle from the center to any of the points in the figure, yielding a minimal cap &lt;em&gt;with that center&lt;/em&gt;.&amp;#160; The center, however, is determined by summing the vectors from the center of the globe to each vertex in the figure, essentially averaging the vertices.&amp;#160; This means that if the points in our figure are lopsided—e.g., if add more points on the eastern edge—we will compute a cap that no longer looks very minimal:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;&lt;font face="Consolas"&gt;POLYGON ((-50 -10, 50 -10, 50 -5, 50 0, 50 5, 50 10, -50 10, -50 -10))&lt;/font&gt;&lt;/p&gt;    &lt;p&gt;&lt;a href="http://blogs.msdn.com/blogfiles/isaac/WindowsLiveWriter/TheGeographyHemisphereLimitation_7200/image_12.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" src="http://blogs.msdn.com/blogfiles/isaac/WindowsLiveWriter/TheGeographyHemisphereLimitation_7200/image_thumb_5.png" width="520" height="273" /&gt;&lt;/a&gt;&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;Now the cap center is skewed, so the angle has to increase—to 77.4 degrees—to contain the object.&amp;#160; If we add more points on the eastern edge we get into trouble:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;&lt;font face="Consolas"&gt;POLYGON ((-50 -10, 50 -10, 50 -8, 50 -6, 50 -5 50 -4, 50 -2, 50 0, 50 2, 50 4, 50 5, 50 6, 50 8, 50 10, -50 10, -50 -10))&lt;/font&gt;&lt;/p&gt;    &lt;p&gt;&lt;font color="#ff0000"&gt;Msg 6522, Level 16, State 1, Line 1        &lt;br /&gt;A .NET Framework error occurred during execution of user-defined routine or aggregate &amp;quot;geography&amp;quot;:         &lt;br /&gt;Microsoft.SqlServer.Types.GLArgumentException: 24205: The specified input does not represent a valid geography instance because it exceeds a single hemisphere. Each geography instance must fit inside a single hemisphere. A common reason for this error is that a polygon has the wrong ring orientation.         &lt;br /&gt;Microsoft.SqlServer.Types.GLArgumentException:         &lt;br /&gt;&amp;#160;&amp;#160; at Microsoft.SqlServer.Types.GLNativeMethods.ThrowExceptionForHr(GL_HResult errorCode)         &lt;br /&gt;&amp;#160;&amp;#160; at Microsoft.SqlServer.Types.GLNativeMethods.GeodeticIsValid(GeoData g)         &lt;br /&gt;&amp;#160;&amp;#160; at Microsoft.SqlServer.Types.SqlGeography.IsValidExpensive()         &lt;br /&gt;&amp;#160;&amp;#160; at Microsoft.SqlServer.Types.SqlGeography.ConstructGeographyFromUserInput(GeoData g, Int32 srid)         &lt;br /&gt;&amp;#160;&amp;#160; at Microsoft.SqlServer.Types.SqlGeography.GeographyFromText(OpenGisType type, SqlChars taggedText, Int32 srid)         &lt;br /&gt;&amp;#160;&amp;#160; at Microsoft.SqlServer.Types.SqlGeography.STGeomFromText(SqlChars geometryTaggedText, Int32 srid)         &lt;br /&gt;&amp;#160;&amp;#160; at Microsoft.SqlServer.Types.SqlGeography.Parse(SqlString s)         &lt;br /&gt;.&lt;/font&gt;&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;So although our object hasn’t changed—the extra vertices we added were chosen so they don’t change the shape—SQL Server now thinks we’ve exceeded a hemisphere.&lt;/p&gt;  &lt;p&gt;Let me answer two more obvious questions.&amp;#160; First: why do we compute caps this way instead of computing a true minimal bounding cap?&amp;#160; It turns out that finding a minimal cap is difficult computationally, and because this operation happens a lot, we need something cheap.&lt;/p&gt;  &lt;p&gt;Second: why does SQL Server have the hemisphere limitation at all?&amp;#160; A complete answer will require another post.&amp;#160; Suffice to say, it’s an implementation artifact that the SQL Server team absolutely abhors.&amp;#160; That SQL Server isn’t the only system with such a limitation doesn’t make it any less annoying, and removing the limit is high on everyone’s priorities.&lt;/p&gt;  &lt;p&gt;Cheers,    &lt;br /&gt;-Isaac&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9402737" width="1" height="1"&gt;</content><author><name>Isaac Kunen</name><uri>http://blogs.msdn.com/isaackunen_4000_stdin.org/ProfileUrlRedirect.ashx</uri></author></entry><entry><title>Good Spatial Blog Resources</title><link rel="alternate" type="text/html" href="http://blogs.msdn.com/b/isaac/archive/2008/12/11/good-spatial-blog-resources.aspx" /><id>http://blogs.msdn.com/b/isaac/archive/2008/12/11/good-spatial-blog-resources.aspx</id><published>2008-12-11T13:20:00Z</published><updated>2008-12-11T13:20:00Z</updated><content type="html">&lt;p&gt;Hi Folks,&lt;/p&gt;  &lt;p&gt;While I continue to procrastinate, here are some excellent spatial resources to peruse.&lt;/p&gt;  &lt;p&gt;First, David Lean, a Microsoft evangelist, has very comprehensive list of spatial posts over on his &lt;a href="http://blogs.msdn.com/davidlean/archive/tags/SQL+Server+Spatial/default.aspx"&gt;Dave does Data&lt;/a&gt; blog.&amp;#160; He covers a wide range of spatial methods, the builder/sink API, as well as some pointers on creating spatial applications.&lt;/p&gt;  &lt;p&gt;Second, John O’Brien, a Microsoft MVP, has a couple articles (&lt;a href="http://www.sql-server-performance.com/articles/dev/Powerful_Geographical_Visualisations_SQL_2008_Spatial_Part1_p1.aspx"&gt;here&lt;/a&gt; and &lt;a href="http://www.sql-server-performance.com/articles/dev/Powerful_Geographical_Visualisations_SQL_2008_Spatial_Part2_p1.aspx"&gt;here&lt;/a&gt;) showing how to do some cool data visualization right in Management Studio.&lt;/p&gt;  &lt;p&gt;Finally, &lt;a href="http://johanneskebeck.spaces.live.com/"&gt;Johannes Kebeck&lt;/a&gt; continues with a couple recent posts on creating maps in Virtual Earth based on data coming from SQL Server.&lt;/p&gt;  &lt;p&gt;Enjoy!    &lt;br /&gt;-Isaac&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9197699" width="1" height="1"&gt;</content><author><name>Isaac Kunen</name><uri>http://blogs.msdn.com/isaackunen_4000_stdin.org/ProfileUrlRedirect.ashx</uri></author></entry><entry><title>Puzzle Solution</title><link rel="alternate" type="text/html" href="http://blogs.msdn.com/b/isaac/archive/2008/12/08/puzzle-solution.aspx" /><id>http://blogs.msdn.com/b/isaac/archive/2008/12/08/puzzle-solution.aspx</id><published>2008-12-08T21:33:21Z</published><updated>2008-12-08T21:33:21Z</updated><content type="html">&lt;p&gt;&lt;a href="http://blogs.msdn.com/isaac/archive/2008/12/05/pdc-and-a-nice-geographic-puzzle.aspx"&gt;Last time&lt;/a&gt;, I posted a question sent to me by Rob Mount.&amp;#160; So what solutions exist other than the north pole?&lt;/p&gt;  &lt;p&gt;You did well: jnelso99 got part of the way there; tanoshimi finished it off.&amp;#160; We can find a set of circles around the south pole with lengths of 1/&lt;em&gt;N&lt;/em&gt; miles: 1 mile, 1/2 mile, 1/3 mile, etc.&amp;#160; Any point one mile north of any of these circles will work: you travel south one mile to one of the circles, circle the earth &lt;em&gt;N &lt;/em&gt;times, and then head back north to where you started.&lt;/p&gt;  &lt;p&gt;Where exactly are these circles?&amp;#160; Well, let’s be a bit mathematical about it.&amp;#160; Let &lt;em&gt;R&lt;/em&gt; be the radius of the earth, and let &lt;em&gt;x &lt;/em&gt;be the distance of each leg of our path.&amp;#160; Working in radians, let &lt;em&gt;p0&lt;/em&gt; = (&lt;em&gt;lat&lt;/em&gt;, &lt;em&gt;long&lt;/em&gt;) be our starting point.&amp;#160; (Radians just make the math so much nicer.)&lt;/p&gt;  &lt;p&gt;First we walk&lt;em&gt; &lt;/em&gt;south &lt;em&gt;x &lt;/em&gt;units.&amp;#160; This only changes the latitude, and so we find ourselves at a new point:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;&lt;em&gt;p1&lt;/em&gt; = (&lt;em&gt;lat&lt;/em&gt; – &lt;em&gt;x&lt;/em&gt;/&lt;em&gt;R&lt;/em&gt;, &lt;em&gt;long&lt;/em&gt;)&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;Next we walk &lt;em&gt;x&lt;/em&gt; units east, which only impacts the longitude.&amp;#160; How &lt;em&gt;much&lt;/em&gt; this affects the longitude depends, however, on our current latitude:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;&lt;em&gt;p2&lt;/em&gt; = (&lt;em&gt;lat&lt;/em&gt; – &lt;em&gt;x&lt;/em&gt;/&lt;em&gt;R&lt;/em&gt;, &lt;em&gt;long&lt;/em&gt; + &lt;em&gt;x&lt;/em&gt;/&lt;em&gt;cos&lt;/em&gt;(&lt;em&gt;lat&lt;/em&gt; – &lt;em&gt;x&lt;/em&gt;/&lt;em&gt;R&lt;/em&gt;))&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;Finally we walk x units north.&amp;#160; This brings the latitude back to where we started:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;&lt;em&gt;pf&lt;/em&gt; = (&lt;em&gt;lat&lt;/em&gt;, &lt;em&gt;long&lt;/em&gt; + &lt;em&gt;x&lt;/em&gt;/(&lt;em&gt;R&lt;/em&gt; * &lt;em&gt;cos&lt;/em&gt;(&lt;em&gt;lat&lt;/em&gt; – &lt;em&gt;x&lt;/em&gt;/&lt;em&gt;R&lt;/em&gt;)))&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;Okay, so what do we make of this?&amp;#160; We want &lt;em&gt;p0&lt;/em&gt; to equal &lt;em&gt;pf&lt;/em&gt;.&amp;#160; The latitude is easy, since the latitudes of &lt;em&gt;p0&lt;/em&gt; and &lt;em&gt;pf&lt;/em&gt; are the same.&amp;#160; Further, we note that if &lt;em&gt;lat&lt;/em&gt; is positive or negative &lt;em&gt;pi&lt;/em&gt;/2 then we’re at a pole and the value of &lt;em&gt;long&lt;/em&gt; is irrelevant.&amp;#160; Positive &lt;em&gt;pi&lt;/em&gt;/2 gives us the north pole solution; –&lt;em&gt;pi&lt;/em&gt;/2 ends up being nonsense, since you can’t go south from the south pole.&lt;/p&gt;  &lt;p&gt;But if &lt;em&gt;lat&lt;/em&gt; is not &lt;em&gt;pi&lt;/em&gt;/2, then &lt;em&gt;long&lt;/em&gt; matters.&amp;#160; In particular, our starting longitude has to equal our ending, but it can wrap around, so:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;&lt;em&gt;long&lt;/em&gt; + 2 * &lt;em&gt;pi&lt;/em&gt; *&lt;em&gt; N&lt;/em&gt; = &lt;em&gt;long&lt;/em&gt; + &lt;em&gt;x&lt;/em&gt; / (&lt;em&gt;R&lt;/em&gt; * &lt;em&gt;cos&lt;/em&gt;(&lt;em&gt;lat&lt;/em&gt; – &lt;em&gt;x&lt;/em&gt;/&lt;em&gt;R&lt;/em&gt;))&lt;/p&gt;    &lt;p&gt;2 * &lt;em&gt;pi&lt;/em&gt; *&lt;em&gt; N&lt;/em&gt; = &lt;em&gt;x&lt;/em&gt; / (&lt;em&gt;R * cos&lt;/em&gt;(&lt;em&gt;lat&lt;/em&gt; – &lt;em&gt;x&lt;/em&gt;/&lt;em&gt;R))&lt;/em&gt;&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;Here &lt;em&gt;N &lt;/em&gt;is any integer; the 2 * &lt;em&gt;pi &lt;/em&gt;* &lt;em&gt;N&lt;/em&gt; factor accounts for the fact that we can circle the globe.&amp;#160; Solving for lat we find:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;&lt;em&gt;cos(lat – x/R) = x / &lt;/em&gt;( &lt;em&gt;2 * pi * N * R &lt;/em&gt;)&lt;/p&gt;    &lt;p&gt;&lt;em&gt;lat – x/R = acos( &lt;em&gt;x / &lt;/em&gt;( &lt;em&gt;2 * pi * N * R&lt;/em&gt;) )&lt;/em&gt;&lt;/p&gt;    &lt;p&gt;&lt;em&gt;lat = acos( &lt;em&gt;x / &lt;/em&gt;( &lt;em&gt;2 * pi * N * R&lt;/em&gt;) ) + x/R&lt;/em&gt;&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;The &lt;em&gt;acos &lt;/em&gt;term is undefined if &lt;em&gt;N&lt;/em&gt; = 0, and if &lt;em&gt;N&lt;/em&gt; &amp;lt; 1 then the value lies outside of the range [–&lt;em&gt;pi&lt;/em&gt;/2, &lt;em&gt;pi&lt;/em&gt;/2].&amp;#160; When &lt;em&gt;N&lt;/em&gt; is greater than 0, then the results of the &lt;em&gt;acos&lt;/em&gt; term are in our range, but they could be positive or negative; it turns out that the values we want are negative.&lt;/p&gt;  &lt;p&gt;So what does this mean?&amp;#160; We have derived a set of latitude values that look like solutions, and the longitudes associated with these solutions are unconstrained.&amp;#160; In other words, we have a set of circles around the south pole corresponding to each &lt;em&gt;N &lt;/em&gt;in {1, 2, …}.&amp;#160; These are exactly the circles we’ve already described, but now we can compute exactly where they are.&amp;#160; For&lt;em&gt;&amp;#160; R = &lt;/em&gt;3963 miles and &lt;em&gt;x &lt;/em&gt;= 1:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;N=1: lat = -acos( 1&lt;em&gt; / &lt;/em&gt;(24900.263) ) + 0.000252 = -1.5705041 = -89.983260 degrees&lt;/p&gt;    &lt;p&gt;N=2: lat = -acos( 1&lt;em&gt; / &lt;/em&gt;(49800.527) ) + 0.000252 = -1.5705242 = -89.984410 degrees&lt;/p&gt;    &lt;p&gt;N=3: lat = -acos( 1&lt;em&gt; / &lt;/em&gt;(74700.790) ) + 0.000252 = -1.5705309 = -89.984794 degrees&lt;/p&gt;    &lt;p&gt;…&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;And when &lt;em&gt;N&lt;/em&gt;=1, this circle is indeed about 1.16 miles north of the south pole, just as jnelso99 noted.&lt;/p&gt;  &lt;p&gt;Cheers,    &lt;br /&gt;-Isaac&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9185204" width="1" height="1"&gt;</content><author><name>Isaac Kunen</name><uri>http://blogs.msdn.com/isaackunen_4000_stdin.org/ProfileUrlRedirect.ashx</uri></author></entry><entry><title>PDC and a Nice Geographic Puzzle</title><link rel="alternate" type="text/html" href="http://blogs.msdn.com/b/isaac/archive/2008/12/05/pdc-and-a-nice-geographic-puzzle.aspx" /><id>http://blogs.msdn.com/b/isaac/archive/2008/12/05/pdc-and-a-nice-geographic-puzzle.aspx</id><published>2008-12-05T22:03:09Z</published><updated>2008-12-05T22:03:09Z</updated><content type="html">&lt;p&gt;Hi Folks,&lt;/p&gt;  &lt;p&gt;At PDC I gave a talk largely inspired by topics raised here and in the spatial forums.&amp;#160; But “inspired by” doesn’t equate to “a duplicate of”, and to turn things around, I’ve been meaning to write a few posts here inspired by my PDC talk.&amp;#160; Stay tuned.&lt;/p&gt;  &lt;p&gt;In the meantime, Rob Mount from Intergraph sent me a note that started:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;As I review your PDC presentation I’m reminded of a puzzle I think you’ll enjoy.&amp;#160; &lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;I did indeed, and I hope a lot of you will enjoy it as well.&amp;#160; Rob started out with a puzzle I expect most of us have heard before:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;&lt;/p&gt;    &lt;p&gt;When I was growing up one of my uncles was fond of challenging the children in the family with puzzles.&amp;#160; One of my favorites, as a very young child, was this one: A hunter walks a mile south, a mile east and a mile north and finds himself back at the starting point.&amp;#160; A bear walks by.&amp;#160; What color is the bear?&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;This is well-known enough that I don’t think the answer will be much of a spoiler:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;He, of course, thought the hunter started at the North Pole.&amp;#160; The bear was a polar bear and hence white.&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;A perfectly valid answer, of course.&amp;#160; But Rob continues:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;Years later I finally got my revenge by stumping him with this problem:&amp;#160; I reminded him of the hunter and the polar bear and pointed out that there are actually several other points on the earth that meet the geographic constraint he stated – if you walk a mile south, a mile east and a mile north you find yourself back where you started.&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;Assuming a spherical earth, how many such points exist and where are they?&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;I won’t spoil this one so quickly.&amp;#160; Go ahead and post your answers in the comments; I’ll post the solution in a few days.&lt;/p&gt;  &lt;p&gt;Cheers,    &lt;br /&gt;-Isaac&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9180502" width="1" height="1"&gt;</content><author><name>Isaac Kunen</name><uri>http://blogs.msdn.com/isaackunen_4000_stdin.org/ProfileUrlRedirect.ashx</uri></author></entry><entry><title>Frequently Asked Question: How do I load shapefiles?</title><link rel="alternate" type="text/html" href="http://blogs.msdn.com/b/isaac/archive/2008/11/04/frequently-asked-question-how-do-i-load-shapefiles.aspx" /><id>http://blogs.msdn.com/b/isaac/archive/2008/11/04/frequently-asked-question-how-do-i-load-shapefiles.aspx</id><published>2008-11-05T00:29:34Z</published><updated>2008-11-05T00:29:34Z</updated><content type="html">&lt;p&gt;This has come up &lt;a href="http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=2895872&amp;amp;SiteID=1"&gt;a&lt;/a&gt; &lt;a href="http://forums.microsoft.com/msdn/ShowPost.aspx?PostID=4051644&amp;amp;SiteID=1"&gt;few&lt;/a&gt; &lt;a href="http://blogs.msdn.com/isaac/archive/2007/05/16/sql-server-spatial-support-an-introduction.aspx#9040337"&gt;times&lt;/a&gt; now.&amp;#160; Multiple questions deserve at least one answer, right?&lt;/p&gt;  &lt;p&gt;First, Microsoft has not produced a shapefile loader (or exporter).&amp;#160; If this is important to you, here’s the &lt;a href="https://connect.microsoft.com/SQLServer/feedback/ViewFeedback.aspx?FeedbackID=357045"&gt;Connect item&lt;/a&gt; to hit.&amp;#160; (And yes: we do listen to Connect!)&lt;/p&gt;  &lt;p&gt;So, what are you to do?&amp;#160; There are a few options:&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;If you are a user of one of our &lt;a href="http://www.microsoft.com/sqlserver/2008/en/us/spatial-partners.aspx"&gt;partner GIS vendors&lt;/a&gt;---&lt;a href="http://www.microsoft.com/isv/autodesk"&gt;Autodesk&lt;/a&gt;, &lt;a href="http://www.microsoft.com/isv/esri/"&gt;ESRI&lt;/a&gt;, &lt;a href="http://www.intergraph.com/"&gt;Intergraph&lt;/a&gt;, &lt;a href="http://www.manifold.net/info/sql_server_support.shtml"&gt;Manifold&lt;/a&gt;, or &lt;a href="http://www.mipro.com/"&gt;Pitney Bowes (MapInfo)&lt;/a&gt;---they probably have support for loading shapefiles already.&amp;#160; You’ll have to ask them, though: I’m not an expert in their products.       &lt;br /&gt;&lt;/li&gt;    &lt;li&gt;If not, and if you aren’t interested in a real GIS, then you should check out &lt;a href="http://www.safe.com/microsoft"&gt;Safe Software&lt;/a&gt;: they build spatial ETL software that will take shapefiles (as well as about ~200 other formats) perform transformations on the data, and load into SQL Server.       &lt;br /&gt;&lt;/li&gt;    &lt;li&gt;If you’re looking for a free solution, then there are a few popping up in the wild.&amp;#160; Morten Nielsen has had &lt;a href="http://sharpgis.net/page/SQL-Server-2008-Spatial-Tools.aspx"&gt;his tool&lt;/a&gt; available for some time now, which has both a command line and GUI interfaces.&amp;#160; Scott Ellington has created a &lt;a href="http://www.salmonsalvo.net/blog/?p=105"&gt;command line tool&lt;/a&gt; as well, but I haven’t had a chance to play with it yet.       &lt;br /&gt;&lt;/li&gt;    &lt;li&gt;You could build your own.&amp;#160; I suggest using the sink/builder API---you can find plenty of examples in our &lt;a href="http://codeplex.com/SqlSpatialtools"&gt;Codeplex project&lt;/a&gt;.&lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;Hopefully one of these solutions will work for you.&lt;/p&gt;  &lt;p&gt;Cheers,    &lt;br /&gt;-Isaac&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9041549" width="1" height="1"&gt;</content><author><name>Isaac Kunen</name><uri>http://blogs.msdn.com/isaackunen_4000_stdin.org/ProfileUrlRedirect.ashx</uri></author></entry><entry><title>Off to PDC</title><link rel="alternate" type="text/html" href="http://blogs.msdn.com/b/isaac/archive/2008/10/24/off-to-pdc.aspx" /><id>http://blogs.msdn.com/b/isaac/archive/2008/10/24/off-to-pdc.aspx</id><published>2008-10-24T23:51:00Z</published><updated>2008-10-24T23:51:00Z</updated><content type="html">&lt;p&gt;Despite my relative youth, I can be a bit of a fuddy-duddy.&amp;nbsp; Fighting my natural impulses, I’ve decided to give Twitter a try---at least while I’m at PDC.&amp;nbsp; So, if you’re interested in tracking me down, surf the tubes over to &lt;a href="http://twitter.com/isaackunen" mce_href="http://twitter.com/isaackunen"&gt;my very own Truman Show&lt;/a&gt;.&lt;/p&gt;  &lt;p&gt;Or drop me an old-fashioned email.&lt;/p&gt;  &lt;p&gt;See you at the show!   &lt;br&gt;-Isaac&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9015237" width="1" height="1"&gt;</content><author><name>Isaac Kunen</name><uri>http://blogs.msdn.com/isaackunen_4000_stdin.org/ProfileUrlRedirect.ashx</uri></author><category term="PDC2008" scheme="http://blogs.msdn.com/b/isaac/archive/tags/PDC2008/" /></entry><entry><title>Nearest Neighbors</title><link rel="alternate" type="text/html" href="http://blogs.msdn.com/b/isaac/archive/2008/10/23/nearest-neighbors.aspx" /><id>http://blogs.msdn.com/b/isaac/archive/2008/10/23/nearest-neighbors.aspx</id><published>2008-10-23T02:38:00Z</published><updated>2008-10-23T02:38:00Z</updated><content type="html">&lt;p&gt;Hi Folks,&lt;/p&gt;  &lt;p&gt;Spatial users often want to find the object nearest a given point.&amp;nbsp; This operation, usually referred to as &lt;a href="http://en.wikipedia.org/wiki/Nearest_neighbor_search" mce_href="http://en.wikipedia.org/wiki/Nearest_neighbor_search"&gt;nearest neighbor search&lt;/a&gt;, is remarkably common in many areas of computer science.&amp;nbsp; In general, we may wish to find not only the nearest, but the &lt;a href="http://en.wikipedia.org/wiki/K-nearest_neighbor_algorithm" mce_href="http://en.wikipedia.org/wiki/K-nearest_neighbor_algorithm"&gt;&lt;i&gt;k&lt;/i&gt;-nearest neighbors&lt;/a&gt;.&lt;/p&gt;  &lt;p&gt;How can we accomplish this with SQL Server?&amp;nbsp; Here we’ll look at finding the single nearest neighbor; the extension to &lt;i&gt;k&lt;/i&gt;-nearest neighbors is relatively straight forward.&lt;/p&gt;  &lt;p&gt;First, let's examine the naive method for accomplishing this: simply order the table by distance and restrict the results.&amp;nbsp; For all of these examples, we’ll assume a table &lt;i&gt;T&lt;/i&gt; with a spatial column &lt;i&gt;g&lt;/i&gt;, as well as a parameter @x containing the search point:&lt;/p&gt;  &lt;div class="csharpcode"&gt;   &lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;SELECT&lt;/span&gt; &lt;span class="kwrd"&gt;TOP&lt;/span&gt;(1) *&lt;/pre&gt;

  &lt;pre&gt;&lt;span class="kwrd"&gt;FROM&lt;/span&gt; T &lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;ORDER&lt;/span&gt; &lt;span class="kwrd"&gt;BY&lt;/span&gt; g.STDistance(@x) ASC&lt;/pre&gt;
&lt;/div&gt;
&lt;style type="text/css"&gt;












.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/style&gt;

&lt;p&gt;This solution certainly has simplicity on its side, but consider the work that needs to be done.&amp;nbsp; The &lt;i&gt;entire &lt;/i&gt;table must be scanned, and the distance of each to the search point must be calculated.&amp;nbsp; Ouch.&lt;/p&gt;

&lt;p&gt;We could conceivably improve on this by restricting our search space to to the immediate region around the target point:&lt;/p&gt;

&lt;div class="csharpcode"&gt;
  &lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;DECLARE&lt;/span&gt; @region geography = @x.STBuffer(10000)&lt;/pre&gt;

  &lt;pre&gt;&amp;nbsp;&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;SELECT&lt;/span&gt; &lt;span class="kwrd"&gt;TOP&lt;/span&gt;(1) *&lt;/pre&gt;

  &lt;pre&gt;&lt;span class="kwrd"&gt;FROM&lt;/span&gt; T &lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;WHERE&lt;/span&gt; g.Filter(@region) = 1&lt;/pre&gt;

  &lt;pre&gt;&lt;span class="kwrd"&gt;ORDER&lt;/span&gt; &lt;span class="kwrd"&gt;BY&lt;/span&gt; g.STDistance(@x) ASC&lt;/pre&gt;
&lt;/div&gt;
&lt;style type="text/css"&gt;





.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/style&gt;

&lt;p&gt;But this solution requires that we know our data very well: if there are no rows in the region, then we will fail to find the nearest neighbor; if there are too many, then we will again be left with a rather inefficient query.&lt;/p&gt;

&lt;p&gt;How do we escape this morass?&amp;nbsp; We can do so by starting with a very small region---so small that we can be certain not to encounter too many results---and then keep enlarging it until we find something.&amp;nbsp; Doing this with a loop is not hard, but Steven Hemingray showed me how to do this with entirely declarative syntax:&lt;/p&gt;

&lt;div class="csharpcode"&gt;
  &lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;DECLARE&lt;/span&gt; @&lt;span class="kwrd"&gt;start&lt;/span&gt; &lt;span class="kwrd"&gt;FLOAT&lt;/span&gt; = 1000; &lt;/pre&gt;

  &lt;pre&gt;&amp;nbsp;&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;WITH&lt;/span&gt; NearestPoints &lt;span class="kwrd"&gt;AS&lt;/span&gt;&lt;/pre&gt;

  &lt;pre&gt;(&lt;/pre&gt;

  &lt;pre class="alt"&gt;   &lt;span class="kwrd"&gt;SELECT&lt;/span&gt; &lt;span class="kwrd"&gt;TOP&lt;/span&gt;(1) &lt;span class="kwrd"&gt;WITH TIES&lt;/span&gt; *,  T.g.STDistance(@x) &lt;span class="kwrd"&gt;AS&lt;/span&gt; dist&lt;/pre&gt;

  &lt;pre&gt;   &lt;span class="kwrd"&gt;FROM&lt;/span&gt; Numbers &lt;span class="kwrd"&gt;JOIN&lt;/span&gt; T &lt;span class="kwrd"&gt;WITH&lt;/span&gt;(&lt;span class="kwrd"&gt;INDEX&lt;/span&gt;(spatial_index)) &lt;/pre&gt;

  &lt;pre class="alt"&gt;   &lt;span class="kwrd"&gt;ON&lt;/span&gt; T.g.STDistance(@x) &amp;lt; @&lt;span class="kwrd"&gt;start&lt;/span&gt;*POWER(2,Numbers.n)&lt;/pre&gt;

  &lt;pre&gt;   &lt;span class="kwrd"&gt;ORDER&lt;/span&gt; &lt;span class="kwrd"&gt;BY&lt;/span&gt; n&lt;/pre&gt;

  &lt;pre class="alt"&gt;)&lt;/pre&gt;

  &lt;pre&gt;&lt;span class="kwrd"&gt;SELECT&lt;/span&gt; &lt;span class="kwrd"&gt;TOP(&lt;/span&gt;1) * &lt;span class="kwrd"&gt;FROM&lt;/span&gt; NearestPoints&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;ORDER&lt;/span&gt; &lt;span class="kwrd"&gt;BY&lt;/span&gt; n, dist&lt;/pre&gt;
&lt;/div&gt;
&lt;style type="text/css"&gt;




.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/style&gt;

&lt;p&gt;This requires some explanation.&amp;nbsp; First, the &lt;i&gt;@start&lt;/i&gt; parameter gives the initial region to search.&amp;nbsp; I’ve chosen one kilometer, but this can be adjusted downward if your data is very dense.&amp;nbsp; Second, you’ll notice that we make use of a &lt;i&gt;Numbers&lt;/i&gt; table, which just contains the numbers 1 through &lt;i&gt;n&lt;/i&gt;.&amp;nbsp; This&amp;nbsp; just contains a long list of integers, which is is useful in many situations.&lt;/p&gt;

&lt;p&gt;The inner query examines a set of exponentially-expanding regions.&amp;nbsp; The &lt;i&gt;ORDER BY&lt;/i&gt; clause along with the &lt;i&gt;TOP(1)&lt;/i&gt; allows the query to stop as soon as it finds the smallest non-empty region.&amp;nbsp; The &lt;i&gt;WITH TIES &lt;/i&gt;statement makes sure that &lt;i&gt;all&lt;/i&gt; of the objects in that region will be in the result set.&lt;/p&gt;

&lt;p&gt;Once the inner query returns a list of potential results, the outer query examines them to find which is actually nearest.&amp;nbsp; With this approach, we can select a start area small enough to keep the cost low in dense data, but also be guaranteed to find a distant nearest neighbor.&lt;/p&gt;

&lt;p&gt;Incidentally, if you don’t already have a numbers table, you can create one quite quickly with some mildly-black magic like this:&lt;/p&gt;

&lt;div class="csharpcode"&gt;
  &lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;SELECT&lt;/span&gt; &lt;span class="kwrd"&gt;TOP&lt;/span&gt; 100000 &lt;span class="kwrd"&gt;IDENTITY&lt;/span&gt;(&lt;span class="kwrd"&gt;int&lt;/span&gt;,1,1) &lt;span class="kwrd"&gt;AS&lt;/span&gt; n &lt;/pre&gt;

  &lt;pre&gt;&lt;span class="kwrd"&gt;INTO&lt;/span&gt; numbers &lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;FROM&lt;/span&gt; MASTER..spt_values a, MASTER..spt_values b&lt;/pre&gt;

  &lt;pre&gt;&amp;nbsp;&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;CREATE&lt;/span&gt; &lt;span class="kwrd"&gt;UNIQUE&lt;/span&gt; &lt;span class="kwrd"&gt;CLUSTERED&lt;/span&gt; &lt;span class="kwrd"&gt;INDEX&lt;/span&gt; idx_1 &lt;span class="kwrd"&gt;ON&lt;/span&gt; numbers(n)&lt;/pre&gt;
&lt;/div&gt;
&lt;style type="text/css"&gt;




.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/style&gt;

&lt;p&gt;This isn’t a particularly pretty solution, but to proactively answer a question, we didn’t add a method for this primarily because we ran out of time.&amp;nbsp; Look for something more built-in the next go around.&lt;/p&gt;

&lt;p&gt;Cheers, 
  &lt;br&gt;-Isaac&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9011920" width="1" height="1"&gt;</content><author><name>Isaac Kunen</name><uri>http://blogs.msdn.com/isaackunen_4000_stdin.org/ProfileUrlRedirect.ashx</uri></author></entry><entry><title>A Few Strange Functions</title><link rel="alternate" type="text/html" href="http://blogs.msdn.com/b/isaac/archive/2008/10/16/a-few-strange-functions.aspx" /><id>http://blogs.msdn.com/b/isaac/archive/2008/10/16/a-few-strange-functions.aspx</id><published>2008-10-16T20:13:45Z</published><updated>2008-10-16T20:13:45Z</updated><content type="html">&lt;p&gt;Hi Folks,&lt;/p&gt;  &lt;p&gt;A &lt;a href="http://forums.microsoft.com/msdn/ShowPost.aspx?PostID=3949700&amp;amp;SiteID=1"&gt;post on the spatial forum&lt;/a&gt; last week caught my attention for entirely non-spatial reasons: it made use of two functions---RADIANS() and DEGREES()---that I never knew existed.&lt;/p&gt;  &lt;p&gt;It seems rather strange that out of the innumerable (well, technically &lt;a href="http://en.wikipedia.org/wiki/Enumerable"&gt;enumerable&lt;/a&gt;) list of functions that we could implement, someone felt these were worth the effort.&amp;#160; For example, we save exactly 0 characters by using these functions:&lt;/p&gt;  &lt;div&gt;   &lt;div style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;     &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;RADIANS(@x)&lt;/pre&gt;

    &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;DEGREES(@y)&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;Becomes:&lt;/p&gt;

&lt;div&gt;
  &lt;div style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;
    &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;@x*PI()/180&lt;/pre&gt;

    &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;@y*180/PI()&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;Granted, using the functions is clearer and less error prone; but I’m not arguing that they are &lt;em&gt;bad &lt;/em&gt;functions, just surprising.&lt;/p&gt;

&lt;p&gt;What is surprising &lt;em&gt;and bad&lt;/em&gt;, if you ask me, is that both RADIANS() and DEGREES() have int—&amp;gt;int overloads.&amp;#160; In other words, if you call these functions with an integer, you get an integer result:&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;div&gt;
  &lt;div style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;
    &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;SELECT RADIANS(180) -- 3, not 3.141592653589793100&lt;/pre&gt;

    &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;SELECT DEGREES(3)   -- 171, not 171.887338539246970000&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;This behavior is very strange.&amp;#160; I cannot think of a case in which it is useful, yet plenty where it could cause harm.&amp;#160; The behavior is noted in &lt;a href="http://msdn.microsoft.com/en-us/library/ms177516.aspx"&gt;BOL&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Arithmetic functions, such as ABS, CEILING, DEGREES, FLOOR, POWER, RADIANS, and SIGN, return a value having the same data type as the input value.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Of these, only RADIANS() and DEGREES() have natural floating-point return values: all others are naturally integers, and while promoting them to floats may not be necessary, it doesn’t seem problematic.&lt;/p&gt;

&lt;p&gt;Let me know if you can see a benefit of this behavior; I’d love to see these overloads on our deprecation list.&lt;/p&gt;

&lt;p&gt;Cheers, 
  &lt;br /&gt;-Isaac&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9002004" width="1" height="1"&gt;</content><author><name>Isaac Kunen</name><uri>http://blogs.msdn.com/isaackunen_4000_stdin.org/ProfileUrlRedirect.ashx</uri></author></entry><entry><title>Conference Correction</title><link rel="alternate" type="text/html" href="http://blogs.msdn.com/b/isaac/archive/2008/10/09/conference-correction.aspx" /><id>http://blogs.msdn.com/b/isaac/archive/2008/10/09/conference-correction.aspx</id><published>2008-10-09T18:49:27Z</published><updated>2008-10-09T18:49:27Z</updated><content type="html">&lt;p&gt;Hi Folks,&lt;/p&gt;  &lt;p&gt;Unfortunately, I need to correct an &lt;a href="http://blogs.msdn.com/isaac/archive/2008/09/17/upcoming-conferences.aspx"&gt;earlier post of mine&lt;/a&gt;.&amp;#160; I will &lt;em&gt;not &lt;/em&gt;be speaking at PASS this year---it looks like there were some mixed signals.&amp;#160; If you’re looking for your spatial fix, Michael Rys will be talking about &lt;a href="http://www.softconference.com/pass/ProgramSessions/program-sessiondetail.asp?SID=135499"&gt;types and indexing&lt;/a&gt;.&lt;/p&gt;  &lt;p&gt;Still, PASS is on my home turf, so I’ll be around: come see me at the Ask the Experts session, or drop me a line and we can meet up.&lt;/p&gt;  &lt;p&gt;PDC and Autodesk University are still on until they tell me otherwise.&lt;/p&gt;  &lt;p&gt;Cheers,   &lt;br /&gt;-Isaac&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=8992957" width="1" height="1"&gt;</content><author><name>Isaac Kunen</name><uri>http://blogs.msdn.com/isaackunen_4000_stdin.org/ProfileUrlRedirect.ashx</uri></author></entry></feed>