<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="http://blogs.msdn.com/utility/FeedStylesheets/rss.xsl" media="screen"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:wfw="http://wellformedweb.org/CommentAPI/"><channel><title>Isaac @ MSDN : sql server</title><link>http://blogs.msdn.com/isaac/archive/tags/sql+server/default.aspx</link><description>Tags: sql server</description><dc:language>en-US</dc:language><generator>CommunityServer 2.1 SP1 (Build: 61025.2)</generator><item><title>Where are my Spatial Columns?</title><link>http://blogs.msdn.com/isaac/archive/2008/04/15/where-are-my-spatial-columns.aspx</link><pubDate>Tue, 15 Apr 2008 23:48:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:8398197</guid><dc:creator>isaac</dc:creator><slash:comments>3</slash:comments><comments>http://blogs.msdn.com/isaac/comments/8398197.aspx</comments><wfw:commentRss>http://blogs.msdn.com/isaac/commentrss.aspx?PostID=8398197</wfw:commentRss><wfw:comment>http://blogs.msdn.com/isaac/rsscomments.aspx?PostID=8398197</wfw:comment><description>&lt;DIV&gt;
&lt;P&gt;Hi Folks,&lt;/P&gt;
&lt;P&gt;I've been asked a few times how to find out what spatial columns are defined in a database.&amp;nbsp; We don't have any special table for this, but you can easily find out by looking at the usual system views:&lt;/P&gt;&lt;PRE class=csharpcode&gt;&lt;SPAN class=kwrd&gt;SELECT&lt;/SPAN&gt; ta.name &lt;SPAN class=kwrd&gt;as&lt;/SPAN&gt; table_name, co.name &lt;SPAN class=kwrd&gt;as&lt;/SPAN&gt; column_name&lt;BR&gt;&lt;SPAN class=kwrd&gt;FROM&lt;/SPAN&gt; sys.tables ta &lt;SPAN class=kwrd&gt;JOIN&lt;/SPAN&gt; sys.columns co&lt;BR&gt;      &lt;SPAN class=kwrd&gt;ON&lt;/SPAN&gt; ta.object_id = co.object_id&lt;BR&gt;&lt;SPAN class=kwrd&gt;JOIN&lt;/SPAN&gt; sys.types ty&lt;BR&gt;      &lt;SPAN class=kwrd&gt;ON&lt;/SPAN&gt; co.user_type_id = ty.user_type_id&lt;BR&gt;&lt;SPAN class=kwrd&gt;WHERE&lt;/SPAN&gt; ty.name = &lt;SPAN class=str&gt;'geography'&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;OR&lt;/SPAN&gt; ty.name = &lt;SPAN class=str&gt;&lt;FONT color=red&gt;'geometry'&lt;/FONT&gt;&lt;/SPAN&gt;&lt;/PRE&gt;
&lt;P&gt;There's nothing special about spatial here: you can replace the type names in the WHERE clause of the query with any other type you'd like to find as well.&amp;nbsp; For example, a simple change finds all integer columns:&lt;/P&gt;
&lt;DIV&gt;&lt;PRE class=csharpcode&gt;&lt;SPAN class=kwrd&gt;SELECT&lt;/SPAN&gt; ta.name &lt;SPAN class=kwrd&gt;as&lt;/SPAN&gt; table_name, co.name &lt;SPAN class=kwrd&gt;as&lt;/SPAN&gt; column_name&lt;BR&gt;&lt;SPAN class=kwrd&gt;FROM&lt;/SPAN&gt; sys.tables ta &lt;SPAN class=kwrd&gt;JOIN&lt;/SPAN&gt; sys.columns co&lt;BR&gt;      &lt;SPAN class=kwrd&gt;ON&lt;/SPAN&gt; ta.object_id = co.object_id&lt;BR&gt;&lt;SPAN class=kwrd&gt;JOIN&lt;/SPAN&gt; sys.types ty&lt;BR&gt;      &lt;SPAN class=kwrd&gt;ON&lt;/SPAN&gt; co.user_type_id = ty.user_type_id&lt;BR&gt;&lt;SPAN class=kwrd&gt;WHERE&lt;/SPAN&gt; ty.name = &lt;SPAN class=str&gt;'int'&lt;/SPAN&gt;&lt;/PRE&gt;&lt;/DIV&gt;
&lt;P&gt;Cheers, &lt;BR&gt;-Isaac&lt;/P&gt;
&lt;P&gt;[16 April 2008]:&amp;nbsp;Updated to correct a typo in the first query.&lt;/P&gt;&lt;/DIV&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=8398197" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/isaac/archive/tags/sql+server/default.aspx">sql server</category><category domain="http://blogs.msdn.com/isaac/archive/tags/t-sql/default.aspx">t-sql</category><category domain="http://blogs.msdn.com/isaac/archive/tags/spatial/default.aspx">spatial</category></item><item><title>Connect and Implicit Casts</title><link>http://blogs.msdn.com/isaac/archive/2008/04/10/connect-and-implicit-casts.aspx</link><pubDate>Thu, 10 Apr 2008 19:57:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:8375523</guid><dc:creator>isaac</dc:creator><slash:comments>4</slash:comments><comments>http://blogs.msdn.com/isaac/comments/8375523.aspx</comments><wfw:commentRss>http://blogs.msdn.com/isaac/commentrss.aspx?PostID=8375523</wfw:commentRss><wfw:comment>http://blogs.msdn.com/isaac/rsscomments.aspx?PostID=8375523</wfw:comment><description>&lt;P&gt;Hi Folks,&lt;/P&gt;
&lt;P&gt;Perhaps it is surprising, based on the content here, that I'm not a full-time spatial head here in SQL Server land.&amp;nbsp; (We leave that job to &lt;A href="http://blogs.msdn.com/edkatibah/default.aspx" mce_href="http://blogs.msdn.com/edkatibah/default.aspx"&gt;Ed&lt;/A&gt;.)&amp;nbsp; I have, of course, been spending a lot of time on spatial, but it turns out I have other responsibilities as well, particularly around the broader type system.&amp;nbsp; One of my jobs is to take a look at issues that come in through &lt;A href="http://connect.microsoft.com/" mce_href="http://connect.microsoft.com"&gt;Connect&lt;/A&gt; that have to do with the type system and make sure they get handled appropriately.&lt;/P&gt;
&lt;P&gt;(If you don't use Connect, please do!&amp;nbsp; Issues filed there funnel directly into our bug-tracking system, giving you a direct line to the engineering team.&amp;nbsp; It is &lt;I&gt;the&lt;/I&gt; place to go with that pesky bug or feature request.)&lt;/P&gt;
&lt;P&gt;These Connect issues are an interesting mix. some good, solid bugs, and some not bugs at all.&amp;nbsp; It's these latter ones I find most interesting, since the majority of them point out quirks in our behavior that, while correct (and often even documented) are still somewhat confusing.&amp;nbsp; I'm going to try to start writing a bit more about common issues here in the hopes of clearing at least a little of that confusion.&lt;/P&gt;
&lt;P&gt;Which brings us to implicit casts.&amp;nbsp; An implicit cast is a cast that happens without any explicit direction from the user.&amp;nbsp; If you use CAST or CONVERT, you're using an explicit cast, and that's not what we're talking about here.&amp;nbsp; We're talking about code like this:&lt;/P&gt;
&lt;BLOCKQUOTE&gt;&lt;PRE class=csharpcode&gt;&lt;SPAN class=kwrd&gt;SELECT&lt;/SPAN&gt; &lt;SPAN class=str&gt;'1'&lt;/SPAN&gt;&lt;BR&gt;&lt;SPAN class=kwrd&gt;UNION&lt;/SPAN&gt;&lt;BR&gt;&lt;SPAN class=kwrd&gt;SELECT&lt;/SPAN&gt; 37&lt;/PRE&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;Since the UNION operator has to produce a consistent result, the types of each of its inputs must be the same.&amp;nbsp; Of course, that's not the case here: the first SELECT yields a varchar, the second an int.&amp;nbsp; Faced with this, the system inserts an implicit conversion, attempting to coerce the varchar to an int.&lt;/P&gt;
&lt;P&gt;But why convert the varchar to an int and not the other way around?&amp;nbsp; After all, it could convert 37 to '37' instead.&amp;nbsp; First, we have to understand that while this case is simple---the values are literals---this need not be the case. and so it may be very hard for the system to determine up-front what the actual values are.&amp;nbsp; E.g.:&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;DIV&gt;&lt;PRE class=csharpcode&gt;&lt;SPAN class=kwrd&gt;SELECT&lt;/SPAN&gt; T.a &lt;SPAN class=rem&gt;-- a varchar column&lt;/SPAN&gt;&lt;BR&gt;&lt;SPAN class=kwrd&gt;UNION&lt;/SPAN&gt;&lt;BR&gt;&lt;SPAN class=kwrd&gt;SELECT&lt;/SPAN&gt; U.b &lt;SPAN class=rem&gt;-- an int column&lt;/SPAN&gt;&lt;/PRE&gt;&lt;/DIV&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;Or worse:&lt;/P&gt;
&lt;BLOCKQUOTE&gt;&lt;PRE class=csharpcode&gt;&lt;SPAN class=kwrd&gt;SELECT&lt;/SPAN&gt; M.a &lt;SPAN class=kwrd&gt;FROM&lt;/SPAN&gt; &lt;SPAN class=rem&gt;-- some horribly complex query returning a varchar&lt;/SPAN&gt;&lt;BR&gt;&lt;SPAN class=kwrd&gt;UNION&lt;/SPAN&gt;&lt;BR&gt;&lt;SPAN class=kwrd&gt;SELECT&lt;/SPAN&gt; N.b &lt;SPAN class=kwrd&gt;FROM&lt;/SPAN&gt; -- another equally horrible query returning an int&lt;/PRE&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;In order to base this decision on the actual data, SQL Server would have to accumulate each side of the UNION, inspect all of the values, and hope to find a type that each of the values could be coerced to.&amp;nbsp; Perhaps worse, if the type depended on the actual data retrieved, then it could be very hard to determine what the result type of the query would be; it could even change if the data were updated.&lt;/P&gt;
&lt;P&gt;So SQL Server doesn't do this.&amp;nbsp; Instead of basing the conversion on the data itself, it bases it on the type of the data.&amp;nbsp; So, when the server looks at any of these examples, all it really sees is:&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;DIV&gt;&lt;PRE class=csharpcode&gt;&lt;SPAN class=kwrd&gt;SELECT&lt;/SPAN&gt; &amp;lt;&lt;SPAN class=kwrd&gt;varchar&lt;/SPAN&gt;&amp;gt;&lt;BR&gt;&lt;SPAN class=kwrd&gt;UNION&lt;/SPAN&gt;&lt;BR&gt;&lt;SPAN class=kwrd&gt;SELECT&lt;/SPAN&gt; &amp;lt;&lt;SPAN class=kwrd&gt;int&lt;/SPAN&gt;&amp;gt;&lt;/PRE&gt;&lt;/DIV&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;The server then decides which one to convert, in this case it converts the varchar to an int.&amp;nbsp; How does it make this choice?&amp;nbsp; It simply has a precedence list of types, which we can see in the &lt;A href="http://msdn2.microsoft.com/en-us/library/ms190309%28SQL.100%29.aspx" mce_href="http://msdn2.microsoft.com/en-us/library/ms190309(SQL.100).aspx"&gt;Data Type Precedence&lt;/A&gt; topic of Books Online.&amp;nbsp; The abbreviated version is:&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;1. user-defined data types (highest) &lt;BR&gt;2. sql_variant &lt;BR&gt;3. xml &lt;BR&gt;... &lt;BR&gt;16. int &lt;BR&gt;... &lt;BR&gt;27. varchar &lt;BR&gt;...&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;Int lands higher than varchar, and so the varchar is converted to an int.&amp;nbsp; The actual data returned by each select is not used at all in making this decision, only the types.&amp;nbsp; The system can make this decision with relatively simple logic, and the type of the result is consistent as well.&lt;/P&gt;
&lt;P&gt;This brings us to our pop-quiz.&amp;nbsp; What will this do?&lt;/P&gt;
&lt;BLOCKQUOTE&gt;&lt;PRE class=csharpcode&gt;&lt;SPAN class=kwrd&gt;SELECT&lt;/SPAN&gt; &lt;SPAN class=str&gt;'a'&lt;/SPAN&gt;&lt;BR&gt;&lt;SPAN class=kwrd&gt;UNION&lt;/SPAN&gt;&lt;BR&gt;&lt;SPAN class=kwrd&gt;SELECT&lt;/SPAN&gt; 37&lt;/PRE&gt;&lt;/BLOCKQUOTE&gt;
&lt;P mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;I'll give you a minute...&lt;/P&gt;
&lt;P mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;Got it?&lt;/P&gt;
&lt;P mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;Okay, here's the result:&lt;/P&gt;
&lt;BLOCKQUOTE&gt;&lt;PRE class=csharpcode&gt;Msg 245, &lt;SPAN class=kwrd&gt;Level&lt;/SPAN&gt; 16, &lt;SPAN class=kwrd&gt;State&lt;/SPAN&gt; 1, Line 1&lt;BR&gt;Conversion failed &lt;SPAN class=kwrd&gt;when&lt;/SPAN&gt; converting the &lt;SPAN class=kwrd&gt;varchar&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;value&lt;/SPAN&gt; &lt;SPAN class=str&gt;'a'&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;to&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;data&lt;/SPAN&gt; type &lt;SPAN class=kwrd&gt;int&lt;/SPAN&gt;.&lt;/PRE&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;Make sense?&lt;/P&gt;
&lt;P&gt;Cheers, &lt;BR&gt;-Isaac&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=8375523" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/isaac/archive/tags/sql+server/default.aspx">sql server</category><category domain="http://blogs.msdn.com/isaac/archive/tags/t-sql/default.aspx">t-sql</category></item><item><title>More on the Multi-Level Grid</title><link>http://blogs.msdn.com/isaac/archive/2008/04/08/more-on-the-multi-level-grid.aspx</link><pubDate>Tue, 08 Apr 2008 19:32:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:8369313</guid><dc:creator>isaac</dc:creator><slash:comments>5</slash:comments><comments>http://blogs.msdn.com/isaac/comments/8369313.aspx</comments><wfw:commentRss>http://blogs.msdn.com/isaac/commentrss.aspx?PostID=8369313</wfw:commentRss><wfw:comment>http://blogs.msdn.com/isaac/rsscomments.aspx?PostID=8369313</wfw:comment><description>&lt;P&gt;Hi Folks,&lt;/P&gt;
&lt;P&gt;In my &lt;A href="http://blogs.msdn.com/isaac/archive/2008/03/01/basic-multi-level-grids.aspx" mce_href="http://blogs.msdn.com/isaac/archive/2008/03/01/basic-multi-level-grids.aspx"&gt;last indexing post&lt;/A&gt;, I filled in most of the details about our multi-level grid index.&amp;nbsp; Let me clean up a few lingering questions about our planar grid. We'll do this Q&amp;amp;A style:&lt;/P&gt;
&lt;P&gt;&lt;B&gt;Q:&lt;/B&gt; &lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;&lt;I&gt;What happens if I set the maximum number of cells-per-object so small that I cannot obtain a covering of my object?&lt;/I&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;&lt;B&gt;A: &lt;/B&gt;&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;To make this concrete, let's take a look at one of the pictures from last time:&lt;/P&gt;
&lt;P&gt;&lt;A href="http://blogs.msdn.com/blogfiles/isaac/WindowsLiveWriter/MoreontheMultiLevelGrid_85A2/image_2.png" mce_href="http://blogs.msdn.com/blogfiles/isaac/WindowsLiveWriter/MoreontheMultiLevelGrid_85A2/image_2.png"&gt;&lt;IMG style="BORDER-RIGHT: 0px; BORDER-TOP: 0px; BORDER-LEFT: 0px; BORDER-BOTTOM: 0px" height=240 alt=image src="http://blogs.msdn.com/blogfiles/isaac/WindowsLiveWriter/MoreontheMultiLevelGrid_85A2/image_thumb.png" width=240 border=0 mce_src="http://blogs.msdn.com/blogfiles/isaac/WindowsLiveWriter/MoreontheMultiLevelGrid_85A2/image_thumb.png"&gt;&lt;/A&gt; &lt;/P&gt;
&lt;P&gt;In this schematic, there are four top-level cells, and we can see that we need at least three cells to tile the object.&amp;nbsp; In this picture, we are using 13 cells, so we've set the maximum number of cells-per-object to at least that.&amp;nbsp; But what if we set it to two?&lt;/P&gt;
&lt;P&gt;The answer is that in the case where the number of first-level cells needed to tile the object exceeds the max cells-per-object, we violate cells-per-object constraint.&amp;nbsp; This is really the only situation in which we'll do that, but it's necessary in order to ensure that we tile the object, and this is required in order to guarantee correct query results.&lt;/P&gt;
&lt;P&gt;Keep in mind that in a real index, the number of top level cells is either 16, 64, or 256, and this will only happen if the max cells-per-object exceeds that value.&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;&lt;B&gt;Q:&lt;/B&gt;&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;&lt;I&gt;What if I have an object that falls outside, or partially outside the bounding box I have defined?&amp;nbsp; Will I miss results?&lt;/I&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;&lt;B&gt;A:&lt;/B&gt;&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;There is an implicit extra cell in the tessellation, what we call the &lt;I&gt;root cell&lt;/I&gt;.&amp;nbsp; The root cell covers everything outside of the bounding box you've defined, and will be used to cover any object that touches it.&amp;nbsp; We can use this to guarantee correct results even if your object isn't well contained by your bounding box.&amp;nbsp; What will suffer is performance, and so it is still important to get the bounding box correct.&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;&lt;B&gt;Q:&lt;/B&gt;&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;&lt;I&gt;Are there times where you can answer the query using solely the index?&lt;/I&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;&lt;B&gt;A:&lt;/B&gt;&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;Yes.&amp;nbsp; Consider a cell that is touched by one object, and &lt;I&gt;completely covered&lt;/I&gt; by another.&amp;nbsp; We can tell that these two objects must intersect based solely on this fact: there is no need to actually run the intersection predicate.&amp;nbsp; We call this "intermediate filtering" (not the best name, but we needed something to call it) and we do implement it.&amp;nbsp; To do this, we store whether the object touches or covers the cell in the index row.&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;&lt;B&gt;Q:&lt;/B&gt; &lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;&lt;I&gt;Which predicates are supported on an index?&lt;/I&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;&lt;B&gt;A:&lt;/B&gt;&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;It depends on the type.&amp;nbsp; For geometry, we support STIntersects, STEquals, STOverlaps, STTouches, STWithin, STContains, STDistance, and STFilter.&amp;nbsp; On geography we only support STIntersects, STEquals, STDistance, and Filter.&amp;nbsp; We don't support the others simply because they don't exist on the type.&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;&lt;B&gt;Q:&lt;/B&gt;&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;&lt;I&gt;What is the difference between STIntersects and Filter?&lt;/I&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;&lt;B&gt;A:&lt;/B&gt;&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;If there isn't an index, they do exactly the same thing.&amp;nbsp; This can happen on the client, or on the server if you haven't defined an index (or if the index isn't chosen for some reason).&amp;nbsp; When there is an index involved, Filter will &lt;I&gt;not &lt;/I&gt;do any secondary filtering.&amp;nbsp; I.e., it is only guaranteed to return a superset of the results an STIntersects predicate will return: it may return extras.&lt;/P&gt;
&lt;P&gt;This is useful for applications that are simply displaying results, are not sensitive to some extras, and want to avoid the cost of the secondary filter.&amp;nbsp; If you need precise results, use STIntersects.&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;If there are more questions, please ask, and I'll answer them here.&amp;nbsp; So far we've only talked about geometry, so next time I'll either fill in the gaps around geography or answer more questions.&lt;/P&gt;
&lt;P&gt;Cheers, &lt;BR&gt;-Isaac&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=8369313" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/isaac/archive/tags/sql+server/default.aspx">sql server</category><category domain="http://blogs.msdn.com/isaac/archive/tags/spatial/default.aspx">spatial</category></item><item><title>The Unexpected Too-Large Polygon</title><link>http://blogs.msdn.com/isaac/archive/2008/04/06/the-unexpected-too-large-polygon.aspx</link><pubDate>Sun, 06 Apr 2008 03:25:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:8361857</guid><dc:creator>isaac</dc:creator><slash:comments>4</slash:comments><comments>http://blogs.msdn.com/isaac/comments/8361857.aspx</comments><wfw:commentRss>http://blogs.msdn.com/isaac/commentrss.aspx?PostID=8361857</wfw:commentRss><wfw:comment>http://blogs.msdn.com/isaac/rsscomments.aspx?PostID=8361857</wfw:comment><description>&lt;P&gt;Hi Folks,&lt;/P&gt;
&lt;P&gt;I recently got contacted via email with the following problem:&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;...&lt;/P&gt;
&lt;P&gt;I have 2 complex polygons, representing district boundaries.&amp;nbsp; The polygons look correct, but I'm getting exceptions when I try to create the type. &lt;BR&gt;&lt;BR&gt;I've attached the wkt polygons to the email. &lt;BR&gt;&lt;BR&gt;These polygons are stored in a table, but I've tried it without the table and get the same result. &lt;BR&gt;&lt;BR&gt;Here's the sql I'm trying to execute: &lt;BR&gt;&lt;BR&gt;declare @g geography; &lt;BR&gt;set @g = geography::STPolyFromText(@wkt, 4268) &lt;BR&gt;select @g.ToString() &lt;BR&gt;&lt;BR&gt;where @wkt is replaced by the correct polygon string.&lt;/P&gt;
&lt;P&gt;...&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;Now, I should point out that this is a very nice error report.&amp;nbsp; They've told me what their data is, they included their data, and they told me very clearly what they're trying to do.&amp;nbsp; (Perhaps knowing what version they're using would good, but I'm getting picky.)&lt;/P&gt;
&lt;P&gt;But here's the kicker that saved me any debugging:&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;... &lt;BR&gt;Here is the error message I receive: &lt;BR&gt;&lt;BR&gt;A .NET Framework error occurred during execution of user defined routine or aggregate 'geography': &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;nbsp;&amp;nbsp; at Microsoft.SqlServer.Types.GLNativeMethods.ThrowExceptionForHr(GL_HResult errorCode) &lt;BR&gt;&amp;nbsp;&amp;nbsp; at Microsoft.SqlServer.Types.GLNativeMethods.GeodeticIsValid(GeometryData g) &lt;BR&gt;&amp;nbsp;&amp;nbsp; at Microsoft.SqlServer.Types.SqlGeography.IsValidExpensive() &lt;BR&gt;&amp;nbsp;&amp;nbsp; at Microsoft.SqlServer.Types.SqlGeography.ConstructGeographyFromUserInput(GeometryData g, Int32 srid) &lt;BR&gt;&amp;nbsp;&amp;nbsp; at Microsoft.SqlServer.Types.SqlGeography.STPolyFromText(SqlChars polygonTaggedText, Int32 srid) &lt;BR&gt;&lt;BR&gt;I looked at all the nodes, and they are all in the same hemisphere, so I'm a little confused with what might be going on. &lt;BR&gt;...&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;So, what's going on?&amp;nbsp; Ring ordering. &lt;/P&gt;
&lt;P&gt;I've &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;posted on this before&lt;/A&gt;, but let's recap.&amp;nbsp; On a round Earth, defining a polygon by a ring is ambiguous.&amp;nbsp; Consider the polygon defined by a ring around the equator: does this describe the northern or southern hemisphere?&amp;nbsp; A small ring could describe either, say, a small island in a large ocean, or the large ocean itself.&lt;/P&gt;
&lt;P&gt;To get out of this pickle, we disambiguate with a standard trick: we take ring orientation into account.&amp;nbsp; We simply define the left side of the ring as it is drawn to be inside the polygon.&lt;/P&gt;
&lt;P&gt;If we put this together with our current (unfortunate) limitation that we do not deal with objects that exceed a hemisphere, and it becomes clear what's going on.&amp;nbsp; While the polygon looks like it's nice and small, the rings are inverted, and so it's actually quite large.&amp;nbsp; We can't handle it: cue the exception.&lt;/P&gt;
&lt;P&gt;I describe this hemisphere limitation as unfortunate, and it remains one of the biggest items the spatial team would like to fix up, but in this case it has actually helped catch an error.&lt;/P&gt;
&lt;P&gt;I'll talk a bit more about our hemisphere limitation in a future post.&amp;nbsp; It's not quite as simple as we let on.&lt;/P&gt;
&lt;P&gt;Cheers, &lt;BR&gt;-Isaac&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=8361857" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/isaac/archive/tags/sql+server/default.aspx">sql server</category><category domain="http://blogs.msdn.com/isaac/archive/tags/spatial/default.aspx">spatial</category></item><item><title>February CTP Optimizer Issue</title><link>http://blogs.msdn.com/isaac/archive/2008/03/11/february-ctp-optimizer-issue.aspx</link><pubDate>Tue, 11 Mar 2008 06:42:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:8143705</guid><dc:creator>isaac</dc:creator><slash:comments>0</slash:comments><comments>http://blogs.msdn.com/isaac/comments/8143705.aspx</comments><wfw:commentRss>http://blogs.msdn.com/isaac/commentrss.aspx?PostID=8143705</wfw:commentRss><wfw:comment>http://blogs.msdn.com/isaac/rsscomments.aspx?PostID=8143705</wfw:comment><description>&lt;P style="FONT-SIZE: 11pt; MARGIN: 0in; FONT-FAMILY: Calibri"&gt;Hi Folks,&lt;/P&gt;
&lt;P style="FONT-SIZE: 11pt; MARGIN: 0in; FONT-FAMILY: Calibri" mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P style="FONT-SIZE: 11pt; MARGIN: 0in; FONT-FAMILY: Calibri"&gt;We don't call them betas, but that's basically what CTPs are: they let us suss out problems before we drop a final product on everyone.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;Well, we've found a regression in the February CTP spatial support that we'd like to let you know about.&lt;/P&gt;
&lt;P style="FONT-SIZE: 11pt; MARGIN: 0in; FONT-FAMILY: Calibri" mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P style="FONT-SIZE: 11pt; MARGIN: 0in; FONT-FAMILY: Calibri"&gt;Essentially, a costing problem was introduced that leads us to choose poor plans for spatial queries.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;This seems to usually manifest itself by choosing merge joins instead of loop joins between the spatial index and the base table, and that generally doesn't work too well.&lt;/P&gt;
&lt;P style="FONT-SIZE: 11pt; MARGIN: 0in; FONT-FAMILY: Calibri" mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P style="FONT-SIZE: 11pt; MARGIN: 0in; FONT-FAMILY: Calibri"&gt;Why is a merge join such a bad plan in this case?&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;If you've been following my indexing posts, you'll understand that we generally end up with a small number of rows that pass our primary filter (our index).&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;We have to then join those back to the base table to pull out the spatial object to which the index row refers.&lt;/P&gt;
&lt;P style="FONT-SIZE: 11pt; MARGIN: 0in; FONT-FAMILY: Calibri" mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P style="FONT-SIZE: 11pt; MARGIN: 0in; FONT-FAMILY: Calibri"&gt;This is usually best done through a loop join that runs over each index row and &lt;SPAN style="FONT-STYLE: italic"&gt;seeks&lt;/SPAN&gt; into the base table for each of the objects.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;However, if a merge join is chosen, then we risk &lt;SPAN style="FONT-STYLE: italic"&gt;scanning &lt;/SPAN&gt;the entire base table to feed into our merge.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;This is usually not a wise choice.&lt;/P&gt;
&lt;P style="FONT-SIZE: 11pt; MARGIN: 0in; FONT-FAMILY: Calibri" mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P style="FONT-SIZE: 11pt; MARGIN: 0in; FONT-FAMILY: Calibri"&gt;What can you do about this if you're running the February CTP?&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;A good general fix is to force loop joins in your query.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;Perhaps the simplest way to do this is by adding an "OPTION (LOOP JOIN)" to the end of your query.&lt;/P&gt;
&lt;P style="FONT-SIZE: 11pt; MARGIN: 0in; FONT-FAMILY: Calibri" mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P style="FONT-SIZE: 11pt; MARGIN: 0in; FONT-FAMILY: Calibri"&gt;On the positive side, this has already been fixed, so you should see better plans in our next public release.&lt;/P&gt;
&lt;P style="FONT-SIZE: 11pt; MARGIN: 0in; FONT-FAMILY: Calibri" mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P style="FONT-SIZE: 11pt; MARGIN: 0in; FONT-FAMILY: Calibri"&gt;Cheers,&lt;/P&gt;
&lt;P style="FONT-SIZE: 11pt; MARGIN: 0in; FONT-FAMILY: Calibri"&gt;-Isaac&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=8143705" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/isaac/archive/tags/sql+server/default.aspx">sql server</category><category domain="http://blogs.msdn.com/isaac/archive/tags/spatial/default.aspx">spatial</category></item><item><title>The Upcoming Geography Coordinate Order Swap---A FAQ</title><link>http://blogs.msdn.com/isaac/archive/2008/03/05/the-upcoming-geography-coordinate-order-swap-a-faq.aspx</link><pubDate>Wed, 05 Mar 2008 20:24:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:8053398</guid><dc:creator>isaac</dc:creator><slash:comments>14</slash:comments><comments>http://blogs.msdn.com/isaac/comments/8053398.aspx</comments><wfw:commentRss>http://blogs.msdn.com/isaac/commentrss.aspx?PostID=8053398</wfw:commentRss><wfw:comment>http://blogs.msdn.com/isaac/rsscomments.aspx?PostID=8053398</wfw:comment><description>&lt;P&gt;Hi Folks,&lt;/P&gt;
&lt;P&gt;I just thought I'd take a few moments clarify the upcoming &lt;A class="" href="http://blogs.msdn.com/isaac/archive/2007/12/27/latitude-longitude-ordering.aspx" mce_href="http://blogs.msdn.com/isaac/archive/2007/12/27/latitude-longitude-ordering.aspx"&gt;coordinate order swap&lt;/A&gt; for the geography type.&amp;nbsp; Here's a quick FAQ on the issue:&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;What exactly is the change?&lt;BR&gt;&lt;BR&gt;We are&amp;nbsp;swapping the coordinate order for well-known text (WKT) and well-known binary (WKB) formats from latitude-longitude to longitude-latitude.&amp;nbsp;&amp;nbsp;E.g.,&amp;nbsp;a point in the Seattle area might be represented in WKT as "POINT(44 -122)" in the current ordering; in the new order&amp;nbsp;it will be "POINT(-122 44)".&lt;BR&gt;&lt;/LI&gt;
&lt;LI&gt;Why are we making this change?&lt;BR&gt;&lt;BR&gt;Because of customer feedback.&amp;nbsp; While&amp;nbsp;common practice&amp;nbsp;almost universally uses latitude-longitude ordering, the de facto standard&amp;nbsp;for WKT and WKB is to use a longitude-latitude order.&amp;nbsp;&amp;nbsp;Making this change will make it much easier for&amp;nbsp;customers to load WKT and WKB data into the geography type.&lt;BR&gt;&amp;nbsp;&lt;/LI&gt;
&lt;LI&gt;What about GML?&amp;nbsp;&lt;BR&gt;&lt;BR&gt;The standard paractice for GML is to use latitude-longitude ordering, and so no change will be made for GML.&lt;BR&gt;&lt;/LI&gt;
&lt;LI&gt;Is the on-disk format changing?&lt;BR&gt;&lt;BR&gt;Nope.&amp;nbsp; Ths is just a matter of changing our routines that import and export data.&amp;nbsp; Nothing beyond those routines will change.&lt;BR&gt;&lt;/LI&gt;
&lt;LI&gt;What about geometry?&lt;BR&gt;&lt;BR&gt;There is no change to the geometry type.&amp;nbsp; Geometry deals with objects on the plane, and is pretty agnostic about the coordinate order outsidfe of the STX and STY properties.&lt;BR&gt;&lt;/LI&gt;
&lt;LI&gt;When is the swap happening?&lt;BR&gt;&lt;BR&gt;It is not the current Februrary CTP, but the team is working on it now.&amp;nbsp; Expect to see it in our next public release.&lt;/LI&gt;&lt;/UL&gt;
&lt;P mce_keep="true"&gt;If there are more questions, I'll be happy to answer them here.&lt;/P&gt;
&lt;P mce_keep="true"&gt;Cheers,&lt;BR&gt;-Isaac&lt;/P&gt;
&lt;P mce_keep="true"&gt;Minor&amp;nbsp;Update:&amp;nbsp;I originally got the WKT examples at the top wrong, placing commas between coordinates.&amp;nbsp; The examples have been updated to their correct, comma-free state.&amp;nbsp; (Thanks, Steven!)&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=8053398" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/isaac/archive/tags/sql+server/default.aspx">sql server</category><category domain="http://blogs.msdn.com/isaac/archive/tags/spatial/default.aspx">spatial</category></item><item><title>Basic Multi-Level Grids</title><link>http://blogs.msdn.com/isaac/archive/2008/03/01/basic-multi-level-grids.aspx</link><pubDate>Sat, 01 Mar 2008 05:17:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:7968742</guid><dc:creator>isaac</dc:creator><slash:comments>3</slash:comments><comments>http://blogs.msdn.com/isaac/comments/7968742.aspx</comments><wfw:commentRss>http://blogs.msdn.com/isaac/commentrss.aspx?PostID=7968742</wfw:commentRss><wfw:comment>http://blogs.msdn.com/isaac/rsscomments.aspx?PostID=7968742</wfw:comment><description>&lt;P&gt;Hi Folks,&lt;/P&gt;
&lt;P&gt;&lt;A class="" href="http://blogs.msdn.com/isaac/archive/2008/02/05/picking-up-on-indexing-moving-beyond-the-simple-grid.aspx" mce_href="http://blogs.msdn.com/isaac/archive/2008/02/05/picking-up-on-indexing-moving-beyond-the-simple-grid.aspx"&gt;Last time&lt;/A&gt;, we highlighted several problems with a simple grid index.&amp;nbsp; If you don't recall---and since it's been a while, that wouldn't be a surprise---you may want to review them.&amp;nbsp; In this post I'll start to describe how we get around them.&lt;/P&gt;
&lt;P&gt;In SQL Server, we don't use a simple grid like the one described.&amp;nbsp; Instead, we use a multi-level grid, which ends up looking very much like a quad tree.&amp;nbsp; Basically, instead of having one grid level, we have four, with each lower-level grid nested in the one above.&lt;/P&gt;
&lt;P&gt;Let's look at an example.&amp;nbsp; If we have a 2x2 grid at each level, then we can tile the object below with three tiles at the top-level grid:&lt;/P&gt;
&lt;P&gt;&lt;IMG style="WIDTH: 330px; HEIGHT: 330px" height=330 src="http://blogs.msdn.com/photos/isaac/images/7968868/original.aspx" width=330 mce_src="http://blogs.msdn.com/photos/isaac/images/7968868/original.aspx"&gt;&lt;/P&gt;
&lt;P&gt;These tiles cover the object, which is a property we want to maintain for our indexing scheme, but there's a lot of extra coverage.&amp;nbsp; This extra means we're likely to have a good number of false positives from our primary filter.&amp;nbsp; We can go to a second-level gridding instead:&lt;/P&gt;
&lt;P mce_keep="true"&gt;&lt;IMG style="WIDTH: 330px; HEIGHT: 330px" height=330 src="http://blogs.msdn.com/photos/isaac/images/7968975/original.aspx" width=330 mce_src="http://blogs.msdn.com/photos/isaac/images/7968975/original.aspx"&gt;&lt;/P&gt;
&lt;P mce_keep="true"&gt;At this level, we've trimmed some of the extra slop from the edges, but our description of the object has become more complex as well.&amp;nbsp;&amp;nbsp;With our four levels, we can push this even further---here's what a fourth-level tiling of the object would look like:&lt;/P&gt;
&lt;P mce_keep="true"&gt;&lt;IMG style="WIDTH: 330px; HEIGHT: 330px" height=330 src="http://blogs.msdn.com/photos/isaac/images/7968875/original.aspx" width=330 mce_src="http://blogs.msdn.com/photos/isaac/images/7968875/original.aspx"&gt;&lt;/P&gt;
&lt;P mce_keep="true"&gt;This description is nice and tight---there's very extra covering of the object---but it's also very complicated.&amp;nbsp; What's key to&amp;nbsp;keeping the complexity down is that&amp;nbsp;we don't require that all object use the same level tiling, nor do we require that all tiles for a particular object all be at the same level.&amp;nbsp; We can mix as we wish.&lt;/P&gt;
&lt;P mce_keep="true"&gt;The ability to mix levels in our tiling leads us to two optimizations.&amp;nbsp; The first, which is always used, is that if we find that all subtiles of a particular tile are touched by the object, then we won't further subdivide the cell.&amp;nbsp; Subdividing gives us nothing but more cells.&amp;nbsp; Perhaps this is clearer visually; below is a picture of the same tiling above with this optimization applied:&lt;/P&gt;
&lt;P mce_keep="true"&gt;&lt;IMG style="WIDTH: 330px; HEIGHT: 330px" height=330 src="http://blogs.msdn.com/photos/isaac/images/7968877/original.aspx" width=330 mce_src="http://blogs.msdn.com/photos/isaac/images/7968877/original.aspx"&gt;&lt;/P&gt;
&lt;P mce_keep="true"&gt;As you can see, this greatly reduces the number of tiles we have, and does so by mixing levels.&amp;nbsp; A second way to reduce tiles is through an explicit limit.&amp;nbsp; We default this limit to 16, but the user can tweak it to their liking.&amp;nbsp; When we decompose an object, we do a breath-first walk down the tree decomposing tiles, and we stop when we hit the pre-defined limit.&amp;nbsp; E.g., we might end up with:&lt;/P&gt;
&lt;P mce_keep="true"&gt;&lt;IMG style="WIDTH: 330px; HEIGHT: 330px" height=330 src="http://blogs.msdn.com/photos/isaac/images/7968888/original.aspx" width=330 mce_src="http://blogs.msdn.com/photos/isaac/images/7968888/original.aspx"&gt;&lt;/P&gt;
&lt;P mce_keep="true"&gt;There's much more to say about this, but before I leave it for now, let me point out that&amp;nbsp;while these examples use 2x2 decompositions at each level, we&amp;nbsp;use more.&amp;nbsp; The exact amount is, in fact, adjustable: the user can set each level to low (4x4) medium (8x8) or high&amp;nbsp;(16x16).&lt;/P&gt;
&lt;P mce_keep="true"&gt;How should the user tweak these various parameters?&amp;nbsp; It's hard to give general advice, as it's a very data- and query-dependent calculation, but we feel that we have picked some defaults that will work well for most people.&amp;nbsp; We may have better advice as more people start using the index and we get reports on what worked for them.&amp;nbsp; (Yes, we're begging you to send us your findings!)&lt;/P&gt;
&lt;P mce_keep="true"&gt;Next&amp;nbsp;time we'll continue with some more details about the mult-level grid.&lt;/P&gt;
&lt;P mce_keep="true"&gt;Cheers,&lt;BR&gt;-Isaac&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=7968742" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/isaac/archive/tags/sql+server/default.aspx">sql server</category><category domain="http://blogs.msdn.com/isaac/archive/tags/spatial/default.aspx">spatial</category><category domain="http://blogs.msdn.com/isaac/archive/tags/spatial+indexing/default.aspx">spatial indexing</category></item><item><title>One Type, Two Types...</title><link>http://blogs.msdn.com/isaac/archive/2007/05/29/one-type-two-types.aspx</link><pubDate>Tue, 29 May 2007 17:15:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:2969351</guid><dc:creator>isaac</dc:creator><slash:comments>10</slash:comments><comments>http://blogs.msdn.com/isaac/comments/2969351.aspx</comments><wfw:commentRss>http://blogs.msdn.com/isaac/commentrss.aspx?PostID=2969351</wfw:commentRss><wfw:comment>http://blogs.msdn.com/isaac/rsscomments.aspx?PostID=2969351</wfw:comment><description>&lt;P&gt;&lt;SPAN style="FONT-SIZE: 12pt; FONT-FAMILY: Calibri"&gt;This is a little bit less of an introductory post than the &lt;/SPAN&gt;&lt;A href="http://blogs.msdn.com/isaac/archive/2007/05/16/sql-server-spatial-support-an-introduction.aspx" mce_href="http://blogs.msdn.com/isaac/archive/2007/05/16/sql-server-spatial-support-an-introduction.aspx"&gt;&lt;SPAN style="FONT-SIZE: 12pt; FONT-FAMILY: Calibri"&gt;last one&lt;/SPAN&gt;&lt;/A&gt;&lt;SPAN style="FONT-SIZE: 12pt; FONT-FAMILY: Calibri"&gt;, but there was quite a bit of discussion about our decision to split our spatial types in two---one for our planar ("flat-Earth") model and one for our ellipsoidal ("round-Earth") model---so I thought I'd address it.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;To be honest, this is something that we struggled with, but in the end we favored the two-type model.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;Here's a quick look at of some of our reasoning.&lt;/SPAN&gt;&lt;/P&gt;
&lt;P style="FONT-SIZE: 12pt; MARGIN: 0in; FONT-FAMILY: Calibri" mce_keep="true"&gt;Let me begin with a roughly analogous situation: SQL Server's floating- and fixed-point types, float and decimal.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;These types really have the same interface, so we could have conceivably had one type with a floating-point/fixed-point option.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;Why choose two types over one?&lt;/P&gt;
&lt;P style="FONT-SIZE: 12pt; MARGIN: 0in; FONT-FAMILY: Calibri" mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P style="FONT-SIZE: 12pt; MARGIN: 0in; FONT-FAMILY: Calibri"&gt;One reason is that mingling the two would be confusing, since their semantics differ.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;If we didn't separate the types, then we could write a method that took that single numeric type as input.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;If we performed any operations that depended on the difference in semantics, then we would have to be careful to check which one we were dealing with and proceed accordingly.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;We could skip these checks if we always expected, say, fixed-point, but we could be almost certain that if our code survived long enough, some schmuck would eventually hand us a floating-point value.&lt;/P&gt;
&lt;P style="FONT-SIZE: 12pt; MARGIN: 0in; FONT-FAMILY: Calibri" mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P style="FONT-SIZE: 12pt; MARGIN: 0in; FONT-FAMILY: Calibri"&gt;By separating the types, there is a clear division, and given an instance of a particular type we know exactly what we're dealing with.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;Additionally, we know that nobody could hand us the wrong type later on.&lt;/P&gt;
&lt;P style="FONT-SIZE: 12pt; MARGIN: 0in; FONT-FAMILY: Calibri" mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P style="FONT-SIZE: 12pt; MARGIN: 0in; FONT-FAMILY: Calibri"&gt;So by separating the types we've made things more explicit and clear, but one can argue that since the semantics are often the same---or at least close enough that we don't care---we could save code by unifying the types.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;This is undoubtedly true: there's a tradeoff to be made.&lt;/P&gt;
&lt;P style="FONT-SIZE: 12pt; MARGIN: 0in; FONT-FAMILY: Calibri" mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P style="FONT-SIZE: 12pt; MARGIN: 0in; FONT-FAMILY: Calibri"&gt;We face a similar problem with spatial types.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;The two types often behave quite similarly, but there are some key differences.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;The tradeoff is the same: you can save code by unifying the types at the expense of clarity and robustness.&lt;/P&gt;
&lt;P style="FONT-SIZE: 12pt; MARGIN: 0in; FONT-FAMILY: Calibri" mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P style="FONT-SIZE: 12pt; MARGIN: 0in; FONT-FAMILY: Calibri" mce_keep="true"&gt;So, what's different between the planar and ellipsoidal&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;types?&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;Well, beyond the obvious---one is flat, one is round---here are some examples:&lt;/P&gt;
&lt;P style="FONT-SIZE: 12pt; MARGIN: 0in 0in 0in 0.375in; FONT-FAMILY: Calibri" mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;
&lt;LI style="MARGIN-TOP: 0px; MARGIN-BOTTOM: 0px; VERTICAL-ALIGN: middle; LIST-STYLE-TYPE: disc"&gt;&lt;SPAN style="FONT-SIZE: 12pt; FONT-FAMILY: Calibri"&gt;In the planar system, distances and areas are given in the same unit of measure as coordinates.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;E.g., the distance between (2, 2) and (5, 6) is 5 units, regardless of what units are.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;In a geodetic system, coordinates are given in degrees, but it hardly makes sense to give lengths and areas in degrees or square degrees---we'd much prefer something like meters.&lt;/SPAN&gt;&lt;/LI&gt;
&lt;P style="FONT-SIZE: 12pt; MARGIN: 0in; FONT-FAMILY: Calibri" mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;
&lt;LI style="MARGIN-TOP: 0px; MARGIN-BOTTOM: 0px; VERTICAL-ALIGN: middle; LIST-STYLE-TYPE: disc"&gt;&lt;SPAN style="FONT-SIZE: 12pt; FONT-FAMILY: Calibri"&gt;In the planar system, we don't care about the orientation of a polygon.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;E.g., a polygon described by ((0, 0), (10, 0), (0, 20), (0, 0)) is the same as one described by ((0, 0), (0, 20), (10, 0), (0, 0)).&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;The OGC Simple Features for SQL specification doesn't dictate a ring ordering, so we don't enforce one.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;In a geodetic system, a polygon is ambiguous without an orientation.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;E.g., which hemisphere would a ring around the equator describe?&lt;/SPAN&gt;&lt;/LI&gt;
&lt;P style="FONT-SIZE: 12pt; MARGIN: 0in; FONT-FAMILY: Calibri" mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;
&lt;LI style="MARGIN-TOP: 0px; MARGIN-BOTTOM: 0px; VERTICAL-ALIGN: middle; LIST-STYLE-TYPE: disc"&gt;&lt;SPAN style="FONT-SIZE: 12pt; FONT-FAMILY: Calibri"&gt;In planar coordinates, it makes sense to use a bounding box as a cheap substitute for an object.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;In geodetic coordinates, a bounding circle is more natural.&lt;/SPAN&gt;&lt;/LI&gt;
&lt;P style="FONT-SIZE: 12pt; MARGIN: 0in; FONT-FAMILY: Calibri" mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;
&lt;LI style="MARGIN-TOP: 0px; MARGIN-BOTTOM: 0px; VERTICAL-ALIGN: middle; LIST-STYLE-TYPE: disc"&gt;&lt;SPAN style="FONT-SIZE: 12pt; FONT-FAMILY: Calibri"&gt;OGC talks about outer rings and inner rings, but this distinction makes little sense for a geodetic type: any ring of a polygon can be taken to be the outer one.&lt;/SPAN&gt;&lt;/LI&gt;
&lt;P style="FONT-SIZE: 12pt; MARGIN: 0in; FONT-FAMILY: Calibri" mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P style="FONT-SIZE: 12pt; MARGIN: 0in; FONT-FAMILY: Calibri"&gt;Of course, this is only a start.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;In addition, we are aiming to simplify things a little bit in our round-Earth type.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;We thought that given all of this, merging the two types would be confusing, especially for the non-experts out there, so we decided to separate things into two types.&lt;/P&gt;
&lt;P style="FONT-SIZE: 12pt; MARGIN: 0in; FONT-FAMILY: Calibri" mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P style="FONT-SIZE: 12pt; MARGIN: 0in; FONT-FAMILY: Calibri"&gt;Is that the right decision?&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;We think so, but we recognize that not everyone may agree with us.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;We look forward to hearing from you.&lt;/P&gt;
&lt;P style="FONT-SIZE: 12pt; MARGIN: 0in; FONT-FAMILY: Calibri" mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P style="FONT-SIZE: 12pt; MARGIN: 0in; FONT-FAMILY: Calibri"&gt;Cheers,&lt;/P&gt;
&lt;P style="FONT-SIZE: 12pt; MARGIN: 0in; FONT-FAMILY: Calibri"&gt;-Isaac&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=2969351" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/isaac/archive/tags/sql+server/default.aspx">sql server</category><category domain="http://blogs.msdn.com/isaac/archive/tags/spatial/default.aspx">spatial</category></item><item><title>SQL Server Spatial Support: An Introduction</title><link>http://blogs.msdn.com/isaac/archive/2007/05/16/sql-server-spatial-support-an-introduction.aspx</link><pubDate>Thu, 17 May 2007 01:28:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:2681837</guid><dc:creator>isaac</dc:creator><slash:comments>32</slash:comments><comments>http://blogs.msdn.com/isaac/comments/2681837.aspx</comments><wfw:commentRss>http://blogs.msdn.com/isaac/commentrss.aspx?PostID=2681837</wfw:commentRss><wfw:comment>http://blogs.msdn.com/isaac/rsscomments.aspx?PostID=2681837</wfw:comment><description>&lt;FONT face=Calibri&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 10pt"&gt;&lt;FONT size=3&gt;I’ve been pretty quiet around here, and at least part of the reason is that we’ve been pretty tight-lipped about what we’ve been up to.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;We’ve now gone public—we’re providing support for geospatial data in our next version of SQL Server, codenamed Katmai.&amp;nbsp; The Virtual Earth folks &lt;A class="" href="http://virtualearth.spaces.live.com/blog/cns!2BBC66E99FDCDB98!8675.entry#comment" mce_href="http://virtualearth.spaces.live.com/blog/cns!2BBC66E99FDCDB98!8675.entry#comment"&gt;mentioned this in their blog&lt;/A&gt;&amp;nbsp;(&lt;A class="" href="http://www.spatiallyadjusted.com/2007/05/10/microsoft-sql-server-2008-to-have-spatial-data-natively/" mce_href="http://www.spatiallyadjusted.com/2007/05/10/microsoft-sql-server-2008-to-have-spatial-data-natively/"&gt;others&lt;/A&gt;, &lt;A class="" href="http://www.directionsmag.com/article.php?article_id=2459&amp;amp;trv=1" mce_href="http://www.directionsmag.com/article.php?article_id=2459&amp;amp;trv=1"&gt;too&lt;/A&gt;)&amp;nbsp;but&amp;nbsp;now&amp;nbsp;I can make a little more noise.&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 10pt"&gt;&lt;FONT size=3&gt;What I’d like to do first is try to explain to the folks out there who aren’t experts in the field what this all means and give a very high-level tour of what we’re providing.&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 10pt"&gt;&lt;FONT size=3&gt;First, what is geospatial data?&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;For starters, we mean locations on the Earth.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;It’s more than location, though: we mean the location and shape of objects on the Earth.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;Think of the description of roads, states, lakes, etc.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;For example, think of something like Live Maps:&lt;/FONT&gt;&lt;/P&gt;&lt;/FONT&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 10pt"&gt;&lt;FONT face=Calibri size=3&gt;&lt;IMG title="Microsoft's Main Campus" style="WIDTH: 491px; HEIGHT: 474px" height=474 alt="Microsoft's Main Campus" src="http://blogs.msdn.com/photos/isaac/images/2681687/original.aspx" width=491 mce_src="http://blogs.msdn.com/photos/isaac/images/2681687/original.aspx"&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 10pt"&gt;&lt;FONT face=Calibri size=3&gt;In addition to the normal objects, I’ve added a polygon that shows Microsoft’s main campus.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;We want to be able to store all of the data on this map—the roads, the parks, and user-generated polygon—in SQL Server.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;Being a database, we want to be able to ask questions about the data.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;For example, “What are the roads that intersect Microsoft’s main campus?”&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;A more complex example would be “What is the area of all parks within 1 kilometer of Microsoft’s main campus?”&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 10pt"&gt;&lt;FONT face=Calibri size=3&gt;How do we do this?&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;First, we need new data types to be able to store this information.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;Toward this end, we are introducing two new types in Katmai:&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoListParagraphCxSpFirst style="MARGIN: 0in 0in 0pt 0.5in; TEXT-INDENT: -0.25in; mso-list: l0 level1 lfo1"&gt;&lt;SPAN style="FONT-FAMILY: Symbol; mso-fareast-font-family: Symbol; mso-bidi-font-family: Symbol"&gt;&lt;SPAN style="mso-list: Ignore"&gt;&lt;FONT size=3&gt;·&lt;/FONT&gt;&lt;SPAN style="FONT: 7pt 'Times New Roman'"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;FONT face=Calibri size=3&gt;The first type, “geography”, will store points, lines, polygons, and collections of these in latitude/longitude coordinates using a round-Earth model.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;Most commonly-available data is given in latitude/longitude coordinates, so we expect that most people will want to use this type.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;Furthermore, this type will give correct computations on a true ellipsoidal model of the planet.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;What is the area of Indonesia?&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;Will my flight from Seattle to Beijing take me over North Korea?&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;Where can I store my GPS readings?&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;This is the type for you.&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoListParagraphCxSpMiddle style="MARGIN: 0in 0in 0pt 0.5in"&gt;&lt;?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" /&gt;&lt;o:p&gt;&lt;FONT face=Calibri size=3&gt;&amp;nbsp;&lt;/FONT&gt;&lt;/o:p&gt;&lt;/P&gt;
&lt;P class=MsoListParagraphCxSpLast style="MARGIN: 0in 0in 10pt 0.5in; TEXT-INDENT: -0.25in; mso-list: l0 level1 lfo1"&gt;&lt;SPAN style="FONT-FAMILY: Symbol; mso-fareast-font-family: Symbol; mso-bidi-font-family: Symbol"&gt;&lt;SPAN style="mso-list: Ignore"&gt;&lt;FONT size=3&gt;·&lt;/FONT&gt;&lt;SPAN style="FONT: 7pt 'Times New Roman'"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;FONT face=Calibri size=3&gt;A “geometry” type to support flat-earth data.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;For those of you who are familiar with such things, this type is our OGC-compliant offering.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;In some ways, this is a more specialty offering for people who need to work in projected map coordinates either for legacy or legal reasons, but this type can be used for things like interior spaces as well, e.g., “Where in this warehouse is my book?”&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 10pt"&gt;&lt;FONT face=Calibri size=3&gt;If we take our roads data above—perhaps all of the roads for the United States—we could store them in a table Roads:&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 10pt"&gt;&lt;FONT face=Calibri size=3&gt;Roads(name varchar(30), location geography)&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 10pt"&gt;&lt;FONT face=Calibri size=3&gt;I.e., geography is a column type just like any other.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;We expose a pretty comprehensive set of operations on these type through a method-based interface.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;For example, if we have a geometry variable @microsoft that represents Microsoft’s main campus, we can find out which roads intersect it with the query:&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 10pt 0.5in"&gt;&lt;FONT face=Calibri size=3&gt;SELECT name&lt;BR&gt;FROM Roads&lt;BR&gt;WHERE location.STIntersects(@microsoft) = 1&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 10pt"&gt;&lt;FONT face=Calibri size=3&gt;Given a similar Parks table containing all US parks, we can ask our parks question from above:&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 10pt 0.5in"&gt;&lt;FONT face=Calibri size=3&gt;SELECT SUM(location.STArea())&lt;BR&gt;FROM Parks&lt;BR&gt;WHERE location.STDistance(@microsoft) &amp;lt; 1.0&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 10pt"&gt;&lt;SPAN style="FONT-SIZE: 11pt; LINE-HEIGHT: 115%; FONT-FAMILY: 'Calibri','sans-serif'; mso-fareast-font-family: Calibri; mso-bidi-font-family: 'Times New Roman'; mso-ascii-theme-font: minor-latin; mso-fareast-theme-font: minor-latin; mso-hansi-theme-font: minor-latin; mso-bidi-theme-font: minor-bidi; mso-ansi-language: EN-US; mso-fareast-language: EN-US; mso-bidi-language: AR-SA"&gt;Of course, beyond answering this query, we need to be able to answer the query quickly.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;Since my data may be very large, speed is going to mean having a good spatial index.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;Perhaps that will be the subject of my next post.&amp;nbsp; Watch this space for more.&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 10pt"&gt;&lt;SPAN style="FONT-SIZE: 11pt; LINE-HEIGHT: 115%; FONT-FAMILY: 'Calibri','sans-serif'; mso-fareast-font-family: Calibri; mso-bidi-font-family: 'Times New Roman'; mso-ascii-theme-font: minor-latin; mso-fareast-theme-font: minor-latin; mso-hansi-theme-font: minor-latin; mso-bidi-theme-font: minor-bidi; mso-ansi-language: EN-US; mso-fareast-language: EN-US; mso-bidi-language: AR-SA"&gt;&amp;nbsp;Cheers,&lt;BR&gt;-Isaac&lt;/SPAN&gt;&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=2681837" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/isaac/archive/tags/live+maps/default.aspx">live maps</category><category domain="http://blogs.msdn.com/isaac/archive/tags/sql+server/default.aspx">sql server</category><category domain="http://blogs.msdn.com/isaac/archive/tags/spatial/default.aspx">spatial</category></item></channel></rss>