<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	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/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Transactions on InnoDB</title>
	<atom:link href="http://blogs.innodb.com/wp/feed/" rel="self" type="application/rss+xml" />
	<link>http://blogs.innodb.com/wp</link>
	<description>&#34;The word&#34; about InnoDB Products and Technology</description>
	<lastBuildDate>Tue, 17 Apr 2012 05:45:10 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
		<item>
		<title>Optimizing neighbor flush behavior</title>
		<link>http://blogs.innodb.com/wp/2012/04/optimizing-neighbor-flush-behavior/</link>
		<comments>http://blogs.innodb.com/wp/2012/04/optimizing-neighbor-flush-behavior/#comments</comments>
		<pubDate>Mon, 16 Apr 2012 15:30:37 +0000</pubDate>
		<dc:creator>Yasufumi</dc:creator>
				<category><![CDATA[Bug fix]]></category>
		<category><![CDATA[InnoDB Plugin]]></category>
		<category><![CDATA[Performance]]></category>

		<guid isPermaLink="false">http://blogs.innodb.com/wp/?p=1763</guid>
		<description><![CDATA[The performance of flush_list flushing of InnoDB decides the basic performance for modifying workloads. So, it is important to optimize the flush behavior. In this post we&#8217;ll consider how to optimize the neighbor-flushing behavior. Factor 1: Characteristics of storage Depending on the characteristics of your storage&#8217;s throughput for write IO, you can term your storage [...]]]></description>
			<content:encoded><![CDATA[<p>The performance of flush_list flushing of InnoDB decides the basic performance for modifying workloads. So, it is important to optimize the flush behavior. In this post we&#8217;ll consider how to optimize the neighbor-flushing behavior.</p>
<p><strong>Factor 1: Characteristics of storage</strong></p>
<p>Depending on the characteristics of your storage&#8217;s throughput for write IO, you can term your storage as either <strong>&#8220;write amount bound&#8221;</strong> or <strong>&#8220;write times bound&#8221;</strong>. The minimum unit of the InnoDB datafile is page size (16KB or less). And InnoDB attempts to combines them in a single IO up to 1 extent (1MB) maximum, if they are contiguous.</p>
<p><strong><em>&lt;one HDD&gt;</em></strong>:  Almost &#8220;write <strong>times</strong> bound&#8221;. Because head-seek time is the most effective factor for access time of HDD. And around 1MB size can be treated by the 1 head-seek.</p>
<p><strong><em>&lt;RAID-HDD&gt;</em></strong>: It depends on the striping size of the RAID. In many cases, the striping size is set to 256KB ~ 1MB (much larger than the page size of datafile), with the intention that 1IO &#8211; 1HDD (both for keeping sequential access advantage of HDD and for keeping parallel ability for IO requests using several HDD in RAID). For the such general striping size, RAID-HDD is &#8220;write <strong>times</strong> bound&#8221;. (For the small striping size around same size as the page size, it should be &#8220;write <strong>amount</strong> bound&#8221;. But I don&#8217;t recommend such small striping size from the viewpoint of this post, because it just loses the sequential access advantage.)</p>
<p><span id="more-1763"></span></p>
<p><em><strong>&lt;SSD&gt;</strong></em>: It depends on internal write unit of SSD. For newer high-end SSD, the size is 4KB or more. It is not larger than InnoDB page size. Such high-end SSD is &#8220;write <strong>amount</strong> bound&#8221;. However, the unit size is very different according to each SSD&#8217;s internal implementations. Low-end or older SSD might have unit size over 1MB (and the throughput might be slow) and might be &#8220;write <strong>times</strong> bound&#8221;. You can estimate the write unit size of your SSD by random write benchmark with several block sizes 4,8,16KB,&#8230;,1MB, and the largest block size of the &#8220;write times bound&#8221; expected as the unit size.</p>
<p>&nbsp;</p>
<p><strong>Factor 2: Oldest modified age</strong></p>
<p>The redo log in InnoDB is used in a circular fashion. The reusable redo space is limited by the oldest modification in the oldest modified block i.e.: the max oldest modified age which is equal to current_LSN (Log Sequenc Number) &#8211; the oldest modification LSN cannot be higher than the log capacity of the redo log files. When there is no reusable redo space available other modification operations cannot be done until the oldest modified age is decreased by flushing the oldest dirty pages.</p>
<p>The flushing throughput of the oldest dirty pages decides the workload throughput. It is important, how to effectively use the limited write IO bound for flushing &#8220;oldest&#8221; dirty pages.</p>
<p>&nbsp;</p>
<p><strong>Tuning flush_list flushing effective<br />
</strong></p>
<p>The first priority of flushing is to reduce the oldest modified age assuming there is no shortage of  free blocks. So, this<em> &#8220;flushing the oldest blocks only&#8221;</em> is the basic strategy.</p>
<p>For &#8220;write <strong>amount</strong> bound&#8221; storage (e.g. high-end SSD), this is already the best strategy. It equals to &#8220;<strong>innodb_flush_neighbors = false</strong>&#8220;.</p>
<p>On the other hand, for &#8220;write <strong>times</strong> bound&#8221; storage (e.g. HDD base), the contiguous dirty neighbors of the oldest dirty pages can be flushed <strong>without wasting the write IO bound</strong>, because of the sequential advantage. So, <strong>flushing also the contiguous pages</strong> is really worth to do. But non-contiguous and non-oldest blocks should not be flushed at the same time, because non-contiguous flushing will become another IO request and has high probability to be treated as another raw block writing in the storage (waste the write IO bound).</p>
<p>The flush_neighbors of InnoDB traditional implementation flushes non-contiguous dirty blocks also. And it is not the best behavior for both type of storage &#8220;write times bound&#8221; and &#8220;write amount bound&#8221;. In MySQL labs release 2012 we have fixed this behavior to flush contiguous pages only, for &#8220;write times bound&#8221; storage.</p>
<p>&nbsp;</p>
<p><strong>Conclusion</strong></p>
<p>In the end, the conclusion is followings</p>
<ul>
<li>For <strong>HDD</strong> or <strong>HDD-RAID</strong> (stripe size about 256KB ~ 1MB): <strong>use the new flush_neighbors</strong> (flushing contiguous dirty blocks only)</li>
</ul>
<ul>
<li>For <strong>SSD</strong> (internal write unit size =&lt; InnoDB data page size): <strong>disable flush_neighbors</strong></li>
</ul>
<p>&nbsp;</p>
]]></content:encoded>
			<wfw:commentRss>http://blogs.innodb.com/wp/2012/04/optimizing-neighbor-flush-behavior/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>New flushing algorithm in InnoDB</title>
		<link>http://blogs.innodb.com/wp/2012/04/new-flushing-algorithm-in-innodb/</link>
		<comments>http://blogs.innodb.com/wp/2012/04/new-flushing-algorithm-in-innodb/#comments</comments>
		<pubDate>Fri, 13 Apr 2012 04:24:29 +0000</pubDate>
		<dc:creator>Inaam Rana</dc:creator>
				<category><![CDATA[Feature]]></category>
		<category><![CDATA[InnoDB Plugin]]></category>
		<category><![CDATA[Performance]]></category>

		<guid isPermaLink="false">http://blogs.innodb.com/wp/?p=1677</guid>
		<description><![CDATA[In MySQL labs release April 2012 we have reworked the flushing heuristics in InnoDB. In this post I&#8217;ll give an overview of what we have changed and the various configuration variables we have introduced to fine tune the flushing algorithm. If you are interested in finding out how our new flushing algorithm fares in benchmarks [...]]]></description>
			<content:encoded><![CDATA[<p>In MySQL labs release April 2012 we have reworked the flushing heuristics in InnoDB. In this post I&#8217;ll give an overview of what we have changed and the various configuration variables we have introduced to fine tune the flushing algorithm. If you are interested in finding out how our new flushing algorithm fares in benchmarks you can get these details in Dimitri&#8217;s well-explained blog <a href="http://dimitrik.free.fr/blog/archives/2012/04/mysql-performance-improved-adaptive-flushing-in-56labs.html">here</a>.</p>
<p>Flushing means writing dirty pages to disk. I have explained in some detail about <a href="http://blogs.innodb.com/wp/2010/09/mysql-5-5-innodb-adaptive_flushing-how-it-works/">adaptive_flushing</a> and <a href="http://blogs.innodb.com/wp/2011/04/introducing-page_cleaner-thread-in-innodb/">types of flushing</a> in my previous notes. Please go through these notes if you want to make sense of what follows.</p>
<p>The page_cleaner thread checks the state of the system every second and takes into account number of dirty pages, amount of reusable redo space, the rate at which redo is generated and the IO capacity for which the server is configured and based on these factors decide how many pages we need to flush.</p>
<p>In the new scheme of things the page_cleaner thread uses a single non-linear formula to calculate how many pages we need to flush to have sufficient reusable redo space. This is different from current flushing heuristic where async_water_mark is taken as point where we change our flushing algorithm. Similarly, instead of using <code>innodb_max_dirty_pages_pct</code> as a switch which triggers flushing we have introduced the concept of a range where the flushing to control the dirty pages percentage starts once we cross the low water mark and gets more and more aggressive as we near the high water mark.</p>
<p>There are four new configuration variables. Note that if your system is not experiencing any IO spikes due to checkpoints then you can probably leave all of the following as is. All the variables are global in scope and can be set dynamically.<span id="more-1677"></span></p>
<ul>
<li><strong><code>innodb_adaptive_flushing_lwm</code>:</strong> Low water mark measured in %age of total redo log size at which adaptive flushing kicks in. If currently unusable redo space is less then this value no background flushing will happen. Default value is 10 and permissible values are 0 &#8211; 70.</li>
</ul>
<ul>
<li><strong><code>innodb_max_dirty_pages_pct_lwm</code></strong>: Low water mark of dirty pages in %age where preflushing to control dirty page ratio kicks in. Default value is 0 which has the special meaning of this value having no effect. Allowable values are 0 &#8211; 99.</li>
</ul>
<ul>
<li><strong><code>innodb_max_io_capacity</code>:</strong> InnoDB generally attempts to work within the limits of <code>innodb_io_capacity</code>. However, if it needs to do aggressive flushing then <code>innodb_max_io_capacity</code> defines the limit to which the write IOPs can be stretched. Default value is 2000 which is ten times the default value for <code>innodb_io_capacity</code>.</li>
</ul>
<ul>
<li><strong><code>innodb_flushing_avg_loops</code>:</strong> Number of iterations for which we keep the previously caculated snapshot of the flushing state. This variable is roughly a measure of how smooth you want the transition in the flushing activity to be. The higher the value the smoother will be the transition in flushing in face of rapidly changing workload. A lower value implies that the flushing algorithm is more responsive but it also means that flushing acitivity can become spiky when confronted with a quickly changing workload. Default value is 30 and permissible range is 1 &#8211; 1000.</li>
</ul>
<p>Finally, there is a wealth of information availabe to you to monitor the impact of changing these variables. You can get a good inside view of how flushing activity is working by querying innodb_metrics table.</p>
<blockquote><p>mysql&gt; select name, comment from information_schema.innodb_metrics where name like &#8216;Buffer_flush%&#8217;;<br />
+&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-+&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-+<br />
| name | comment |<br />
+&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-+&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-+<br />
| buffer_flush_batch_scanned | Total pages scanned as part of flush batch |<br />
| buffer_flush_batch_num_scan | Number of times buffer flush list flush is called |<br />
| buffer_flush_batch_scanned_per_call | Pages scanned per flush batch scan |<br />
| buffer_flush_batch_total_pages | Total pages flushed as part of flush batch |<br />
| buffer_flush_batches | Number of flush batches |<br />
| buffer_flush_batch_pages | Pages queued as a flush batch |<br />
| buffer_flush_neighbor_total_pages | Total neighbors flushed as part of neighbor flush |<br />
| buffer_flush_neighbor | Number of times neighbors flushing is invoked |<br />
| buffer_flush_neighbor_pages | Pages queued as a neighbor batch |<br />
| buffer_flush_n_to_flush_requested | Number of pages requested for flushing. |<br />
| buffer_flush_avg_page_rate | Average number of pages at which flushing is happening |<br />
| buffer_flush_lsn_avg_rate | Average redo generation rate |<br />
| buffer_flush_pct_for_dirty | Percent of IO capacity used to avoid max dirty page limit |<br />
| buffer_flush_pct_for_lsn | Percent of IO capacity used to avoid reusable redo space limit |<br />
| buffer_flush_adaptive_total_pages | Total pages flushed as part of adaptive flushing |<br />
| buffer_flush_adaptive | Number of adaptive batches |<br />
| buffer_flush_adaptive_pages | Pages queued as an adaptive batch |<br />
| buffer_flush_sync_total_pages | Total pages flushed as part of sync batches |<br />
| buffer_flush_sync | Number of sync batches |<br />
| buffer_flush_sync_pages | Pages queued as a sync batch |<br />
| buffer_flush_background_total_pages | Total pages flushed as part of background batches |<br />
| buffer_flush_background | Number of background batches |<br />
| buffer_flush_background_pages | Pages queued as a background batch |<br />
+&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-+&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-+<br />
23 rows in set (0.00 sec)</p></blockquote>
]]></content:encoded>
			<wfw:commentRss>http://blogs.innodb.com/wp/2012/04/new-flushing-algorithm-in-innodb/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>InnoDB persistent stats got a friendly UI</title>
		<link>http://blogs.innodb.com/wp/2012/04/innodb-persistent-stats-got-a-friendly-ui/</link>
		<comments>http://blogs.innodb.com/wp/2012/04/innodb-persistent-stats-got-a-friendly-ui/#comments</comments>
		<pubDate>Wed, 11 Apr 2012 07:13:35 +0000</pubDate>
		<dc:creator>Vasil Dimov</dc:creator>
				<category><![CDATA[Feature]]></category>
		<category><![CDATA[InnoDB Builtin]]></category>
		<category><![CDATA[InnoDB Plugin]]></category>

		<guid isPermaLink="false">http://blogs.innodb.com/wp/?p=1748</guid>
		<description><![CDATA[After introducing InnoDB persistent statistics in MySQL 5.6, in this April Labs release we have dressed it up in a nice UI and refactored the internals a bit to make the code more elegant and straight-forward. The persistent stats are now controlled globally and can also be overridden at table level, should any table require [...]]]></description>
			<content:encoded><![CDATA[<p>After introducing <a title="InnoDB persistent statistics" href="http://blogs.innodb.com/wp/2011/04/innodb-persistent-statistics-at-last/">InnoDB persistent statistics</a> in MySQL 5.6, in this April Labs release we have dressed it up in a nice UI and refactored the internals a bit to make the code more elegant and straight-forward.</p>
<p>The persistent stats are now controlled globally and can also be overridden at table level, should any table require a different behavior.</p>
<h4><strong>Global</strong></h4>
<p>The server global flag &#8211;innodb-stats-persistent (boolean) now controls whether all InnoDB tables use persistent statistics or not. Keep in mind that if a table is using persistent stats then its statistics will not be updated automatically and you are responsible for running ANALYZE TABLE periodically, whenever you think the table contents has changed too much. Thus the default for &#8211;innodb-stats-persistent is currently set to OFF.</p>
<h4><strong>Per table</strong></h4>
<p><span id="more-1748"></span></p>
<p>The persistent stats ON/OFF setting can be overridden at a table level with a table option like this:</p>
<pre>CREATE TABLE t (a INT) ENGINE=INNODB PERSISTENT_STATS=0|1|default;</pre>
<p>or</p>
<pre>ALTER TABLE t PERSISTENT_STATS=0|1|default;</pre>
<p>where &#8217;0&#8242; means no persistent stats for this table (regardless of the setting of the global &#8211;innodb-stats-persistent), &#8217;1&#8242; means to always use persistent stats for this table and &#8216;default&#8217; means to use the server global setting, whatever it is.</p>
<p>Another goodie is that now you do not need to restart the server if you have manually updated the stats values in mysql.innodb_table_stats and/or mysql.innodb_index_stats and want your changes to take effect. Just do</p>
<pre>FLUSH TABLE t;</pre>
<p>to force InnoDB to reread what&#8217;s in mysql.innodb_table_stats and mysql.innodb_index_stats.</p>
<p>What to expect next? Maybe a fully controlled automatic persistent stats update so you do not have to worry about having to run ANALYZE TABLE periodically but still your query plans are stable? Wouldn&#8217;t that be nice?</p>
]]></content:encoded>
			<wfw:commentRss>http://blogs.innodb.com/wp/2012/04/innodb-persistent-stats-got-a-friendly-ui/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Memcached With SASL Support</title>
		<link>http://blogs.innodb.com/wp/2012/04/memcached-with-sasl-support/</link>
		<comments>http://blogs.innodb.com/wp/2012/04/memcached-with-sasl-support/#comments</comments>
		<pubDate>Wed, 11 Apr 2012 03:10:25 +0000</pubDate>
		<dc:creator>Jimmy Yang</dc:creator>
				<category><![CDATA[Feature]]></category>

		<guid isPermaLink="false">http://blogs.innodb.com/wp/?p=1645</guid>
		<description><![CDATA[In this April MySQL Lab release, we&#8217;ll provide you a more robust and release-ready InnoDB Memcached Engine with a few enhancements. The most notable addition is the SASL support, which gives users the capability to protect their MySQL database from unauthenticated access through memcached clients. In this blog, I will walk you through steps of [...]]]></description>
			<content:encoded><![CDATA[<p>In this April MySQL Lab release, we&#8217;ll provide you a more robust and release-ready InnoDB Memcached Engine with a few enhancements. The most notable addition is the SASL support, which gives users the capability to protect their MySQL database from unauthenticated access through memcached clients. In this blog, I will walk you through steps of getting this option enabled.</p>
<p><strong>Background Info:</strong><br />
SASL stands for &#8220;Simple Authentication and Security Layer&#8221;, which is a Standard for adding authentication support to connection-based protocols. Memcached added SASL support starting its 1.4.3 release. And here is a <a title="good article" href="http://blog.couchbase.com/sasl-memcached-now-available" target="_blank">good article</a> that gives you some background on why and how SASL is supported in Memcached.</p>
<p>For InnoDB Memcached, the &#8220;Memcached mapped&#8221; user table must be registered in the &#8220;container&#8221; &#8220;system table&#8221;. And memcached client(s) can only access such &#8220;registered&#8221; table.  Even though the DBA can add access restrictions on such table,  he/she has no control over who can access it through the memcached client(s). And this is exactly the reason we want to provide a means (in this case SASL) for DBA being able to have some control over who can access our InnoDB table(s).</p>
<p>In the following section, we will go through with you the steps to build, enable and test an SASL-enabled InnoDB Memcached plugin.</p>
<p><strong>Steps to Build and Enable SASL in InnoDB Memcached Plugin:</strong></p>
<p><span id="more-1645"></span></p>
<p>By default, SASL-enabled InnoDB Memcached is not built-in (and included in the release package), since it relies on some SASL libraries to build SASL into Memcached Engine. So you will need to download the source and rebuild the InnoDB Memcached plugin after you download the SASL libraries. The detail is described in following sections:</p>
<p>1) First, you would need to get SASL development and utility libraries. For example, on Ubuntu, you can get these libraries through:</p>
<p><em>&gt; sudo apt-get -f install libsasl2-2 sasl2-bin libsasl2-2 libsasl2-dev libsasl2-modules</em></p>
<p>2) Then build InnoDB Memcached Engine plugin (shared libraries) with SASL capability. This is done by adding ENABLE_MEMCACHED_SASL=1 to the cmake option. In addition, Memcached provides a simple plaintext passwords support, which is easier to use for testing, so we have support for that too. And this is enabled by setting the option ENABLE_MEMCACHED_SASL_PWDB=1.</p>
<p>So overall, we will need to add following three options to the cmake:</p>
<pre>
&gt; cmake ... -DWITH_INNODB_MEMCACHED=1
  -DENABLE_MEMCACHED_SASL=1 -DENABLE_MEMCACHED_SASL_PWDB=1
</pre>
<p>3) The third step is to install the InnoDB Memcached Plugin as before. Please refer to my <a href="http://blogs.innodb.com/wp/2011/04/get-started-with-innodb-memcached-daemon-plugin/" target="_blank">earlier blog posts</a> on the procedures.</p>
<p>4) As mentioned in section 2), Memcached provides a simple plaintext password support through SASL, which will be used for this demo.  There was a <a href="http://trondn.blogspot.jp/2010/02/memcached-with-sasl-on-opensolaris.html" target="_blank">good blog</a> from Thond Norbye describes the steps, so you can follow the instruction there too. I will repeat the important steps here.</p>
<p>a) Create a user named &#8220;testname&#8221; and its password as &#8220;testpasswd&#8221; in a file:</p>
<pre>&gt; echo "testname:testpasswd:::::::" &gt;/home/jy/memcached-sasl-db</pre>
<p>b) Let memcached know about it by setting environment variable MEMCACHED_SASL_PWDB:</p>
<pre>&gt; export MEMCACHED_SASL_PWDB=/home/jy/memcached-sasl-db</pre>
<p>c) Also tell memcached that it is a plaintext password:</p>
<pre>
&gt; echo "mech_list: plain" &gt; /home/jy/work2/msasl/clients/memcached.conf
&gt; export SASL_CONF_PATH=/home/jy/work2/msasl/clients/memcached.conf
</pre>
<p>4) Then we are ready to reboot the server, and add a &#8220;daemon_memcached&#8221; option &#8220;-S&#8221;, to enable SASL:</p>
<pre>&gt; mysqld .. --daemon_memcached_option="-S"</pre>
<p>5) Now we are done the setup. Let&#8217;s test it. To do so, you might need SASL-enabled client. I used a <a href="https://code.launchpad.net/~trond-norbye/libmemcached/sasl" target="_blank">SASL-enabled libmemcached</a> as described in Thond Norbye&#8217;s blog, and tested it accordingly:</p>
<pre>
&gt; memcp --servers=localhost:11211 --binary  --username=testname --password=testpasswd myfile.txt
&gt; memcat --servers=localhost:11211 --binary --username=testname --password=testpasswd myfile.txt
</pre>
<p>Without appropriate user name or password, above operation will be rejected by error message &#8220;memcache error AUTHENTICATION FAILURE&#8221;. Otherwise, the operation will be completed. You can also play with the plaintext password set in /home/jy/memcached-sasl-db to verify it.</p>
<p>There are other methods to test the SASL with memcahced. But the one described above is the most straightforward.</p>
<p><strong>Other changes for InnoDB Memcached:</strong></p>
<p>Besides the SASL support, there are a few changes in this release that worth mentioning:<br />
1) We added a configuration option <code>innodb_api_trx_level</code>, so that user can control the transaction isolation level on the queries through InnoDB APIs, or in this case, the memcached.</p>
<p>In theory, for memcached, there is no such concept of &#8220;transactions&#8221;, so this is an extra property that we added on top of it, so that user has some level of control when issuing DMLs through the SQL interface. By default, it is set to &#8220;read uncommitted&#8221;.</p>
<p>2) Another option we added is <code>innodb_api_enable_mdl</code>, the &#8220;mdl&#8221; stands for &#8220;metadata locking&#8221;. This basically &#8220;locks&#8221; the table from the MySQL level, so that the mapped table cannot be dropped or altered by DDL through the SQL interfaces. Without the lock, the table can be dropped from MySQL layer, but will be kept in the InnoDB storage until memcached or any other user stops using it.</p>
<p>3) A configure option name change. To enable binlog, the configure variable name has changed from <code>innodb_direct_access_enable_binlog</code> to <code>innodb_api_enable_binlog</code>.</p>
<p><strong>Summary:</strong></p>
<p>In summary, this release provides you a more robust InnoDB Memcached Engine with SASL support. The steps to enable such support is fairly straightforward and almost identical to those you would do to enable SASL for a Memcached server. So if you are familiar with using SASL for memcached, then it would just some name flipping to build and enable it. And if you are not familiar with the operation, above steps also give you a quick start to use it.</p>
]]></content:encoded>
			<wfw:commentRss>http://blogs.innodb.com/wp/2012/04/memcached-with-sasl-support/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>InnoDB performance improvements</title>
		<link>http://blogs.innodb.com/wp/2012/04/innodb-performance-improvements/</link>
		<comments>http://blogs.innodb.com/wp/2012/04/innodb-performance-improvements/#comments</comments>
		<pubDate>Wed, 11 Apr 2012 01:08:20 +0000</pubDate>
		<dc:creator>Sunny Bains</dc:creator>
				<category><![CDATA[Performance]]></category>

		<guid isPermaLink="false">http://blogs.innodb.com/wp/?p=1636</guid>
		<description><![CDATA[The problem After making several performance fixes, notable among them being the kernel mutex split and the new handling of read-only transaction and in particular non-locking auto-commit read-only transactions, we weren&#8217;t seeing any increase in transaction per second (TPS) on our high-end hardware. On this one particular host, a 24 core with 2 threads per [...]]]></description>
			<content:encoded><![CDATA[<p><strong>The problem</strong><br />
After making several performance fixes, notable among them being the kernel mutex split and the new handling of read-only transaction and in particular non-locking auto-commit read-only transactions, we weren&#8217;t seeing any increase in transaction per second (TPS) on our high-end hardware. On this one particular host, a 24 core with 2 threads per core host. The TPS using Sysbench was a tepid 5.6K at 16 threads and more or less plateaued till 1K user threads. No matter what config setting we used, we would more or less end up with the same result.</p>
<p>We ended up getting together for a meeting at Paris to discuss this issue and during the brain storming, one of the potential issues that cropped up was the effect of <a title="Cache ping pong" href="http://en.wikipedia.org/wiki/Cache_coherence">cache coherence</a> and/or <a title="False sharing" href="http://en.wikipedia.org/wiki/False_sharing">false sharing</a>. After using the excellent Linux tool <a title="Linux perf" href="https://perf.wiki.kernel.org/index.html">perf</a> we were able to narrow it down to a global statistic counter in row_sel_search_for_mysql(). <a title="MySQL scalability in April 2012 labs release" href="http://mikaelronstrom.blogspot.com/2012/04/mysql-team-increases-scalability-by-50.html">Mikael Ronstrom explains this in more detail</a>.</p>
<p><strong>The solution</strong><br />
Create a generic counter class (InnoDB code is now C++) that splits the counter into multiple (configurable) slots that are on separate 64 byte cache lines. Use the thread id of the updating thread to index into a slot to reduce the contention/sharing and it had the desired effect. The TPS went from 5.6 to 15K at 64 user threads and stayed close to stable right up to 1K, very slow degradation. This was using Sysbench OLTP_RO for autocommit-non-locking-read-only queries (Sysench option &#8211;oltp-skip-trx=off).</p>
<p>The code and binary can be downloaded from <a title="MySQL labs release download" href="http://labs.mysql.com">labs release downloads</a>, the current release is mysql-5.6.6-labs-april-2012-*. See the code in include/os0thread.h. The new class is ib_counter_t.</p>
<p>We have now refactored the code and grouped all the InnoDB statistic counters in srv_counter_t. This will help in further consolidation and improvements. Currently, most of the InnoDB config and statistics variables are defined in srv0srv.cc (with a few exceptions). We need to start paying even more attention to their layout and alignment from now on. There seem to be some false sharing issues that we haven&#8217;t completely identified yet.</p>
<p><span id="more-1636"></span></p>
<p><strong>Results</strong><br />
I think it is better to look at Dimitri&#8217;s <a title="Dimitri's performance BLOG" href="http://dimitrik.free.fr/blog/archives/2012/04/mysql-performance-56labs-is-opening-a-new-era.html">blog</a> for results that reflect the improvements.</p>
<p>Enjoy!</p>
]]></content:encoded>
			<wfw:commentRss>http://blogs.innodb.com/wp/2012/04/innodb-performance-improvements/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>April 2012 Labs Release &#8211; Online DDL Improvements</title>
		<link>http://blogs.innodb.com/wp/2012/04/labs-release-online-ddl/</link>
		<comments>http://blogs.innodb.com/wp/2012/04/labs-release-online-ddl/#comments</comments>
		<pubDate>Wed, 11 Apr 2012 00:01:45 +0000</pubDate>
		<dc:creator>john</dc:creator>
				<category><![CDATA[Feature]]></category>
		<category><![CDATA[Performance]]></category>

		<guid isPermaLink="false">http://blogs.innodb.com/wp/?p=1660</guid>
		<description><![CDATA[This feature is a continuation of the “Fast Index Creation” feature introduced in Fast Index Creation in the InnoDB Storage Engine. Now you can perform other kinds of DDL operations on InnoDB tables online: that is, with minimal delay for operations on that table, and without rebuilding the entire table. This enhancement improves responsiveness and [...]]]></description>
			<content:encoded><![CDATA[<p>
This feature is a continuation of the “<span class="quote">Fast Index Creation</span>” feature introduced in <a href="http://dev.mysql.com/doc/refman/5.6/en/innodb-create-index.html" target="_top">Fast Index Creation in the <code class="literal">InnoDB</code> Storage Engine</a>. Now you can perform other kinds of <a href="http://dev.mysql.com/doc/refman/5.6/en/glossary.html#glos_ddl" target="_top">DDL</a> operations on InnoDB tables <a href="http://dev.mysql.com/doc/refman/5.6/en/glossary.html#glos_online" target="_top">online</a>: that is, with minimal delay for operations on that table, and without rebuilding the entire table. This enhancement improves responsiveness and availability in busy production environments, where making a table unavailable for seconds or minutes whenever its column definitions change is not practical.
</p>
<p>
The DDL operations enhanced by this feature are these variations on the <a href="http://dev.mysql.com/doc/refman/5.6/en/alter-table.html" target="_top"><code class="literal">ALTER TABLE</code></a> statement:
</p>
<div class="itemizedlist">
<ul type="disc">
<li>
<p>
Create <a href="http://dev.mysql.com/doc/refman/5.6/en/glossary.html#glos_secondary_index" target="_top">secondary indexes</a>: <code class="literal">CREATE INDEX <em class="replaceable"><code>name</code></em> ON <em class="replaceable"><code>table</code></em> (<em class="replaceable"><code>col_list</code></em>)</code> or <code class="literal">ALTER TABLE <em class="replaceable"><code>table</code></em> ADD INDEX <em class="replaceable"><code>name</code></em> (<em class="replaceable"><code>col_list</code></em>)</code>
</p>
<p><span id="more-1660"></span></p>
<p>
Drop <a href="http://dev.mysql.com/doc/refman/5.6/en/glossary.html#glos_secondary_index" target="_top">secondary indexes</a>: <code class="literal">DROP INDEX <em class="replaceable"><code>name</code></em> ON <em class="replaceable"><code>table</code></em>;</code> or <code class="literal">ALTER TABLE <em class="replaceable"><code>table</code></em> DROP INDEX <em class="replaceable"><code>name</code></em></code>
</p>
<p>
Creating and dropping secondary indexes on <code class="literal">InnoDB</code> tables has avoided the table-copying behavior since the days of MySQL 5.1 with the <code class="literal">InnoDB</code> Plugin. Now, the table remains available for read and write operations while the index is being created or dropped. The <a href="http://dev.mysql.com/doc/refman/5.6/en/create-index.html" target="_top"> <code class="literal">CREATE INDEX</code> </a> or <a href="http://dev.mysql.com/doc/refman/5.6/en/drop-index.html" target="_top"><code class="literal">DROP INDEX</code></a> statement only finishes after all transactions that are modifying the table are completed, so that the initial state of the index reflects the most recent contents of the table.
</p>
<p>
Previously, modifying the table while an index was being created or dropped typically resulted in a <a href="http://dev.mysql.com/doc/refman/5.6/en/glossary.html#glos_deadlock" target="_top">deadlock</a> that cancelled the insert, update, or delete statement on the table.
</p>
</li>
<li>
<p>
Changing the <a href="http://dev.mysql.com/doc/refman/5.6/en/glossary.html#glos_auto_increment" target="_top">auto-increment</a> value for a column: <code class="literal">ALTER TABLE <em class="replaceable"><code>table</code></em> AUTO_INCREMENT=<em class="replaceable"><code>next_value</code></em>;</code>
</p>
<p>
Especially in a distributed system using replication or sharding, you sometimes reset the auto-increment counter for a table to a specific value. The next row inserted into the table uses the specified value for its auto-increment column.  You might also use this technique in a data warehousing environment where you periodically empty all the tables and reload them, and you can restart the auto-increment sequence from 1.
</p>
</li>
<li>
<p>
Drop a <a href="http://dev.mysql.com/doc/refman/5.6/en/glossary.html#glos_foreign_key_constraint" target="_top">foreign key constraint</a>: <code class="literal">ALTER TABLE <em class="replaceable"><code>tbl</code></em> DROP FOREIGN KEY <em class="replaceable"><code>fk_name</code></em></code>
</p>
<p>
Currently, online DDL only includes the <code class="literal">DROP</code> operation for foreign keys, not <code class="literal">ADD</code> to create foreign keys.
</p>
<p>
If you do not know the names of the foreign key constraints on a particular table, issue the following statement and find the constraint name in the <code class="literal">CONSTRAINT</code> clause for each foreign key:
</p>
<pre class="programlisting">show create table <em class="replaceable"><code>table</code></em>\G
</pre>
<p>
Or, query the <a href="http://dev.mysql.com/doc/refman/5.6/en/table-constraints-table.html" target="_top"><code class="literal">information_schema.table_constraints</code></a> table and use the <code class="literal">constraint_name</code> and <code class="literal">constraint_type</code> columns to identify the foreign key names.
</p>
<p>
As a consequence of this enhancement, you can now also drop a foreign key and its associated index in a single statement, which previously required separate statements in a strict order:
</p>
<pre class="programlisting">
ALTER TABLE <em class="replaceable"> <code>table</code></em> DROP FOREIGN KEY <em class="replaceable"> <code>constraint</code></em>, DROP INDEX <em class="replaceable"><code>index</code></em>;
</pre>
</li>
<li>
<p>
Rename a column: <code class="literal">ALTER TABLE <em class="replaceable"><code>tbl</code></em> CHANGE <em class="replaceable"><code>old_col_name</code></em> <em class="replaceable"><code>new_col_name</code></em> <em class="replaceable"><code>datatype</code></em></code>
</p>
<p>
When you keep the same data type and only change the column name, this operation can always be performed online.  As part of this enhancement, you can now rename a column that is part of a foreign key constraint, which was not allowed before.
</p>
</li>
</ul>
</div>
<div xmlns="http://www.w3.org/1999/xhtml" class="note" style="margin-left: 0.5in; margin-right: 0.5in;">
<div class="admon-title"><b>Note</b></div>
<p xmlns="">
As your database schema evolves with new columns, data types, constraints, indexes, and so on, keep your <a href="http://dev.mysql.com/doc/refman/5.6/en/create-table.html" target="_top"><code class="literal">CREATE TABLE</code></a> statements up to date with the latest table definitions. Even with the performance improvements of online DDL, it is more efficient to create stable database structures at the beginning, rather than creating part of the schema and then issuing <a href="http://dev.mysql.com/doc/refman/5.6/en/alter-table.html" target="_top"><code class="literal">ALTER TABLE</code></a> statements afterward.
</p>
<p xmlns="">
The main exception to this guideline is for secondary indexes on tables with large numbers of rows. It is typically most efficient to create the table with all details specified except the secondary indexes, load the data, then create the secondary indexes.
</p>
<p xmlns="">
Whatever sequence of <a href="http://dev.mysql.com/doc/refman/5.6/en/create-table.html" target="_top"><code class="literal">CREATE TABLE</code></a>, <a href="http://dev.mysql.com/doc/refman/5.6/en/create-index.html" target="_top"><code class="literal">CREATE INDEX</code></a>, <a href="http://dev.mysql.com/doc/refman/5.6/en/alter-table.html" target="_top"><code class="literal">ALTER TABLE</code></a>, and similar statements went into putting a table together, you can capture the SQL needed to reconstruct the current form of the table by issuing the statement <code class="literal">SHOW CREATE TABLE <em class="replaceable"><code>table</code></em>\G</code> (uppercase <code class="literal">\G</code> required for tidy formatting). This output shows clauses such as numeric precision, <code class="literal">NOT NULL</code>, and <code class="literal">CHARACTER SET</code> that are sometimes added behind the scenes, and you might otherwise leave out when cloning the table on a new system or setting up foreign key columns with identical type.
</p>
</div>
<h4>Performance and Availability Considerations</h4>
<p>
Avoiding a table copy during DDL improves several aspects of MySQL operation, such as performance, concurrency, availability, and scalability:
</p>
<div class="itemizedlist">
<ul type="disc">
<li>
<p>
By avoiding the disk I/O and CPU cycles to rebuild the table, you minimize the overall load on the database and maintain good performance and high throughput during the DDL operation.
</p>
</li>
<li>
<p>
Because the DDL operation completes in less time, there is a shorter period when queries and <a href="http://dev.mysql.com/doc/refman/5.6/en/glossary.html#glos_dml" target="_top">DML</a> operations on that table are blocked, making your application more responsive.
</p>
</li>
<li>
<p>
Because less data is read into the <a href="http://dev.mysql.com/doc/refman/5.6/en/glossary.html#glos_buffer_pool" target="_top">buffer pool</a>, you avoid purging frequently accessed data from the memory cache, which typically causes a temporary performance dip after a DDL operation.
</p>
</li>
<li>
<p>
Because there is a shorter period when queries and DML operations queue up waiting for the DDL to finish, there is less locking and waiting for other resources all throughout the MySQL server. Reducing this type of overhead leads to greater scalability, even for operations not involving the table being altered.
</p>
</li>
</ul>
</div>
<h4>Benchmarking</h4>
<p>
To judge the relative performance of online DDL operations, you can run such operations on a big <code class="literal">InnoDB</code> table using current and earlier versions of MySQL. You can also run all the performance tests under the latest MySQL version, simulating the previous DDL behavior for the “<span class="quote">before</span>” results, by setting the <a href="http://dev.mysql.com/doc/refman/5.6/en/server-system-variables.html#sysvar_old_alter_table" target="_top"><code class="literal">old_alter_table</code></a> system variable. Issue the statement <code class="literal">set old_alter_table=1</code> in the session, and measure DDL performance to record the “<span class="quote">before</span>” figures. Then <code class="literal">set old_alter_table=0</code> to re-enable the newer, faster behavior, and run the DDL operations again to record the “<span class="quote">after</span>” figures.
</p>
<p>
For a basic idea of whether a DDL operation does its changes in-place or performs a table copy, look at the “<span class="quote">rows affected</span>” value displayed after the command finishes. For example, here are lines you might see after doing different types of DDL operations:
</p>
<div class="itemizedlist">
<ul type="disc">
<li>
<p>
Changing the default value of a column (super-fast, does not affect the table data at all):
</p>
<pre class="programlisting">Query OK, 0 rows affected (0.07 sec)</pre>
</li>
<li>
<p>
Adding an index (takes time, but <code class="literal">0 rows affected</code> shows that the table is not copied):
</p>
<pre class="programlisting">Query OK, 0 rows affected (21.42 sec)</pre>
</li>
<li>
<p>
Changing the data type of a column (takes substantial time and does require rebuilding all the rows of the table):
</p>
<pre class="programlisting">Query OK, 1671168 rows affected (1 min 35.54 sec)</pre>
</li>
</ul>
</div>
<p>
For example, before running a DDL operation on a big table, you might check whether the operation will be fast or slow as follows:
</p>
<div class="orderedlist">
<ol type="1">
<li>
<p>
Clone the table structure.
</p>
</li>
<li>
<p>
Populate the cloned table with a tiny amount of data.
</p>
</li>
<li>
<p>
Run the DDL operation on the cloned table.
</p>
</li>
<li>
<p>
Check whether the “<span class="quote">rows affected</span>” value is zero or not. A non-zero value means the operation will require rebuilding the entire table, which might require special planning. For example, you might do the DDL operation during a period of scheduled downtime, or on each replication slave server one at a time.
</p>
</li>
</ol>
</div>
<p>
For a deeper understanding of the reduction in MySQL processing, examine the <code class="literal">PERFORMANCE_SCHEMA</code> and <code class="literal">INFORMATION_SCHEMA</code> tables related to <code class="literal">InnoDB</code> before and after DDL operations, to see the number of physical reads, writes, memory allocations, and so on.
</p>
<h4>Background Information</h4>
<p>
Historically, the MySQL server and <code class="literal">InnoDB</code> have each kept their own metadata about table and index structures. The MySQL server stores this information in <a href="http://dev.mysql.com/doc/refman/5.6/en/glossary.html#glos_frm_file" target="_top">.frm files</a> that are not protected by a transactional mechanism, while <code class="literal">InnoDB</code> has its own <a href="http://dev.mysql.com/doc/refman/5.6/en/glossary.html#glos_data_dictionary" target="_top">data dictionary</a> as part of the <a href="http://dev.mysql.com/doc/refman/5.6/en/glossary.html#glos_system_tablespace" target="_top">system tablespace</a>. If a DDL operation was interrupted by a crash or other unexpected event partway through, the metadata could be left inconsistent between these two locations, causing problems such as startup errors or inability to access the table that was being altered. Now that <code class="literal">InnoDB</code> is the default storage engine, addressing such issues is a high priority. These enhancements to DDL operations reduce the window of opportunity for such issues to occur.
</p>
<h4>Examples</h4>
<p>
Here are code examples showing some operations whose performance, concurrency, and scalability are improved by this new feature.
</p>
<div class="example">
<p class="title">
<b>Example 1. Schema Setup Code for Online DDL Experiments</b>
</p>
<p>
Here is the code that sets up the initial tables used in these demonstrations:
</p>
<p><a name="online-ddl-setup"></a></p>
<pre class="programlisting">/*
Setup code for the online DDL demonstration:
- Set up some config variables.
- Create 2 tables that are clones of one of the INFORMATION_SCHEMA tables
  that always has some data. The "small" table has a couple of thousand rows.
  For the "big" table, keep doubling the data until it reaches over a million rows.
- Set up a primary key for the sample tables, since we are demonstrating InnoDB aspects.
*/ 

set autocommit = 0;
set foreign_key_checks = 1;
set global innodb_file_per_table = 1;
set old_alter_table=0;
prompt mysql: 

use test;

\! echo "Setting up 'small' table:"
drop table if exists small_table;
<b>create table small_table as select * from information_schema.columns;</b>
<b>alter table small_table add id int unsigned not null primary key auto_increment;</b>
select count(id) from small_table;

\! echo "Setting up 'big' table:"
drop table if exists big_table;
<b>create table big_table as select * from information_schema.columns;</b>
show create table big_table\G

insert into big_table select * from big_table;
insert into big_table select * from big_table;
insert into big_table select * from big_table;
insert into big_table select * from big_table;
insert into big_table select * from big_table;
insert into big_table select * from big_table;
insert into big_table select * from big_table;
insert into big_table select * from big_table;
insert into big_table select * from big_table;
insert into big_table select * from big_table;
commit;

<b>alter table big_table add id int unsigned not null primary key auto_increment;</b>
select count(id) from big_table;
</pre>
<p>
Running this code gives this output, condensed for brevity and with the most important points bolded:
</p>
<pre class="programlisting">
Setting up 'small' table:

Query OK, 1678 rows affected (0.13 sec)
Query OK, 1678 rows affected (0.07 sec)

+-----------+
| count(id) |
+-----------+
|      1678 |
+-----------+
1 row in set (0.00 sec)

Setting up 'big' table:

Query OK, 1678 rows affected (0.17 sec)

*************************** 1. row ***************************
       Table: big_table
Create Table: CREATE TABLE `big_table` (
  `TABLE_CATALOG` varchar(512) CHARACTER SET utf8 NOT NULL DEFAULT '',
  `TABLE_SCHEMA` varchar(64) CHARACTER SET utf8 NOT NULL DEFAULT '',
  <b>`TABLE_NAME` varchar(64) CHARACTER SET utf8 NOT NULL DEFAULT '',</b>
  `COLUMN_NAME` varchar(64) CHARACTER SET utf8 NOT NULL DEFAULT '',
  `ORDINAL_POSITION` bigint(21) unsigned NOT NULL DEFAULT '0',
  `COLUMN_DEFAULT` longtext CHARACTER SET utf8,
  <b>`IS_NULLABLE` varchar(3) CHARACTER SET utf8 NOT NULL DEFAULT '',</b>
  `DATA_TYPE` varchar(64) CHARACTER SET utf8 NOT NULL DEFAULT '',
  `CHARACTER_MAXIMUM_LENGTH` bigint(21) unsigned DEFAULT NULL,
  `CHARACTER_OCTET_LENGTH` bigint(21) unsigned DEFAULT NULL,
  `NUMERIC_PRECISION` bigint(21) unsigned DEFAULT NULL,
  `NUMERIC_SCALE` bigint(21) unsigned DEFAULT NULL,
  `DATETIME_PRECISION` bigint(21) unsigned DEFAULT NULL,
  <b>`CHARACTER_SET_NAME` varchar(32) CHARACTER SET utf8 DEFAULT NULL,</b>
  `COLLATION_NAME` varchar(32) CHARACTER SET utf8 DEFAULT NULL,
  `COLUMN_TYPE` longtext CHARACTER SET utf8 NOT NULL,
  `COLUMN_KEY` varchar(3) CHARACTER SET utf8 NOT NULL DEFAULT '',
  `EXTRA` varchar(30) CHARACTER SET utf8 NOT NULL DEFAULT '',
  `PRIVILEGES` varchar(80) CHARACTER SET utf8 NOT NULL DEFAULT '',
  `COLUMN_COMMENT` varchar(1024) CHARACTER SET utf8 NOT NULL DEFAULT ''
) <b>ENGINE=InnoDB</b> DEFAULT CHARSET=latin1
1 row in set (0.00 sec)

Query OK, 1678 rows affected (0.09 sec)
Query OK, 3356 rows affected (0.07 sec)
Query OK, 6712 rows affected (0.17 sec)
Query OK, 13424 rows affected (0.44 sec)
Query OK, 26848 rows affected (0.63 sec)
Query OK, 53696 rows affected (1.72 sec)
Query OK, 107392 rows affected (3.02 sec)
Query OK, 214784 rows affected (6.28 sec)
Query OK, 429568 rows affected (13.25 sec)
Query OK, 859136 rows affected (28.16 sec)
Query OK, 1718272 rows affected (1 min 9.22 sec)

<b>+-----------+
| count(id) |
+-----------+
|   1718272 |
+-----------+</b>
1 row in set (1.75 sec)
</pre>
</div>
<div class="example">
<p class="title">
<b>Example 2. Speed and Efficiency of CREATE INDEX and DROP INDEX</b>
</p>
<p>
Here is a sequence of statements demonstrating the relative speed of <a href="http://dev.mysql.com/doc/refman/5.6/en/create-index.html" target="_top"><code class="literal">CREATE INDEX</code></a> and <a href="http://dev.mysql.com/doc/refman/5.6/en/drop-index.html" target="_top"><code class="literal">DROP INDEX</code></a> statements. For a small table, the elapsed time is less than a second whether we use the fast or slow technique, so we look at the “<span class="quote">rows affected</span>” output to verify which operations can avoid the table rebuild. For a large table, the difference in efficiency is obvious because skipping the table rebuild saves substantial time.
</p>
<p><a name="online-ddl-create_drop_index"></a></p>
<pre class="programlisting">
\! clear

-- Make sure we're using the new-style fast DDL.
-- Outside of benchmarking and testing, you would
-- never enable the old_alter_table setting.
set old_alter_table=0;

\! echo "=== Create and drop index (small table, new/fast technique) ==="
\! echo
\! echo "Data size (kilobytes) before index created: "
\! du -k data/test/small_table.ibd
<b>create index i_dtyp_small on small_table (data_type);</b>
\! echo "Data size after index created: "
\! du -k data/test/small_table.ibd
<b>drop index i_dtyp_small on small_table;</b>

-- Revert to the older slower DDL for comparison.
set old_alter_table=1;

\! echo "=== Create and drop index (small table, old/slow technique) ==="
\! echo
\! echo "Data size (kilobytes) before index created: "
\! du -k data/test/small_table.ibd
create index i_dtyp_small on small_table (data_type);
\! echo "Data size after index created: "
\! du -k data/test/small_table.ibd
drop index i_dtyp_small on small_table;

-- In the above example, we examined the "rows affected" number,
-- ideally looking for a zero figure. Let's try again with a larger
-- sample size, where we'll see that the actual time taken can
-- vary significantly.

-- Back to the new/fast behavior:
set old_alter_table=0;

\! echo "=== Create and drop index (big table, new/fast technique) ==="
\! echo
\! echo "Data size (kilobytes) before index created: "
\! du -k data/test/big_table.ibd
<b>create index i_dtyp_big on big_table (data_type);</b>
\! echo "Data size after index created: "
\! du -k data/test/big_table.ibd
<b>drop index i_dtyp_big on big_table;</b>

-- Let's see that again, in slow motion:
set old_alter_table=1;

\! echo "=== Create and drop index (big table, old/slow technique) ==="
\! echo
\! echo "Data size (kilobytes) before index created: "
\! du -k data/test/big_table.ibd
create index i_dtyp_big on big_table (data_type);
\! echo "Data size after index created: "
\! du -k data/test/big_table.ibd
drop index i_dtyp_big on big_table;
</pre>
<p>
Running this code gives this output, condensed for brevity and with the most important points bolded:
</p>
<pre class="programlisting">
=== Create and drop index (small table, new/fast technique) ===

Data size (kilobytes) before index created:
384	data/test/small_table.ibd
<b>Query OK, 0 rows affected (0.04 sec)</b>

Data size after index created:
432	data/test/small_table.ibd
<b>Query OK, 0 rows affected (0.02 sec)</b>

=== Create and drop index (small table, old/slow technique) ===

Data size (kilobytes) before index created:
432	data/test/small_table.ibd
<b>Query OK, 1678 rows affected (0.12 sec)</b>

Data size after index created:
448	data/test/small_table.ibd
<b>Query OK, 1678 rows affected (0.10 sec)</b>

=== Create and drop index (big table, new/fast technique) ===

Data size (kilobytes) before index created:
315392	data/test/big_table.ibd
<b>Query OK, 0 rows affected (33.32 sec)</b>

Data size after index created:
335872	data/test/big_table.ibd
<b>Query OK, 0 rows affected (0.02 sec)</b>

=== Create and drop index (big table, old/slow technique) ===

Data size (kilobytes) before index created:
335872	data/test/big_table.ibd
<b>Query OK, 1718272 rows affected (1 min 5.01 sec)</b>

Data size after index created:
348160	data/test/big_table.ibd
<b>Query OK, 1718272 rows affected (46.59 sec)</b>
</pre>
</div>
<div class="example">
<p class="title">
<b>Example 3. Concurrent DML During CREATE INDEX and DROP INDEX</b>
</p>
<p>
Here are some snippets of code that I ran in separate <span><strong class="command">mysql</strong></span> sessions connected to the same database, to illustrate DML statements (insert, update, or delete) running at the same time as <a href="http://dev.mysql.com/doc/refman/5.6/en/create-index.html" target="_top"><code class="literal">CREATE INDEX</code></a> and <a href="http://dev.mysql.com/doc/refman/5.6/en/drop-index.html" target="_top"><code class="literal">DROP INDEX</code></a>.
</p>
<p><code>CREATE INDEX</code> statement (in session 1):</p>
<pre class="programlisting">
/*
CREATE INDEX statement to run against a table while
insert/update/delete statements are modifying the
column being indexed.
*/

-- We'll run this script in one session, while simultaneously creating and dropping
-- an index on test/big_table.table_name in another session.

use test;
<b>create index i_concurrent on big_table(table_name);</b>
</pre>
<p><code>DROP INDEX</code> statement (in session 1):</p>
<pre class="programlisting">/*
DROP INDEX statement to run against a table while
insert/update/delete statements are modifying the
column being indexed.
*/

-- We'll run this script in one session, while simultaneously creating and dropping
-- an index on test/big_table.table_name in another session.

use test;
<b>drop index i_concurrent on big_table;</b>
</pre>
<p>DML statements (in session 2). I ran these <code>DELETE</code> statements while the <code>CREATE INDEX</code> was running.<br />
Because <code>DROP INDEX</code> in this case takes less than a second, I started the <code>DELETE</code> first and then ran the <code>DROP INDEX</code> while the DML was in progress. In each case, the DML statement waited until the transaction with the <code>DELETE</code> was finished. (That&#8217;s why the timing numbers are higher than in the other examples. I waited for a while before issuing the <code>ROLLBACK</code> statement at the <code>mysql</code> command line.)</p>
<pre class="programlisting">
/*
Some queries and insert/update/delete statements to run against a table
while an index is being created or dropped. Previously, these operations
would have stalled during the index create/drop period and possibly
timed out or deadlocked.
*/

-- We'll run this script in one session, while simultaneously creating and dropping
-- an index on test/big_table.table_name in another session.

-- In our test instance, that column has about 1.7M rows, with 136 different values.

set autocommit = 0;
use test;

select distinct character_set_name from big_table where table_name = 'FILES';
<b>delete from big_table where table_name = 'FILES';</b>
select distinct character_set_name from big_table where table_name = 'FILES';

-- I'll issue the final rollback interactively, not via script,
-- the better to control the timing.
-- rollback;
</pre>
<p>
Running this code gives this output, condensed for brevity and with the most important points bolded:
</p>
<pre class="programlisting">
mysql: source concurrent_ddl_create.sql
Database changed
<b>Query OK, 0 rows affected (1 min 25.15 sec)</b>
Records: 0  Duplicates: 0  Warnings: 0

mysql: source concurrent_ddl_drop.sql
Database changed
<b>Query OK, 0 rows affected (24.98 sec)</b>
Records: 0  Duplicates: 0  Warnings: 0

mysql: source concurrent_dml.sql
Query OK, 0 rows affected (0.00 sec)

Database changed
+--------------------+
| character_set_name |
+--------------------+
| NULL               |
| utf8               |
+--------------------+
2 rows in set (0.32 sec)

<b>Query OK, 38912 rows affected (1.84 sec)</b>

Empty set (0.01 sec)

mysql: rollback;
Query OK, 0 rows affected (1.05 sec)
</pre>
</div>
<div class="example">
<p class="title">
<b>Example 4. Renaming a Column</b>
</p>
<p>
Here is a demonstration of using <a href="http://dev.mysql.com/doc/refman/5.6/en/alter-table.html" target="_top"><code class="literal">ALTER TABLE</code></a> to rename a column. We use the new, fast DDL mechanism to change the name, then the old, slow DDL mechanism (with <code class="literal">old_alter_table=1</code>) to restore the original column name.
</p>
<div xmlns="http://www.w3.org/1999/xhtml" class="note" style="margin-left: 0.5in; margin-right: 0.5in;">
<div class="admon-title"><b>Note</b></div>
<div xmlns="" class="itemizedlist">
<ul type="disc">
<li>
<p>
Because the syntax for renaming a column also involves re-specifying the data type, be very careful to specify exactly the same data type to avoid a costly table rebuild. In this case, we checked the output of <code class="literal">show create table <em class="replaceable"><code>table</code></em>\G</code> and copied any clauses such as <code class="literal">CHARACTER SET</code> and <code class="literal">NOT NULL</code> from the original column definition.
</p>
</li>
<li>
<p>
Again, renaming a column for a small table is fast enough that we need to examine the “<span class="quote">rows affected</span>” number to verify that the new DDL mechanism is more efficient than the old one. With a big table, the difference in elapsed time makes the improvement obvious.
</p>
</li>
</ul>
</div>
</div>
<p><a name="online-ddl-rename_column"></a></p>
<pre class="programlisting">
/*
Run through a sequence of 'rename column' statements.
Because this operation involves only metadata, not table data,
it is fast for big and small tables, with new or old DDL mechanisms.
*/

\! clear

\! echo "Rename column (fast technique, small table):"
set old_alter_table=0;
<b>alter table small_table change `IS_NULLABLE` `NULLABLE`
  varchar(3) character set utf8 not null;</b>
\! echo "Rename back to original name (slow technique):"
set old_alter_table=1;
<b>alter table small_table change `NULLABLE` `IS_NULLABLE`
  varchar(3) character set utf8 not null;</b>

\! echo "Rename column (fast technique, big table):"
set old_alter_table=0;
<b>alter table big_table change `IS_NULLABLE` `NULLABLE`
  varchar(3) character set utf8 not null;</b>
\! echo "Rename back to original name (slow technique):"
set old_alter_table=1;
<b>alter table big_table change `NULLABLE` `IS_NULLABLE`
  varchar(3) character set utf8 not null;</b>
set old_alter_table=0;</pre>
<p>
Running this code gives this output, condensed for brevity and with the most important points bolded:
</p>
<pre class="programlisting">
Rename column (fast technique, small table):
<b>Query OK, 0 rows affected (0.13 sec)</b>

Rename back to original name (slow technique):
<b>Query OK, 1678 rows affected (0.35 sec)</b>

Rename column (fast technique, big table):
<b>Query OK, 0 rows affected (0.11 sec)</b>

Rename back to original name (slow technique):
<b>Query OK, 1718272 rows affected (1 min 0.00 sec)</b>
</pre>
</div>
<div class="example">
<p class="title">
<b>Example 5. Dropping Foreign Keys</b>
</p>
<p>
Here is a demonstration of foreign keys, including improvement to the speed of dropping a foreign key constraint.
</p>
<p><a name="online-ddl-foreign_key"></a></p>
<pre class="programlisting">
/*
Demonstrate aspects of foreign keys that are or aren't affected by the DDL improvements.
- Create a new table with only a few values to serve as the parent table.
- Set up the 'small' and 'big' tables as child tables using a foreign key.
- Verify that the ON DELETE CASCADE clause makes changes ripple from parent to child tables.
- Drop the foreign key constraints, and optionally associated indexes.
  (This is the operation that is sped up.)
*/

\! clear

-- Make sure foreign keys are being enforced, and allow
-- rollback after doing some DELETEs that affect both
-- parent and child tables.
set foreign_key_checks = 1;
set autocommit = 0;

-- Create a parent table, containing values that we know are already present
-- in the child tables.
drop table if exists schema_names;
<b>create table schema_names (id int unsigned not null primary key auto_increment,
  schema_name varchar(64) character set utf8 not null, index i_schema (schema_name))
  as select distinct table_schema schema_name from small_table;</b>

show create table schema_names\G
show create table small_table\G
show create table big_table\G

-- Creating the foreign key constraint isn't any faster than before.
-- It still involves a table rebuild, as illustrated by the "rows affected" figure.
<b>alter table small_table add constraint small_fk
  foreign key i_table_schema (table_schema) references schema_names(schema_name)
  on delete cascade;</b>
<b>alter table big_table add constraint big_fk
  foreign key i_table_schema (table_schema) references schema_names(schema_name)
  on delete cascade;</b>

show create table small_table\G
show create table big_table\G

select schema_name from schema_names order by schema_name;
select count(table_schema) howmany, table_schema from small_table group by table_schema;
select count(table_schema) howmany, table_schema from big_table group by table_schema;

-- big_table is the parent table.
-- schema_names is the parent table.
-- big_table is the child table.
-- (One row in the parent table can have many "children" in the child table.)
-- Changes to the parent table can ripple through to the child table.
-- For example, removing the value 'test' from schema_names.schema_name will
-- result in the removal of 20K or so rows from big_table.

delete from schema_names where schema_name = 'test';

select schema_name from schema_names order by schema_name;
select count(table_schema) howmany, table_schema from small_table group by table_schema;
select count(table_schema) howmany, table_schema from big_table group by table_schema;

-- Because we've turned off autocommit, we can still get back those deleted rows
-- if the DELETE was issued by mistake.
rollback;

select schema_name from schema_names order by schema_name;
select count(table_schema) howmany, table_schema from small_table group by table_schema;
select count(table_schema) howmany, table_schema from big_table group by table_schema;

-- All of the cross-checking between parent and child tables would be
-- deadly slow if there wasn't the requirement for the corresponding
-- columns to be indexed!

-- But we can get rid of the foreign key using a fast operation
-- that doesn't rebuild the table.
-- If we didn't specify a constraint name when setting up the foreign key, we would
-- have to find the auto-generated name such as 'big_table_ibfk_1' in the
-- output from 'show create table'.

-- For the small table, we'll drop the foreign key and the associated index.
-- Having an index on a small table is less critical.

\! echo "DROP FOREIGN KEY and INDEX from small_table:"
<b>alter table small_table drop foreign key small_fk, drop index small_fk;</b>

-- For the big table, we'll drop the foreign key and leave the associated index.
-- If we are still doing queries that reference the indexed column, the index is
-- very important to avoid a full table scan of the big table.
\! echo "DROP FOREIGN KEY from big_table:"
<b>alter table big_table drop foreign key big_fk;</b>

show create table small_table\G
show create table big_table\G
</pre>
<p>
Running this code gives this output, condensed for brevity and with the most important points bolded:
</p>
<pre class="programlisting">
Query OK, 4 rows affected (0.03 sec)

*************************** 1. row ***************************
       Table: schema_names
Create Table: CREATE TABLE `schema_names` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  <b>`schema_name` varchar(64) CHARACTER SET utf8 NOT NULL,</b>
  PRIMARY KEY (`id`),
  <b>KEY `i_schema` (`schema_name`)</b>
) <b>ENGINE=InnoDB</b> AUTO_INCREMENT=8 DEFAULT CHARSET=latin1
1 row in set (0.00 sec)

*************************** 1. row ***************************
       Table: small_table
Create Table: CREATE TABLE `small_table` (
  `TABLE_CATALOG` varchar(512) CHARACTER SET utf8 NOT NULL DEFAULT '',
  <b>`TABLE_SCHEMA` varchar(64) CHARACTER SET utf8 NOT NULL DEFAULT '',</b>
  `TABLE_NAME` varchar(64) CHARACTER SET utf8 NOT NULL DEFAULT '',
  `COLUMN_NAME` varchar(64) CHARACTER SET utf8 NOT NULL DEFAULT '',
  `ORDINAL_POSITION` bigint(21) unsigned NOT NULL DEFAULT '0',
  `COLUMN_DEFAULT` longtext CHARACTER SET utf8,
  `IS_NULLABLE` varchar(3) CHARACTER SET utf8 NOT NULL,
  `DATA_TYPE` varchar(64) CHARACTER SET utf8 NOT NULL DEFAULT '',
  `CHARACTER_MAXIMUM_LENGTH` bigint(21) unsigned DEFAULT NULL,
  `CHARACTER_OCTET_LENGTH` bigint(21) unsigned DEFAULT NULL,
  `NUMERIC_PRECISION` bigint(21) unsigned DEFAULT NULL,
  `NUMERIC_SCALE` bigint(21) unsigned DEFAULT NULL,
  `DATETIME_PRECISION` bigint(21) unsigned DEFAULT NULL,
  `CHARACTER_SET_NAME` varchar(32) CHARACTER SET utf8 DEFAULT NULL,
  `COLLATION_NAME` varchar(32) CHARACTER SET utf8 DEFAULT NULL,
  `COLUMN_TYPE` longtext CHARACTER SET utf8 NOT NULL,
  `COLUMN_KEY` varchar(3) CHARACTER SET utf8 NOT NULL DEFAULT '',
  `EXTRA` varchar(30) CHARACTER SET utf8 NOT NULL DEFAULT '',
  `PRIVILEGES` varchar(80) CHARACTER SET utf8 NOT NULL DEFAULT '',
  `COLUMN_COMMENT` varchar(1024) CHARACTER SET utf8 NOT NULL DEFAULT '',
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  PRIMARY KEY (`id`)
) <b>ENGINE=InnoDB</b> AUTO_INCREMENT=1679 DEFAULT CHARSET=latin1
1 row in set (0.00 sec)

*************************** 1. row ***************************
       Table: big_table
Create Table: CREATE TABLE `big_table` (
  `TABLE_CATALOG` varchar(512) CHARACTER SET utf8 NOT NULL DEFAULT '',
  <b>`TABLE_SCHEMA` varchar(64) CHARACTER SET utf8 NOT NULL DEFAULT '',</b>
  `TABLE_NAME` varchar(64) CHARACTER SET utf8 NOT NULL DEFAULT '',
  `COLUMN_NAME` varchar(64) CHARACTER SET utf8 NOT NULL DEFAULT '',
  `ORDINAL_POSITION` bigint(21) unsigned NOT NULL DEFAULT '0',
  `COLUMN_DEFAULT` longtext CHARACTER SET utf8,
  `IS_NULLABLE` varchar(3) CHARACTER SET utf8 NOT NULL,
  `DATA_TYPE` varchar(64) CHARACTER SET utf8 NOT NULL DEFAULT '',
  `CHARACTER_MAXIMUM_LENGTH` bigint(21) unsigned DEFAULT NULL,
  `CHARACTER_OCTET_LENGTH` bigint(21) unsigned DEFAULT NULL,
  `NUMERIC_PRECISION` bigint(21) unsigned DEFAULT NULL,
  `NUMERIC_SCALE` bigint(21) unsigned DEFAULT NULL,
  `DATETIME_PRECISION` bigint(21) unsigned DEFAULT NULL,
  `CHARACTER_SET_NAME` varchar(32) CHARACTER SET utf8 DEFAULT NULL,
  `COLLATION_NAME` varchar(32) CHARACTER SET utf8 DEFAULT NULL,
  `COLUMN_TYPE` longtext CHARACTER SET utf8 NOT NULL,
  `COLUMN_KEY` varchar(3) CHARACTER SET utf8 NOT NULL DEFAULT '',
  `EXTRA` varchar(30) CHARACTER SET utf8 NOT NULL DEFAULT '',
  `PRIVILEGES` varchar(80) CHARACTER SET utf8 NOT NULL DEFAULT '',
  `COLUMN_COMMENT` varchar(1024) CHARACTER SET utf8 NOT NULL DEFAULT '',
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  PRIMARY KEY (`id`),
  <b>KEY `big_fk` (`TABLE_SCHEMA`)</b>
) <b>ENGINE=InnoDB</b> AUTO_INCREMENT=1718273 DEFAULT CHARSET=latin1
1 row in set (0.00 sec)

<b>Query OK, 1678 rows affected (0.10 sec)</b>
<b>Query OK, 1718272 rows affected (1 min 14.54 sec)</b>

*************************** 1. row ***************************
       Table: small_table
Create Table: CREATE TABLE `small_table` (
  `TABLE_CATALOG` varchar(512) CHARACTER SET utf8 NOT NULL DEFAULT '',
  <b>`TABLE_SCHEMA` varchar(64) CHARACTER SET utf8 NOT NULL DEFAULT '',</b>
  `TABLE_NAME` varchar(64) CHARACTER SET utf8 NOT NULL DEFAULT '',
  ...
  `COLUMN_COMMENT` varchar(1024) CHARACTER SET utf8 NOT NULL DEFAULT '',
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  PRIMARY KEY (`id`),
  <b>KEY `small_fk` (`TABLE_SCHEMA`),</b>
  <b>CONSTRAINT `small_fk` FOREIGN KEY (`TABLE_SCHEMA`)
  REFERENCES `schema_names` (`schema_name`)
  ON DELETE CASCADE</b>
) <b>ENGINE=InnoDB</b> AUTO_INCREMENT=1679 DEFAULT CHARSET=latin1
1 row in set (0.12 sec)

*************************** 1. row ***************************
       Table: big_table
Create Table: CREATE TABLE `big_table` (
  `TABLE_CATALOG` varchar(512) CHARACTER SET utf8 NOT NULL DEFAULT '',
  <b>`TABLE_SCHEMA` varchar(64) CHARACTER SET utf8 NOT NULL DEFAULT '',</b>
  `TABLE_NAME` varchar(64) CHARACTER SET utf8 NOT NULL DEFAULT '',
  ...
  `COLUMN_COMMENT` varchar(1024) CHARACTER SET utf8 NOT NULL DEFAULT '',
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  PRIMARY KEY (`id`),
  <b>KEY `big_fk` (`TABLE_SCHEMA`),</b>
  <b>CONSTRAINT `big_fk` FOREIGN KEY (`TABLE_SCHEMA`)
  REFERENCES `schema_names` (`schema_name`)
  ON DELETE CASCADE</b>
) <b>ENGINE=InnoDB</b> AUTO_INCREMENT=1718273 DEFAULT CHARSET=latin1
1 row in set (0.01 sec)

+--------------------+
| schema_name        |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
| test               |
+--------------------+
4 rows in set (0.00 sec)

+---------+--------------------+
| howmany | table_schema       |
+---------+--------------------+
|     563 | information_schema |
|     286 | mysql              |
|     786 | performance_schema |
|      43 | test               |
+---------+--------------------+
4 rows in set (0.01 sec)

+---------+--------------------+
| howmany | table_schema       |
+---------+--------------------+
|  576512 | information_schema |
|  292864 | mysql              |
|  804864 | performance_schema |
|   44032 | test               |
+---------+--------------------+
4 rows in set (2.10 sec)

Query OK, 1 row affected (1.52 sec)

+--------------------+
| schema_name        |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
+--------------------+
3 rows in set (0.00 sec)

+---------+--------------------+
| howmany | table_schema       |
+---------+--------------------+
|     563 | information_schema |
|     286 | mysql              |
|     786 | performance_schema |
+---------+--------------------+
3 rows in set (0.00 sec)

+---------+--------------------+
| howmany | table_schema       |
+---------+--------------------+
|  576512 | information_schema |
|  292864 | mysql              |
|  804864 | performance_schema |
+---------+--------------------+
3 rows in set (1.74 sec)

Query OK, 0 rows affected (0.60 sec)

+--------------------+
| schema_name        |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
| test               |
+--------------------+
4 rows in set (0.00 sec)

+---------+--------------------+
| howmany | table_schema       |
+---------+--------------------+
|     563 | information_schema |
|     286 | mysql              |
|     786 | performance_schema |
|      43 | test               |
+---------+--------------------+
4 rows in set (0.01 sec)

+---------+--------------------+
| howmany | table_schema       |
+---------+--------------------+
|  576512 | information_schema |
|  292864 | mysql              |
|  804864 | performance_schema |
|   44032 | test               |
+---------+--------------------+
4 rows in set (1.59 sec)

DROP FOREIGN KEY and INDEX from small_table:
<b>Query OK, 0 rows affected (0.02 sec)</b>

DROP FOREIGN KEY from big_table:
<b>Query OK, 0 rows affected (0.02 sec)</b>

*************************** 1. row ***************************
       Table: small_table
Create Table: CREATE TABLE `small_table` (
  `TABLE_CATALOG` varchar(512) CHARACTER SET utf8 NOT NULL DEFAULT '',
  `TABLE_SCHEMA` varchar(64) CHARACTER SET utf8 NOT NULL DEFAULT '',
  `TABLE_NAME` varchar(64) CHARACTER SET utf8 NOT NULL DEFAULT '',
  ...
  `COLUMN_COMMENT` varchar(1024) CHARACTER SET utf8 NOT NULL DEFAULT '',
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1679 DEFAULT CHARSET=latin1
1 row in set (0.00 sec)

*************************** 1. row ***************************
       Table: big_table
Create Table: CREATE TABLE `big_table` (
  `TABLE_CATALOG` varchar(512) CHARACTER SET utf8 NOT NULL DEFAULT '',
  `TABLE_SCHEMA` varchar(64) CHARACTER SET utf8 NOT NULL DEFAULT '',
  `TABLE_NAME` varchar(64) CHARACTER SET utf8 NOT NULL DEFAULT '',
  ...
  `COLUMN_COMMENT` varchar(1024) CHARACTER SET utf8 NOT NULL DEFAULT '',
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  PRIMARY KEY (`id`),
  KEY `big_fk` (`TABLE_SCHEMA`)
) ENGINE=InnoDB AUTO_INCREMENT=1718273 DEFAULT CHARSET=latin1
1 row in set (0.00 sec)
</pre>
</div>
<div class="example">
<p class="title">
<b>Example 6. Changing Auto-Increment Value</b>
</p>
<p>
Here is an illustration of increasing the <a href="http://dev.mysql.com/doc/refman/5.6/en/glossary.html#glos_auto_increment" target="_top">auto-increment</a> lower limit for a table column, demonstrating how this operation now avoids a table rebuild, plus some other fun facts about <code class="literal">InnoDB</code> auto-increment columns.
</p>
<p><a name="online-ddl-autoinc"></a></p>
<pre class="programlisting">
/*
If this script is run after foreign_key.sql, the schema_names table is
already set up. But to allow this script to run multiple times without
running into duplicate ID errors, we set up the schema_names table
all over again.
*/

\! clear

\! echo "=== Adjusting the Auto-Increment Limit for a Table ==="
\! echo

drop table if exists schema_names;
<b>create table schema_names (id int unsigned not null primary key auto_increment,
  schema_name varchar(64) character set utf8 not null,
  index i_schema (schema_name))
  as select distinct table_schema schema_name from small_table;</b>

\! echo "Initial state of schema_names table."
\! echo "AUTO_INCREMENT is included in SHOW CREATE TABLE output."
\! echo "Note how MySQL reserved a block of IDs,"
\! echo "but only needed 4 of them in this transaction,"
\! echo "so the next inserted values would get IDs 8 and 9."
show create table schema_names\G
select * from schema_names order by id;

\! echo "Inserting even a tiny amount of data can produce gaps in the ID sequence."
insert into schema_names (schema_name) values ('eight'), ('nine');

set old_alter_table=0;
\! echo "Bumping auto-increment lower limit to 20 (fast mechanism):"
<b>alter table schema_names auto_increment=20;</b>

\! echo "Inserting 2 rows that should get IDs 20 and 21:"
insert into schema_names (schema_name) values ('foo'), ('bar');
commit;

set old_alter_table=1;
\! echo "Bumping auto-increment lower limit to 30 (slow mechanism):"
<b>alter table schema_names auto_increment=30;</b>

\! echo "Inserting 2 rows that should get IDs 30 and 31:"
insert into schema_names (schema_name) values ('bletch'),('baz');
commit;

select * from schema_names order by id;

set old_alter_table=0;

\! echo "Final state of schema_names table."
\! echo "AUTO_INCREMENT value shows the next inserted row would get ID=32."
show create table schema_names\G
</pre>
<p>
Running this code gives this output, condensed for brevity and with the most important points bolded:
</p>
<pre class="programlisting">
=== Adjusting the Auto-Increment Limit for a Table ===

Query OK, 0 rows affected (0.01 sec)

Query OK, 4 rows affected (0.02 sec)
Records: 4  Duplicates: 0  Warnings: 0

Initial state of schema_names table.
AUTO_INCREMENT is included in SHOW CREATE TABLE output.
Note how MySQL reserved a block of IDs,
but only needed 4 of them in this transaction,
so the next inserted values would get IDs 8 and 9.
*************************** 1. row ***************************
       Table: schema_names
Create Table: CREATE TABLE `schema_names` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `schema_name` varchar(64) CHARACTER SET utf8 NOT NULL,
  PRIMARY KEY (`id`),
  KEY `i_schema` (`schema_name`)
) <b>ENGINE=InnoDB AUTO_INCREMENT=8</b> DEFAULT CHARSET=latin1
1 row in set (0.00 sec)

+----+--------------------+
| id | schema_name        |
+----+--------------------+
|  1 | information_schema |
|  2 | mysql              |
|  3 | performance_schema |
|  4 | test               |
+----+--------------------+
4 rows in set (0.00 sec)

Inserting even a tiny amount of data can produce gaps in the ID sequence.
Query OK, 2 rows affected (0.00 sec)
Records: 2  Duplicates: 0  Warnings: 0

Bumping auto-increment lower limit to 20 (fast mechanism):
<b>Query OK, 0 rows affected (0.01 sec)</b>

Inserting 2 rows that should get IDs 20 and 21:
Query OK, 2 rows affected (0.00 sec)

Bumping auto-increment lower limit to 30 (slow mechanism):
<b>Query OK, 8 rows affected (0.02 sec)</b>

Inserting 2 rows that should get IDs 30 and 31:
Query OK, 2 rows affected (0.00 sec)

Query OK, 0 rows affected (0.01 sec)

+----+--------------------+
| id | schema_name        |
+----+--------------------+
|  1 | information_schema |
|  2 | mysql              |
|  3 | performance_schema |
|  4 | test               |
<b>|  8 | eight              |</b>
<b>|  9 | nine               |</b>
<b>| 20 | foo                |</b>
<b>| 21 | bar                |</b>
<b>| 30 | bletch             |</b>
<b>| 31 | baz                |</b>
+----+--------------------+
10 rows in set (0.00 sec)

Final state of schema_names table.
AUTO_INCREMENT value shows the next inserted row would get ID=32.
*************************** 1. row ***************************
       Table: schema_names
Create Table: CREATE TABLE `schema_names` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `schema_name` varchar(64) CHARACTER SET utf8 NOT NULL,
  PRIMARY KEY (`id`),
  KEY `i_schema` (`schema_name`)
) <b>ENGINE=InnoDB AUTO_INCREMENT=32</b> DEFAULT CHARSET=latin1
1 row in set (0.00 sec)
</pre>
</div>
]]></content:encoded>
			<wfw:commentRss>http://blogs.innodb.com/wp/2012/04/labs-release-online-ddl/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>InnoDB transportable tablespaces</title>
		<link>http://blogs.innodb.com/wp/2012/04/innodb-transportable-tablespaces/</link>
		<comments>http://blogs.innodb.com/wp/2012/04/innodb-transportable-tablespaces/#comments</comments>
		<pubDate>Tue, 10 Apr 2012 22:10:14 +0000</pubDate>
		<dc:creator>Sunny Bains</dc:creator>
				<category><![CDATA[Feature]]></category>

		<guid isPermaLink="false">http://blogs.innodb.com/wp/?p=1617</guid>
		<description><![CDATA[The Problem In the past, users were unable to take full advantage of the FLUSH TABLES WITH READ LOCK statement. InnoDB simply ignored the flush to disk part. If the table did not have any dirty pages in the InnoDB buffer that weren&#8217;t synced to disk (due to sheer luck) then it was safe to [...]]]></description>
			<content:encoded><![CDATA[<p><strong>The Problem</strong></p>
<p>In the past, users were unable to take full advantage of the <a title="FLUSH TABLES WITH READ LOCK" href="http://dev.mysql.com/doc/refman/5.6/en/flush.html" target="_blank">FLUSH TABLES WITH READ LOCK</a> statement. InnoDB simply ignored the flush to disk part. If the table did not have any dirty pages in the InnoDB buffer that weren&#8217;t synced to disk (due to sheer luck) then it was safe to copy the .ibd file to another location. Also, the restore was not without its limitations and complications. The .ibd file could not be copied over to another server because InnoDB during <a title="ALTER TABLE T IMPORT TABLESPACE" href="http://dev.mysql.com/doc/refman/5.6/en/alter-table.html" target="_blank">import</a> did not fix up metadata required for a trouble-free import. The main problems during import were:</p>
<ul>
<li>If the tablespace ID of the IMPORTing instance had changed, for example if the table had been dropped and re-created, then the import would fail.</li>
<li>If the table and index IDs in the tablespace were different than on the importing server.</li>
<li>InnoDB uses a global row ID for tables without an explicit primary key. Any such row IDs in an imported tablespace had to be lower than the current maximum on the new server.</li>
<li>The maximum LSN of the tablespace had to be lower than the server&#8217;s current max LSN.</li>
<li>The maximum transaction (trx) ID of the tablespace had to be lower than the server current max trx id.</li>
<li>Purge and change buffer issues.</li>
</ul>
<p>In short, if it worked you were lucky that the above constraints were satisfied, or your tables were probably read-only.</p>
<p><strong>The Solution</strong></p>
<p>Do the flush (export) properly and also the import. During flushing we disable purge, merge all pending change buffer entries to the tablespace and then flush all the dirty pages to disk. <strong>Note: Purge will remain disabled until UNLOCK TABLES; is issued</strong>. Write out a metadata file that contains the table schema, hostname of the exporting server, page size of the exporting instance, the highest autoinc value in memory etc. So that when we do an import, we can check if the table schema matches (currently, it ignores foreign key relationships) and also restore the autoinc value. This metadata file is created in the same directory as the tablespace, with a suffix of .cfg. If the table is named <em>customer</em> then the meta-data file will be named <em>customer.cfg</em> and the tablespace will be named <em>customer.ibd.</em> Note: FLUSH TABLES and IMPORT only work for tables that are stored outside the system tablespace, in their own tablespace. The InnoDB config parameter <a title="innodb_file_per_table" href="http://dev.mysql.com/doc/refman/5.6/en/innodb-parameters.html#sysvar_innodb_file_per_table" target="_blank">innodb_file_per_table</a> must be set when creating the table.</p>
<p><span id="more-1617"></span></p>
<p>Because InnoDB stores data in <a title="Endianness" href="http://en.wikipedia.org/wiki/Endianness" target="_blank">big-endian format</a>, this allows copying data between different architectures. Copying between different operating systems will also work.</p>
<p><strong>Example</strong></p>
<p>If you want to backup a single table:</p>
<p>CREATE DATABASE ftwrl;</p>
<p>SET GLOBAL innodb_file_per_table=1;</p>
<p>CREATE TABLE ftwrl.t (C INT) ENGINE=InnoDB;</p>
<p>INSERT INTO ftwrl.t VALUES(1),(2),(3);</p>
<p>SELECT * FROM ftwrl.t;</p>
<p>FLUSH TABLES ftwrl.t WITH READ LOCK;</p>
<p>From the command line, copy the t.ibd and t.cfg to your backup directory. The files should be in the ftwrl/ sub-directory under <a title="--datadir" href="http://dev.mysql.com/doc/refman/5.6/en/mysql-install-db.html#option_mysql_install_db_datadir" target="_blank">datadir</a>.</p>
<p>UNLOCK TABLES; &#8212; <strong>Note: This will remove the t.cfg file.</strong></p>
<p>DROP TABLE ftwrl.t;</p>
<p>CREATE TABLE ftwrl.t (C INT) ENGINE=InnoDB;</p>
<p>ALTER TABLE ftwrl.t DISCARD TABLESPACE;</p>
<p>The DISCARD tablespace will rename the t.ibd file to t.ibt in the same directory; you have to remove this file manually for now. Once you&#8217;ve removed this file, copy the backed up tablespace t.ibd and the metadata file t.cfg to the ftwrl/ sub-directory. Then issue the folowing:</p>
<p>ALTER TABLE ftwrl.t IMPORT TABLESPACE;<br />
CHECK TABLE ftwrl.t;<br />
SELECT * FROM t;</p>
<p>You should be good to go. If you want to backup multiple tables together, the syntax for that is:</p>
<p>FLUSH TABLES t1, t2, &#8230;, tn WITH READ LOCK;</p>
<p>Copy as before but this time the multiple tablespaces and metadata files.</p>
<p>UNLOCK TABLES;</p>
<p>Then first discard the tablespace as above followed by an import as above.</p>
<p><strong>Other changes</strong><br />
Errors and warnings will be pushed to the client so that the user doesn&#8217;t need to poke around in the server error log files to check why an operation failed. The intention is to send enough information to the user so that the problem can be clearly identified and understood.</p>
<p><strong>Conclusion</strong></p>
<p>The syntax for &#8220;export&#8221; is not finalised yet and may change; for now the above examples using FLUSH TABLES WITH READ LOCK should work. To export tables that are in a foreign key relationship, you must export and import all the tables together, otherwise you may end up with inconsistencies. The export/import doesn&#8217;t work on partitioned tables, this limitation will be addressed later. A matching table definition must exist in the importing server instance, currently we don&#8217;t automagically create the table using the saved metadata during import. The .cfg format is not written in stone yet, we may add more data to this file, for example for partition support.</p>
<p>Your feedback is important to us, so that we can improve this feature further.</p>
]]></content:encoded>
			<wfw:commentRss>http://blogs.innodb.com/wp/2012/04/innodb-transportable-tablespaces/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Choose the Location of your InnoDB File-per-Table Tablespace</title>
		<link>http://blogs.innodb.com/wp/2012/04/remote-innodb-tablespaces/</link>
		<comments>http://blogs.innodb.com/wp/2012/04/remote-innodb-tablespaces/#comments</comments>
		<pubDate>Tue, 10 Apr 2012 16:00:08 +0000</pubDate>
		<dc:creator>Kevin Lewis</dc:creator>
				<category><![CDATA[Feature]]></category>
		<category><![CDATA[Information Schema]]></category>

		<guid isPermaLink="false">http://blogs.innodb.com/wp/?p=1653</guid>
		<description><![CDATA[The April 2012 InnoDB labs release introduces a new feature in InnoDB that allows you to choose the location of specific tables.  For example, you can place critical tables onto an SSD drive while leaving the system tablespace on a hard drive.  Conversely, you can store you primary database files on an SSD and put [...]]]></description>
			<content:encoded><![CDATA[<p>The April 2012 InnoDB labs release introduces a new feature in InnoDB that allows you to choose the location of specific tables.  For example, you can place critical tables onto an SSD drive while leaving the system tablespace on a hard drive.  Conversely, you can store you primary database files on an SSD and put a seldom used but very large archive or reference table on a larger cheaper hard drive.</p>
<p>Innodb now makes use of the following existing syntax in MySQL ;</p>
<p>CREATE TABLE  . . .  DATA DIRECTORY = &#8216;absolute path of data directory&#8217;;</p>
<p>CREATE TABLE  . . .  PARTITION . . . DATA DIRECTORY = &#8216;absolute path of data directory&#8217;;</p>
<p>This syntax is used in MyISAM and Archive engines to make use of symbolic links in those operating systems that support it.  But InnoDB can use this syntax on any OS since it stores the path in a new system table called SYS_DATAFILES.  There is also a new system table called SYS_TABLESPACES.  Both of these can be viewed in the April Labs release of 5.6 by using information schema. For example;<span id="more-1653"></span></p>
<pre>mysql&gt; SET GLOBAL innodb_file_per_table=on;
Query OK, 0 rows affected (0.00 sec)</pre>
<pre>mysql&gt; CREATE TABLE t1 (a int KEY, b text) DATA DIRECTORY='/ssd1/my_data';
 Query OK, 0 rows affected (0.12 sec)</pre>
<pre>mysql&gt; SELECT * FROM INFORMATION_SCHEMA.INNODB_SYS_TABLESPACES;
 +-------+---------+------+-------------+----------------------+-----------+---------------+
 | SPACE | NAME    | FLAG | FILE_FORMAT | ROW_FORMAT           | PAGE_SIZE | ZIP_PAGE_SIZE |
 +-------+---------+------+-------------+----------------------+-----------+---------------+
 |     1 | test/t1 |    0 | Antelope    | Compact or Redundant |     16384 |             0 |
 +-------+---------+------+-------------+----------------------+-----------+---------------+
 1 row in set (0.00 sec)</pre>
<pre>mysql&gt; SELECT * FROM INFORMATION_SCHEMA.INNODB_SYS_DATAFILES;
 +-------+---------------------------+
 | SPACE | PATH                      |
 +-------+---------------------------+
 |     1 | /ssd1/my_data/test/t1.ibd |
 +-------+---------------------------+
 1 row in set (0.00 sec)</pre>
<p>Notice that a directory named for the database is added after the DATA DIRECTORY provided.  This is the same as what is done in the normal data directory.  It allows you to chose the same remote location for all your tablespaces, even if the tables in different databases have the same name.</p>
<p>The last 4 columns in innodb_sys_tablespaces are interpretations of the tablespace flags field. Tablespace flags do not distinguish between Compact and Redundant row format, so you see what is displayed above.  If you want to see the row format of the table, innodb_sys_tables now also interprets the table flags;</p>
<pre>mysql&gt; SELECT * FROM INFORMATION_SCHEMA.INNODB_SYS_TABLES WHERE name like 'test%';
 +----------+---------+------+--------+-------+-------------+------------+---------------+
 | TABLE_ID | NAME    | FLAG | N_COLS | SPACE | FILE_FORMAT | ROW_FORMAT | ZIP_PAGE_SIZE |
 +----------+---------+------+--------+-------+-------------+------------+---------------+
 |       24 | test/t1 |   65 |      5 |     1 | Antelope    | Compact    |             0 |
 +----------+---------+------+--------+-------+-------------+------------+---------------+
 1 row in set (0.00 sec)</pre>
<p>In addition to SYS_DATAFILES, the absolute file path to the tablespace is also written to a text file in the normal datafiles location of the tablespace.  This is also the location of the FRM file written by the MYSQL server.  It has the same name as the FRM except it has the extension &#8216;.isl&#8217; which stands for InnoDB Symbolic Link.  It is there to support recovery which happens before the system tables are opened.  For the example above, the sole contents of t1.isl are;</p>
<pre>/ssd1/my_data/test/t1.ibd</pre>
<p>The ISL file also allows a DBA to move one of these remote tablespaces since ALTER TABLE &#8230; DATA DIRECTORY =  &#8216;. . .&#8217; is currently not supported.  In order to move a tablespace to another location, or to port an entire database along with its remote tablespaces, you must edit this ISL file after moving the OS files.  The ISL file is a simple text file that contains the absolute path and filename of the tablespace.  Just change that to the new location and save your changes.  Do not leave a copy of the tablespace in the old location.</p>
<p>If you have a large existing database that uses file-per-table tablespaces (files with &#8216;.ibd&#8217; extensions), it is possible to move these from the default location next to the FRM file to a remote location such as a new SSD drive.  But you must shut down the MySQL server first. After it is shut down, move the IBD tablespace to the location that you would like, create a text file where it was with the same name except using a &#8216;isl&#8217; extension.  Make the contents of the text file to be the full file path of the ibd file.  Then restart the server.  It will read the isl file, find the tablespace, and update the internal system tables to show where the file resides.</p>
<p><strong>Conclusion</strong></p>
<p>This new feature provides a valuable option to configure your database to make the best use of the hardware available.</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
]]></content:encoded>
			<wfw:commentRss>http://blogs.innodb.com/wp/2012/04/remote-innodb-tablespaces/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>InnoDB 2012 Spring Labs Release</title>
		<link>http://blogs.innodb.com/wp/2012/04/innodb-2012-spring-labs-release/</link>
		<comments>http://blogs.innodb.com/wp/2012/04/innodb-2012-spring-labs-release/#comments</comments>
		<pubDate>Tue, 10 Apr 2012 15:00:40 +0000</pubDate>
		<dc:creator>Calvin Sun</dc:creator>
				<category><![CDATA[Feature]]></category>
		<category><![CDATA[Performance]]></category>
		<category><![CDATA[labs release]]></category>

		<guid isPermaLink="false">http://blogs.innodb.com/wp/?p=1663</guid>
		<description><![CDATA[InnoDB team is pleased to announce the 2012 Spring labs release, with several much anticipated new features and performance enhancements. Please download mysql-5.6-labs-april-2012 from MySQL Labs and give a try. Do not forget to provide your feedback. The 2012 Spring labs release on MySQL Labs consists of the following InnoDB new features, which are not [...]]]></description>
			<content:encoded><![CDATA[<p>InnoDB team is pleased to announce the 2012 Spring labs release, with several much anticipated new features and performance enhancements. Please download mysql-5.6-labs-april-2012 from <a href="http://labs.mysql.com/">MySQL Labs</a> and give a try. Do not forget to provide your feedback.</p>
<p>The 2012 Spring labs release on MySQL Labs consists of the following InnoDB new features, which are not in the newly released <a href="http://dev.mysql.com/downloads/mysql/#downloads">MySQL 5.6.5 DMR</a> yet:</p>
<ul>
<li>Online DDL: some of the DDLs are now truly online, including ADD INDEX, SET DEFAULT, and DROP FOREIGN KEY.</li>
<li>Memcached plugin: with additional features, such as SASL support.</li>
<li>Transportable tablespace: allow user to export data files and import them into another MySQL instance.</li>
<li>Persistent statistics ON/OFF switch: the ability of controlling persistent statistics on table level.</li>
<li>Option for specifying locations of InnoDB tables: allows user to choose the location of specific tables.</li>
</ul>
<p>This labs release also includes several performance and scalability improvements, specially on modern CPUs:</p>
<ul>
<li>Reduced false sharing</li>
<li>Configurable fast mutexes</li>
<li>my_hash_sort_simple() loop unrolling</li>
<li>Improved adaptive flushing</li>
<li>Improved neighbor flushing</li>
</ul>
<p><span id="more-1663"></span></p>
<p>With those improvements, (InnoDB) read-only performance reaches a new high. Please see <a href="http://mikaelronstrom.blogspot.com/2012/04/mysql-team-increases-scalability-by-50.html">Mikael&#8217;s blog</a> for some of the improvements. You will see the benchmark results on <a href="http://dimitrik.free.fr/blog/index.html">DimitriK&#8217;s blog</a>. And the InnoDB team will also continue publishing technical details in the coming days on this site.</p>
<p>We intend to make those new features &amp; improvements into future development milestone releases and GA releases. Thanks for being interested in InnoDB!</p>
]]></content:encoded>
			<wfw:commentRss>http://blogs.innodb.com/wp/2012/04/innodb-2012-spring-labs-release/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Improving InnoDB memory usage continued</title>
		<link>http://blogs.innodb.com/wp/2011/12/improving-innodb-memory-usage-continued/</link>
		<comments>http://blogs.innodb.com/wp/2011/12/improving-innodb-memory-usage-continued/#comments</comments>
		<pubDate>Fri, 23 Dec 2011 11:14:29 +0000</pubDate>
		<dc:creator>Vasil Dimov</dc:creator>
				<category><![CDATA[InnoDB Builtin]]></category>
		<category><![CDATA[InnoDB Plugin]]></category>
		<category><![CDATA[Performance]]></category>

		<guid isPermaLink="false">http://blogs.innodb.com/wp/?p=1591</guid>
		<description><![CDATA[Continues from Improving InnoDB memory usage. Here are some numbers from the fixups described in the above article: The workload consists of 10 partitioned tables, each one containing 1000 partitions. This means 10&#8217;000 InnoDB tables. We truncate the tables, then restart mysqld and run: 1. INSERT a single row into each of the 10 tables [...]]]></description>
			<content:encoded><![CDATA[<p>Continues from <a href="http://blogs.innodb.com/wp/2011/12/improving-innodb-memory-usage/" title="Improving InnoDB memory usage">Improving InnoDB memory usage</a>.</p>
<p>Here are some numbers from the fixups described in the <a href="http://blogs.innodb.com/wp/2011/12/improving-innodb-memory-usage/" title="Improving InnoDB memory usage">above article</a>:</p>
<p>The workload consists of 10 partitioned tables, each one containing 1000 partitions. This means 10&#8217;000 InnoDB tables. We truncate the tables, then restart mysqld and run:</p>
<p>1. INSERT a single row into each of the 10 tables<br />
2. SELECT * from each table<br />
3. FLUSH TABLES (this causes the tables to be closed and reopened on the next run)<br />
4. wait for 10 seconds</p>
<p>we repeat the above steps 10 times. Here is the total memory consumption by mysqld with 1GB InnoDB buffer pool during the workload:</p>
<p><span id="more-1591"></span></p>
<p><img src="http://blogs.innodb.com/wp/wp-content/uploads/2011/12/memfix1.png" alt="" title="Memory " width="700" height="500" class="alignnone size-full wp-image-1601" /></p>
<p>In the fixed case (green line) you can clearly see the peaks when the commands 1. &#8211; 4. are run and the valley bottoms during the 10 seconds waits.</p>
<p>Notice that no memory leaks were fixed in these improvements. This is all about interaction between InnoDB and the system allocator. InnoDB always frees memory it has allocated, but the problem was that the system allocator could not reuse the freed memory optimally due to memory fragmentation. We mainly reduced the number of and the sizes of some of the hottest allocations, mitigating the malloc/free storm.</p>
<p>Notice also that this is somewhat unusual workload &#8211; 10&#8217;000 InnoDB tables, row size of about 64KB and frequent FLUSH TABLES.</p>
]]></content:encoded>
			<wfw:commentRss>http://blogs.innodb.com/wp/2011/12/improving-innodb-memory-usage-continued/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
	</channel>
</rss>

