{"id":112,"date":"2008-08-12T23:13:17","date_gmt":"2008-08-12T21:13:17","guid":{"rendered":"https:\/\/www.sqlinthewild.co.za\/?p=112"},"modified":"2008-08-12T23:13:17","modified_gmt":"2008-08-12T21:13:17","slug":"views-or-functions","status":"publish","type":"post","link":"https:\/\/www.sqlinthewild.co.za\/index.php\/2008\/08\/12\/views-or-functions\/","title":{"rendered":"Views or Functions?"},"content":{"rendered":"<p>Someone asked this question on <a href=\"http:\/\/www.sqlservercentral.com\/\">SQLServerCentral<\/a>, I thought I&#8217;d post the test here for interest.<\/p>\n<p>The question was on which would execute faster, creating a view, then creating a procedure that accepted a parameter and filtered the view, or creating a table valued function that took a parameter.<\/p>\n<p>From testing, the answer is the procedure, but not by much. A inline table-valued-function comes a very close second and the multi-statement table-valued-function waddles in last. Not really surprising. <!--more-->Here&#8217;s the (fairly simplistic) test code for that in case anyone wants to try it out. First a lot of setup<\/p>\n<p>[source:SQL]<\/p>\n<p>SET NOCOUNT ON<\/p>\n<p>CREATE TABLE dbo.LargeTable2(<br \/>\nID int NOT NULL PRIMARY KEY,<br \/>\nSomeString char(6) NULL,<br \/>\nAGuid uniqueidentifier default newID()<br \/>\n)<\/p>\n<p>insert into LargeTable2 (id,SomeString)<br \/>\nSELECT ID, CHAR(FLOOR(RAND(ID*100)*13)+65)+CHAR(FLOOR(RAND(ID*800)*13)+65) + CHAR(FLOOR(RAND(ID*600)*13)+65) FROM (<br \/>\nSELECT top 500000 a.number*10000+b.number AS ID<br \/>\nfrom master..spt_values a cross join master..spt_values b<br \/>\nwhere a.name is null and b.name is null) x<\/p>\n<p>CREATE index idx_someString on LargeTable2 (SomeString)<br \/>\ngo<\/p>\n<p>CREATE TABLE dbo.LargeTable3(<br \/>\nID int identity NOT NULL PRIMARY KEY,<br \/>\nSomeString char(6) NULL,<br \/>\nTheDate DATETIME,<br \/>\n)<br \/>\nGO<br \/>\ninsert into LargeTable3 (SomeString)<br \/>\nSELECT distinct SomeString FROM LargeTable2<br \/>\nGO<\/p>\n<p>UPDATE LargeTable3 SET TheDate = DATEADD(hh,ID,&#8217;1980\/01\/01&#8242;) where TheDate IS NULL<br \/>\nGO<\/p>\n<p>insert into LargeTable3 (SomeString)<br \/>\nSELECT distinct SomeString FROM LargeTable2<br \/>\nGO<\/p>\n<p>UPDATE LargeTable3 SET TheDate = DATEADD(hh,ID,&#8217;2000\/01\/01&#8242;) where TheDate IS NULL<br \/>\nGO<\/p>\n<p>insert into LargeTable3 (SomeString)<br \/>\nSELECT distinct SomeString FROM LargeTable2<br \/>\nGO<\/p>\n<p>UPDATE LargeTable3 SET TheDate = DATEADD(hh,ID,&#8217;2080\/01\/01&#8242;) where TheDate IS NULL<br \/>\nGO<\/p>\n<p>CREATE index idx_someString on LargeTable3 (SomeString)<br \/>\ngo<\/p>\n<p>[\/source]<\/p>\n<p>Now, the view, the procedure and the functions<\/p>\n<p>[source:SQL]<\/p>\n<p>CREATE VIEW Test1 AS<br \/>\nSELECT ID, SomeString, AGuid FROM LargeTable2<br \/>\nGO<\/p>\n<p>&#8212; Inline function<br \/>\nCREATE FUNCTION Testing2 (@StringParam char(6))<br \/>\nRETURNS TABLE &#8212; inline table valued function<br \/>\nAS<br \/>\nRETURN SELECT ID, SomeString FROM LargeTable2 &#8212; from the table<br \/>\nWHERE SomeString = @StringParam<br \/>\nGO<\/p>\n<p>&#8212; multi-statement function<br \/>\nCREATE FUNCTION Testing3 (@StringParam char(6))<br \/>\nRETURNS @desiredRows TABLE<br \/>\n(<br \/>\nID int primary key NOT NULL,<br \/>\nSomeString char(6)<br \/>\n)<br \/>\nAS<br \/>\nBEGIN<br \/>\nINSERT INTO @desiredRows (ID, SomeString)<br \/>\nSELECT ID, SomeString FROM LargeTable2 &#8212; from the table<br \/>\nWHERE SomeString = @StringParam<br \/>\nRETURN<br \/>\nEND<br \/>\nGO<\/p>\n<p>&#8212; Procedure filtering on the view.<br \/>\nCREATE PROCEDURE Testing4 @StringParam char(6) AS<br \/>\nSELECT Test1.ID, Test1.SomeString, LargeTable3.TheDate FROM Test1  &#8212; from the view<br \/>\ninner join LargeTable3 on Test1.SomeString = LargeTable3.SomeString<br \/>\nWHERE Test1.SomeString = @StringParam<br \/>\nGO<\/p>\n<p>[\/source]<\/p>\n<p>So, how did they run? Bear in mind, these tests were run on a desktop and the actual times will vary depending on what hardware is used and what else is running.<\/p>\n<p>[source:SQL]<\/p>\n<p>SET STATISTICS IO ON<br \/>\nGO<br \/>\nSET STATISTICS TIME ON<br \/>\nGO<br \/>\nSET NOCOUNT OFF<br \/>\n&#8212; First the procedure<\/p>\n<p>EXEC Testing4 &#8216;CKK&#8217;<br \/>\nGO<\/p>\n<p>&#8212; the single statement UDF<\/p>\n<p>SELECT T2.ID, T2.SomeString, LargeTable3.TheDate FROM Testing2(&#8216;CKK&#8217;)  T2<br \/>\ninner join LargeTable3 on T2.SomeString = LargeTable3.SomeString<\/p>\n<p>&#8212; the multi statement UDF<\/p>\n<p>SELECT T3.ID, T3.SomeString, LargeTable3.TheDate FROM Testing3(&#8216;CKK&#8217;)  T3<br \/>\ninner join LargeTable3 on T3.SomeString = LargeTable3.SomeString<\/p>\n<p>SET STATISTICS IO OFF<br \/>\nGO<br \/>\nSET STATISTICS TIME OFF<br \/>\nGO<\/p>\n<p>[\/source]<\/p>\n<p>Procedure:<br \/>\n(10938 row(s) affected)<br \/>\nTable &#8216;LargeTable2&#8217;. Scan count 3, logical reads 33<br \/>\nTable &#8216;LargeTable3&#8217;. Scan count 1, logical reads 4<\/p>\n<p>SQL Server Execution Times:<br \/>\nCPU time = 0 ms,  elapsed time = 121 ms.<\/p>\n<p>Inline UDF:<br \/>\n(10938 row(s) affected)<br \/>\nTable &#8216;LargeTable2&#8217;. Scan count 3, logical reads 33<br \/>\nTable &#8216;LargeTable3&#8217;. Scan count 1, logical reads 4<\/p>\n<p>SQL Server Execution Times:<br \/>\nCPU time = 0 ms,  elapsed time = 145 ms.<\/p>\n<p>Multi-statement UDF:<br \/>\n(10938 row(s) affected)<br \/>\nTable &#8216;LargeTable3&#8217;. Scan count 3646, logical reads 29168<br \/>\nTable &#8216;#45BE5BA9&#8217;. Scan count 1, logical reads 11<\/p>\n<p>SQL Server Execution Times:<br \/>\nCPU time = 78 ms,  elapsed time = 486 ms.<\/p>\n<p>More or less as expected.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Someone asked this question on SQLServerCentral, I thought I&#8217;d post the test here for interest. The question was on which would execute faster, creating a view, then creating a procedure that accepted a parameter and filtered the view, or creating&#8230; <a class=\"read-more-button\" href=\"https:\/\/www.sqlinthewild.co.za\/index.php\/2008\/08\/12\/views-or-functions\/\">(Read more)<\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":false,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2}},"categories":[25,15],"tags":[],"class_list":["post-112","post","type-post","status-publish","format-standard","hentry","category-performance","category-sql-server"],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_shortlink":"https:\/\/wp.me\/p7h6n-1O","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/www.sqlinthewild.co.za\/index.php\/wp-json\/wp\/v2\/posts\/112","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.sqlinthewild.co.za\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.sqlinthewild.co.za\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.sqlinthewild.co.za\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.sqlinthewild.co.za\/index.php\/wp-json\/wp\/v2\/comments?post=112"}],"version-history":[{"count":0,"href":"https:\/\/www.sqlinthewild.co.za\/index.php\/wp-json\/wp\/v2\/posts\/112\/revisions"}],"wp:attachment":[{"href":"https:\/\/www.sqlinthewild.co.za\/index.php\/wp-json\/wp\/v2\/media?parent=112"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.sqlinthewild.co.za\/index.php\/wp-json\/wp\/v2\/categories?post=112"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.sqlinthewild.co.za\/index.php\/wp-json\/wp\/v2\/tags?post=112"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}