<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-7171477457129187873</id><updated>2012-02-23T15:26:19.688+01:00</updated><category term='interval'/><category term='range'/><category term='mysql 5.6'/><category term='new feature'/><category term='compound index'/><category term='mysql'/><category term='optimizer trace'/><category term='explain'/><category term='multiple-part index'/><title type='text'>Jørgen's point of view</title><subtitle type='html'>Mostly about the MySQL Optimizer</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://jorgenloland.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7171477457129187873/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://jorgenloland.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Jørgen Løland</name><uri>http://www.blogger.com/profile/07423633132356058535</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://2.bp.blogspot.com/-n1GWxK4D_Bs/Tkklki_Yl8I/AAAAAAAAABM/tOqmc3fXNuo/s220/jorgen.jpg'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>4</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-7171477457129187873.post-8814469961574103155</id><published>2011-10-04T10:02:00.001+02:00</published><updated>2011-10-04T10:02:21.779+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='optimizer trace'/><category scheme='http://www.blogger.com/atom/ns#' term='new feature'/><category scheme='http://www.blogger.com/atom/ns#' term='mysql'/><category scheme='http://www.blogger.com/atom/ns#' term='mysql 5.6'/><category scheme='http://www.blogger.com/atom/ns#' term='explain'/><category scheme='http://www.blogger.com/atom/ns#' term='range'/><title type='text'>Optimizer tracing: Query Execution Plan descriptions beyond EXPLAIN</title><content type='html'>Understanding why MySQL chooses a particular join order or why table scan is chosen instead of range scan is often very hard even for experienced MySQL users. Two almost identical queries, differing only in constant values, may produce completely different plans. That&amp;#39;s why we&amp;#39;re introducing a great new feature in 5.6: &lt;a href="http://forge.mysql.com/wiki/MySQL_Internals_Optimizer_tracing"&gt;&lt;i&gt;Optimizer Tracing&lt;/i&gt;&lt;/a&gt;. The target users of this feature are developers and MySQL users experienced enough to understand the ins and outs of EXPLAIN.&lt;br&gt;&lt;br&gt;&lt;b&gt;What Optimizer Tracing is&lt;/b&gt;&lt;br&gt;You may already have guessed this, but optimizer tracing is a printout  of important decisions the MySQL optimizer has done during the process of making the Query Execution Plan. &lt;br&gt;&lt;br&gt;The trace is presented in JSON format which is easy to read both for humans and others.&lt;br&gt;&lt;br&gt;Currently, the optimizer trace includes short explanations for:&lt;br&gt;&lt;ul&gt;&lt;li&gt;Why the join order was chosen.&lt;/li&gt;&lt;li&gt;Important query transformations like IN to EXISTS.&lt;/li&gt;&lt;li&gt;The access methods applicable and why one of them was chosen.&lt;/li&gt;&lt;li&gt;Which conditions are attached to each table (i.e., what hides behind &amp;quot;Using where&amp;quot; in EXPLAIN)&lt;/li&gt;&lt;/ul&gt;More coverage will be added as we go along.&lt;br&gt;&lt;b&gt;&lt;/b&gt;&lt;br&gt;&lt;br&gt;&lt;b&gt;What Optimizer Tracing is NOT&lt;/b&gt;&lt;br&gt;The feature is not, and never will be, complete in the sense that it does not describe all choices the optimizer does. However, we&amp;#39;re going to add more information when we find valuable things to add. We will not guarantee backwards compatibility like we do for EXPLAIN. This gives us the freedom to improve tracing at a high pace without going through multi-release deprecation warnings etc. In other words: optimizer tracing is not a replacement for EXPLAIN. &lt;br&gt;&lt;br&gt;&lt;b&gt;A quick tour&lt;/b&gt;&lt;br&gt;The best way get a feeling of optimizer tracing is to give it a try. Below is a teaser:&lt;br&gt;&lt;b&gt;&lt;/b&gt;&lt;a href="http://jorgenloland.blogspot.com/2011/10/optimizer-tracing-query-execution-plan.html#more"&gt;Read more »&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7171477457129187873-8814469961574103155?l=jorgenloland.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jorgenloland.blogspot.com/feeds/8814469961574103155/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://jorgenloland.blogspot.com/2011/10/optimizer-tracing-query-execution-plan.html#comment-form' title='6 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7171477457129187873/posts/default/8814469961574103155'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7171477457129187873/posts/default/8814469961574103155'/><link rel='alternate' type='text/html' href='http://jorgenloland.blogspot.com/2011/10/optimizer-tracing-query-execution-plan.html' title='Optimizer tracing: Query Execution Plan descriptions beyond EXPLAIN'/><author><name>Jørgen Løland</name><uri>http://www.blogger.com/profile/07423633132356058535</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://2.bp.blogspot.com/-n1GWxK4D_Bs/Tkklki_Yl8I/AAAAAAAAABM/tOqmc3fXNuo/s220/jorgen.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/--EakL2J2zoQ/ToBsHpbaesI/AAAAAAAAAB4/wP5ICrANpfg/s72-c/trace-json.jpg' height='72' width='72'/><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7171477457129187873.post-6369433373687039343</id><published>2011-09-27T13:42:00.002+02:00</published><updated>2011-09-28T18:41:27.489+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='multiple-part index'/><category scheme='http://www.blogger.com/atom/ns#' term='mysql'/><category scheme='http://www.blogger.com/atom/ns#' term='explain'/><category scheme='http://www.blogger.com/atom/ns#' term='interval'/><category scheme='http://www.blogger.com/atom/ns#' term='range'/><title type='text'>Tips and tricks: Killer response time for non-overlapping intervals</title><content type='html'>Assume you have a table where you store &lt;i&gt;non-overlapping intervals&lt;/i&gt; using two columns, e.g. IP ranges. IP ranges are simple to represent using &lt;a href="http://www.silisoftware.com/tools/ipconverter.php"&gt;integer notation&lt;/a&gt;:&lt;br&gt;&lt;br&gt;&lt;div style="font-family: Verdana,sans-serif;"&gt;&lt;span style="font-size: x-small;"&gt;CREATE TABLE ip_owner (&lt;/span&gt;&lt;/div&gt;&lt;div style="font-family: Verdana,sans-serif;"&gt;&lt;span style="font-size: x-small;"&gt;   owner_id int NOT NULL,&lt;br&gt;   /* some columns */ &lt;/span&gt;&lt;/div&gt;&lt;div style="font-family: Verdana,sans-serif;"&gt;&lt;span style="font-size: x-small;"&gt;   ip_start_int bigint NOT NULL,      /* IP address converted to integer */&lt;br&gt;   ip_end_int bigint NOT NULL,        /* IP address converted to integer */&lt;br&gt;   PRIMARY KEY (owner_id),&lt;/span&gt;&lt;/div&gt;&lt;div style="font-family: Verdana,sans-serif;"&gt;&lt;span style="font-size: x-small;"&gt;   INDEX ip_range (ip_start_int, ip_end_int)&lt;/span&gt;&lt;/div&gt;&lt;div style="font-family: Verdana,sans-serif;"&gt;&lt;span style="font-size: x-small;"&gt;) ENGINE=InnoDB;&lt;/span&gt;&lt;/div&gt;&lt;br&gt;&lt;br&gt;And then you find yourself in a situation where you want to know who, if anyone, owns the IP address &lt;span style="font-size: x-small;"&gt;X&lt;/span&gt;. This can be done using the following query:&lt;br&gt;&lt;br&gt;&lt;div style="font-family: Verdana,sans-serif;"&gt;&lt;span style="font-size: x-small;"&gt;SELECT * FROM ip_owner WHERE ip_start_int &amp;lt;= X AND ip_end_int &amp;gt;= X;&lt;/span&gt;&lt;/div&gt;&lt;br&gt;MySQL can resolve this using a range scan, but will unfortunately only be able to use the &lt;span style="font-size: x-small;"&gt;ip_start_int &amp;lt;= X&lt;/span&gt; part of the condition as a range &lt;a href="http://jorgenloland.blogspot.com/2011/08/mysql-range-access-method-explained.html"&gt;as explained here&lt;/a&gt;. Thus, the query will either be resolved by range scan if fairly few records have &lt;span style="font-size: x-small;"&gt;ip_start_int &amp;lt;= X&lt;/span&gt; or table scan otherwise. That means unreliable response time because it will be much quicker to query low-valued IPs than high valued IPs. I inserted 1M records into the table before running the queries below:&lt;br&gt;&lt;br&gt;&lt;a href="http://jorgenloland.blogspot.com/2011/09/tips-and-tricks-killer-response-time.html#more"&gt;Read more »&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7171477457129187873-6369433373687039343?l=jorgenloland.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jorgenloland.blogspot.com/feeds/6369433373687039343/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://jorgenloland.blogspot.com/2011/09/tips-and-tricks-killer-response-time.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7171477457129187873/posts/default/6369433373687039343'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7171477457129187873/posts/default/6369433373687039343'/><link rel='alternate' type='text/html' href='http://jorgenloland.blogspot.com/2011/09/tips-and-tricks-killer-response-time.html' title='Tips and tricks: Killer response time for non-overlapping intervals'/><author><name>Jørgen Løland</name><uri>http://www.blogger.com/profile/07423633132356058535</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://2.bp.blogspot.com/-n1GWxK4D_Bs/Tkklki_Yl8I/AAAAAAAAABM/tOqmc3fXNuo/s220/jorgen.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7171477457129187873.post-1638616608708737558</id><published>2011-08-23T13:32:00.000+02:00</published><updated>2011-08-23T13:32:28.136+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='multiple-part index'/><category scheme='http://www.blogger.com/atom/ns#' term='mysql'/><category scheme='http://www.blogger.com/atom/ns#' term='compound index'/><category scheme='http://www.blogger.com/atom/ns#' term='explain'/><category scheme='http://www.blogger.com/atom/ns#' term='range'/><title type='text'>The MySQL range access method explained</title><content type='html'>The range access method uses an index to read a subset of rows that form one or multiple continuous index value intervals. The intervals are defined by the query&amp;#39;s range predicates, which are comparisons using any of &lt;span style="font-size: x-small;"&gt;=, &amp;lt;=&amp;gt;, IN(), IS NULL, IS NOT NULL, &amp;gt;, &amp;lt;, &amp;gt;=, &amp;lt;=, BETWEEN, !=, &amp;lt;&amp;gt; or LIKE&lt;/span&gt;.&lt;br&gt;&lt;br&gt;Some examples:&lt;br&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;/div&gt;&lt;div style="font-family: Verdana,sans-serif;"&gt;&lt;span style="font-size: x-small;"&gt;SELECT * FROM blog WHERE author_id IN (1, 7, 8, 10)&lt;/span&gt;&lt;/div&gt;&lt;div style="font-family: Verdana,sans-serif;"&gt;&lt;span style="font-size: x-small;"&gt;SELECT * FROM orders WHERE value &amp;gt; 1000&lt;/span&gt;&lt;/div&gt;&lt;br&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-qFiyZp1rRHI/TlOC9HkoStI/AAAAAAAAABs/1G_bNboXP70/s1600/single.JPG" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="231" src="http://3.bp.blogspot.com/-qFiyZp1rRHI/TlOC9HkoStI/AAAAAAAAABs/1G_bNboXP70/s320/single.JPG" width="320"&gt;&lt;/a&gt;&lt;/div&gt;You know that the range access method is used when EXPLAIN shows &lt;span style="font-size: x-small;"&gt;type=range&lt;/span&gt;.&lt;br&gt;&lt;br&gt;Naturally, there has to be an index on the column used by the range predicate. Since indexes are ordered, MySQL will, for each interval, dive down the index using the interval start value and read it&amp;#39;s way through the index leaves until it reaches the interval end value:&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;a href="http://jorgenloland.blogspot.com/2011/08/mysql-range-access-method-explained.html#more"&gt;Read more »&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7171477457129187873-1638616608708737558?l=jorgenloland.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jorgenloland.blogspot.com/feeds/1638616608708737558/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://jorgenloland.blogspot.com/2011/08/mysql-range-access-method-explained.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7171477457129187873/posts/default/1638616608708737558'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7171477457129187873/posts/default/1638616608708737558'/><link rel='alternate' type='text/html' href='http://jorgenloland.blogspot.com/2011/08/mysql-range-access-method-explained.html' title='The MySQL range access method explained'/><author><name>Jørgen Løland</name><uri>http://www.blogger.com/profile/07423633132356058535</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://2.bp.blogspot.com/-n1GWxK4D_Bs/Tkklki_Yl8I/AAAAAAAAABM/tOqmc3fXNuo/s220/jorgen.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/-qFiyZp1rRHI/TlOC9HkoStI/AAAAAAAAABs/1G_bNboXP70/s72-c/single.JPG' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7171477457129187873.post-3181404526195026473</id><published>2011-08-17T12:52:00.001+02:00</published><updated>2011-08-22T14:33:29.612+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='mysql'/><category scheme='http://www.blogger.com/atom/ns#' term='explain'/><title type='text'>The meaning of ref=func in MySQL EXPLAIN</title><content type='html'>When EXPLAIN shows that a table is accessed using the [eq_]ref access type, we&amp;#39;re used to look at the ref column to see where MySQL gets the value to look up from. Usually, we see either &amp;quot;const&amp;quot; if the value is provided as a constant in the query or a column name if the value is read from a column in an already read table:&lt;br&gt;&lt;br&gt;&lt;div style="background: none repeat scroll 0% 0% black; color: white; height: 100%; line-height: 100%; overflow: auto; padding: 10px; width: 100%;"&gt;&lt;pre&gt;&lt;span style="font-size: xx-small;"&gt;EXPLAIN &lt;br /&gt;SELECT acc_rec.cust_id, acc_rec.amount, acc_rec.invoicenumber&lt;br /&gt;FROM accounts_receivable as acc_rec&lt;br /&gt;WHERE &lt;span style="color: lime;"&gt;acc_rec.cust_id=1&lt;/span&gt;;&lt;br /&gt;+----+-------------+---------+------+---------+-------+&lt;br /&gt;| id | select_type | table   | type | key     | ref   |&lt;br /&gt;+----+-------------+---------+------+---------+-------+&lt;br /&gt;| 1  | SIMPLE      | acc_rec | ref  | cust_id | &lt;span style="color: lime;"&gt;const&lt;/span&gt; |&lt;br /&gt;+----+-------------+---------+------+---------+-------+&lt;br /&gt;&lt;br /&gt;EXPLAIN &lt;br /&gt;SELECT acc_rec.cust_id, acc_rec.amount, acc_rec.invoicenumber,&lt;br /&gt;       customers.firstname, customers.lastname, customers.phone&lt;br /&gt;FROM accounts_receivable AS acc_rec JOIN customers AS cust&lt;br /&gt;ON &lt;span style="color: lime;"&gt;acc_rec.cust_id = customers.cust_id&lt;/span&gt;;&lt;br /&gt;+----+-------------+---------+--------+---------+-----------------+&lt;br /&gt;| id | select_type | table   | type   | key     | ref             |&lt;br /&gt;+----+-------------+---------+--------+---------+-----------------+&lt;br /&gt;| 1  | SIMPLE      | acc_rec | ALL    | NULL    | NULL            |&lt;br /&gt;| 1  | SIMPLE      | cust    | eq_ref | PRIMARY | &lt;span style="color: lime;"&gt;acc_rec.cust_id&lt;/span&gt; |&lt;br /&gt;+----+-------------+---------+--------+---------+-----------------+&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;br&gt;But what if ref shows the value &amp;quot;func&amp;quot;? In this case, the value used as input to [eq_]ref is the output of some function. A few examples:&lt;br&gt;&lt;br&gt;&lt;a href="http://jorgenloland.blogspot.com/2011/08/meaning-of-reffunc-in-mysql-explain.html#more"&gt;Read more »&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7171477457129187873-3181404526195026473?l=jorgenloland.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jorgenloland.blogspot.com/feeds/3181404526195026473/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://jorgenloland.blogspot.com/2011/08/meaning-of-reffunc-in-mysql-explain.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7171477457129187873/posts/default/3181404526195026473'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7171477457129187873/posts/default/3181404526195026473'/><link rel='alternate' type='text/html' href='http://jorgenloland.blogspot.com/2011/08/meaning-of-reffunc-in-mysql-explain.html' title='The meaning of ref=func in MySQL EXPLAIN'/><author><name>Jørgen Løland</name><uri>http://www.blogger.com/profile/07423633132356058535</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://2.bp.blogspot.com/-n1GWxK4D_Bs/Tkklki_Yl8I/AAAAAAAAABM/tOqmc3fXNuo/s220/jorgen.jpg'/></author><thr:total>0</thr:total></entry></feed>
