<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
		>
<channel>
	<title>Comments on: A micro-benchmark of stored routines in MySQL</title>
	<atom:link href="http://www.mysqlperformanceblog.com/2009/08/16/a-micro-benchmark-of-stored-routines-in-mysql/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.mysqlperformanceblog.com/2009/08/16/a-micro-benchmark-of-stored-routines-in-mysql/</link>
	<description>Percona&#039;s MySQL &#38; InnoDB performance and scalability blog</description>
	<lastBuildDate>Sat, 11 Feb 2012 16:45:54 +0000</lastBuildDate>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.2.1</generator>
	<item>
		<title>By: Baron Schwartz</title>
		<link>http://www.mysqlperformanceblog.com/2009/08/16/a-micro-benchmark-of-stored-routines-in-mysql/comment-page-1/#comment-646081</link>
		<dc:creator>Baron Schwartz</dc:creator>
		<pubDate>Thu, 03 Sep 2009 12:38:41 +0000</pubDate>
		<guid isPermaLink="false">http://www.mysqlperformanceblog.com/?p=1018#comment-646081</guid>
		<description>Tim, actually that&#039;s not correct, MySQL 5.1 and earlier don&#039;t execute subqueries from the inside out as you expect.</description>
		<content:encoded><![CDATA[<p>Tim, actually that&#8217;s not correct, MySQL 5.1 and earlier don&#8217;t execute subqueries from the inside out as you expect.</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: Tim Little</title>
		<link>http://www.mysqlperformanceblog.com/2009/08/16/a-micro-benchmark-of-stored-routines-in-mysql/comment-page-1/#comment-645875</link>
		<dc:creator>Tim Little</dc:creator>
		<pubDate>Thu, 03 Sep 2009 05:02:46 +0000</pubDate>
		<guid isPermaLink="false">http://www.mysqlperformanceblog.com/?p=1018#comment-645875</guid>
		<description>It occurs to me (and everyone please feel free to correct me without mercy... 

But doesn&#039;t the other_table retrieval occur just once per query :
SELECT some_stuff FROM some_table 
WHERE a_field IN 
     ( SELECT other_stuff FROM other_table WHERE logic_goes_here )

While my contrasting concern is that the WHERE speaks_english is issued once per row, isn&#039;t it? as :
SELECT sql_no_cache sum(ci.Population) FROM City AS ci WHERE speaks_english(CountryCode)&gt; 0; 

Am I missing something, am I correct?</description>
		<content:encoded><![CDATA[<p>It occurs to me (and everyone please feel free to correct me without mercy&#8230; </p>
<p>But doesn&#8217;t the other_table retrieval occur just once per query :<br />
SELECT some_stuff FROM some_table<br />
WHERE a_field IN<br />
     ( SELECT other_stuff FROM other_table WHERE logic_goes_here )</p>
<p>While my contrasting concern is that the WHERE speaks_english is issued once per row, isn&#8217;t it? as :<br />
SELECT sql_no_cache sum(ci.Population) FROM City AS ci WHERE speaks_english(CountryCode)&gt; 0; </p>
<p>Am I missing something, am I correct?</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: Baron Schwartz</title>
		<link>http://www.mysqlperformanceblog.com/2009/08/16/a-micro-benchmark-of-stored-routines-in-mysql/comment-page-1/#comment-632416</link>
		<dc:creator>Baron Schwartz</dc:creator>
		<pubDate>Tue, 18 Aug 2009 21:36:49 +0000</pubDate>
		<guid isPermaLink="false">http://www.mysqlperformanceblog.com/?p=1018#comment-632416</guid>
		<description>Mark, thanks.  I kind of created this to test a specific client scenario, so I was really focused on the cost of a stored function as a WHERE filter (as opposed to some other options that would roughly approximate the subquery).  I am not sure the client could use a SP in its entirety.  But I appreciate your rewrite, and I&#039;m guessing the client does too!</description>
		<content:encoded><![CDATA[<p>Mark, thanks.  I kind of created this to test a specific client scenario, so I was really focused on the cost of a stored function as a WHERE filter (as opposed to some other options that would roughly approximate the subquery).  I am not sure the client could use a SP in its entirety.  But I appreciate your rewrite, and I&#8217;m guessing the client does too!</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: Mark Leith</title>
		<link>http://www.mysqlperformanceblog.com/2009/08/16/a-micro-benchmark-of-stored-routines-in-mysql/comment-page-1/#comment-631689</link>
		<dc:creator>Mark Leith</dc:creator>
		<pubDate>Mon, 17 Aug 2009 12:34:37 +0000</pubDate>
		<guid isPermaLink="false">http://www.mysqlperformanceblog.com/?p=1018#comment-631689</guid>
		<description>I should note of course, that I understand that this flips how the statements are run, but it *is* an apples to apples comparison, as it achieves exactly what the statement wanted to achieve, yet does it with different logic (as SPs are intended). :)</description>
		<content:encoded><![CDATA[<p>I should note of course, that I understand that this flips how the statements are run, but it *is* an apples to apples comparison, as it achieves exactly what the statement wanted to achieve, yet does it with different logic (as SPs are intended). <img src='http://www.mysqlperformanceblog.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
]]></content:encoded>
	</item>
	<item>
		<title>By: Mark Leith</title>
		<link>http://www.mysqlperformanceblog.com/2009/08/16/a-micro-benchmark-of-stored-routines-in-mysql/comment-page-1/#comment-631686</link>
		<dc:creator>Mark Leith</dc:creator>
		<pubDate>Mon, 17 Aug 2009 12:29:36 +0000</pubDate>
		<guid isPermaLink="false">http://www.mysqlperformanceblog.com/?p=1018#comment-631686</guid>
		<description>Well, let&#039;s try a proper stored procedure.. :) 

I&#039;ll actually mimic what the statement was trying to do - find the population of countries that speak a given language, use a cursor to get the rows for the countries that speak the language (the inner query), and then loop over it:

CREATE PROCEDURE speaks_language (IN in_language VARCHAR(30))
BEGIN

  DECLARE v_countryCode CHAR(3);
  DECLARE v_countrySpeaksEnglish BIGINT DEFAULT 0;
  DECLARE v_sumSpeaksEnglish BIGINT DEFAULT 0;
  DECLARE done INT DEFAULT 0;

  DECLARE countries CURSOR FOR
    SELECT DISTINCT co.Code FROM Country AS co
     INNER JOIN CountryLanguage AS cl ON cl.CountryCode = co.Code
    WHERE cl.Language = in_language;
  DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;

  OPEN countries;

  REPEAT
    FETCH countries INTO v_countryCode;
    IF NOT done THEN 
     SELECT sql_no_cache sum(ci.Population) INTO v_countrySpeaksEnglish
       FROM City AS ci WHERE CountryCode = v_countryCode;
     SET v_sumSpeaksEnglish = v_sumSpeaksEnglish + IFNULL(v_countrySpeaksEnglish, 0);
     END IF;
  UNTIL done END REPEAT;

  CLOSE countries;

  SELECT v_sumSpeaksEnglish;

END//

Here&#039;s the results on my system, including the original query:

mysql&gt; CALL speaks_language(&#039;English&#039;)//
+--------------------+
&#124; v_sumSpeaksEnglish &#124;
+--------------------+
&#124;          237134840 &#124; 
+--------------------+
1 row in set (0.04 sec)

Query OK, 0 rows affected (0.04 sec)

mysql&gt; CALL speaks_language(&#039;English&#039;)//
+--------------------+
&#124; v_sumSpeaksEnglish &#124;
+--------------------+
&#124;          237134840 &#124; 
+--------------------+
1 row in set (0.04 sec)

Query OK, 0 rows affected (0.04 sec)

mysql&gt; CALL speaks_language(&#039;English&#039;)//
+--------------------+
&#124; v_sumSpeaksEnglish &#124;
+--------------------+
&#124;          237134840 &#124; 
+--------------------+
1 row in set (0.05 sec)

Query OK, 0 rows affected (0.05 sec)

mysql&gt; SELECT sql_no_cache sum(ci.Population) FROM City AS ci   WHERE CountryCode IN (     SELECT DISTINCT co.Code FROM Country AS co       INNER JOIN CountryLanguage AS cl ON cl.CountryCode = co.Code     WHERE lower(cl.LANGUAGE) = &#039;English&#039;);//+--------------------+&#124; sum(ci.Population) &#124;+--------------------+
&#124;          237134840 &#124; 
+--------------------+
1 row in set (0.05 sec)

mysql&gt; SELECT sql_no_cache sum(ci.Population) FROM City AS ci   WHERE CountryCode IN (     SELECT DISTINCT co.Code FROM Country AS co       INNER JOIN CountryLanguage AS cl ON cl.CountryCode = co.Code     WHERE lower(cl.LANGUAGE) = &#039;English&#039;);//
+--------------------+
&#124; sum(ci.Population) &#124;
+--------------------+
&#124;          237134840 &#124; 
+--------------------+
1 row in set (0.06 sec)

mysql&gt; SELECT sql_no_cache sum(ci.Population) FROM City AS ci   WHERE CountryCode IN (     SELECT DISTINCT co.Code FROM Country AS co       INNER JOIN CountryLanguage AS cl ON cl.CountryCode = co.Code     WHERE lower(cl.LANGUAGE) = &#039;English&#039;);//
+--------------------+
&#124; sum(ci.Population) &#124;
+--------------------+
&#124;          237134840 &#124; 
+--------------------+
1 row in set (0.05 sec)</description>
		<content:encoded><![CDATA[<p>Well, let&#8217;s try a proper stored procedure.. <img src='http://www.mysqlperformanceblog.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' />  </p>
<p>I&#8217;ll actually mimic what the statement was trying to do &#8211; find the population of countries that speak a given language, use a cursor to get the rows for the countries that speak the language (the inner query), and then loop over it:</p>
<p>CREATE PROCEDURE speaks_language (IN in_language VARCHAR(30))<br />
BEGIN</p>
<p>  DECLARE v_countryCode CHAR(3);<br />
  DECLARE v_countrySpeaksEnglish BIGINT DEFAULT 0;<br />
  DECLARE v_sumSpeaksEnglish BIGINT DEFAULT 0;<br />
  DECLARE done INT DEFAULT 0;</p>
<p>  DECLARE countries CURSOR FOR<br />
    SELECT DISTINCT co.Code FROM Country AS co<br />
     INNER JOIN CountryLanguage AS cl ON cl.CountryCode = co.Code<br />
    WHERE cl.Language = in_language;<br />
  DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;</p>
<p>  OPEN countries;</p>
<p>  REPEAT<br />
    FETCH countries INTO v_countryCode;<br />
    IF NOT done THEN<br />
     SELECT sql_no_cache sum(ci.Population) INTO v_countrySpeaksEnglish<br />
       FROM City AS ci WHERE CountryCode = v_countryCode;<br />
     SET v_sumSpeaksEnglish = v_sumSpeaksEnglish + IFNULL(v_countrySpeaksEnglish, 0);<br />
     END IF;<br />
  UNTIL done END REPEAT;</p>
<p>  CLOSE countries;</p>
<p>  SELECT v_sumSpeaksEnglish;</p>
<p>END//</p>
<p>Here&#8217;s the results on my system, including the original query:</p>
<p>mysql&gt; CALL speaks_language(&#8216;English&#8217;)//<br />
+&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;+<br />
| v_sumSpeaksEnglish |<br />
+&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;+<br />
|          237134840 |<br />
+&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;+<br />
1 row in set (0.04 sec)</p>
<p>Query OK, 0 rows affected (0.04 sec)</p>
<p>mysql&gt; CALL speaks_language(&#8216;English&#8217;)//<br />
+&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;+<br />
| v_sumSpeaksEnglish |<br />
+&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;+<br />
|          237134840 |<br />
+&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;+<br />
1 row in set (0.04 sec)</p>
<p>Query OK, 0 rows affected (0.04 sec)</p>
<p>mysql&gt; CALL speaks_language(&#8216;English&#8217;)//<br />
+&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;+<br />
| v_sumSpeaksEnglish |<br />
+&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;+<br />
|          237134840 |<br />
+&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;+<br />
1 row in set (0.05 sec)</p>
<p>Query OK, 0 rows affected (0.05 sec)</p>
<p>mysql&gt; SELECT sql_no_cache sum(ci.Population) FROM City AS ci   WHERE CountryCode IN (     SELECT DISTINCT co.Code FROM Country AS co       INNER JOIN CountryLanguage AS cl ON cl.CountryCode = co.Code     WHERE lower(cl.LANGUAGE) = &#8216;English&#8217;);//+&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;+| sum(ci.Population) |+&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;+<br />
|          237134840 |<br />
+&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;+<br />
1 row in set (0.05 sec)</p>
<p>mysql&gt; SELECT sql_no_cache sum(ci.Population) FROM City AS ci   WHERE CountryCode IN (     SELECT DISTINCT co.Code FROM Country AS co       INNER JOIN CountryLanguage AS cl ON cl.CountryCode = co.Code     WHERE lower(cl.LANGUAGE) = &#8216;English&#8217;);//<br />
+&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;+<br />
| sum(ci.Population) |<br />
+&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;+<br />
|          237134840 |<br />
+&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;+<br />
1 row in set (0.06 sec)</p>
<p>mysql&gt; SELECT sql_no_cache sum(ci.Population) FROM City AS ci   WHERE CountryCode IN (     SELECT DISTINCT co.Code FROM Country AS co       INNER JOIN CountryLanguage AS cl ON cl.CountryCode = co.Code     WHERE lower(cl.LANGUAGE) = &#8216;English&#8217;);//<br />
+&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;+<br />
| sum(ci.Population) |<br />
+&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;+<br />
|          237134840 |<br />
+&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;+<br />
1 row in set (0.05 sec)</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: Josh Davis</title>
		<link>http://www.mysqlperformanceblog.com/2009/08/16/a-micro-benchmark-of-stored-routines-in-mysql/comment-page-1/#comment-631679</link>
		<dc:creator>Josh Davis</dc:creator>
		<pubDate>Mon, 17 Aug 2009 12:14:57 +0000</pubDate>
		<guid isPermaLink="false">http://www.mysqlperformanceblog.com/?p=1018#comment-631679</guid>
		<description>The stored routine does a COUNT(), unlike the original query. I think you&#039;d be closer to the way the original query works with something like:


DELIMITER //
DROP FUNCTION IF EXISTS speaks_english//
CREATE FUNCTION speaks_english(c char(3)) returns integer deterministic
begin
	RETURN (SELECT 1 FROM Country AS co INNER JOIN CountryLanguage AS cl ON cl.CountryCode = co.Code WHERE lower(cl.LANGUAGE) = &#039;English&#039; AND co.Code = c LIMIT 1);
end//
DELIMITER ;


On my machine it&#039;s still 10 times slower than the subquery, though.</description>
		<content:encoded><![CDATA[<p>The stored routine does a COUNT(), unlike the original query. I think you&#8217;d be closer to the way the original query works with something like:</p>
<p>DELIMITER //<br />
DROP FUNCTION IF EXISTS speaks_english//<br />
CREATE FUNCTION speaks_english(c char(3)) returns integer deterministic<br />
begin<br />
	RETURN (SELECT 1 FROM Country AS co INNER JOIN CountryLanguage AS cl ON cl.CountryCode = co.Code WHERE lower(cl.LANGUAGE) = &#8216;English&#8217; AND co.Code = c LIMIT 1);<br />
end//<br />
DELIMITER ;</p>
<p>On my machine it&#8217;s still 10 times slower than the subquery, though.</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: Morgan Tocker</title>
		<link>http://www.mysqlperformanceblog.com/2009/08/16/a-micro-benchmark-of-stored-routines-in-mysql/comment-page-1/#comment-631462</link>
		<dc:creator>Morgan Tocker</dc:creator>
		<pubDate>Mon, 17 Aug 2009 02:18:46 +0000</pubDate>
		<guid isPermaLink="false">http://www.mysqlperformanceblog.com/?p=1018#comment-631462</guid>
		<description>@Baron - I tried testing this 1 year ago with fibonacci:
http://mtocker.livejournal.com/45222.html

My test wasn&#039;t apples to apples either, but I found that writing stuff in PHP was about ten times faster.  If you add in that MySQL stored procedures don&#039;t have a debugger, it&#039;s a tough sell to write pages and pages of business logic in them.</description>
		<content:encoded><![CDATA[<p>@Baron &#8211; I tried testing this 1 year ago with fibonacci:<br />
<a href="http://mtocker.livejournal.com/45222.html" rel="nofollow">http://mtocker.livejournal.com/45222.html</a></p>
<p>My test wasn&#8217;t apples to apples either, but I found that writing stuff in PHP was about ten times faster.  If you add in that MySQL stored procedures don&#8217;t have a debugger, it&#8217;s a tough sell to write pages and pages of business logic in them.</p>
]]></content:encoded>
	</item>
</channel>
</rss>

