<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="http://sqlblog.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>Peter DeBetta's SQL Programming Blog : Performance</title><link>http://sqlblog.com/blogs/peter_debetta/archive/tags/Performance/default.aspx</link><description>Tags: Performance</description><dc:language>en</dc:language><generator>CommunityServer 2.1 SP2 (Build: 61129.1)</generator><item><title>Multiple-Valued Parameters</title><link>http://sqlblog.com/blogs/peter_debetta/archive/2007/02/12/multiple-valued-parameters.aspx</link><pubDate>Mon, 12 Feb 2007 21:43:00 GMT</pubDate><guid isPermaLink="false">21093a07-8b3d-42db-8cbf-3350fcbf5496:825</guid><dc:creator>Peter W. DeBetta</dc:creator><slash:comments>19</slash:comments><comments>http://sqlblog.com/blogs/peter_debetta/comments/825.aspx</comments><wfw:commentRss>http://sqlblog.com/blogs/peter_debetta/commentrss.aspx?PostID=825</wfw:commentRss><description>&lt;p&gt;&lt;span style="font-size:10pt;"&gt;So I was doing some research on which is the best way to pass multiple-valued parameters into a stored procedure or user-defined function when I found some interesting results. I had always used a string-based user-defined function to parse a delimited list of values and I knew I could use XML to do the same thing, yet I had never compared the two side-by-side to see which is a better choice.
&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-size:10pt;"&gt;So which was faster? Well, using one of many available string-based UDFs, I had unexpected results. I thought that the XML version would be equivalent if not slower, but alas, I was wrong. The XML-based UDF consistently performed about 35% faster than the string-based inline table-valued UDF and about 65% faster than string-based table-valued UDF I tested. 
&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-size:10pt;"&gt;I will be following-up this post soon with a post about various XML-based techniques that I tested…
&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-size:10pt;"&gt;&lt;em&gt;One last item of note – this post was published (tags and all) from Word 2007.
&lt;/em&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-size:10pt;"&gt;As for now, here are the various functions used in the tests:
&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family:Courier New;font-size:10pt;"&gt;&lt;span style="color:blue;"&gt;CREATE&lt;/span&gt;
			&lt;span style="color:blue;"&gt;FUNCTION&lt;/span&gt; dbo&lt;span style="color:gray;"&gt;.&lt;/span&gt;fnString2IntList&lt;span style="color:gray;"&gt;(&lt;/span&gt;@sData &lt;span style="color:blue;"&gt;varchar&lt;/span&gt;&lt;span style="color:gray;"&gt;(&lt;/span&gt;8000&lt;span style="color:gray;"&gt;),&lt;/span&gt; @sDelim &lt;span style="color:blue;"&gt;char&lt;/span&gt;&lt;span style="color:gray;"&gt;(&lt;/span&gt;1&lt;span style="color:gray;"&gt;))&lt;/span&gt;
			&lt;br /&gt;&lt;span style="color:blue;"&gt;RETURNS&lt;/span&gt; @tList &lt;span style="color:blue;"&gt;TABLE&lt;/span&gt;
			&lt;span style="color:gray;"&gt;(&lt;/span&gt;ListValue &lt;span style="color:blue;"&gt;int&lt;/span&gt;&lt;span style="color:gray;"&gt;)&lt;br /&gt;&lt;/span&gt;&lt;span style="color:blue;"&gt;AS&lt;/span&gt;
			&lt;br /&gt;&lt;span style="color:blue;"&gt;BEGIN&lt;br /&gt;&lt;/span&gt;    &lt;span style="color:blue;"&gt;DECLARE&lt;/span&gt; @sTemp &lt;span style="color:blue;"&gt;int&lt;/span&gt;&lt;span style="color:gray;"&gt;,&lt;/span&gt; @nPos &lt;span style="color:blue;"&gt;int&lt;/span&gt;&lt;span style="color:gray;"&gt;,&lt;/span&gt; @nPos2 &lt;span style="color:blue;"&gt;int&lt;br /&gt;&lt;/span&gt;    &lt;span style="color:blue;"&gt;IF&lt;/span&gt;
			&lt;span style="color:gray;"&gt;(&lt;/span&gt;&lt;span style="color:fuchsia;"&gt;Len&lt;/span&gt;&lt;span style="color:gray;"&gt;(&lt;/span&gt;&lt;span style="color:fuchsia;"&gt;RTrim&lt;/span&gt;&lt;span style="color:gray;"&gt;(&lt;/span&gt;&lt;span style="color:fuchsia;"&gt;LTrim&lt;/span&gt;&lt;span style="color:gray;"&gt;(&lt;/span&gt;@sData&lt;span style="color:gray;"&gt;)))&lt;/span&gt;
			&lt;span style="color:gray;"&gt;=&lt;/span&gt; 0&lt;span style="color:gray;"&gt;)&lt;/span&gt;
			&lt;span style="color:blue;"&gt;RETURN&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span style="color:blue;"&gt;SET&lt;/span&gt; @nPos &lt;span style="color:gray;"&gt;=&lt;/span&gt;
			&lt;span style="color:fuchsia;"&gt;CharIndex&lt;/span&gt;&lt;span style="color:gray;"&gt;(&lt;/span&gt;@sDelim&lt;span style="color:gray;"&gt;,&lt;/span&gt; @sData&lt;span style="color:gray;"&gt;,&lt;/span&gt; 1&lt;span style="color:gray;"&gt;)&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span style="color:blue;"&gt;IF&lt;/span&gt; @nPos &lt;span style="color:gray;"&gt;=&lt;/span&gt; 0 &lt;span style="color:gray;"&gt;OR&lt;/span&gt; @nPos &lt;span style="color:gray;"&gt;=&lt;/span&gt;
			&lt;span style="color:fuchsia;"&gt;Len&lt;/span&gt;&lt;span style="color:gray;"&gt;(&lt;/span&gt;@sData&lt;span style="color:gray;"&gt;)&lt;br /&gt;&lt;/span&gt;     &lt;span style="color:blue;"&gt;BEGIN&lt;br /&gt;&lt;/span&gt;        &lt;span style="color:blue;"&gt;SET&lt;/span&gt; @sTemp &lt;span style="color:gray;"&gt;=&lt;/span&gt;
			&lt;span style="color:fuchsia;"&gt;CAST&lt;/span&gt;&lt;span style="color:gray;"&gt;(&lt;/span&gt;&lt;span style="color:fuchsia;"&gt;SubString&lt;/span&gt;&lt;span style="color:gray;"&gt;(&lt;/span&gt;@sData&lt;span style="color:gray;"&gt;,&lt;/span&gt; 1&lt;span style="color:gray;"&gt;,&lt;/span&gt;
			&lt;span style="color:gray;"&gt;(&lt;/span&gt;&lt;span style="color:fuchsia;"&gt;Len&lt;/span&gt;&lt;span style="color:gray;"&gt;(&lt;/span&gt;@sData&lt;span style="color:gray;"&gt;)&lt;/span&gt;
			&lt;span style="color:gray;"&gt;-&lt;/span&gt;
			&lt;span style="color:fuchsia;"&gt;Sign&lt;/span&gt;&lt;span style="color:gray;"&gt;(&lt;/span&gt;@nPos&lt;span style="color:gray;"&gt;)))&lt;/span&gt;
			&lt;span style="color:blue;"&gt;as&lt;/span&gt;
			&lt;span style="color:blue;"&gt;int&lt;/span&gt;&lt;span style="color:gray;"&gt;)&lt;br /&gt;&lt;/span&gt;        &lt;span style="color:blue;"&gt;INSERT&lt;/span&gt;
			&lt;span style="color:blue;"&gt;INTO&lt;/span&gt; @tList &lt;span style="color:blue;"&gt;VALUES&lt;/span&gt;&lt;span style="color:gray;"&gt;(&lt;/span&gt;@sTemp&lt;span style="color:gray;"&gt;)&lt;br /&gt;&lt;/span&gt;        &lt;span style="color:blue;"&gt;RETURN&lt;br /&gt;&lt;/span&gt;     &lt;span style="color:blue;"&gt;END&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;    &lt;span style="color:blue;"&gt;SET&lt;/span&gt; @sTemp &lt;span style="color:gray;"&gt;=&lt;/span&gt;
			&lt;span style="color:fuchsia;"&gt;CAST&lt;/span&gt;&lt;span style="color:gray;"&gt;(&lt;/span&gt;&lt;span style="color:fuchsia;"&gt;SubString&lt;/span&gt;&lt;span style="color:gray;"&gt;(&lt;/span&gt;@sData&lt;span style="color:gray;"&gt;,&lt;/span&gt; 1&lt;span style="color:gray;"&gt;,&lt;/span&gt; @nPos &lt;span style="color:gray;"&gt;-&lt;/span&gt; 1&lt;span style="color:gray;"&gt;)&lt;/span&gt;
			&lt;span style="color:blue;"&gt;as&lt;/span&gt;
			&lt;span style="color:blue;"&gt;int&lt;/span&gt;&lt;span style="color:gray;"&gt;)&lt;br /&gt;&lt;/span&gt;    &lt;span style="color:blue;"&gt;INSERT&lt;/span&gt;
			&lt;span style="color:blue;"&gt;INTO&lt;/span&gt; @tList &lt;span style="color:blue;"&gt;VALUES&lt;/span&gt;&lt;span style="color:gray;"&gt;(&lt;/span&gt;@sTemp&lt;span style="color:gray;"&gt;)&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;    &lt;span style="color:blue;"&gt;WHILE&lt;/span&gt; @nPos &lt;span style="color:gray;"&gt;&amp;gt;&lt;/span&gt; 0&lt;br /&gt;     &lt;span style="color:blue;"&gt;BEGIN&lt;/span&gt;    &lt;br /&gt;        &lt;span style="color:blue;"&gt;SET&lt;/span&gt; @nPos2 &lt;span style="color:gray;"&gt;=&lt;/span&gt;
			&lt;span style="color:fuchsia;"&gt;CharIndex&lt;/span&gt;&lt;span style="color:gray;"&gt;(&lt;/span&gt;@sDelim&lt;span style="color:gray;"&gt;,&lt;/span&gt; @sData&lt;span style="color:gray;"&gt;,&lt;/span&gt; @nPos &lt;span style="color:gray;"&gt;+&lt;/span&gt; 1&lt;span style="color:gray;"&gt;)&lt;br /&gt;&lt;/span&gt;        &lt;span style="color:blue;"&gt;IF&lt;/span&gt;
			&lt;span style="color:gray;"&gt;(&lt;/span&gt;@nPos2 &lt;span style="color:gray;"&gt;=&lt;/span&gt; 0&lt;span style="color:gray;"&gt;)&lt;/span&gt;
			&lt;span style="color:blue;"&gt;SET&lt;/span&gt; @sTemp &lt;span style="color:gray;"&gt;=&lt;/span&gt;
			&lt;span style="color:fuchsia;"&gt;CAST&lt;/span&gt;&lt;span style="color:gray;"&gt;(&lt;/span&gt;&lt;span style="color:fuchsia;"&gt;SubString&lt;/span&gt;&lt;span style="color:gray;"&gt;(&lt;/span&gt;@sData&lt;span style="color:gray;"&gt;,&lt;/span&gt; @nPos &lt;span style="color:gray;"&gt;+&lt;/span&gt; 1&lt;span style="color:gray;"&gt;,&lt;/span&gt;
			&lt;span style="color:fuchsia;"&gt;Len&lt;/span&gt;&lt;span style="color:gray;"&gt;(&lt;/span&gt;@sData&lt;span style="color:gray;"&gt;))&lt;/span&gt;
			&lt;span style="color:blue;"&gt;as&lt;/span&gt;
			&lt;span style="color:blue;"&gt;int&lt;/span&gt;&lt;span style="color:gray;"&gt;)&lt;br /&gt;&lt;/span&gt;        &lt;span style="color:blue;"&gt;ELSE&lt;/span&gt;
			&lt;span style="color:blue;"&gt;SET&lt;/span&gt; @sTemp &lt;span style="color:gray;"&gt;=&lt;/span&gt;
			&lt;span style="color:fuchsia;"&gt;CAST&lt;/span&gt;&lt;span style="color:gray;"&gt;(&lt;/span&gt;&lt;span style="color:fuchsia;"&gt;SubString&lt;/span&gt;&lt;span style="color:gray;"&gt;(&lt;/span&gt;@sData&lt;span style="color:gray;"&gt;,&lt;/span&gt; @nPos &lt;span style="color:gray;"&gt;+&lt;/span&gt; 1&lt;span style="color:gray;"&gt;,&lt;/span&gt;
			&lt;span style="color:fuchsia;"&gt;ABS&lt;/span&gt;&lt;span style="color:gray;"&gt;(&lt;/span&gt;@nPos2 &lt;span style="color:gray;"&gt;-&lt;/span&gt; @nPos &lt;span style="color:gray;"&gt;-&lt;/span&gt; 1&lt;span style="color:gray;"&gt;))&lt;/span&gt;
			&lt;span style="color:blue;"&gt;as&lt;/span&gt;
			&lt;span style="color:blue;"&gt;int&lt;/span&gt;&lt;span style="color:gray;"&gt;)&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;        &lt;span style="color:blue;"&gt;INSERT&lt;/span&gt;
			&lt;span style="color:blue;"&gt;INTO&lt;/span&gt; @tList &lt;span style="color:blue;"&gt;VALUES&lt;/span&gt;&lt;span style="color:gray;"&gt;(&lt;/span&gt;@sTemp&lt;span style="color:gray;"&gt;)&lt;br /&gt;&lt;/span&gt;        &lt;span style="color:blue;"&gt;SET&lt;/span&gt; @nPos &lt;span style="color:gray;"&gt;=&lt;/span&gt;
			&lt;span style="color:fuchsia;"&gt;CharIndex&lt;/span&gt;&lt;span style="color:gray;"&gt;(&lt;/span&gt;@sDelim&lt;span style="color:gray;"&gt;,&lt;/span&gt; @sData&lt;span style="color:gray;"&gt;,&lt;/span&gt; @nPos &lt;span style="color:gray;"&gt;+&lt;/span&gt; 1&lt;span style="color:gray;"&gt;)&lt;br /&gt;&lt;/span&gt;     &lt;span style="color:blue;"&gt;END&lt;br /&gt;&lt;/span&gt;    &lt;span style="color:blue;"&gt;RETURN&lt;br /&gt;END&lt;br /&gt;&lt;/span&gt;GO
