{"id":416,"date":"2008-02-18T21:18:49","date_gmt":"2008-02-18T21:18:49","guid":{"rendered":"\/blogs\/conor\/post\/Operator-of-the-Day-Streaming-Table-Valued-Functions-(aka-the-Dynamic-Management-ViewFunction).aspx"},"modified":"2008-02-18T21:18:49","modified_gmt":"2008-02-18T21:18:49","slug":"operator-of-the-day-streaming-table-valued-functions-aka-the-dynamic-management-viewfunction","status":"publish","type":"post","link":"https:\/\/www.sqlskills.com\/blogs\/conor\/operator-of-the-day-streaming-table-valued-functions-aka-the-dynamic-management-viewfunction\/","title":{"rendered":"Operator of the Day: Streaming Table-Valued Functions (aka the Dynamic Management View\/Function)"},"content":{"rendered":"<p>So I like kung-fu movies.&nbsp; I don&#8217;t care how bad the acting is, as long as there is some master\/relative\/friend who has been killed who needs avenged.&nbsp; Often good movies are made this way.<\/p>\n<p>In software, a good idea often comes out of getting tired of seeing bugs on a sore subject, often not even your fault.&nbsp; So, in a fit of rage, I locked myself in my office for a few weeks and came up with the streaming table-valued function, since used as the proverbial duct-tape within the QP for all sorts of unforseen features.&nbsp; However, it has a &#8220;walking on rice paper without leaving footprints&#8221; vibe, so I will tell you a bit about this guy ;).<\/p>\n<p>(I did the QO part for this operator and a chunk of the architecture for it &#8211; there were others who worked on it too, however).<\/p>\n<p>So a query operator takes rows in the bottom and spits rows out the top (yes, none of the exposed query plan graphs are drawn this way, but that&#8217;s how people talk about it ;).&nbsp; Some operators take more than one input &#8211; most of the ones with 2 inputs are called &#8220;joins&#8221;.&nbsp; Some can take an arbitrary number of inputs (usually called UNIONs).&nbsp; Some take parameters (Compute Scalar).&nbsp; most don&#8217;t take parameters, however.<\/p>\n<p>After you&#8217;ve done the 10 or so common operators in a query processor, there&#8217;s a lot of specialty problems that don&#8217;t really fit well into those operators.&nbsp; So people end up trying all sorts of crazy paths to get the data they need out to customers.&nbsp; Exuberence can often cause a few bugs, however, so eventually something needed to be done.<\/p>\n<p>So, the &#8220;Streaming Table Valued Function&#8221; (STVF) is a relational operator (takes in rows and passes out rows).&nbsp; In this case, it takes in some number of scalar parameters (like any good function) and spits out zero or more rows.&nbsp; The beauty of this operator is that anyone can program anything to get returned, as long as they return back rows &#8211; it&#8217;s like a user-defined operator for internal folks to write features for customers.&nbsp; Amazingly, there are a lot of these, and you can see them in Dynamic Management Views (amongst others).<\/p>\n<p>So, when you are looking at the plans in the plan cache or some other DMV, you are using this nifty operator:<\/p>\n<pre><span style=\"color: Black; background-color: transparent; font-family: Courier New; font-size: 11px;\"><span style=\"color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;\">SELECT<\/span> usecounts, cacheobjtype, objtype, <span style=\"color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;\">text<\/span> \r\n<span style=\"color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;\">FROM<\/span> sys.dm_exec_cached_plans \r\n<span style=\"color: Silver; background-color: transparent; font-family: Courier New; font-size: 11px;\">CROSS<\/span> APPLY sys.dm_exec_sql_text(plan_handle) \r\n<span style=\"color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;\">WHERE<\/span> usecounts &gt; 1 \r\n<span style=\"color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;\">ORDER<\/span> <span style=\"color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;\">BY<\/span> usecounts <span style=\"color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;\">DESC<\/span>;<\/span><\/pre>\n<p>(actually you are using it _twice_ in this case, as there are two different sys.dm* references).<\/p>\n<p>&nbsp; |&#8211;Nested Loops(Inner Join, OUTER REFERENCES:(SYSDMEXECCACHEDPLANS.[plan_handle]))<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |&#8211;Sort(ORDER BY:(SYSDMEXECCACHEDPLANS.[usecounts] DESC))<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |&nbsp;&nbsp;&nbsp; |&#8211;Filter(WHERE:(SYSDMEXECCACHEDPLANS.[usecounts]&gt;(1)))<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |&#8211;Table-valued function<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |&#8211;Table-valued function<\/p>\n<p>In this plan, you can see that rows are pulled from one TVF, are filtered, then sorted, then passed into the second TVF.<\/p>\n<p>The &#8220;OUTER REFERENCE&#8221; is the key that the loops join is passing something from the inner side to the outer side (remember in the crazy syntax used here, the first row below the Nested Loops is the &#8220;inner&#8221; and the second line is the &#8220;outer&#8221;.&nbsp; So, the Sort\/Filter\/TVF is the &#8220;inner&#8221; in this case.<\/p>\n<p>These things differ from the traditional TVFs that you could create in SQL Server as a user.&nbsp; Those were actually backed by temporary tables in many cases, and this made it a pretty heavy-weight solution if you just want to pass a few rows into the server.&nbsp; _Streaming_ sounds a lot better than that, you must admit.<\/p>\n<p>Many operators in a QP are streaming &#8211; filter is, as is a table scan.&nbsp; However a sort operator is called a &#8220;stop-and-go&#8221; operator because it generally consumes all of its input rows before producing the first output row.&nbsp; Streaming TVFs would fall into the &#8220;not stop-and-go&#8221; category.<\/p>\n<p>This operator is used heavily starting in SQL 2005 in lots and lots of places.&nbsp; It is not really something you can directly reference (there is no exposed syntax for this operator), and as such it requires a bit of hunting to track down the various places it gets used.<\/p>\n<p>I&#8217;ll leave it as an exercise for you guys to find a few non-DMV places that use STVFs.&nbsp; Any TVF that takes arguments is likely an STVF.&nbsp; So go look at those query plans, folks!&nbsp; First one who tells me a non-DMV\/DMF STVF feature gets a star next to their name!&nbsp; <\/p>\n<p>I also know that there is at least one new feature in SQL Server 2008 that uses the STVF.<\/p>\n<p>Happy querying!<\/p>\n<p>Conor Cunningham<\/p>\n","protected":false},"excerpt":{"rendered":"<p>So I like kung-fu movies.&nbsp; I don&#8217;t care how bad the acting is, as long as there is some master\/relative\/friend who has been killed who needs avenged.&nbsp; Often good movies are made this way. In software, a good idea often comes out of getting tired of seeing bugs on a sore subject, often not even [&hellip;]<\/p>\n","protected":false},"author":6,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-416","post","type-post","status-publish","format-standard","hentry","category-uncategorized"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v21.9.1 - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>Operator of the Day: Streaming Table-Valued Functions (aka the Dynamic Management View\/Function) - Conor Cunningham<\/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\/conor\/operator-of-the-day-streaming-table-valued-functions-aka-the-dynamic-management-viewfunction\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Operator of the Day: Streaming Table-Valued Functions (aka the Dynamic Management View\/Function) - Conor Cunningham\" \/>\n<meta property=\"og:description\" content=\"So I like kung-fu movies.&nbsp; I don&#8217;t care how bad the acting is, as long as there is some master\/relative\/friend who has been killed who needs avenged.&nbsp; Often good movies are made this way. In software, a good idea often comes out of getting tired of seeing bugs on a sore subject, often not even [&hellip;]\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.sqlskills.com\/blogs\/conor\/operator-of-the-day-streaming-table-valued-functions-aka-the-dynamic-management-viewfunction\/\" \/>\n<meta property=\"og:site_name\" content=\"Conor Cunningham\" \/>\n<meta property=\"article:published_time\" content=\"2008-02-18T21:18:49+00:00\" \/>\n<meta name=\"author\" content=\"Conor Cunningham\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Conor Cunningham\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"4 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"WebPage\",\"@id\":\"https:\/\/www.sqlskills.com\/blogs\/conor\/operator-of-the-day-streaming-table-valued-functions-aka-the-dynamic-management-viewfunction\/\",\"url\":\"https:\/\/www.sqlskills.com\/blogs\/conor\/operator-of-the-day-streaming-table-valued-functions-aka-the-dynamic-management-viewfunction\/\",\"name\":\"Operator of the Day: Streaming Table-Valued Functions (aka the Dynamic Management View\/Function) - Conor Cunningham\",\"isPartOf\":{\"@id\":\"https:\/\/www.sqlskills.com\/blogs\/conor\/#website\"},\"datePublished\":\"2008-02-18T21:18:49+00:00\",\"dateModified\":\"2008-02-18T21:18:49+00:00\",\"author\":{\"@id\":\"https:\/\/www.sqlskills.com\/blogs\/conor\/#\/schema\/person\/f9106e03423de6b5157295891b8c3ae3\"},\"breadcrumb\":{\"@id\":\"https:\/\/www.sqlskills.com\/blogs\/conor\/operator-of-the-day-streaming-table-valued-functions-aka-the-dynamic-management-viewfunction\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/www.sqlskills.com\/blogs\/conor\/operator-of-the-day-streaming-table-valued-functions-aka-the-dynamic-management-viewfunction\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/www.sqlskills.com\/blogs\/conor\/operator-of-the-day-streaming-table-valued-functions-aka-the-dynamic-management-viewfunction\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/www.sqlskills.com\/blogs\/conor\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Operator of the Day: Streaming Table-Valued Functions (aka the Dynamic Management View\/Function)\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/www.sqlskills.com\/blogs\/conor\/#website\",\"url\":\"https:\/\/www.sqlskills.com\/blogs\/conor\/\",\"name\":\"Conor Cunningham\",\"description\":\"\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/www.sqlskills.com\/blogs\/conor\/?s={search_term_string}\"},\"query-input\":\"required name=search_term_string\"}],\"inLanguage\":\"en-US\"},{\"@type\":\"Person\",\"@id\":\"https:\/\/www.sqlskills.com\/blogs\/conor\/#\/schema\/person\/f9106e03423de6b5157295891b8c3ae3\",\"name\":\"Conor Cunningham\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.sqlskills.com\/blogs\/conor\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/d9c37eff231ec89c1b244347d966860875eea8b55b366911d2694e8cd9913e57?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/d9c37eff231ec89c1b244347d966860875eea8b55b366911d2694e8cd9913e57?s=96&d=mm&r=g\",\"caption\":\"Conor Cunningham\"},\"url\":\"https:\/\/www.sqlskills.com\/blogs\/conor\/author\/conor\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Operator of the Day: Streaming Table-Valued Functions (aka the Dynamic Management View\/Function) - Conor Cunningham","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\/conor\/operator-of-the-day-streaming-table-valued-functions-aka-the-dynamic-management-viewfunction\/","og_locale":"en_US","og_type":"article","og_title":"Operator of the Day: Streaming Table-Valued Functions (aka the Dynamic Management View\/Function) - Conor Cunningham","og_description":"So I like kung-fu movies.&nbsp; I don&#8217;t care how bad the acting is, as long as there is some master\/relative\/friend who has been killed who needs avenged.&nbsp; Often good movies are made this way. In software, a good idea often comes out of getting tired of seeing bugs on a sore subject, often not even [&hellip;]","og_url":"https:\/\/www.sqlskills.com\/blogs\/conor\/operator-of-the-day-streaming-table-valued-functions-aka-the-dynamic-management-viewfunction\/","og_site_name":"Conor Cunningham","article_published_time":"2008-02-18T21:18:49+00:00","author":"Conor Cunningham","twitter_misc":{"Written by":"Conor Cunningham","Est. reading time":"4 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"WebPage","@id":"https:\/\/www.sqlskills.com\/blogs\/conor\/operator-of-the-day-streaming-table-valued-functions-aka-the-dynamic-management-viewfunction\/","url":"https:\/\/www.sqlskills.com\/blogs\/conor\/operator-of-the-day-streaming-table-valued-functions-aka-the-dynamic-management-viewfunction\/","name":"Operator of the Day: Streaming Table-Valued Functions (aka the Dynamic Management View\/Function) - Conor Cunningham","isPartOf":{"@id":"https:\/\/www.sqlskills.com\/blogs\/conor\/#website"},"datePublished":"2008-02-18T21:18:49+00:00","dateModified":"2008-02-18T21:18:49+00:00","author":{"@id":"https:\/\/www.sqlskills.com\/blogs\/conor\/#\/schema\/person\/f9106e03423de6b5157295891b8c3ae3"},"breadcrumb":{"@id":"https:\/\/www.sqlskills.com\/blogs\/conor\/operator-of-the-day-streaming-table-valued-functions-aka-the-dynamic-management-viewfunction\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.sqlskills.com\/blogs\/conor\/operator-of-the-day-streaming-table-valued-functions-aka-the-dynamic-management-viewfunction\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/www.sqlskills.com\/blogs\/conor\/operator-of-the-day-streaming-table-valued-functions-aka-the-dynamic-management-viewfunction\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.sqlskills.com\/blogs\/conor\/"},{"@type":"ListItem","position":2,"name":"Operator of the Day: Streaming Table-Valued Functions (aka the Dynamic Management View\/Function)"}]},{"@type":"WebSite","@id":"https:\/\/www.sqlskills.com\/blogs\/conor\/#website","url":"https:\/\/www.sqlskills.com\/blogs\/conor\/","name":"Conor Cunningham","description":"","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.sqlskills.com\/blogs\/conor\/?s={search_term_string}"},"query-input":"required name=search_term_string"}],"inLanguage":"en-US"},{"@type":"Person","@id":"https:\/\/www.sqlskills.com\/blogs\/conor\/#\/schema\/person\/f9106e03423de6b5157295891b8c3ae3","name":"Conor Cunningham","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.sqlskills.com\/blogs\/conor\/#\/schema\/person\/image\/","url":"https:\/\/secure.gravatar.com\/avatar\/d9c37eff231ec89c1b244347d966860875eea8b55b366911d2694e8cd9913e57?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/d9c37eff231ec89c1b244347d966860875eea8b55b366911d2694e8cd9913e57?s=96&d=mm&r=g","caption":"Conor Cunningham"},"url":"https:\/\/www.sqlskills.com\/blogs\/conor\/author\/conor\/"}]}},"_links":{"self":[{"href":"https:\/\/www.sqlskills.com\/blogs\/conor\/wp-json\/wp\/v2\/posts\/416","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.sqlskills.com\/blogs\/conor\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.sqlskills.com\/blogs\/conor\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.sqlskills.com\/blogs\/conor\/wp-json\/wp\/v2\/users\/6"}],"replies":[{"embeddable":true,"href":"https:\/\/www.sqlskills.com\/blogs\/conor\/wp-json\/wp\/v2\/comments?post=416"}],"version-history":[{"count":0,"href":"https:\/\/www.sqlskills.com\/blogs\/conor\/wp-json\/wp\/v2\/posts\/416\/revisions"}],"wp:attachment":[{"href":"https:\/\/www.sqlskills.com\/blogs\/conor\/wp-json\/wp\/v2\/media?parent=416"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.sqlskills.com\/blogs\/conor\/wp-json\/wp\/v2\/categories?post=416"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.sqlskills.com\/blogs\/conor\/wp-json\/wp\/v2\/tags?post=416"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}