{"id":740,"date":"2007-11-21T00:39:00","date_gmt":"2007-11-21T00:39:00","guid":{"rendered":"\/blogs\/bobb\/post\/SQL-Server-2008-Ordered-SQLCLR-table-valued-functions.aspx"},"modified":"2007-11-21T00:39:00","modified_gmt":"2007-11-21T00:39:00","slug":"sql-server-2008-ordered-sqlclr-table-valued-functions","status":"publish","type":"post","link":"https:\/\/www.sqlskills.com\/blogs\/bobb\/sql-server-2008-ordered-sqlclr-table-valued-functions\/","title":{"rendered":"SQL Server 2008: Ordered SQLCLR table-valued functions"},"content":{"rendered":"<p>\nAnother cool SQLCLR feature in SQL Server 2008 is the ability to define a table-valued function with an&nbsp;ORDER clause. If you have intimate knowledge that the function always returns rows in sorted order, you declare your SQLCLR UDF with an ORDER clause in the CREATE FUNCTION DDL statement. Let&#39;s experiment with this using the cheap and easy Fibonacci sequence function from Dan Sullivan and my SQL Server 2005 Developer&#39;s Guide.\n<\/p>\n<p>\ncreate assembly orderedtvf from &#39;C:\\temp\\OrderedTVF.dll&#39;<br \/>\ngo\n<\/p>\n<p>\n&#8212; no order clause<br \/>\ncreate function FibonacciUnOrdered (@prevstart int, @start int, @rows int)<br \/>\nreturns table (next int, prev int)<br \/>\nas external name orderedtvf.FData.Fibonacci<br \/>\ngo\n<\/p>\n<p>\nThe Fibonacci sequences generated are always in ascending order because that&#39;s how the function is implemented. In fact, they are in order by both the &quot;next&quot; and &quot;prev&quot; column. Because there is no limit to the number of method signatures we can have over the same SQLCLR UDF, we use the same SQLCLR method, just changing the DDL statement and function name.\n<\/p>\n<p>\ncreate function FibonacciByNext (@prevstart int, @start int, @rows int)<br \/>\nreturns table (next int, prev int)<br \/>\norder (next asc) &#8212; this is new<br \/>\nas external name orderedtvf.FData.Fibonacci<br \/>\ngo\n<\/p>\n<p>\ncreate function FibonacciByPrev (@prevstart int, @start int, @rows int)<br \/>\nreturns table (next int, prev int)<br \/>\norder (prev asc) &#8212; same concept, different ordering column<br \/>\nas external name orderedtvf.FData.Fibonacci<br \/>\ngo\n<\/p>\n<p>\nNow let&#39;s do some testing. The query plan iterators and plan cost are shown as comments.\n<\/p>\n<p>\n&#8212; cost: 0.0279081 <br \/>\n&#8212; TVF -&gt; Sort -&gt; Select<br \/>\nselect * from dbo.FibonacciUnordered(3,4,5)<br \/>\norder by next\n<\/p>\n<p>\nWith an ordered TVF, there is no SORT iterator, but there are extra query plan steps to operate on the ordered set. AND&#8230; the query cost is over 10x lower.\n<\/p>\n<p>\n&#8212; cost: 0.0023802<br \/>\n&#8212; TVF -&gt; Segment -&gt; Sequence Project -&gt; Assert -&gt; Select<br \/>\nselect * from dbo.FibonacciByNext(3,4,5)<br \/>\norder by next\n<\/p>\n<p>\n&#8212; cost: 0.0023802<br \/>\n&#8212; TVF -&gt; Segment -&gt; Sequence Project -&gt; Assert -&gt; Select<br \/>\nselect * from dbo.FibonacciByPrev(3,4,5)<br \/>\norder by prev\n<\/p>\n<p>\nNote that it IS best to have a different TVF name for each sort order, and &quot;no order&quot;, if you plan to use different ORDER BY clauses. This one has a Sort AND its cost is greater than the function that&#39;s declared UnOrdered\n<\/p>\n<p>\n&#8212; Different order<br \/>\n&#8212; cost: 0.0292881 (more than Unordered = 0.0279081)<br \/>\n&#8212; TVF -&gt; Segment -&gt; Sequence Project -&gt; Assert -&gt; Sort -&gt; Select<br \/>\nselect * from dbo.FibonacciByNext(3,4,5)<br \/>\norder by prev\n<\/p>\n<p>\nIn addition, the query plan guarentees that you don&#39;t lie in your order clause. Here&#39;s proof.\n<\/p>\n<p>\ncreate function FibonacciWrong (@prevstart int, @start int, @rows int)<br \/>\nreturns table (next int, prev int)<br \/>\norder (prev desc) &#8212; THEY ARE IN ASCENDING ORDER, NOT DESCENDING<br \/>\nas external name orderedtvf.FData.Fibonacci<br \/>\ngo\n<\/p>\n<p>\n&#8212; Error:<br \/>\n&#8212; The order of the data in the stream does not conform to the ORDER hint <br \/>\n&#8212; specified for the CLR TVF &#39;dbo.FibonacciWrong&#39;. <br \/>\n&#8212; The order of the&nbsp; data must match the order specified in the ORDER hint for a CLR TVF. <br \/>\n&#8212; Update the ORDER hint to reflect the order in which the input data is ordered, <br \/>\n&#8212; or update the CLR TVF to match the order specified by the ORDER hint.<br \/>\nselect * from dbo.FibonacciWrong(3,4,5)<br \/>\norder by prev\n<\/p>\n<p>\nRemember, you&#39;re not only saving a SORT iterator in the query plan, you&#39;re saving memory too. The SORT iterator requires a memory grant. And because there are no stats for SQL Server to use in these &quot;opaque to SQL&quot;&nbsp;functions, the memory grant for the SORT iterator in FibonacciUnOrdered is 1024K. And, we hope that the rather generous memory grant is enough, else memory is being allocated during query execution.\n<\/p>\n<p>\nSo, declaring ordered TVFs is worth it.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Another cool SQLCLR feature in SQL Server 2008 is the ability to define a table-valued function with an&nbsp;ORDER clause. If you have intimate knowledge that the function always returns rows in sorted order, you declare your SQLCLR UDF with an ORDER clause in the CREATE FUNCTION DDL statement. Let&#39;s experiment with this using the cheap [&hellip;]<\/p>\n","protected":false},"author":7,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[29,38],"tags":[],"class_list":["post-740","post","type-post","status-publish","format-standard","hentry","category-sql-server-2008","category-sqlclr"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v21.9.1 - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>SQL Server 2008: Ordered SQLCLR table-valued functions - Bob Beauchemin<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.sqlskills.com\/blogs\/bobb\/sql-server-2008-ordered-sqlclr-table-valued-functions\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"SQL Server 2008: Ordered SQLCLR table-valued functions - Bob Beauchemin\" \/>\n<meta property=\"og:description\" content=\"Another cool SQLCLR feature in SQL Server 2008 is the ability to define a table-valued function with an&nbsp;ORDER clause. If you have intimate knowledge that the function always returns rows in sorted order, you declare your SQLCLR UDF with an ORDER clause in the CREATE FUNCTION DDL statement. Let&#039;s experiment with this using the cheap [&hellip;]\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.sqlskills.com\/blogs\/bobb\/sql-server-2008-ordered-sqlclr-table-valued-functions\/\" \/>\n<meta property=\"og:site_name\" content=\"Bob Beauchemin\" \/>\n<meta property=\"article:published_time\" content=\"2007-11-21T00:39:00+00:00\" \/>\n<meta name=\"author\" content=\"Bob Beauchemin\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Bob Beauchemin\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"3 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"WebPage\",\"@id\":\"https:\/\/www.sqlskills.com\/blogs\/bobb\/sql-server-2008-ordered-sqlclr-table-valued-functions\/\",\"url\":\"https:\/\/www.sqlskills.com\/blogs\/bobb\/sql-server-2008-ordered-sqlclr-table-valued-functions\/\",\"name\":\"SQL Server 2008: Ordered SQLCLR table-valued functions - Bob Beauchemin\",\"isPartOf\":{\"@id\":\"https:\/\/www.sqlskills.com\/blogs\/bobb\/#website\"},\"datePublished\":\"2007-11-21T00:39:00+00:00\",\"dateModified\":\"2007-11-21T00:39:00+00:00\",\"author\":{\"@id\":\"https:\/\/www.sqlskills.com\/blogs\/bobb\/#\/schema\/person\/62bfa986c5b5d28fcffd8b4fc409c73e\"},\"breadcrumb\":{\"@id\":\"https:\/\/www.sqlskills.com\/blogs\/bobb\/sql-server-2008-ordered-sqlclr-table-valued-functions\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/www.sqlskills.com\/blogs\/bobb\/sql-server-2008-ordered-sqlclr-table-valued-functions\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/www.sqlskills.com\/blogs\/bobb\/sql-server-2008-ordered-sqlclr-table-valued-functions\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/www.sqlskills.com\/blogs\/bobb\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"SQL Server 2008\",\"item\":\"https:\/\/www.sqlskills.com\/blogs\/bobb\/category\/sql-server-2008\/\"},{\"@type\":\"ListItem\",\"position\":3,\"name\":\"SQL Server 2008: Ordered SQLCLR table-valued functions\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/www.sqlskills.com\/blogs\/bobb\/#website\",\"url\":\"https:\/\/www.sqlskills.com\/blogs\/bobb\/\",\"name\":\"Bob Beauchemin\",\"description\":\"SQL Server Blog\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/www.sqlskills.com\/blogs\/bobb\/?s={search_term_string}\"},\"query-input\":\"required name=search_term_string\"}],\"inLanguage\":\"en-US\"},{\"@type\":\"Person\",\"@id\":\"https:\/\/www.sqlskills.com\/blogs\/bobb\/#\/schema\/person\/62bfa986c5b5d28fcffd8b4fc409c73e\",\"name\":\"Bob Beauchemin\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.sqlskills.com\/blogs\/bobb\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/6f80e6cc667410857fa6a21931dc528b8092f4d112bf7a8ff7c267674d44ee37?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/6f80e6cc667410857fa6a21931dc528b8092f4d112bf7a8ff7c267674d44ee37?s=96&d=mm&r=g\",\"caption\":\"Bob Beauchemin\"},\"sameAs\":[\"http:\/www.sqlskills.com\/blogs\/bobb\/\"],\"url\":\"https:\/\/www.sqlskills.com\/blogs\/bobb\/author\/bobb\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"SQL Server 2008: Ordered SQLCLR table-valued functions - Bob Beauchemin","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.sqlskills.com\/blogs\/bobb\/sql-server-2008-ordered-sqlclr-table-valued-functions\/","og_locale":"en_US","og_type":"article","og_title":"SQL Server 2008: Ordered SQLCLR table-valued functions - Bob Beauchemin","og_description":"Another cool SQLCLR feature in SQL Server 2008 is the ability to define a table-valued function with an&nbsp;ORDER clause. If you have intimate knowledge that the function always returns rows in sorted order, you declare your SQLCLR UDF with an ORDER clause in the CREATE FUNCTION DDL statement. Let&#39;s experiment with this using the cheap [&hellip;]","og_url":"https:\/\/www.sqlskills.com\/blogs\/bobb\/sql-server-2008-ordered-sqlclr-table-valued-functions\/","og_site_name":"Bob Beauchemin","article_published_time":"2007-11-21T00:39:00+00:00","author":"Bob Beauchemin","twitter_misc":{"Written by":"Bob Beauchemin","Est. reading time":"3 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"WebPage","@id":"https:\/\/www.sqlskills.com\/blogs\/bobb\/sql-server-2008-ordered-sqlclr-table-valued-functions\/","url":"https:\/\/www.sqlskills.com\/blogs\/bobb\/sql-server-2008-ordered-sqlclr-table-valued-functions\/","name":"SQL Server 2008: Ordered SQLCLR table-valued functions - Bob Beauchemin","isPartOf":{"@id":"https:\/\/www.sqlskills.com\/blogs\/bobb\/#website"},"datePublished":"2007-11-21T00:39:00+00:00","dateModified":"2007-11-21T00:39:00+00:00","author":{"@id":"https:\/\/www.sqlskills.com\/blogs\/bobb\/#\/schema\/person\/62bfa986c5b5d28fcffd8b4fc409c73e"},"breadcrumb":{"@id":"https:\/\/www.sqlskills.com\/blogs\/bobb\/sql-server-2008-ordered-sqlclr-table-valued-functions\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.sqlskills.com\/blogs\/bobb\/sql-server-2008-ordered-sqlclr-table-valued-functions\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/www.sqlskills.com\/blogs\/bobb\/sql-server-2008-ordered-sqlclr-table-valued-functions\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.sqlskills.com\/blogs\/bobb\/"},{"@type":"ListItem","position":2,"name":"SQL Server 2008","item":"https:\/\/www.sqlskills.com\/blogs\/bobb\/category\/sql-server-2008\/"},{"@type":"ListItem","position":3,"name":"SQL Server 2008: Ordered SQLCLR table-valued functions"}]},{"@type":"WebSite","@id":"https:\/\/www.sqlskills.com\/blogs\/bobb\/#website","url":"https:\/\/www.sqlskills.com\/blogs\/bobb\/","name":"Bob Beauchemin","description":"SQL Server Blog","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.sqlskills.com\/blogs\/bobb\/?s={search_term_string}"},"query-input":"required name=search_term_string"}],"inLanguage":"en-US"},{"@type":"Person","@id":"https:\/\/www.sqlskills.com\/blogs\/bobb\/#\/schema\/person\/62bfa986c5b5d28fcffd8b4fc409c73e","name":"Bob Beauchemin","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.sqlskills.com\/blogs\/bobb\/#\/schema\/person\/image\/","url":"https:\/\/secure.gravatar.com\/avatar\/6f80e6cc667410857fa6a21931dc528b8092f4d112bf7a8ff7c267674d44ee37?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/6f80e6cc667410857fa6a21931dc528b8092f4d112bf7a8ff7c267674d44ee37?s=96&d=mm&r=g","caption":"Bob Beauchemin"},"sameAs":["http:\/www.sqlskills.com\/blogs\/bobb\/"],"url":"https:\/\/www.sqlskills.com\/blogs\/bobb\/author\/bobb\/"}]}},"_links":{"self":[{"href":"https:\/\/www.sqlskills.com\/blogs\/bobb\/wp-json\/wp\/v2\/posts\/740","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.sqlskills.com\/blogs\/bobb\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.sqlskills.com\/blogs\/bobb\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.sqlskills.com\/blogs\/bobb\/wp-json\/wp\/v2\/users\/7"}],"replies":[{"embeddable":true,"href":"https:\/\/www.sqlskills.com\/blogs\/bobb\/wp-json\/wp\/v2\/comments?post=740"}],"version-history":[{"count":0,"href":"https:\/\/www.sqlskills.com\/blogs\/bobb\/wp-json\/wp\/v2\/posts\/740\/revisions"}],"wp:attachment":[{"href":"https:\/\/www.sqlskills.com\/blogs\/bobb\/wp-json\/wp\/v2\/media?parent=740"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.sqlskills.com\/blogs\/bobb\/wp-json\/wp\/v2\/categories?post=740"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.sqlskills.com\/blogs\/bobb\/wp-json\/wp\/v2\/tags?post=740"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}