&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family:Courier New;font-size:10pt;"&gt;&lt;span style="color:blue;"&gt;CREATE&lt;/span&gt;
			&lt;span style="color:blue;"&gt;FUNCTION&lt;/span&gt; dbo&lt;span style="color:gray;"&gt;.&lt;/span&gt;fnString2IntList2&lt;span style="color:gray;"&gt;(&lt;/span&gt;@sData &lt;span style="color:blue;"&gt;varchar&lt;/span&gt;&lt;span style="color:gray;"&gt;(&lt;/span&gt;8000&lt;span style="color:gray;"&gt;),&lt;/span&gt; @sDelim &lt;span style="color:blue;"&gt;char&lt;/span&gt;&lt;span style="color:gray;"&gt;(&lt;/span&gt;1&lt;span style="color:gray;"&gt;))&lt;/span&gt;
			&lt;br /&gt;&lt;span style="color:blue;"&gt;RETURNS&lt;/span&gt;
			&lt;span style="color:blue;"&gt;TABLE&lt;/span&gt;
			&lt;br /&gt;&lt;span style="color:blue;"&gt;AS&lt;/span&gt;
			&lt;br /&gt;    &lt;span style="color:blue;"&gt;RETURN&lt;/span&gt;
			&lt;br /&gt;    &lt;span style="color:gray;"&gt;(&lt;/span&gt;&lt;span style="color:blue;"&gt;WITH&lt;/span&gt; csvtbl&lt;span style="color:gray;"&gt;(&lt;/span&gt;i&lt;span style="color:gray;"&gt;,&lt;/span&gt;j&lt;span style="color:gray;"&gt;)&lt;br /&gt;&lt;/span&gt;    &lt;span style="color:blue;"&gt;AS&lt;br /&gt;&lt;/span&gt;    &lt;span style="color:gray;"&gt;(&lt;br /&gt;&lt;/span&gt;        &lt;span style="color:blue;"&gt;SELECT&lt;/span&gt; i &lt;span style="color:gray;"&gt;=&lt;/span&gt; 1&lt;span style="color:gray;"&gt;,&lt;/span&gt; j &lt;span style="color:gray;"&gt;=&lt;/span&gt;
			&lt;span style="color:fuchsia;"&gt;CHARINDEX&lt;/span&gt;&lt;span style="color:gray;"&gt;(&lt;/span&gt;@sDelim&lt;span style="color:gray;"&gt;,&lt;/span&gt; @sData &lt;span style="color:gray;"&gt;+&lt;/span&gt; @sDelim&lt;span style="color:gray;"&gt;)&lt;br /&gt;&lt;/span&gt;        &lt;span style="color:blue;"&gt;UNION&lt;/span&gt;
			&lt;span style="color:gray;"&gt;ALL&lt;br /&gt;&lt;/span&gt;        &lt;span style="color:blue;"&gt;SELECT&lt;/span&gt; i &lt;span style="color:gray;"&gt;=&lt;/span&gt; j &lt;span style="color:gray;"&gt;+&lt;/span&gt; 1&lt;span style="color:gray;"&gt;,&lt;/span&gt; j &lt;span style="color:gray;"&gt;=&lt;/span&gt;
			&lt;span style="color:fuchsia;"&gt;CHARINDEX&lt;/span&gt;&lt;span style="color:gray;"&gt;(&lt;/span&gt;@sDelim&lt;span style="color:gray;"&gt;,&lt;/span&gt; @sData &lt;span style="color:gray;"&gt;+&lt;/span&gt; @sDelim&lt;span style="color:gray;"&gt;,&lt;/span&gt; j &lt;span style="color:gray;"&gt;+&lt;/span&gt; 1&lt;span style="color:gray;"&gt;)&lt;/span&gt;
			&lt;br /&gt;        &lt;span style="color:blue;"&gt;FROM&lt;/span&gt; csvtbl&lt;br /&gt;           &lt;span style="color:blue;"&gt;WHERE&lt;/span&gt;
			&lt;span style="color:fuchsia;"&gt;CHARINDEX&lt;/span&gt;&lt;span style="color:gray;"&gt;(&lt;/span&gt;@sDelim&lt;span style="color:gray;"&gt;,&lt;/span&gt; @sData &lt;span style="color:gray;"&gt;+&lt;/span&gt; @sDelim&lt;span style="color:gray;"&gt;,&lt;/span&gt; j &lt;span style="color:gray;"&gt;+&lt;/span&gt; 1&lt;span style="color:gray;"&gt;)&lt;/span&gt;
			&lt;span style="color:gray;"&gt;&amp;lt;&amp;gt;&lt;/span&gt; 0&lt;br /&gt;    &lt;span style="color:gray;"&gt;)&lt;br /&gt;&lt;/span&gt;    &lt;span style="color:blue;"&gt;SELECT&lt;/span&gt;
			&lt;span style="color:fuchsia;"&gt;CAST&lt;/span&gt;&lt;span style="color:gray;"&gt;(&lt;/span&gt;&lt;span style="color:fuchsia;"&gt;SUBSTRING&lt;/span&gt;&lt;span style="color:gray;"&gt;(&lt;/span&gt;@sData&lt;span style="color:gray;"&gt;,&lt;/span&gt; i&lt;span style="color:gray;"&gt;,&lt;/span&gt; j &lt;span style="color:gray;"&gt;-&lt;/span&gt; i&lt;span style="color:gray;"&gt;)&lt;/span&gt;
			&lt;span style="color:blue;"&gt;as&lt;/span&gt;
			&lt;span style="color:blue;"&gt;int&lt;/span&gt;&lt;span style="color:gray;"&gt;)&lt;/span&gt;
			&lt;span style="color:blue;"&gt;AS&lt;/span&gt; ListValue&lt;br /&gt;    &lt;span style="color:blue;"&gt;FROM&lt;/span&gt; csvtbl&lt;span style="color:gray;"&gt;)&lt;br /&gt;&lt;/span&gt;GO&lt;br /&gt;&lt;span style="color:green;"&gt;
			&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family:Courier New;font-size:10pt;"&gt;&lt;span style="color:green;"&gt;/*    Assumes XML is as such&lt;br /&gt;    &amp;lt;list&amp;gt;&lt;br /&gt;        &amp;lt;i&amp;gt;1&amp;lt;/i&amp;gt;&lt;br /&gt;        &amp;lt;i&amp;gt;23&amp;lt;/i&amp;gt;&lt;br /&gt;    &amp;lt;/list&amp;gt;&lt;br /&gt;    etc...&lt;br /&gt;&lt;br /&gt;    Uses minimal xml markup to keep input size as small as possible &lt;br /&gt;*/&lt;/span&gt;&lt;br /&gt;&lt;span style="color:blue;"&gt;ALTER&lt;/span&gt;
			&lt;span style="color:blue;"&gt;FUNCTION&lt;/span&gt; dbo&lt;span style="color:gray;"&gt;.&lt;/span&gt;fnXml2IntList&lt;span style="color:gray;"&gt;(&lt;/span&gt;@xmlList &lt;span style="color:blue;"&gt;xml&lt;/span&gt;&lt;span style="color:gray;"&gt;)&lt;/span&gt;
			&lt;br /&gt;&lt;span style="color:blue;"&gt;RETURNS&lt;/span&gt;
			&lt;span style="color:blue;"&gt;TABLE&lt;/span&gt;
			&lt;br /&gt;&lt;span style="color:blue;"&gt;AS&lt;/span&gt;
			&lt;br /&gt;    &lt;span style="color:blue;"&gt;RETURN&lt;/span&gt;
			&lt;span style="color:gray;"&gt;(&lt;/span&gt;&lt;span style="color:blue;"&gt;SELECT&lt;/span&gt; tList&lt;span style="color:gray;"&gt;.&lt;/span&gt;ListValue&lt;span style="color:gray;"&gt;.&lt;/span&gt;&lt;span style="color:blue;"&gt;value&lt;/span&gt;&lt;span style="color:gray;"&gt;(&lt;/span&gt;&lt;span style="color:red;"&gt;'.'&lt;/span&gt;&lt;span style="color:gray;"&gt;,&lt;/span&gt;
			&lt;span style="color:red;"&gt;'int'&lt;/span&gt;&lt;span style="color:gray;"&gt;)&lt;/span&gt;
			&lt;span style="color:blue;"&gt;AS&lt;/span&gt; ListValue&lt;br /&gt;            &lt;span style="color:blue;"&gt;FROM&lt;/span&gt; @xmlList&lt;span style="color:gray;"&gt;.&lt;/span&gt;nodes&lt;span style="color:gray;"&gt;(&lt;/span&gt;&lt;span style="color:red;"&gt;'list/i'&lt;/span&gt;&lt;span style="color:gray;"&gt;)&lt;/span&gt;
			&lt;span style="color:blue;"&gt;AS&lt;/span&gt; tList&lt;span style="color:gray;"&gt;(&lt;/span&gt;ListValue&lt;span style="color:gray;"&gt;))&lt;br /&gt;&lt;/span&gt;GO
&lt;/span&gt;&lt;/p&gt;&lt;img src="http://sqlblog.com/aggbug.aspx?PostID=825" width="1" height="1"&gt;</description><category domain="http://sqlblog.com/blogs/peter_debetta/archive/tags/T-SQL/default.aspx">T-SQL</category><category domain="http://sqlblog.com/blogs/peter_debetta/archive/tags/XML/default.aspx">XML</category><category domain="http://sqlblog.com/blogs/peter_debetta/archive/tags/Performance/default.aspx">Performance</category></item><item><title>Medians, Actual Query Cost, and Statistics</title><link>http://sqlblog.com/blogs/peter_debetta/archive/2006/12/20/Medians-Actual-Query-Cost-and-Statistics.aspx</link><pubDate>Wed, 20 Dec 2006 10:48:00 GMT</pubDate><guid isPermaLink="false">21093a07-8b3d-42db-8cbf-3350fcbf5496:450</guid><dc:creator>Peter W. DeBetta</dc:creator><slash:comments>2</slash:comments><comments>http://sqlblog.com/blogs/peter_debetta/comments/450.aspx</comments><wfw:commentRss>http://sqlblog.com/blogs/peter_debetta/commentrss.aspx?PostID=450</wfw:commentRss><description>&lt;P&gt;I was going to comment on Adam's post "&lt;A href="http://sqlblog.com/blogs/adam_machanic/archive/2006/12/18/437.aspx"&gt;Medians, ROW_NUMBERs, and performance&lt;/A&gt;" (which&amp;nbsp;was a follow-up&amp;nbsp;to Aaron's post "&lt;A href="http://sqlblog.com/blogs/aaron_bertrand/archive/2006/12/15/428.aspx"&gt;Take the high road to middle ground&lt;/A&gt;") and I realized that I needed to show some code and alas, comments are not so nice about formatting code, so I am posting a follow-up post...&lt;/P&gt;
&lt;P&gt;At the PASS Summit back in November, Itzik and I were examining this issue of the QP doing the table spool when one would think it shouldn't need to and we were both stumped as to why. But further examination revealed some strangeness: Even though the logical reads for Ben-Gan's solution is quite high, the actual query cost is less than Celko's solution. It makes one wonder: Which is the better indicator of better perfromance - actual query cost or statistics such as time and IO? I have seen people use actual query cost as the basis for choosing one solution over another. Is using actual query cost a valid way of deciding which solution to choose? Like I said, it makes one wonder....&lt;/P&gt;
&lt;P&gt;For Ben-Gan's solution, I also was dissatisfied with the QP's choice in doing the table spool. And so I decided to create a variation on Ben-Gan's solution that calculated the count for each CustomerID separately. Although the logical reads is higher than Celko's solution, it is only 748 as compared to the 703 of Celko's solution; and better yet, the execution time is [on average] just slightly better and the query cost is always better (37% versus 63%). Put a supporting index in place (CustomerID, TotalDue) and this solution's logical reads drops to 121 (versus 76 for Celko's) but is consistently better in execution time and actual query cost (12% versus 88%) &lt;/P&gt;
&lt;P&gt;Here is the query:&lt;/P&gt;&lt;FONT color=#808080&gt;
&lt;P&gt;&lt;FONT face="Courier New"&gt;;&lt;/FONT&gt;&lt;/FONT&gt;&lt;FONT face="Courier New"&gt;&lt;FONT color=#0000ff&gt;with&lt;/FONT&gt; c &lt;/FONT&gt;&lt;FONT face="Courier New"&gt;&lt;FONT color=#0000ff&gt;as&lt;BR&gt;&lt;/FONT&gt;&lt;FONT color=#808080&gt;&amp;nbsp;&amp;nbsp;(&lt;/FONT&gt;&lt;FONT color=#0000ff&gt;SELECT&lt;/FONT&gt; CustomerId &lt;FONT color=#808080&gt;,&lt;/FONT&gt; TotalDue,&amp;nbsp;&lt;BR&gt;&lt;FONT color=#808080&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/FONT&gt;Row_Number&lt;FONT color=#808080&gt;()&lt;/FONT&gt; &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;FONT color=#0000ff&gt;OVER&lt;/FONT&gt; &lt;FONT color=#808080&gt;(&lt;/FONT&gt;&lt;FONT color=#0000ff&gt;PARTITION&lt;/FONT&gt; &lt;FONT color=#0000ff&gt;BY&lt;/FONT&gt; CustomerId &lt;FONT color=#0000ff&gt;ORDER&lt;/FONT&gt; &lt;FONT color=#0000ff&gt;BY&lt;/FONT&gt;&amp;nbsp;TotalDue&lt;FONT color=#808080&gt;)&lt;/FONT&gt; &lt;FONT color=#0000ff&gt;as&lt;/FONT&gt; rn&lt;BR&gt;&lt;FONT color=#0000ff&gt;&amp;nbsp; FROM&lt;/FONT&gt; Sales&lt;FONT color=#808080&gt;.&lt;/FONT&gt;SalesOrderHeader&lt;/FONT&gt;&lt;FONT face="Courier New"&gt;&lt;FONT color=#808080&gt;)&lt;BR&gt;,&lt;/FONT&gt; d &lt;FONT color=#0000ff&gt;as&lt;/FONT&gt; &lt;BR&gt;&lt;FONT color=#808080&gt;&amp;nbsp; (&lt;/FONT&gt;&lt;FONT color=#0000ff&gt;SELECT&lt;/FONT&gt; CustomerId &lt;FONT color=#808080&gt;,&lt;/FONT&gt; &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;FONT color=#808080&gt;(&lt;/FONT&gt;&lt;FONT color=#ff00ff&gt;COUNT&lt;/FONT&gt;&lt;FONT color=#808080&gt;(*)+&lt;/FONT&gt;1&lt;FONT color=#808080&gt;)&lt;/FONT&gt; &lt;FONT color=#808080&gt;/&lt;/FONT&gt;2 &lt;FONT color=#0000ff&gt;as&lt;/FONT&gt; cnt1&lt;FONT color=#808080&gt;,&lt;/FONT&gt; &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;FONT color=#808080&gt;(&lt;/FONT&gt;&lt;FONT color=#ff00ff&gt;COUNT&lt;/FONT&gt;&lt;FONT color=#808080&gt;(*)+&lt;/FONT&gt;2&lt;FONT color=#808080&gt;)&lt;/FONT&gt; &lt;FONT color=#808080&gt;/&lt;/FONT&gt;2 &lt;FONT color=#0000ff&gt;as&lt;/FONT&gt; cnt2&lt;BR&gt;&lt;FONT color=#0000ff&gt;&amp;nbsp; FROM&lt;/FONT&gt; Sales&lt;FONT color=#808080&gt;.&lt;/FONT&gt;SalesOrderHeader&lt;BR&gt;&lt;FONT color=#0000ff&gt;&amp;nbsp; GROUP&lt;/FONT&gt; &lt;FONT color=#0000ff&gt;BY&lt;/FONT&gt; CustomerID&lt;/FONT&gt;&lt;FONT face="Courier New"&gt;&lt;FONT color=#808080&gt;)&lt;BR&gt;&lt;/FONT&gt;&lt;FONT color=#0000ff&gt;SELECT&lt;/FONT&gt; c&lt;FONT color=#808080&gt;.&lt;/FONT&gt;CustomerId&lt;FONT color=#808080&gt;,&lt;/FONT&gt; &lt;FONT color=#ff00ff&gt;Avg&lt;/FONT&gt;&lt;FONT color=#808080&gt;(&lt;/FONT&gt;c&lt;FONT color=#808080&gt;.&lt;/FONT&gt;TotalDue&lt;FONT color=#808080&gt;)&lt;/FONT&gt; &lt;FONT color=#0000ff&gt;AS&lt;/FONT&gt; Median&lt;BR&gt;&lt;FONT color=#0000ff&gt;FROM&lt;/FONT&gt; C&lt;BR&gt;&lt;FONT color=#808080&gt;&amp;nbsp; INNER&lt;/FONT&gt; &lt;FONT color=#808080&gt;JOIN&lt;/FONT&gt; d &lt;BR&gt;&amp;nbsp; &amp;nbsp; &lt;FONT color=#0000ff&gt;ON&lt;/FONT&gt; c&lt;FONT color=#808080&gt;.&lt;/FONT&gt;CustomerId &lt;FONT color=#808080&gt;=&lt;/FONT&gt; d&lt;FONT color=#808080&gt;.&lt;/FONT&gt;CustomerId &lt;FONT color=#808080&gt;AND&lt;/FONT&gt; c&lt;FONT color=#808080&gt;.&lt;/FONT&gt;rn &lt;FONT color=#808080&gt;IN&lt;/FONT&gt; &lt;FONT color=#808080&gt;(&lt;/FONT&gt;d&lt;FONT color=#808080&gt;.&lt;/FONT&gt;cnt1&lt;FONT color=#808080&gt;,&lt;/FONT&gt; d&lt;FONT color=#808080&gt;.&lt;/FONT&gt;cnt2&lt;FONT color=#808080&gt;)&lt;/FONT&gt; &lt;BR&gt;&lt;FONT color=#0000ff&gt;GROUP&lt;/FONT&gt; &lt;FONT color=#0000ff&gt;BY&lt;/FONT&gt; c&lt;FONT color=#808080&gt;.&lt;/FONT&gt;CustomerId&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;I agree with Adam that &lt;EM&gt;cost-based optimization is far from perfect.&lt;/EM&gt; But I don't like the inconsistency in the various results of STATISTICS IO, STATISTICS TIME, and actual query cost. And so what is the best way to decide which query performs better and which will scale better: STATISTICS IO, STATISTICS TIME, actual query cost, a combination of all of these, or perhaps something else (such as a detailed analysis of the actual query plans)?&lt;/P&gt;&lt;img src="http://sqlblog.com/aggbug.aspx?PostID=450" width="1" height="1"&gt;</description><category domain="http://sqlblog.com/blogs/peter_debetta/archive/tags/T-SQL/default.aspx">T-SQL</category><category domain="http://sqlblog.com/blogs/peter_debetta/archive/tags/Performance/default.aspx">Performance</category></item></channel></rss>