﻿<?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>P.Linux Laboratory &#187; MySQL</title>
	<atom:link href="http://www.penglixun.com/tag/mysql/feed" rel="self" type="application/rss+xml" />
	<link>http://www.penglixun.com</link>
	<description>MySQL DBA &#38; Linux SA</description>
	<lastBuildDate>Sun, 22 Jan 2012 16:34:39 +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>一个InnoDB性能超过Oracle的调优Case</title>
		<link>http://www.penglixun.com/tech/database/case_about_innodb_faster_than_oracle.html</link>
		<comments>http://www.penglixun.com/tech/database/case_about_innodb_faster_than_oracle.html#comments</comments>
		<pubDate>Sun, 22 Jan 2012 16:00:59 +0000</pubDate>
		<dc:creator>P.Linux</dc:creator>
				<category><![CDATA[数据库]]></category>
		<category><![CDATA[AIO]]></category>
		<category><![CDATA[InnoDB]]></category>
		<category><![CDATA[Kernel]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[Percona]]></category>
		<category><![CDATA[XtraDB]]></category>

		<guid isPermaLink="false">http://www.penglixun.com/?p=1232</guid>
		<description><![CDATA[年前抽空到兄弟公司支援了一下Oracle迁移MySQL的测试，本想把MySQL调优到接近Oracle的性能即可，但经过 @何_登成 @淘宝丁奇 @淘宝褚霸 @淘伯松 诸位大牛的指导和帮助（排名不分先后，仅按第一次... ]]></description>
			<content:encoded><![CDATA[<p>年前抽空到兄弟公司支援了一下Oracle迁移MySQL的测试，本想把MySQL调优到接近Oracle的性能即可，但经过 @何_登成 @淘宝丁奇 @淘宝褚霸 @淘伯松 诸位大牛的指导和帮助（排名不分先后，仅按第一次为此CASE而骚扰的时间排序），不断修正方案，最终获得了比Oracle更好的性能，虽然是个特殊场景，但是我觉得意义是很广泛的，值得参考，遂记录于此。<br />
所有涉及表结构和具体业务模型的部分全部略去，也请勿咨询，不能透露，敬请谅解。</p>
<h2>一、测试模型：</h2>
<p>包含12张业务表，每个事务包含12个<acronym title="Structured Query Language">SQL</acronym>，每个<acronym title="Structured Query Language">SQL</acronym>向一张表做INSERT，做完12个<acronym title="Structured Query Language">SQL</acronym>即完成一个事务。</p>
<p>用一个C <acronym title="Application Programming Interface">API</acronym>编写的程序连接MySQL，不断执行如下操作</p>
<blockquote><p>开始事务：START TRANSACTION;<br />
每张表插入一行：INSERT INTO xxx VALUES (val1,val2,…); #一共12次<br />
提交事务：COMMIT;</p></blockquote>
<p>通过一个Shell脚本来启动32个测试程序并发测试</p>
<h2>二、测试环境：</h2>
<h3>1. 机型：</h3>
<p>R510<br />
CPU：Intel(R) Xeon(R) CPU E5645 @ 2.40GHz 双路24线程<br />
内存：6 * 8G 48G<br />
存储：FusionIO 320G MLC</p>
<p>R910<br />
CPU：Intel(R) Xeon(R) CPU E7530 @ 1.87GHz 四路48线程<br />
内存：32* 4G 128G<br />
存储：FusionIO 640G MLC</p>
<h3>2. Linux配置：</h3>
<p>单实例启动数据库：/boot/grub/menu.lst修改kernel启动参数增加numa=off<br />
多实例启动数据库：numactl &#8211;cpunodebind=$BIND_NO &#8211;localalloc $MYSQLD</p>
<p>RHEL 5.4 with 2.6.18内置内核<br />
RHEL 6.1 with 2.6.32淘宝版内核</p>
<p>fs.aio-max-nr = 1048576 #调整系统允许的最大异步IO队列长度<br />
vm.nr_hugepages = 18000 #大页页数<br />
vm.hugetlb_shm_group = 601 #允许使用大页的用户id，即mysql用户<br />
vm.swappiness = 0 #不倾向使用SWAP</p>
<h3>3. FusionIO配置：</h3>
<p>启动配置：<br />
/etc/modprobe.d/iomemory-vsl.conf<br />
options iomemory-vsl use_workqueue=0 # 忽略Linux IO调度<br />
options iomemory-vsl disable-msi=0 # 开启MSI中断<br />
options iomemory-vsl use_large_pcie_rx_buffer=1 # 打开PCIE缓冲<br />
options iomemory-vsl preallocate_memory=SN号 # 预分配管理内存</p>
<p>格式化配置：<br />
fio-format -b 4K /dev/fct0 # 格式化设备为4K匹配NAND芯片页大小<br />
mkfs.xfs -f -i attr=2 -l lazy-count=1,sectsize=4096 -b size=4096 -d sectsize=4096 -L data /dev/fioa # 调整XFS与FusionIO 4K页匹配，比较激进，需要更多稳定性测试认为这组参数充分安全</p>
<p>mount配置：<br />
/dev/fioa on /data type xfs (rw,noatime,nodiratime,noikeep,nobarrier,allocsize=100M,attr2,largeio,inode64,swalloc) # FusionIO的逻辑Block是100M，所以设为100M的预扩展</p>
<h3>4. MySQL版本和通用配置：</h3>
<p>Percona 5.1.60-13.1 原版<br />
Percona 5.1.60-13.1 修改版<br />
* 允许自定义InnoDB AIO队列申请长度 (5.5_change_aio_io_limit.patch)<br />
Percona 5.5.19-24.0 原版<br />
* 允许innodb_flush_neighbor_pages=2来合并真正相邻的脏页合并<br />
* Group Commit<br />
Percona 5.5.18-23.0 修改版<br />
* 允许自定义InnoDB AIO队列申请长度 (5.5_change_aio_io_limit.patch)<br />
* 允许预先扩展数据文件 (5.5_innodb_extent_tablespace.patch，@淘宝丁奇 贡献)<br />
* Group Cimmit</p>
<p>innodb_buffer_pool_size=20G<br />
sync_binlog=1<br />
innodb_flush_log_at_trx_commit=1</p>
<p>测试并发：32</p>
<h3>5. 修改补丁</h3>
<p>#cat 5.5_change_aio_io_limit.patch</p>

<div class="wp_codebox"><table><tr id="p12323"><td class="code" id="p1232code3"><pre class="cpp" style="font-family:monospace;"><span style="color: #000040;">---</span> Percona<span style="color: #000040;">-</span>Server<span style="color: #000040;">-</span>5.5.18<span style="color: #000040;">-</span><span style="color:#800080;">23.0</span><span style="color: #000040;">/</span>storage<span style="color: #000040;">/</span>innobase<span style="color: #000040;">/</span>handler<span style="color: #000040;">/</span>ha_innodb.<span style="color: #007788;">cc</span>	<span style="color: #0000dd;">2011</span><span style="color: #000040;">-</span><span style="color: #0000dd;">12</span><span style="color: #000040;">-</span><span style="color: #0000dd;">20</span> <span style="color: #208080;">06</span><span style="color: #008080;">:</span><span style="color: #0000dd;">38</span><span style="color: #008080;">:</span><span style="color:#800080;">58.000000000</span> <span style="color: #000040;">+</span><span style="color:#800080;">0800</span>
<span style="color: #000040;">+++</span> Percona<span style="color: #000040;">-</span>Server<span style="color: #000040;">-</span>5.5.18<span style="color: #000040;">-</span><span style="color:#800080;">23.0</span><span style="color: #000040;">-</span>debug<span style="color: #000040;">/</span>storage<span style="color: #000040;">/</span>innobase<span style="color: #000040;">/</span>handler<span style="color: #000040;">/</span>ha_innodb.<span style="color: #007788;">cc</span>	<span style="color: #0000dd;">2012</span><span style="color: #000040;">-</span><span style="color: #208080;">01</span><span style="color: #000040;">-</span><span style="color: #0000dd;">17</span> <span style="color: #0000dd;">10</span><span style="color: #008080;">:</span><span style="color: #0000dd;">13</span><span style="color: #008080;">:</span><span style="color:#800080;">41.000000000</span> <span style="color: #000040;">+</span><span style="color:#800080;">0800</span>
@@ <span style="color: #000040;">-</span><span style="color: #0000dd;">146</span>,<span style="color: #0000dd;">6</span> <span style="color: #000040;">+</span><span style="color: #0000dd;">146</span>,<span style="color: #0000dd;">7</span> @@
 <span style="color: #0000ff;">static</span> ulong innobase_commit_concurrency <span style="color: #000080;">=</span> <span style="color: #0000dd;">0</span><span style="color: #008080;">;</span>
 <span style="color: #0000ff;">static</span> ulong innobase_read_io_threads<span style="color: #008080;">;</span>
 <span style="color: #0000ff;">static</span> ulong innobase_write_io_threads<span style="color: #008080;">;</span>
<span style="color: #000040;">+</span><span style="color: #0000ff;">static</span> ulong innobase_aio_pending_ios_per_thread<span style="color: #008080;">;</span> <span style="color: #666666;">// Change AIO io_limit By P.Linux</span>
 <span style="color: #0000ff;">static</span> <span style="color: #0000ff;">long</span> innobase_buffer_pool_instances <span style="color: #000080;">=</span> <span style="color: #0000dd;">1</span><span style="color: #008080;">;</span>
&nbsp;
 <span style="color: #0000ff;">static</span> ulong innobase_page_size<span style="color: #008080;">;</span>
@@ <span style="color: #000040;">-</span><span style="color: #0000dd;">2870</span>,<span style="color: #0000dd;">6</span> <span style="color: #000040;">+</span><span style="color: #0000dd;">2871</span>,<span style="color: #0000dd;">7</span> @@
 	srv_n_file_io_threads <span style="color: #000080;">=</span> <span style="color: #008000;">&#40;</span>ulint<span style="color: #008000;">&#41;</span> innobase_file_io_threads<span style="color: #008080;">;</span>
 	srv_n_read_io_threads <span style="color: #000080;">=</span> <span style="color: #008000;">&#40;</span>ulint<span style="color: #008000;">&#41;</span> innobase_read_io_threads<span style="color: #008080;">;</span>
 	srv_n_write_io_threads <span style="color: #000080;">=</span> <span style="color: #008000;">&#40;</span>ulint<span style="color: #008000;">&#41;</span> innobase_write_io_threads<span style="color: #008080;">;</span>
<span style="color: #000040;">+</span>	srv_n_aio_pending_ios_per_thread <span style="color: #000080;">=</span> <span style="color: #008000;">&#40;</span>ulint<span style="color: #008000;">&#41;</span> innobase_aio_pending_ios_per_thread<span style="color: #008080;">;</span>
&nbsp;
 	srv_read_ahead <span style="color: #000040;">&amp;</span>amp<span style="color: #008080;">;</span><span style="color: #000080;">=</span> <span style="color: #0000dd;">3</span><span style="color: #008080;">;</span>
 	srv_adaptive_flushing_method <span style="color: #000040;">%</span><span style="color: #000080;">=</span> <span style="color: #0000dd;">3</span><span style="color: #008080;">;</span>
@@ <span style="color: #000040;">-</span><span style="color: #0000dd;">12282</span>,<span style="color: #0000dd;">6</span> <span style="color: #000040;">+</span><span style="color: #0000dd;">12284</span>,<span style="color: #0000dd;">11</span> @@
   <span style="color: #FF0000;">&quot;Number of background write I/O threads in InnoDB.&quot;</span>,
   <span style="color: #0000ff;">NULL</span>, <span style="color: #0000ff;">NULL</span>, <span style="color: #0000dd;">4</span>, <span style="color: #0000dd;">1</span>, <span style="color: #0000dd;">64</span>, <span style="color: #0000dd;">0</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
&nbsp;
<span style="color: #000040;">+</span><span style="color: #0000ff;">static</span> MYSQL_SYSVAR_ULONG<span style="color: #008000;">&#40;</span>aio_pending_ios_per_thread, innobase_aio_pending_ios_per_thread,
<span style="color: #000040;">+</span>  PLUGIN_VAR_RQCMDARG <span style="color: #000040;">|</span> PLUGIN_VAR_READONLY,
<span style="color: #000040;">+</span>  <span style="color: #FF0000;">&quot;Number of AIO pending IOS per-thread in InnoDB.&quot;</span>,
<span style="color: #000040;">+</span>  <span style="color: #0000ff;">NULL</span>, <span style="color: #0000ff;">NULL</span>, <span style="color: #0000dd;">4</span>, <span style="color: #0000dd;">32</span>, <span style="color: #0000dd;">4096</span>, <span style="color: #0000dd;">0</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
<span style="color: #000040;">+</span>
 <span style="color: #0000ff;">static</span> MYSQL_SYSVAR_LONG<span style="color: #008000;">&#40;</span>force_recovery, innobase_force_recovery,
   PLUGIN_VAR_RQCMDARG <span style="color: #000040;">|</span> PLUGIN_VAR_READONLY,
   <span style="color: #FF0000;">&quot;Helps to save your data in case the disk image of the database becomes corrupt.&quot;</span>,
<span style="color: #000040;">---</span> Percona<span style="color: #000040;">-</span>Server<span style="color: #000040;">-</span>5.5.18<span style="color: #000040;">-</span><span style="color:#800080;">23.0</span><span style="color: #000040;">/</span>storage<span style="color: #000040;">/</span>innobase<span style="color: #000040;">/</span>srv<span style="color: #000040;">/</span>srv0srv.<span style="color: #007788;">c</span>	<span style="color: #0000dd;">2011</span><span style="color: #000040;">-</span><span style="color: #0000dd;">12</span><span style="color: #000040;">-</span><span style="color: #0000dd;">20</span> <span style="color: #208080;">06</span><span style="color: #008080;">:</span><span style="color: #0000dd;">38</span><span style="color: #008080;">:</span><span style="color:#800080;">57.000000000</span> <span style="color: #000040;">+</span><span style="color:#800080;">0800</span>
<span style="color: #000040;">+++</span> Percona<span style="color: #000040;">-</span>Server<span style="color: #000040;">-</span>5.5.18<span style="color: #000040;">-</span><span style="color:#800080;">23.0</span><span style="color: #000040;">-</span>debug<span style="color: #000040;">/</span>storage<span style="color: #000040;">/</span>innobase<span style="color: #000040;">/</span>srv<span style="color: #000040;">/</span>srv0srv.<span style="color: #007788;">c</span>	<span style="color: #0000dd;">2012</span><span style="color: #000040;">-</span><span style="color: #208080;">01</span><span style="color: #000040;">-</span><span style="color: #0000dd;">17</span> <span style="color: #0000dd;">10</span><span style="color: #008080;">:</span><span style="color: #0000dd;">23</span><span style="color: #008080;">:</span><span style="color:#800080;">35.000000000</span> <span style="color: #000040;">+</span><span style="color:#800080;">0800</span>
@@ <span style="color: #000040;">-</span><span style="color: #0000dd;">242</span>,<span style="color: #0000dd;">6</span> <span style="color: #000040;">+</span><span style="color: #0000dd;">242</span>,<span style="color: #0000dd;">7</span> @@
 UNIV_INTERN ulint	srv_n_file_io_threads	<span style="color: #000080;">=</span> ULINT_MAX<span style="color: #008080;">;</span>
 UNIV_INTERN ulint	srv_n_read_io_threads	<span style="color: #000080;">=</span> ULINT_MAX<span style="color: #008080;">;</span>
 UNIV_INTERN ulint	srv_n_write_io_threads	<span style="color: #000080;">=</span> ULINT_MAX<span style="color: #008080;">;</span>
<span style="color: #000040;">+</span>UNIV_INTERN ulint   srv_n_aio_pending_ios_per_thread <span style="color: #000080;">=</span> ULINT_MAX<span style="color: #008080;">;</span> <span style="color: #666666;">// Change AIO io_limit By P.Linux</span>
&nbsp;
 <span style="color: #ff0000; font-style: italic;">/* Switch to enable random read ahead. */</span>
 UNIV_INTERN my_bool	srv_random_read_ahead	<span style="color: #000080;">=</span> FALSE<span style="color: #008080;">;</span>
<span style="color: #000040;">---</span> Percona<span style="color: #000040;">-</span>Server<span style="color: #000040;">-</span>5.5.18<span style="color: #000040;">-</span><span style="color:#800080;">23.0</span><span style="color: #000040;">/</span>storage<span style="color: #000040;">/</span>innobase<span style="color: #000040;">/</span>srv<span style="color: #000040;">/</span>srv0start.<span style="color: #007788;">c</span>	<span style="color: #0000dd;">2011</span><span style="color: #000040;">-</span><span style="color: #0000dd;">12</span><span style="color: #000040;">-</span><span style="color: #0000dd;">20</span> <span style="color: #208080;">06</span><span style="color: #008080;">:</span><span style="color: #0000dd;">38</span><span style="color: #008080;">:</span><span style="color:#800080;">57.000000000</span> <span style="color: #000040;">+</span><span style="color:#800080;">0800</span>
<span style="color: #000040;">+++</span> Percona<span style="color: #000040;">-</span>Server<span style="color: #000040;">-</span>5.5.18<span style="color: #000040;">-</span><span style="color:#800080;">23.0</span><span style="color: #000040;">-</span>debug<span style="color: #000040;">/</span>storage<span style="color: #000040;">/</span>innobase<span style="color: #000040;">/</span>srv<span style="color: #000040;">/</span>srv0start.<span style="color: #007788;">c</span>	<span style="color: #0000dd;">2012</span><span style="color: #000040;">-</span><span style="color: #208080;">01</span><span style="color: #000040;">-</span><span style="color: #0000dd;">17</span> <span style="color: #0000dd;">10</span><span style="color: #008080;">:</span><span style="color: #0000dd;">25</span><span style="color: #008080;">:</span><span style="color:#800080;">12.000000000</span> <span style="color: #000040;">+</span><span style="color:#800080;">0800</span>
@@ <span style="color: #000040;">-</span><span style="color: #0000dd;">1475</span>,<span style="color: #0000dd;">14</span> <span style="color: #000040;">+</span><span style="color: #0000dd;">1475</span>,<span style="color: #0000dd;">16</span> @@
&nbsp;
 	ut_a<span style="color: #008000;">&#40;</span>srv_n_file_io_threads</pre></td></tr></table></div>

<p>#cat 5.5_innodb_extent_tablespace.patch</p>

<div class="wp_codebox"><table><tr id="p12324"><td class="code" id="p1232code4"><pre class="cpp" style="font-family:monospace;"><span style="color: #000040;">---</span> Percona<span style="color: #000040;">-</span>Server<span style="color: #000040;">-</span>5.5.18<span style="color: #000040;">-</span><span style="color:#800080;">23.0</span><span style="color: #000040;">/</span>sql<span style="color: #000040;">/</span>sql_yacc.<span style="color: #007788;">yy</span>	<span style="color: #0000dd;">2011</span><span style="color: #000040;">-</span><span style="color: #0000dd;">12</span><span style="color: #000040;">-</span><span style="color: #0000dd;">20</span> <span style="color: #208080;">06</span><span style="color: #008080;">:</span><span style="color: #0000dd;">38</span><span style="color: #008080;">:</span><span style="color:#800080;">58.000000000</span> <span style="color: #000040;">+</span><span style="color:#800080;">0800</span>
<span style="color: #000040;">+++</span> Percona<span style="color: #000040;">-</span>Server<span style="color: #000040;">-</span>5.5.18<span style="color: #000040;">-</span><span style="color:#800080;">23.0</span><span style="color: #000040;">-</span>debug<span style="color: #000040;">/</span>sql<span style="color: #000040;">/</span>sql_yacc.<span style="color: #007788;">yy</span>	<span style="color: #0000dd;">2012</span><span style="color: #000040;">-</span><span style="color: #208080;">01</span><span style="color: #000040;">-</span><span style="color: #0000dd;">17</span> <span style="color: #0000dd;">14</span><span style="color: #008080;">:</span><span style="color: #0000dd;">45</span><span style="color: #008080;">:</span><span style="color:#800080;">47.000000000</span> <span style="color: #000040;">+</span><span style="color:#800080;">0800</span>
@@ <span style="color: #000040;">-</span><span style="color: #0000dd;">3878</span>,<span style="color: #0000dd;">6</span> <span style="color: #000040;">+</span><span style="color: #0000dd;">3878</span>,<span style="color: #0000dd;">14</span> @@
           <span style="color: #008000;">&#123;</span> 
             Lex<span style="color: #000040;">-</span><span style="color: #000040;">&amp;</span>gt<span style="color: #008080;">;</span>alter_tablespace_info<span style="color: #000040;">-</span><span style="color: #000040;">&amp;</span>gt<span style="color: #008080;">;</span>ts_alter_tablespace_type<span style="color: #000080;">=</span> ALTER_TABLESPACE_DROP_FILE<span style="color: #008080;">;</span> 
           <span style="color: #008000;">&#125;</span>
<span style="color: #000040;">+</span>        <span style="color: #ff0000; font-style: italic;">/* innodb_extent_tablespace By P.Linux */</span>
<span style="color: #000040;">+</span>        <span style="color: #000040;">|</span> tablespace_name
<span style="color: #000040;">+</span>          SET
<span style="color: #000040;">+</span>          opt_ts_extent_size
<span style="color: #000040;">+</span>          <span style="color: #008000;">&#123;</span>
<span style="color: #000040;">+</span>            Lex<span style="color: #000040;">-</span><span style="color: #000040;">&amp;</span>gt<span style="color: #008080;">;</span>alter_tablespace_info<span style="color: #000040;">-</span><span style="color: #000040;">&amp;</span>gt<span style="color: #008080;">;</span>ts_alter_tablespace_type<span style="color: #000080;">=</span> ALTER_TABLESPACE_ALTER_FILE<span style="color: #008080;">;</span>
<span style="color: #000040;">+</span>          <span style="color: #008000;">&#125;</span>
<span style="color: #000040;">+</span>        <span style="color: #ff0000; font-style: italic;">/* End */</span>
         <span style="color: #008080;">;</span>
&nbsp;
 logfile_group_info<span style="color: #008080;">:</span>
<span style="color: #000040;">---</span> Percona<span style="color: #000040;">-</span>Server<span style="color: #000040;">-</span>5.5.18<span style="color: #000040;">-</span><span style="color:#800080;">23.0</span><span style="color: #000040;">/</span>sql<span style="color: #000040;">/</span>handler.<span style="color: #007788;">h</span>	<span style="color: #0000dd;">2011</span><span style="color: #000040;">-</span><span style="color: #0000dd;">12</span><span style="color: #000040;">-</span><span style="color: #0000dd;">20</span> <span style="color: #208080;">06</span><span style="color: #008080;">:</span><span style="color: #0000dd;">38</span><span style="color: #008080;">:</span><span style="color:#800080;">58.000000000</span> <span style="color: #000040;">+</span><span style="color:#800080;">0800</span>
<span style="color: #000040;">+++</span> Percona<span style="color: #000040;">-</span>Server<span style="color: #000040;">-</span>5.5.18<span style="color: #000040;">-</span><span style="color:#800080;">23.0</span><span style="color: #000040;">-</span>debug<span style="color: #000040;">/</span>sql<span style="color: #000040;">/</span>handler.<span style="color: #007788;">h</span>	<span style="color: #0000dd;">2012</span><span style="color: #000040;">-</span><span style="color: #208080;">01</span><span style="color: #000040;">-</span><span style="color: #0000dd;">17</span> <span style="color: #0000dd;">14</span><span style="color: #008080;">:</span><span style="color: #0000dd;">29</span><span style="color: #008080;">:</span><span style="color:#800080;">17.000000000</span> <span style="color: #000040;">+</span><span style="color:#800080;">0800</span>
@@ <span style="color: #000040;">-</span><span style="color: #0000dd;">501</span>,<span style="color: #0000dd;">7</span> <span style="color: #000040;">+</span><span style="color: #0000dd;">501</span>,<span style="color: #0000dd;">8</span> @@
 <span style="color: #008000;">&#123;</span>
   TS_ALTER_TABLESPACE_TYPE_NOT_DEFINED <span style="color: #000080;">=</span> <span style="color: #000040;">-</span><span style="color: #0000dd;">1</span>,
   ALTER_TABLESPACE_ADD_FILE <span style="color: #000080;">=</span> <span style="color: #0000dd;">1</span>,
<span style="color: #000040;">-</span>  ALTER_TABLESPACE_DROP_FILE <span style="color: #000080;">=</span> <span style="color: #0000dd;">2</span>
<span style="color: #000040;">+</span>  ALTER_TABLESPACE_DROP_FILE <span style="color: #000080;">=</span> <span style="color: #0000dd;">2</span>,
<span style="color: #000040;">+</span>  ALTER_TABLESPACE_ALTER_FILE <span style="color: #000080;">=</span> <span style="color: #0000dd;">3</span> <span style="color: #666666;">// innodb_extent_tablespace By P.Linux</span>
 <span style="color: #008000;">&#125;</span><span style="color: #008080;">;</span>
&nbsp;
 <span style="color: #0000ff;">enum</span> tablespace_access_mode
<span style="color: #000040;">---</span> Percona<span style="color: #000040;">-</span>Server<span style="color: #000040;">-</span>5.5.18<span style="color: #000040;">-</span><span style="color:#800080;">23.0</span><span style="color: #000040;">/</span>storage<span style="color: #000040;">/</span>innobase<span style="color: #000040;">/</span>fil<span style="color: #000040;">/</span>fil0fil.<span style="color: #007788;">c</span>	<span style="color: #0000dd;">2011</span><span style="color: #000040;">-</span><span style="color: #0000dd;">12</span><span style="color: #000040;">-</span><span style="color: #0000dd;">20</span> <span style="color: #208080;">06</span><span style="color: #008080;">:</span><span style="color: #0000dd;">38</span><span style="color: #008080;">:</span><span style="color:#800080;">57.000000000</span> <span style="color: #000040;">+</span><span style="color:#800080;">0800</span>
<span style="color: #000040;">+++</span> Percona<span style="color: #000040;">-</span>Server<span style="color: #000040;">-</span>5.5.18<span style="color: #000040;">-</span><span style="color:#800080;">23.0</span><span style="color: #000040;">-</span>debug<span style="color: #000040;">/</span>storage<span style="color: #000040;">/</span>innobase<span style="color: #000040;">/</span>fil<span style="color: #000040;">/</span>fil0fil.<span style="color: #007788;">c</span>	<span style="color: #0000dd;">2012</span><span style="color: #000040;">-</span><span style="color: #208080;">01</span><span style="color: #000040;">-</span><span style="color: #0000dd;">17</span> <span style="color: #0000dd;">14</span><span style="color: #008080;">:</span><span style="color: #0000dd;">31</span><span style="color: #008080;">:</span><span style="color:#800080;">40.000000000</span> <span style="color: #000040;">+</span><span style="color:#800080;">0800</span>
@@ <span style="color: #000040;">-</span><span style="color: #0000dd;">368</span>,<span style="color: #0000dd;">7</span> <span style="color: #000040;">+</span><span style="color: #0000dd;">368</span>,<span style="color: #0000dd;">8</span> @@
 Checks <span style="color: #0000ff;">if</span> a single<span style="color: #000040;">-</span>table tablespace <span style="color: #0000ff;">for</span> a given table name exists in the
 tablespace memory cache.
 @<span style="color: #0000ff;">return</span>	space id, ULINT_UNDEFINED <span style="color: #0000ff;">if</span> not found <span style="color: #000040;">*/</span>
<span style="color: #000040;">-</span><span style="color: #0000ff;">static</span>
<span style="color: #000040;">+</span><span style="color: #666666;">//static</span>
<span style="color: #000040;">+</span>UNIV_INTERN <span style="color: #666666;">// innodb_extent_tablespace By P.Linux</span>
 ulint
 fil_get_space_id_for_table<span style="color: #008000;">&#40;</span>
 <span style="color: #ff0000; font-style: italic;">/*=======================*/</span>
@@ <span style="color: #000040;">-</span><span style="color: #0000dd;">4676</span>,<span style="color: #0000dd;">7</span> <span style="color: #000040;">+</span><span style="color: #0000dd;">4677</span>,<span style="color: #0000dd;">8</span> @@
 Checks <span style="color: #0000ff;">if</span> a single<span style="color: #000040;">-</span>table tablespace <span style="color: #0000ff;">for</span> a given table name exists in the
 tablespace memory cache.
 @<span style="color: #0000ff;">return</span>	space id, ULINT_UNDEFINED <span style="color: #0000ff;">if</span> not found <span style="color: #000040;">*/</span>
<span style="color: #000040;">-</span><span style="color: #0000ff;">static</span>
<span style="color: #000040;">+</span><span style="color: #666666;">//static</span>
<span style="color: #000040;">+</span>UNIV_INTERN <span style="color: #666666;">// innodb_extent_tablespace By P.Linux</span>
 ulint
 fil_get_space_id_for_table<span style="color: #008000;">&#40;</span>
 <span style="color: #ff0000; font-style: italic;">/*=======================*/</span>
<span style="color: #000040;">---</span> Percona<span style="color: #000040;">-</span>Server<span style="color: #000040;">-</span>5.5.18<span style="color: #000040;">-</span><span style="color:#800080;">23.0</span><span style="color: #000040;">/</span>storage<span style="color: #000040;">/</span>innobase<span style="color: #000040;">/</span>handler<span style="color: #000040;">/</span>ha_innodb.<span style="color: #007788;">cc</span>	<span style="color: #0000dd;">2011</span><span style="color: #000040;">-</span><span style="color: #0000dd;">12</span><span style="color: #000040;">-</span><span style="color: #0000dd;">20</span> <span style="color: #208080;">06</span><span style="color: #008080;">:</span><span style="color: #0000dd;">38</span><span style="color: #008080;">:</span><span style="color:#800080;">58.000000000</span> <span style="color: #000040;">+</span><span style="color:#800080;">0800</span>
<span style="color: #000040;">+++</span> Percona<span style="color: #000040;">-</span>Server<span style="color: #000040;">-</span>5.5.18<span style="color: #000040;">-</span><span style="color:#800080;">23.0</span><span style="color: #000040;">-</span>debug<span style="color: #000040;">/</span>storage<span style="color: #000040;">/</span>innobase<span style="color: #000040;">/</span>handler<span style="color: #000040;">/</span>ha_innodb.<span style="color: #007788;">cc</span>	<span style="color: #0000dd;">2012</span><span style="color: #000040;">-</span><span style="color: #208080;">01</span><span style="color: #000040;">-</span><span style="color: #0000dd;">17</span> <span style="color: #0000dd;">14</span><span style="color: #008080;">:</span><span style="color: #0000dd;">37</span><span style="color: #008080;">:</span><span style="color:#800080;">49.000000000</span> <span style="color: #000040;">+</span><span style="color:#800080;">0800</span>
@@ <span style="color: #000040;">-</span><span style="color: #0000dd;">433</span>,<span style="color: #0000dd;">6</span> <span style="color: #000040;">+</span><span style="color: #0000dd;">434</span>,<span style="color: #0000dd;">12</span> @@
 <span style="color: #ff0000; font-style: italic;">/*=======================*/</span>
 	uint	flags<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
&nbsp;
<span style="color: #000040;">+</span><span style="color: #ff0000; font-style: italic;">/****************************************************************/</span><span style="color: #ff0000; font-style: italic;">/**
+Alter tablespace supported in an InnoDB table. Allow setting extent space. */</span>
<span style="color: #000040;">+</span><span style="color: #0000ff;">int</span> innobase_alter_tablespace<span style="color: #008000;">&#40;</span>handlerton <span style="color: #000040;">*</span>hton,
<span style="color: #000040;">+</span>                                THD<span style="color: #000040;">*</span> thd, st_alter_tablespace <span style="color: #000040;">*</span>alter_info<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
<span style="color: #000040;">+</span><span style="color: #ff0000; font-style: italic;">/* innodb_extent_tablespace By P.Linux */</span>
<span style="color: #000040;">+</span>
 <span style="color: #0000ff;">static</span> <span style="color: #0000ff;">const</span> <span style="color: #0000ff;">char</span> innobase_hton_name<span style="color: #008000;">&#91;</span><span style="color: #008000;">&#93;</span><span style="color: #000080;">=</span> <span style="color: #FF0000;">&quot;InnoDB&quot;</span><span style="color: #008080;">;</span>
&nbsp;
 <span style="color: #ff0000; font-style: italic;">/*************************************************************/</span><span style="color: #ff0000; font-style: italic;">/**
@@ -2489,6 +2496,7 @@
         innobase_hton-&amp;gt;flags=HTON_NO_FLAGS;
         innobase_hton-&amp;gt;release_temporary_latches=innobase_release_temporary_latches;
 	innobase_hton-&amp;gt;alter_table_flags = innobase_alter_table_flags;
+	innobase_hton-&amp;gt;alter_tablespace= innobase_alter_tablespace; // innodb_extent_tablespace By P.Linux
&nbsp;
 	ut_a(DATA_MYSQL_TRUE_VARCHAR == (ulint)MYSQL_TYPE_VARCHAR);
&nbsp;
@@ -3146,6 +3155,33 @@
 		| HA_INPLACE_ADD_PK_INDEX_NO_READ_WRITE);
 }
&nbsp;
+/****************************************************************/</span><span style="color: #ff0000; font-style: italic;">/**
+Alter tablespace supported in an InnoDB table. Allow setting extent space. */</span>
<span style="color: #000040;">+</span><span style="color: #0000ff;">int</span> innobase_alter_tablespace<span style="color: #008000;">&#40;</span>handlerton <span style="color: #000040;">*</span>hton,
<span style="color: #000040;">+</span>                                THD<span style="color: #000040;">*</span> thd, st_alter_tablespace <span style="color: #000040;">*</span>alter_info<span style="color: #008000;">&#41;</span>
<span style="color: #000040;">+</span><span style="color: #008000;">&#123;</span>
<span style="color: #000040;">+</span>       <span style="color: #0000ff;">if</span> <span style="color: #008000;">&#40;</span>alter_info<span style="color: #000040;">-</span><span style="color: #000040;">&amp;</span>gt<span style="color: #008080;">;</span>ts_alter_tablespace_type <span style="color: #000040;">!</span><span style="color: #000080;">=</span> ALTER_TABLESPACE_ALTER_FILE<span style="color: #008000;">&#41;</span>
<span style="color: #000040;">+</span>       <span style="color: #008000;">&#123;</span>
<span style="color: #000040;">+</span>               <span style="color: #0000ff;">return</span> HA_ADMIN_NOT_IMPLEMENTED<span style="color: #008080;">;</span>
<span style="color: #000040;">+</span>       <span style="color: #008000;">&#125;</span>
<span style="color: #000040;">+</span>
<span style="color: #000040;">+</span>       ulint table_space<span style="color: #000080;">=</span> fil_get_space_id_for_table<span style="color: #008000;">&#40;</span>alter_info<span style="color: #000040;">-</span><span style="color: #000040;">&amp;</span>gt<span style="color: #008080;">;</span>tablespace_name<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
<span style="color: #000040;">+</span>
<span style="color: #000040;">+</span>       <span style="color: #0000ff;">if</span> <span style="color: #008000;">&#40;</span>table_space <span style="color: #000080;">==</span> ULINT_UNDEFINED<span style="color: #008000;">&#41;</span>
<span style="color: #000040;">+</span>       <span style="color: #008000;">&#123;</span>
<span style="color: #000040;">+</span>               my_error<span style="color: #008000;">&#40;</span>ER_WRONG_TABLE_NAME, MYF<span style="color: #008000;">&#40;</span><span style="color: #0000dd;">0</span><span style="color: #008000;">&#41;</span>, alter_info<span style="color: #000040;">-</span><span style="color: #000040;">&amp;</span>gt<span style="color: #008080;">;</span>tablespace_name<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
<span style="color: #000040;">+</span>               <span style="color: #0000ff;">return</span> EE_FILENOTFOUND<span style="color: #008080;">;</span>
<span style="color: #000040;">+</span>       <span style="color: #008000;">&#125;</span>
<span style="color: #000040;">+</span>
<span style="color: #000040;">+</span>       ulint extent_size<span style="color: #000080;">=</span> alter_info<span style="color: #000040;">-</span><span style="color: #000040;">&amp;</span>gt<span style="color: #008080;">;</span>extent_size<span style="color: #008080;">;</span>
<span style="color: #000040;">+</span>       
<span style="color: #000040;">+</span>       ulint actual_size<span style="color: #000080;">=</span><span style="color: #0000dd;">0</span><span style="color: #008080;">;</span>
<span style="color: #000040;">+</span>       fil_extend_space_to_desired_size<span style="color: #008000;">&#40;</span><span style="color: #000040;">&amp;</span>amp<span style="color: #008080;">;</span>actual_size, table_space, extent_size<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
<span style="color: #000040;">+</span>
<span style="color: #000040;">+</span>       <span style="color: #0000ff;">return</span> <span style="color: #0000dd;">0</span><span style="color: #008080;">;</span>
<span style="color: #000040;">+</span><span style="color: #008000;">&#125;</span>
<span style="color: #000040;">+</span><span style="color: #ff0000; font-style: italic;">/* innodb_extent_tablespace By P.Linux */</span>
<span style="color: #000040;">+</span>
 <span style="color: #ff0000; font-style: italic;">/*****************************************************************/</span><span style="color: #ff0000; font-style: italic;">/**
 Commits a transaction in an InnoDB database. */</span>
 <span style="color: #0000ff;">static</span>
<span style="color: #000040;">---</span> Percona<span style="color: #000040;">-</span>Server<span style="color: #000040;">-</span>5.5.18<span style="color: #000040;">-</span><span style="color:#800080;">23.0</span><span style="color: #000040;">/</span>storage<span style="color: #000040;">/</span>innobase<span style="color: #000040;">/</span>include<span style="color: #000040;">/</span>fil0fil.<span style="color: #007788;">h</span>	<span style="color: #0000dd;">2011</span><span style="color: #000040;">-</span><span style="color: #0000dd;">12</span><span style="color: #000040;">-</span><span style="color: #0000dd;">20</span> <span style="color: #208080;">06</span><span style="color: #008080;">:</span><span style="color: #0000dd;">38</span><span style="color: #008080;">:</span><span style="color:#800080;">57.000000000</span> <span style="color: #000040;">+</span><span style="color:#800080;">0800</span>
<span style="color: #000040;">+++</span> Percona<span style="color: #000040;">-</span>Server<span style="color: #000040;">-</span>5.5.18<span style="color: #000040;">-</span><span style="color:#800080;">23.0</span><span style="color: #000040;">-</span>debug<span style="color: #000040;">/</span>storage<span style="color: #000040;">/</span>innobase<span style="color: #000040;">/</span>include<span style="color: #000040;">/</span>fil0fil.<span style="color: #007788;">h</span>	<span style="color: #0000dd;">2012</span><span style="color: #000040;">-</span><span style="color: #208080;">01</span><span style="color: #000040;">-</span><span style="color: #0000dd;">17</span> <span style="color: #0000dd;">14</span><span style="color: #008080;">:</span><span style="color: #0000dd;">39</span><span style="color: #008080;">:</span><span style="color:#800080;">20.000000000</span> <span style="color: #000040;">+</span><span style="color:#800080;">0800</span>
@@ <span style="color: #000040;">-</span><span style="color: #0000dd;">744</span>,<span style="color: #0000dd;">6</span> <span style="color: #000040;">+</span><span style="color: #0000dd;">744</span>,<span style="color: #0000dd;">18</span> @@
 <span style="color: #ff0000; font-style: italic;">/*============================*/</span>
 	ulint		id<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>	<span style="color: #ff0000; font-style: italic;">/*!&amp;lt; in: space id */</span>
&nbsp;
<span style="color: #000040;">+</span><span style="color: #ff0000; font-style: italic;">/*******************************************************************/</span><span style="color: #ff0000; font-style: italic;">/**
+Checks if a single-table tablespace for a given table name exists in the
+tablespace memory cache.
+@return        space id, ULINT_UNDEFINED if not found */</span>
<span style="color: #000040;">+</span>UNIV_INTERN
<span style="color: #000040;">+</span>ulint
<span style="color: #000040;">+</span>fil_get_space_id_for_table<span style="color: #008000;">&#40;</span>
<span style="color: #000040;">+</span><span style="color: #ff0000; font-style: italic;">/*=======================*/</span>
<span style="color: #000040;">+</span>       <span style="color: #0000ff;">const</span> <span style="color: #0000ff;">char</span><span style="color: #000040;">*</span>     name<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>  <span style="color: #ff0000; font-style: italic;">/*!&amp;lt; in: table name in the standard
+                               'databasename/tablename' format */</span>
<span style="color: #000040;">+</span><span style="color: #ff0000; font-style: italic;">/* innodb_extent_tablespace By P.Linux */</span>
<span style="color: #000040;">+</span>
 <span style="color: #ff0000; font-style: italic;">/*************************************************************************
 Return local hash table informations. */</span></pre></td></tr></table></div>

<h2>三、测试结果：</h2>
<h3>1. R910 Oracle单实例</h3>
<p>测试人：童家旺，支付宝<br />
TPS：稳定值2000,峰值2600 （我没参与测试，也没有报告，无法确定详情）<br />
我的补充：Oracle已经是调优的过的，请相信我们的Oracle <acronym title="Database Administrator">DBA</acronym>不是吃素的。我把听Oracle <acronym title="Database Administrator">DBA</acronym>描述的只言碎语随便写下，Oracle跑到后面TPS也是有所下降，不是能一直100%稳定，最后CPU已经吃尽了，所以基本上再怎么优化提升的幅度会比较小。</p>
<h3>2. R910 MySQL单实例 Percona 5.1.59 原版</h3>
<p>测试人：帝俊，支付宝<br />
TPS：峰值1500，无法稳定（具体不祥）<br />
测试人描述：<br />
目前的测试数据显示，由于MySQL在checkpoint上处理跟不上，不足以持续支持1.5K/s的事务数，10MB/s的redo量下的交易创建。该负载下，FIO的写出速度为160～190MB/s，写IOPS为2～2.3k，测试FIO的写吞吐量可以到600MB/s，写IOPS有8K+，需要进一步研究如何进一步提升系统的吞吐量。</p>
<h3>3. R910 MySQL多实例 Percona 5.1.60-13.1原版</h3>
<p>测试人：彭立勋，B2B<br />
TPS：峰值500*4（无法稳定），谷值100，均值450＊4<br />
重要配置：<br />
innodb_page_size=4K # 修改数据页大小与FusionIO匹配<br />
innodb_log_block_size=4K # 修改日志页大小于FusionIO匹配<br />
innodb_log_file_size=1G<br />
innodb_log_files_in_group=3<br />
innodb_buffer_pool_size=20G<br />
innodb_max_dirty_pages_pct=75<br />
innodb_flush_method=ALL_O_DIRECT # 修改文件写入方式全部为O_DIRECT<br />
innodb_read_io_threads=2<br />
innodb_write_io_threads=10<br />
innodb_io_capacity=20000<br />
innodb_extra_rsegments=16<br />
innodb_use_purge_thread=4<br />
innodb_adaptive_flushing_method=3 # 采用Keep_average刷新方式<br />
innodb_flush_neighbor_pages=0 # 不为了凑顺序IO刷相邻未修改的页<br />
测试人描述：<br />
每颗物理CPU绑定一个MySQL实例，四个实例同时接受测试。可以看到在测试过程中，IOPS抖动很大，在4K～17K之间抖动，可以判定，是Checkpoint机制不完善导致刷新间歇性繁忙，在IO闲置的时候不能充分发挥性能。但多实例可以提升整体TPS接近Oracle的均值，说明MySQL内部可能某些常量设置不合理，或者锁定力度太粗导致单实例不能充分发挥单机性能。</p>
<h3>4. R910 MySQL多实例 Percona 5.1.60-13.1 修改版</h3>
<p>测试人：彭立勋，B2B<br />
TPS：峰值1200*4，谷值0，均值950*4<br />
重要配置：（在测试3的基础上）<br />
innodb_aio_pending_ios_per_thread=1024<br />
测试人描述：<br />
经过对测试3的分析，可以发现，InnoDB已经标记了很多Page到Flush_list，但是并没有被即时的回写，可以在INNODB_BUFFER_POOL_PAGES系统表中发现很页flush_type=2，即在Flush_list中。<br />
经过review代码，发现InnoDB申请的AIO队列的长度只有256，由常量OS_AIO_N_PENDING_IOS_PER_THREAD（os0file.h）定义。将此常量修改为InnoDB的参数后，重新测试，可以使FusionIO的IOPS达到7K～18K，IO利用率得以提升，整体性能已经超越Oracle，但存在严重的低谷，大约每10s一次。</p>
<h3>5.R510 MySQL单实例 Percona 5.5.18-23.0 修改版</h3>
<p>测试人：彭立勋,B2B<br />
TPS：峰值2800，谷值2300，均值2500<br />
重要配置：（在测试3的基础上）<br />
innodb_aio_pending_ios_per_thread=512<br />
alter tablespace `trade/xxx` set extent_size=5000000; # 预先扩展数据文件<br />
测试人描述：<br />
根据测试4的结果进行分析，需要解决的主要问题就是抖动，抖动可能是两个原因导致的，一个是Checkpoint机制不完善，一个是数据文件扩展。Checkpoint机制不完善这个暂时无法改进，只能先解决数据文件扩展上的问题，采用淘宝丁奇的方法，对MySQL增加预先扩展文件的功能，在测试前先将文件扩展至测试写满需要的大小，使测试过程中无需扩展文件。<br />
实例测试中发现非常有效，抖动范围在2300～2800之间，可以接受。但是Buffer Pool一旦脏页写满，为了控制脏页量InnoDB就会加大刷新量，影响到TPS。实际上在脏页未满的时候，IOPS就没有用完，但是InnoDB计算刷新量并没有考虑操作系统反馈的影响信息，只是根据自己的redo产生量计算。<br />
<a href="http://www.yupoo.com/photos/plinux/84222190/" title="R510_1"><img src="http://pic.yupoo.com/plinux/BGH3jg5X/medish.jpg" alt="R510_1" width="533" height="462" border="0" /></a><br />
同时观察CPU还发现，2.6.18内核会将所有软中断发送到Core0上处理，这可能也是瓶颈之一。（当时忘记拷贝状态，这是后来确认内核问题看得，可以看这篇文章，一样的，<a href="http://dbahacker.com/linux/cpu%E8%BD%AF%E4%B8%AD%E6%96%AD%E5%AE%9E%E8%B7%B5%E4%B8%80" title="CPU软中断实践" target="_blank">CPU软中断实践</a>）<br />
03:05:17 PM CPU %user %nice %sys %iowait %irq %soft %steal %idle intr/s<br />
03:05:18 PM all 0.00 0.00 0.00 0.00 0.00 0.00 0.00 100.00 1014.00<br />
03:05:18 PM 0 0.00 0.00 0.00 0.00 0.00 0.00 0.00 100.00 1000.00</p>
<h3>6. R510 MySQL单实例 Percona 5.5.19-24.0 原版</h3>
<p>测试人：彭立勋，B2B<br />
TPS：峰值3100，谷值2400，均值2700<br />
重要配置：（在测试3的基础上）<br />
替换内核版本为2.6.32淘宝版，使用IO中断负载均衡。<br />
innodb_adaptive_flushing_method = 2<br />
innodb_flush_neighbor_pages = cont<br />
测试人描述：<br />
采用淘宝版内核后，可以发现每个CPU都被用的比较满：(部分)<br />
06:27:26 PM  CPU    %usr   %nice    %sys %iowait    %irq   %soft  %steal  %guest   %idle<br />
06:27:27 PM  all   69.80    0.00   18.68    0.51    0.00    0.17    0.00    0.00   10.84<br />
06:27:27 PM    0   74.75    0.00   17.17    0.00    0.00    0.00    0.00    0.00    8.08<br />
06:27:27 PM    1   73.96    0.00   16.67    1.04    0.00    0.00    0.00    0.00    8.33<br />
06:27:27 PM    2   73.20    0.00   17.53    1.03    0.00    0.00    0.00    0.00    8.25<br />
06:27:27 PM    3   71.72    0.00   19.19    1.01    0.00    0.00    0.00    0.00    8.08<br />
06:27:27 PM    4   71.43    0.00   18.37    1.02    0.00    0.00    0.00    0.00    9.18<br />
06:27:27 PM    5   70.71    0.00   19.19    1.01    0.00    0.00    0.00    0.00    9.09</p>
<p>这是个好现象，说明CPU被充分用起来了，在脏页未满之前，TPS可以比较稳定的维持在3000以上。但还是老问题，脏页一满，速度就下降，到测试结束时下降为2400。<br />
<a href="http://www.yupoo.com/photos/plinux/84222191/" title="R510_2"><img src="http://pic.yupoo.com/plinux/BGH3jipn/q6QVk.jpg" alt="R510_2" width="530" height="372" border="0" /></a></p>
<h2>四、测试结论：</h2>
<p>MySQL的调优与操作系统结合非常紧密，需要整体联动才能获得好的效果，InnoDB琐粒度较粗的缺陷，在代码实现简单的情况下，实际上对并发的影响不是很明显。<br />
目前MySQL对高速硬件的利用主要缺陷是，不少常量写死，Checkpoint机制不完善，Checkpoint刷新脏页&#8211;&gt;InnoDB AIO队列&#8211;&gt;操作系统IO队列&#8211;&gt;存储设备，中间任何一环存在问题，都可能导致性能下降。<br />
InnoDB AIO队列可以通过补丁开放参数设置，这个瓶颈已经消除。<br />
操作系统IO队列可以通过淘宝的内核补丁将中断分散到每个核上处理来解决。<br />
目前存在最大的问题就是Checkpoint刷新脏页的机制，仅仅依赖redo产生的速度，其实硬件IO还有很多余量，但InnoDB并不知道。<br />
如果能限定一种机型，限定一种操作系统，在MySQL内获取操作系统报告的硬件状态，自适应的决策自己的行为，这样可以充分利用系统资源，例如IO util%并不高的时候，即使脏页还没到阈值，也可以加大刷新量，充分利用IO，这样可能系统根本就达不到脏页阈值，可以一直保持搞TPS，至少可以延缓TPS下降的趋势。<br />
抖动问题则是Oracle和MySQL都存在的问题，扩展数据文件的瞬间必然导致TPS下降，淘宝丁奇的方法可以完美解决，Oracle也是类似的方法通过预先分配表空间文件解决。</p>
<h2>五、测试缺陷：</h2>
<p>测试CASE不全，没有在R910上测试5.5（虽然已经超了Oracle，但R910上应该还能猛一点），没有测试5.5多实例下可以获得何种性能，没有测试5.1在2.6.32内核下的表现，没有测试不同的页大小对InnoDB的影响。<br />
没有稳定性测试，原版+多实例 属于稳定方案，其他改动是否100%不影响稳定，尚需测试。<br />
在R910上的测试没有监控系统，也就没有图，坑爹了。</p>
<h2>六、后续Action</h2>
<p>在InnoDB控制刷赃页量的地方加入对系统diskstat的监控，当系统IO util%<80%的时候，增加(IO_CAPACITY-当前系统IO数-redo计算的刷新量)个页的刷新，在系统不忙的时候提前加大刷新量，期望保持TPS稳定。</p>
<h2>七、随意补充</h2>
<p>为什么读为主的应用不用担心IO用不完？因为读操作是同步IO，一旦请求就被发送到磁盘，所以只要并发够多，总能把IO压爆。但是写为了加速，几乎所有数据库都是先写到内存，再异步写到磁盘，当然你要是搞最大保护模式，应该也是有数据库可以直接同步写磁盘的，但是对大部分数据库都是先写内存，再异步到磁盘，所以如果异步IO这里存在设计上的瓶颈，不管加多少并发，都是徒劳，内存一旦写满，链接线程就都堵住了，要等异步IO消化完才能继续，所以对于写为主的应用，这个CASE都是很有参考价值的。</p><h2  class="related_post_title">类似的文章</h2><ul class="related_post"><li>2011年12月23日 -- <a href="http://www.penglixun.com/tech/database/server_kill_idle_transaction.html" title="在Server层实现Kill Idle Transaction">在Server层实现Kill Idle Transaction</a> (1)</li><li>2010年12月6日 -- <a href="http://www.penglixun.com/tech/database/percona_vs_mysql.html" title="Percona对MySQL标准版本的改进">Percona对MySQL标准版本的改进</a> (3)</li><li>2010年01月14日 -- <a href="http://www.penglixun.com/tech/database/xtradb_compile_error.html" title="XtraDB 1.0.6-9编译错误的解决">XtraDB 1.0.6-9编译错误的解决</a> (0)</li></ul>]]></content:encoded>
			<wfw:commentRss>http://www.penglixun.com/tech/database/case_about_innodb_faster_than_oracle.html/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>在Server层实现Kill Idle Transaction</title>
		<link>http://www.penglixun.com/tech/database/server_kill_idle_transaction.html</link>
		<comments>http://www.penglixun.com/tech/database/server_kill_idle_transaction.html#comments</comments>
		<pubDate>Fri, 23 Dec 2011 12:43:22 +0000</pubDate>
		<dc:creator>P.Linux</dc:creator>
				<category><![CDATA[数据库]]></category>
		<category><![CDATA[InnoDB]]></category>
		<category><![CDATA[kill_idle_transaction]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[patch]]></category>
		<category><![CDATA[Percona]]></category>
		<category><![CDATA[XtraDB]]></category>

		<guid isPermaLink="false">http://www.penglixun.com/?p=1230</guid>
		<description><![CDATA[本文内容遵从CC版权协议, 可以随意转载, 但必须以超链接形式标明文章原始出处和作者信息及版权声明网址: http://www.penglixun.com/tech/database/server_kill_idle_transaction.html 在上一篇文章里我们写了如... ]]></description>
			<content:encoded><![CDATA[<p><span style="color: #888888;">本文内容遵从<a href="http://creativecommons.org/licenses/by-nc-sa/3.0/deed.zh" target="_blank">CC版权协议</a>, 可以随意转载, 但必须以超链接形式标明文章原始出处和作者信息及版权声明</br>网址: http://www.penglixun.com/tech/database/server_kill_idle_transaction.html </p>
<p></span>在上一篇文章里我们写了如何针对InnoDB清理空闲事务《<a title="如何杀掉空闲事务" href="http://www.penglixun.com/tech/database/how_to_kill_idle_trx.html" target="_blank">如何杀掉空闲事务</a>》，在@sleebin9 的提示下，这个功能不仅可以针对InnoDB，也可以用于所有MySQL的事务引擎。</p>
<p>如何在Server层实现呢，sql/sql_parse.cc的do_command()函数是个好函数，连接线程会循环调用do_command()来读取并执行命令，在do_command()函数中，会调用my_net_set_read_timeout(net, thd->variables.net_wait_timeout)来设置线程socket连接超时时间，于是在这里可以下手。<br />
主要代码：</p>

<div class="wp_codebox"><table><tr id="p12307"><td class="code" id="p1230code7"><pre class="cpp" style="font-family:monospace;"><span style="color: #0000dd;">830</span>   <span style="color: #ff0000; font-style: italic;">/*
 831     This thread will do a blocking read from the client which
 832     will be interrupted when the next command is received from
 833     the client, the connection is closed or &quot;net_wait_timeout&quot;
 834     number of seconds has passed
 835   */</span>
 <span style="color: #0000dd;">836</span>   <span style="color: #ff0000; font-style: italic;">/* Add For Kill Idle Transaction By P.Linux */</span>
 <span style="color: #0000dd;">837</span>   <span style="color: #0000ff;">if</span> <span style="color: #008000;">&#40;</span>thd<span style="color: #000040;">-</span><span style="color: #000080;">&gt;</span>active_transaction<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span>
 <span style="color: #0000dd;">838</span>   <span style="color: #008000;">&#123;</span>
 <span style="color: #0000dd;">839</span>     <span style="color: #0000ff;">if</span> <span style="color: #008000;">&#40;</span>thd<span style="color: #000040;">-</span><span style="color: #000080;">&gt;</span>variables.<span style="color: #007788;">trx_idle_timeout</span> <span style="color: #000080;">&gt;</span> <span style="color: #0000dd;">0</span><span style="color: #008000;">&#41;</span>
 <span style="color: #0000dd;">840</span>     <span style="color: #008000;">&#123;</span>
 <span style="color: #0000dd;">841</span>       my_net_set_read_timeout<span style="color: #008000;">&#40;</span>net, thd<span style="color: #000040;">-</span><span style="color: #000080;">&gt;</span>variables.<span style="color: #007788;">trx_idle_timeout</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
 <span style="color: #0000dd;">842</span>     <span style="color: #008000;">&#125;</span> <span style="color: #0000ff;">else</span> <span style="color: #0000ff;">if</span> <span style="color: #008000;">&#40;</span>thd<span style="color: #000040;">-</span><span style="color: #000080;">&gt;</span>variables.<span style="color: #007788;">trx_readonly_idle_timeout</span> <span style="color: #000080;">&gt;</span> <span style="color: #0000dd;">0</span> <span style="color: #000040;">&amp;&amp;</span> thd<span style="color: #000040;">-</span><span style="color: #000080;">&gt;</span>is_readonly_trx<span style="color: #008000;">&#41;</span>
 <span style="color: #0000dd;">843</span>     <span style="color: #008000;">&#123;</span>
 <span style="color: #0000dd;">844</span>       my_net_set_read_timeout<span style="color: #008000;">&#40;</span>net, thd<span style="color: #000040;">-</span><span style="color: #000080;">&gt;</span>variables.<span style="color: #007788;">trx_readonly_idle_timeout</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
 <span style="color: #0000dd;">845</span>     <span style="color: #008000;">&#125;</span> <span style="color: #0000ff;">else</span> <span style="color: #0000ff;">if</span> <span style="color: #008000;">&#40;</span>thd<span style="color: #000040;">-</span><span style="color: #000080;">&gt;</span>variables.<span style="color: #007788;">trx_changes_idle_timeout</span> <span style="color: #000080;">&gt;</span> <span style="color: #0000dd;">0</span> <span style="color: #000040;">&amp;&amp;</span> <span style="color: #000040;">!</span>thd<span style="color: #000040;">-</span><span style="color: #000080;">&gt;</span>is_readonly_trx<span style="color: #008000;">&#41;</span>
 <span style="color: #0000dd;">846</span>     <span style="color: #008000;">&#123;</span>
 <span style="color: #0000dd;">847</span>       my_net_set_read_timeout<span style="color: #008000;">&#40;</span>net, thd<span style="color: #000040;">-</span><span style="color: #000080;">&gt;</span>variables.<span style="color: #007788;">trx_changes_idle_timeout</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
 <span style="color: #0000dd;">848</span>     <span style="color: #008000;">&#125;</span> <span style="color: #0000ff;">else</span> <span style="color: #008000;">&#123;</span>
 <span style="color: #0000dd;">849</span>       my_net_set_read_timeout<span style="color: #008000;">&#40;</span>net, thd<span style="color: #000040;">-</span><span style="color: #000080;">&gt;</span>variables.<span style="color: #007788;">net_wait_timeout</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
 <span style="color: #0000dd;">850</span>     <span style="color: #008000;">&#125;</span>
 <span style="color: #0000dd;">851</span>   <span style="color: #008000;">&#125;</span> <span style="color: #0000ff;">else</span> <span style="color: #008000;">&#123;</span>
 <span style="color: #0000dd;">852</span>     my_net_set_read_timeout<span style="color: #008000;">&#40;</span>net, thd<span style="color: #000040;">-</span><span style="color: #000080;">&gt;</span>variables.<span style="color: #007788;">net_wait_timeout</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
 <span style="color: #0000dd;">853</span>   <span style="color: #008000;">&#125;</span>
 <span style="color: #0000dd;">854</span>   <span style="color: #ff0000; font-style: italic;">/* End */</span></pre></td></tr></table></div>

<p>大家看明白了吗？其实这是偷梁换柱，本来在这里是要设置wait_timeout的，先判断线程是不是在事务里，就可以转而实现空闲事务的超时。</p>
<blockquote><p>    trx_idle_timeout 控制所有事务的超时，优先级最高<br />
    trx_changes_idle_timeout 控制非只读事务的超时<br />
    trx_readonly_idle_timeout 控制只读事务的超时</p></blockquote>
<p>效果：</p>

<div class="wp_codebox"><table><tr id="p12308"><td class="code" id="p1230code8"><pre class="sql" style="font-family:monospace;">root@localhost : <span style="color: #66cc66;">&#40;</span>none<span style="color: #66cc66;">&#41;</span> 08:<span style="color: #cc66cc;">39</span>:<span style="color: #cc66cc;">49</span><span style="color: #66cc66;">&gt;</span> <span style="color: #993333; font-weight: bold;">set</span> autocommit <span style="color: #66cc66;">=</span> <span style="color: #cc66cc;">0</span> ;
Query OK<span style="color: #66cc66;">,</span> <span style="color: #cc66cc;">0</span> rows affected <span style="color: #66cc66;">&#40;</span><span style="color: #cc66cc;">0.00</span> sec<span style="color: #66cc66;">&#41;</span>
&nbsp;
root@localhost : <span style="color: #66cc66;">&#40;</span>none<span style="color: #66cc66;">&#41;</span> 08:<span style="color: #cc66cc;">39</span>:<span style="color: #cc66cc;">56</span><span style="color: #66cc66;">&gt;</span> <span style="color: #993333; font-weight: bold;">set</span> trx_idle_timeout <span style="color: #66cc66;">=</span> <span style="color: #cc66cc;">5</span>;
Query OK<span style="color: #66cc66;">,</span> <span style="color: #cc66cc;">0</span> rows affected <span style="color: #66cc66;">&#40;</span><span style="color: #cc66cc;">0.00</span> sec<span style="color: #66cc66;">&#41;</span>
&nbsp;
root@localhost : <span style="color: #66cc66;">&#40;</span>none<span style="color: #66cc66;">&#41;</span> 08:<span style="color: #cc66cc;">40</span>:<span style="color: #cc66cc;">17</span><span style="color: #66cc66;">&gt;</span> <span style="color: #993333; font-weight: bold;">use</span> perf 
<span style="color: #993333; font-weight: bold;">Database</span> changed
root@localhost : perf 08:<span style="color: #cc66cc;">40</span>:<span style="color: #cc66cc;">19</span><span style="color: #66cc66;">&gt;</span> <span style="color: #993333; font-weight: bold;">insert</span> <span style="color: #993333; font-weight: bold;">into</span> perf <span style="color: #66cc66;">&#40;</span>info <span style="color: #66cc66;">&#41;</span> <span style="color: #993333; font-weight: bold;">values</span><span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">'11'</span><span style="color: #66cc66;">&#41;</span>;
Query OK<span style="color: #66cc66;">,</span> <span style="color: #cc66cc;">1</span> row affected <span style="color: #66cc66;">&#40;</span><span style="color: #cc66cc;">0.00</span> sec<span style="color: #66cc66;">&#41;</span>
&nbsp;
root@localhost : perf 08:<span style="color: #cc66cc;">40</span>:<span style="color: #cc66cc;">26</span><span style="color: #66cc66;">&gt;</span> <span style="color: #993333; font-weight: bold;">select</span> <span style="color: #66cc66;">*</span> <span style="color: #993333; font-weight: bold;">from</span> perf;
ERROR <span style="color: #cc66cc;">2006</span> <span style="color: #66cc66;">&#40;</span>HY000<span style="color: #66cc66;">&#41;</span>: MySQL server has gone away
No connection<span style="color: #66cc66;">.</span> Trying <span style="color: #993333; font-weight: bold;">to</span> reconnect<span style="color: #66cc66;">...</span>
Connection id:    <span style="color: #cc66cc;">6</span>
Current <span style="color: #993333; font-weight: bold;">database</span>: perf
&nbsp;
<span style="color: #66cc66;">+</span><span style="color: #808080; font-style: italic;">----+------+</span>
<span style="color: #66cc66;">|</span> id <span style="color: #66cc66;">|</span> info <span style="color: #66cc66;">|</span>
<span style="color: #66cc66;">+</span><span style="color: #808080; font-style: italic;">----+------+</span>
<span style="color: #66cc66;">|</span>  <span style="color: #cc66cc;">7</span> <span style="color: #66cc66;">|</span> aaaa <span style="color: #66cc66;">|</span>
<span style="color: #66cc66;">|</span>  <span style="color: #cc66cc;">9</span> <span style="color: #66cc66;">|</span> aaaa <span style="color: #66cc66;">|</span>
<span style="color: #66cc66;">|</span> <span style="color: #cc66cc;">11</span> <span style="color: #66cc66;">|</span> aaaa <span style="color: #66cc66;">|</span>
<span style="color: #66cc66;">+</span><span style="color: #808080; font-style: italic;">----+------+</span>
<span style="color: #cc66cc;">3</span> rows <span style="color: #993333; font-weight: bold;">in</span> <span style="color: #993333; font-weight: bold;">set</span> <span style="color: #66cc66;">&#40;</span><span style="color: #cc66cc;">0.00</span> sec<span style="color: #66cc66;">&#41;</span></pre></td></tr></table></div>

<p>完整的patch这里下载：<br />
Note: There is a file embedded within this post, please visit this post to download the file.</p><h2  class="related_post_title">类似的文章</h2><ul class="related_post"><li>2012年01月23日 -- <a href="http://www.penglixun.com/tech/database/case_about_innodb_faster_than_oracle.html" title="一个InnoDB性能超过Oracle的调优Case">一个InnoDB性能超过Oracle的调优Case</a> (1)</li><li>2010年12月6日 -- <a href="http://www.penglixun.com/tech/database/percona_vs_mysql.html" title="Percona对MySQL标准版本的改进">Percona对MySQL标准版本的改进</a> (3)</li><li>2010年01月14日 -- <a href="http://www.penglixun.com/tech/database/xtradb_compile_error.html" title="XtraDB 1.0.6-9编译错误的解决">XtraDB 1.0.6-9编译错误的解决</a> (0)</li></ul>]]></content:encoded>
			<wfw:commentRss>http://www.penglixun.com/tech/database/server_kill_idle_transaction.html/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>如何杀掉空闲事务</title>
		<link>http://www.penglixun.com/tech/database/how_to_kill_idle_trx.html</link>
		<comments>http://www.penglixun.com/tech/database/how_to_kill_idle_trx.html#comments</comments>
		<pubDate>Mon, 28 Nov 2011 17:01:19 +0000</pubDate>
		<dc:creator>P.Linux</dc:creator>
				<category><![CDATA[数据库]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[Percona]]></category>

		<guid isPermaLink="false">http://www.penglixun.com/?p=1229</guid>
		<description><![CDATA[本文内容遵从CC版权协议, 可以随意转载, 但必须以超链接形式标明文章原始出处和作者信息及版权声明网址: http://www.penglixun.com/tech/database/how_to_kill_idle_trx.html 我们经常遇到一个情况，就是网络... ]]></description>
			<content:encoded><![CDATA[<p><span style="color: #888888;">本文内容遵从<a href="http://creativecommons.org/licenses/by-nc-sa/3.0/deed.zh" target="_blank">CC版权协议</a>, 可以随意转载, 但必须以超链接形式标明文章原始出处和作者信息及版权声明</br>网址: http://www.penglixun.com/tech/database/how_to_kill_idle_trx.html </p>
<p></span>我们经常遇到一个情况，就是网络断开或程序Bug导致COMMIT/ROLLBACK语句没有传到数据库，也没有释放线程，但是线上事务锁定等待严重，连接数暴涨，尤其在测试库这种情况很多，线上也偶有发生，于是想为MySQL增加一个杀掉空闲事务的功能。</p>
<p>那么如何实现呢，通过MySQL Server层有很多不确定因素，最保险还是在存储引擎层实现，我们用的几乎都是InnoDB/XtraDB，所以就基于Percona来修改了，Oracle版的MySQL也可以照着修改。</p>
<p><strong>需求：</strong><br />
1. 一个事务启动，如果事务内最后一个语句执行完超过一个时间(innodb_idle_trx_timeout)，就应该关闭链接。<br />
2. 如果事务是纯读事务，因为不加锁，所以无害，不需要关闭，保持即可。<br />
虽然这个思路被Percona的指出Alexey Kopytov可能存在“Even though SELECT queries do not place row locks by default (there are exceptions), they can still block undo log records from being purged.”的问题，但是我们确实有场景SELECT是绝对不能kill的，除非之后的INSERT/UPDATE/DELETE发生了，所以我根据我们的业务特点来修改。<br />
跟Percona的Yasufumi Kinoshita和Alexey Kopytov提出过纯SELECT事务不应被kill，但通过一个参数控制的方案还没有被Alexey Kopytov接受，作为通用处理我提出了用两个变量分别控制纯读事务的空闲超时时间和有锁事务的空闲超时时间，还在等待Percona的回复，因为这个方案还在测试，就先不开放修改了，当然如果你很熟悉MYSQL源码，我提出这个思路你肯定知道怎么分成这两个参数控制了。</p>
<p>根据这两个需求我们来设计方法，首先想到这个功能肯定是放在InnoDB Master Thread最方便，Master Thread每秒调度一次，可以顺便检查空闲事务，然后关闭，因为在事务中操作trx->mysql_thd并不安全，所以一般来说最好在InnoDB层换成Thread ID操作，并且InnoDB中除了ha_innodb.cc，其他地方不能饮用THD，所以Master Thread中需要的线程数值，都需要在ha_innodb中计算好传递整型或布尔型返回值给master thread调用。<br />
<span id="more-1229"></span></p>
<p>首先，我们要增加一个参数：idle_trx_timeout，它表示事务多久没有下一条语句发生就超时关闭。<br />
在storage/innodb_plugin/srv/srv0srv.c的“<strong>/* plugin options */</strong>”注释下增加如下代码注册idle_trx_timeout变量。</p>

<div class="wp_codebox"><table><tr id="p122919"><td class="code" id="p1229code19"><pre class="cpp" style="font-family:monospace;"><span style="color: #0000ff;">static</span> MYSQL_SYSVAR_LONG<span style="color: #008000;">&#40;</span>idle_trx_timeout, srv_idle_trx_timeout,
  PLUGIN_VAR_RQCMDARG,
  <span style="color: #FF0000;">&quot;If zero then this function no effect, if no-zero then wait idle_trx_timeout seconds this transaction will be closed&quot;</span>,
  <span style="color: #FF0000;">&quot;Seconds of Idle-Transaction timeout&quot;</span>,
  <span style="color: #0000ff;">NULL</span>, <span style="color: #0000ff;">NULL</span>, <span style="color: #0000dd;">0</span>, <span style="color: #0000dd;">0</span>, <span style="color: #0000ff;">LONG_MAX</span>, <span style="color: #0000dd;">0</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span></pre></td></tr></table></div>

<p>代码往下找在innobase_system_variables结构体内加上：</p>

<div class="wp_codebox"><table><tr id="p122920"><td class="code" id="p1229code20"><pre class="cpp" style="font-family:monospace;">MYSQL_SYSVAR<span style="color: #008000;">&#40;</span>idle_trx_timeout<span style="color: #008000;">&#41;</span>,</pre></td></tr></table></div>

<p>有了这个变量，我们需要在Master Thread(storage/innodb_plugin/srv/srv0srv.c )中执行检测函数查找空闲事务。在loop循环的if (sync_array_print_long_waits(&#038;waiter, &#038;sema)判断后加上这段判断</p>

<div class="wp_codebox"><table><tr id="p122921"><td class="code" id="p1229code21"><pre class="cpp" style="font-family:monospace;">    <span style="color: #0000ff;">if</span> <span style="color: #008000;">&#40;</span>srv_idle_trx_timeout <span style="color: #000040;">&amp;&amp;</span> trx_sys<span style="color: #008000;">&#41;</span> <span style="color: #008000;">&#123;</span>
        trx_t<span style="color: #000040;">*</span>  trx<span style="color: #008080;">;</span>
        <span style="color: #0000ff;">time_t</span>  now<span style="color: #008080;">;</span>
rescan_idle<span style="color: #008080;">:</span>
        now <span style="color: #000080;">=</span> <span style="color: #0000dd;">time</span><span style="color: #008000;">&#40;</span><span style="color: #0000ff;">NULL</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
        mutex_enter<span style="color: #008000;">&#40;</span><span style="color: #000040;">&amp;</span>kernel_mutex<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
        trx <span style="color: #000080;">=</span> UT_LIST_GET_FIRST<span style="color: #008000;">&#40;</span>trx_sys<span style="color: #000040;">-</span><span style="color: #000080;">&gt;</span>mysql_trx_list<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> <span style="color: #339900;"># 从当前事务列表里获取第一个事务</span>
        <span style="color: #0000ff;">while</span> <span style="color: #008000;">&#40;</span>trx<span style="color: #008000;">&#41;</span> <span style="color: #008000;">&#123;</span> <span style="color: #339900;"># 依次循环每个事务进行检查</span>
            <span style="color: #0000ff;">if</span> <span style="color: #008000;">&#40;</span>trx<span style="color: #000040;">-</span><span style="color: #000080;">&gt;</span>conc_state <span style="color: #000080;">==</span> TRX_ACTIVE
                <span style="color: #000040;">&amp;&amp;</span> trx<span style="color: #000040;">-</span><span style="color: #000080;">&gt;</span>mysql_thd
                <span style="color: #000040;">&amp;&amp;</span> innobase_thd_is_idle<span style="color: #008000;">&#40;</span>trx<span style="color: #000040;">-</span><span style="color: #000080;">&gt;</span>mysql_thd<span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span> <span style="color: #008000;">&#123;</span> <span style="color: #339900;"># 如果事务还活着并且它的状态时空闲的</span>
&nbsp;
                ib_int64_t  start_time <span style="color: #000080;">=</span> innobase_thd_get_start_time<span style="color: #008000;">&#40;</span>trx<span style="color: #000040;">-</span><span style="color: #000080;">&gt;</span>mysql_thd<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> <span style="color: #339900;"># 获取线程最后一个语句的开始时间</span>
                ulong       thd_id <span style="color: #000080;">=</span> innobase_thd_get_thread_id<span style="color: #008000;">&#40;</span>trx<span style="color: #000040;">-</span><span style="color: #000080;">&gt;</span>mysql_thd<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> <span style="color: #339900;">#获取线程ID，因为存储引擎内直接操作THD不安全</span>
&nbsp;
                <span style="color: #0000ff;">if</span> <span style="color: #008000;">&#40;</span>trx<span style="color: #000040;">-</span><span style="color: #000080;">&gt;</span>last_stmt_start <span style="color: #000040;">!</span><span style="color: #000080;">=</span> start_time<span style="color: #008000;">&#41;</span> <span style="color: #008000;">&#123;</span> <span style="color: #339900;"># 如果事务最后语句起始时间不等于线程最后语句起始时间说明事务是新起的</span>
                    trx<span style="color: #000040;">-</span><span style="color: #000080;">&gt;</span>idle_start <span style="color: #000080;">=</span> now<span style="color: #008080;">;</span> <span style="color: #339900;"># 更新事务的空闲起始时间</span>
                    trx<span style="color: #000040;">-</span><span style="color: #000080;">&gt;</span>last_stmt_start <span style="color: #000080;">=</span> start_time<span style="color: #008080;">;</span> <span style="color: #339900;"># 更新事务的最后语句起始时间</span>
                <span style="color: #008000;">&#125;</span> <span style="color: #0000ff;">else</span> <span style="color: #0000ff;">if</span> <span style="color: #008000;">&#40;</span><span style="color: #0000dd;">difftime</span><span style="color: #008000;">&#40;</span>now, trx<span style="color: #000040;">-</span><span style="color: #000080;">&gt;</span>idle_start<span style="color: #008000;">&#41;</span> <span style="color: #339900;"># 如果事务不是新起的，已经执行了一部分则判断空闲时间有多长了</span>
                       <span style="color: #000080;">&gt;</span> srv_idle_trx_timeout<span style="color: #008000;">&#41;</span> <span style="color: #008000;">&#123;</span> <span style="color: #339900;"># 如果空闲时间超过阈值则杀掉链接</span>
                    <span style="color: #ff0000; font-style: italic;">/* kill the session */</span>
                    mutex_exit<span style="color: #008000;">&#40;</span><span style="color: #000040;">&amp;</span>kernel_mutex<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
                    thd_kill<span style="color: #008000;">&#40;</span>thd_id<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> <span style="color: #339900;"># 杀链接</span>
                    <span style="color: #0000ff;">goto</span> rescan_idle<span style="color: #008080;">;</span>
                <span style="color: #008000;">&#125;</span>
            <span style="color: #008000;">&#125;</span>
            trx <span style="color: #000080;">=</span> UT_LIST_GET_NEXT<span style="color: #008000;">&#40;</span>mysql_trx_list, trx<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> <span style="color: #339900;"># 检查下一个事务</span>
        <span style="color: #008000;">&#125;</span>
        mutex_exit<span style="color: #008000;">&#40;</span><span style="color: #000040;">&amp;</span>kernel_mutex<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
    <span style="color: #008000;">&#125;</span></pre></td></tr></table></div>

<p>其中trx中的变量是新加的，在storage/innodb_plugin/include/trx0trx.h的trx_truct加上需要的变量：</p>

<div class="wp_codebox"><table><tr id="p122922"><td class="code" id="p1229code22"><pre class="cpp" style="font-family:monospace;"><span style="color: #0000ff;">struct</span> trx_struct<span style="color: #008000;">&#123;</span>
...
    <span style="color: #0000ff;">time_t</span>      idle_start<span style="color: #008080;">;</span>
    ib_int64_t  last_stmt_start<span style="color: #008080;">;</span>
...
<span style="color: #008000;">&#125;</span></pre></td></tr></table></div>

<p>这里有几个函数是自定义的：</p>

<div class="wp_codebox"><table><tr id="p122923"><td class="code" id="p1229code23"><pre class="cpp" style="font-family:monospace;">ibool      innobase_thd_is_idle<span style="color: #008000;">&#40;</span><span style="color: #0000ff;">const</span> <span style="color: #0000ff;">void</span><span style="color: #000040;">*</span> thd<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
ib_int64_t innobase_thd_get_start_time<span style="color: #008000;">&#40;</span><span style="color: #0000ff;">const</span> <span style="color: #0000ff;">void</span><span style="color: #000040;">*</span> thd<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
ulong      innobase_thd_get_thread_id<span style="color: #008000;">&#40;</span><span style="color: #0000ff;">const</span> <span style="color: #0000ff;">void</span><span style="color: #000040;">*</span> thd<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span></pre></td></tr></table></div>

<p>这些函数在ha_innodb.cc中实现，需要在storage/innodb_plugin/srv/srv0srv.c头文件定义下加上这些函数的引用形势。</p>
<p>然后在storage/innodb_plugin/handler/ha_innodb.cc 中定义这些函数的实现：</p>

<div class="wp_codebox"><table><tr id="p122924"><td class="code" id="p1229code24"><pre class="cpp" style="font-family:monospace;"><span style="color: #0000ff;">extern</span> <span style="color: #FF0000;">&quot;C&quot;</span>
ibool
innobase_thd_is_idle<span style="color: #008000;">&#40;</span>
    <span style="color: #0000ff;">const</span> <span style="color: #0000ff;">void</span><span style="color: #000040;">*</span> thd<span style="color: #008000;">&#41;</span>    <span style="color: #ff0000; font-style: italic;">/*!&lt; in: thread handle (THD*) */</span>
<span style="color: #008000;">&#123;</span>
    <span style="color: #0000ff;">return</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#40;</span><span style="color: #0000ff;">const</span> THD<span style="color: #000040;">*</span><span style="color: #008000;">&#41;</span>thd<span style="color: #008000;">&#41;</span><span style="color: #000040;">-</span><span style="color: #000080;">&gt;</span>command <span style="color: #000080;">==</span> COM_SLEEP<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
<span style="color: #008000;">&#125;</span>
<span style="color: #0000ff;">extern</span> <span style="color: #FF0000;">&quot;C&quot;</span>
ib_int64_t
innobase_thd_get_start_time<span style="color: #008000;">&#40;</span>
    <span style="color: #0000ff;">const</span> <span style="color: #0000ff;">void</span><span style="color: #000040;">*</span> thd<span style="color: #008000;">&#41;</span>    <span style="color: #ff0000; font-style: italic;">/*!&lt; in: thread handle (THD*) */</span>
<span style="color: #008000;">&#123;</span>
    <span style="color: #0000ff;">return</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#40;</span>ib_int64_t<span style="color: #008000;">&#41;</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#40;</span><span style="color: #0000ff;">const</span> THD<span style="color: #000040;">*</span><span style="color: #008000;">&#41;</span>thd<span style="color: #008000;">&#41;</span><span style="color: #000040;">-</span><span style="color: #000080;">&gt;</span>start_time<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
<span style="color: #008000;">&#125;</span>
<span style="color: #0000ff;">extern</span> <span style="color: #FF0000;">&quot;C&quot;</span>
ulong
innobase_thd_get_thread_id<span style="color: #008000;">&#40;</span>
        <span style="color: #0000ff;">const</span> <span style="color: #0000ff;">void</span><span style="color: #000040;">*</span> thd<span style="color: #008000;">&#41;</span>
<span style="color: #008000;">&#123;</span>
    <span style="color: #0000ff;">return</span><span style="color: #008000;">&#40;</span>thd_get_thread_id<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#40;</span><span style="color: #0000ff;">const</span> THD<span style="color: #000040;">*</span><span style="color: #008000;">&#41;</span> thd<span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
<span style="color: #008000;">&#125;</span></pre></td></tr></table></div>

<p>还有最重要的thd_kill函数负责杀线程的，在sql/sql_class.cc中，找个地方定义这个函数：</p>

<div class="wp_codebox"><table><tr id="p122925"><td class="code" id="p1229code25"><pre class="cpp" style="font-family:monospace;"><span style="color: #0000ff;">void</span> thd_kill<span style="color: #008000;">&#40;</span>ulong id<span style="color: #008000;">&#41;</span>
<span style="color: #008000;">&#123;</span>
    THD <span style="color: #000040;">*</span>tmp<span style="color: #008080;">;</span>
    VOID<span style="color: #008000;">&#40;</span>pthread_mutex_lock<span style="color: #008000;">&#40;</span><span style="color: #000040;">&amp;</span>LOCK_thread_count<span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
    I_List_iterator<span style="color: #000080;">&lt;</span>THD<span style="color: #000080;">&gt;</span> it<span style="color: #008000;">&#40;</span>threads<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
    <span style="color: #0000ff;">while</span> <span style="color: #008000;">&#40;</span><span style="color: #008000;">&#40;</span>tmp<span style="color: #000080;">=</span>it<span style="color: #000040;">++</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span>
    <span style="color: #008000;">&#123;</span>
        <span style="color: #0000ff;">if</span> <span style="color: #008000;">&#40;</span>tmp<span style="color: #000040;">-</span><span style="color: #000080;">&gt;</span>command <span style="color: #000080;">==</span> COM_DAEMON <span style="color: #000040;">||</span> tmp<span style="color: #000040;">-</span><span style="color: #000080;">&gt;</span>is_have_lock_thd <span style="color: #000080;">==</span> <span style="color: #0000dd;">0</span> <span style="color: #008000;">&#41;</span> <span style="color: #339900;"># 如果是DAEMON线程和不含锁的线程就不要kill了</span>
            <span style="color: #0000ff;">continue</span><span style="color: #008080;">;</span>
        <span style="color: #0000ff;">if</span> <span style="color: #008000;">&#40;</span>tmp<span style="color: #000040;">-</span><span style="color: #000080;">&gt;</span>thread_id <span style="color: #000080;">==</span> id<span style="color: #008000;">&#41;</span>
        <span style="color: #008000;">&#123;</span>
            pthread_mutex_lock<span style="color: #008000;">&#40;</span><span style="color: #000040;">&amp;</span>tmp<span style="color: #000040;">-</span><span style="color: #000080;">&gt;</span>LOCK_thd_data<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
            <span style="color: #0000ff;">break</span><span style="color: #008080;">;</span>
        <span style="color: #008000;">&#125;</span>
    <span style="color: #008000;">&#125;</span>
    VOID<span style="color: #008000;">&#40;</span>pthread_mutex_unlock<span style="color: #008000;">&#40;</span><span style="color: #000040;">&amp;</span>LOCK_thread_count<span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
    <span style="color: #0000ff;">if</span> <span style="color: #008000;">&#40;</span>tmp<span style="color: #008000;">&#41;</span>
    <span style="color: #008000;">&#123;</span>
        tmp<span style="color: #000040;">-</span><span style="color: #000080;">&gt;</span>awake<span style="color: #008000;">&#40;</span>THD<span style="color: #008080;">::</span><span style="color: #007788;">KILL_CONNECTION</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
        pthread_mutex_unlock<span style="color: #008000;">&#40;</span><span style="color: #000040;">&amp;</span>tmp<span style="color: #000040;">-</span><span style="color: #000080;">&gt;</span>LOCK_thd_data<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
    <span style="color: #008000;">&#125;</span>
<span style="color: #008000;">&#125;</span></pre></td></tr></table></div>

<p>为了存储引擎能引用到这个函数，我们要把它定义到plugin中：<br />
include/mysql/plugin.h和include/mysql/plugin.h中加上</p>

<div class="wp_codebox"><table><tr id="p122926"><td class="code" id="p1229code26"><pre class="cpp" style="font-family:monospace;"><span style="color: #0000ff;">void</span> thd_kill<span style="color: #008000;">&#40;</span><span style="color: #0000ff;">unsigned</span> <span style="color: #0000ff;">long</span> id<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span></pre></td></tr></table></div>

<p>如何判定线程的is_have_lock_thd值？首先在THD中加上这个变量（sql/sql_class.cc）：</p>

<div class="wp_codebox"><table><tr id="p122927"><td class="code" id="p1229code27"><pre class="cpp" style="font-family:monospace;"><span style="color: #0000ff;">class</span> THD <span style="color: #008080;">:</span><span style="color: #0000ff;">public</span> Statement,
           <span style="color: #0000ff;">public</span> Open_tables_state
<span style="color: #008000;">&#123;</span>
....
  <span style="color: #007788;">uint16</span>    is_have_lock_thd<span style="color: #008080;">;</span>
....
<span style="color: #008000;">&#125;</span></pre></td></tr></table></div>

<p>然后在<acronym title="Structured Query Language">SQL</acronym>的必经之路mysql_execute_command拦上一刀，判断是有锁操作发生了还是事务提交或新起事务。</p>

<div class="wp_codebox"><table><tr id="p122928"><td class="code" id="p1229code28"><pre class="cpp" style="font-family:monospace;">  <span style="color: #0000ff;">switch</span> <span style="color: #008000;">&#40;</span>lex<span style="color: #000040;">-</span><span style="color: #000080;">&gt;</span>sql_command<span style="color: #008000;">&#41;</span> <span style="color: #008000;">&#123;</span>
  <span style="color: #0000ff;">case</span> SQLCOM_REPLACE<span style="color: #008080;">:</span>
  <span style="color: #0000ff;">case</span> SQLCOM_REPLACE_SELECT<span style="color: #008080;">:</span>
  <span style="color: #0000ff;">case</span> SQLCOM_UPDATE<span style="color: #008080;">:</span>
  <span style="color: #0000ff;">case</span> SQLCOM_UPDATE_MULTI<span style="color: #008080;">:</span>
  <span style="color: #0000ff;">case</span> SQLCOM_DELETE<span style="color: #008080;">:</span>
  <span style="color: #0000ff;">case</span> SQLCOM_DELETE_MULTI<span style="color: #008080;">:</span>
  <span style="color: #0000ff;">case</span> SQLCOM_INSERT<span style="color: #008080;">:</span>
  <span style="color: #0000ff;">case</span> SQLCOM_INSERT_SELECT<span style="color: #008080;">:</span>
      thd<span style="color: #000040;">-</span><span style="color: #000080;">&gt;</span>is_have_lock_thd <span style="color: #000080;">=</span> <span style="color: #0000dd;">1</span><span style="color: #008080;">;</span>
      <span style="color: #0000ff;">break</span><span style="color: #008080;">;</span>
  <span style="color: #0000ff;">case</span> SQLCOM_COMMIT<span style="color: #008080;">:</span>
  <span style="color: #0000ff;">case</span> SQLCOM_ROLLBACK<span style="color: #008080;">:</span>
  <span style="color: #0000ff;">case</span> SQLCOM_XA_START<span style="color: #008080;">:</span>
  <span style="color: #0000ff;">case</span> SQLCOM_XA_END<span style="color: #008080;">:</span>
  <span style="color: #0000ff;">case</span> SQLCOM_XA_PREPARE<span style="color: #008080;">:</span>
  <span style="color: #0000ff;">case</span> SQLCOM_XA_COMMIT<span style="color: #008080;">:</span>
  <span style="color: #0000ff;">case</span> SQLCOM_XA_ROLLBACK<span style="color: #008080;">:</span>
  <span style="color: #0000ff;">case</span> SQLCOM_XA_RECOVER<span style="color: #008080;">:</span>
      thd<span style="color: #000040;">-</span><span style="color: #000080;">&gt;</span>is_have_lock_thd <span style="color: #000080;">=</span> <span style="color: #0000dd;">0</span><span style="color: #008080;">;</span>
      <span style="color: #0000ff;">break</span><span style="color: #008080;">;</span>
  <span style="color: #008000;">&#125;</span></pre></td></tr></table></div>

<p>为了尽可能兼容Percona的补丁，能引用的都引用了Percona的操作，有些函数调用是在层次太多看不下去了就简化了。<br />
另外还有一个版本是我自己弄的，在THD中增加了一个last_sql_end_time，在do_command结束后更新last_sql_end_time，然后在事务中拿到THD查看last_sql_end_time就可以得出idle时间，Oracle版我还是建议这么做，不要去改trx_struct结构体了，那个感觉更危险。</p><h2  class="related_post_title">类似的文章</h2><ul class="related_post"><li>2012年01月23日 -- <a href="http://www.penglixun.com/tech/database/case_about_innodb_faster_than_oracle.html" title="一个InnoDB性能超过Oracle的调优Case">一个InnoDB性能超过Oracle的调优Case</a> (1)</li><li>2011年12月23日 -- <a href="http://www.penglixun.com/tech/database/server_kill_idle_transaction.html" title="在Server层实现Kill Idle Transaction">在Server层实现Kill Idle Transaction</a> (1)</li><li>2011年01月6日 -- <a href="http://www.penglixun.com/tech/database/icc_static_compile_percona.html" title="ICC静态编译Percona">ICC静态编译Percona</a> (9)</li></ul>]]></content:encoded>
			<wfw:commentRss>http://www.penglixun.com/tech/database/how_to_kill_idle_trx.html/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>MySQL的timeout那点事</title>
		<link>http://www.penglixun.com/tech/database/mysql_timeout.html</link>
		<comments>http://www.penglixun.com/tech/database/mysql_timeout.html#comments</comments>
		<pubDate>Thu, 24 Nov 2011 05:39:20 +0000</pubDate>
		<dc:creator>P.Linux</dc:creator>
				<category><![CDATA[数据库]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[timeout]]></category>

		<guid isPermaLink="false">http://www.penglixun.com/?p=1227</guid>
		<description><![CDATA[本文内容遵从CC版权协议, 可以随意转载, 但必须以超链接形式标明文章原始出处和作者信息及版权声明网址: http://www.penglixun.com/tech/database/mysql_timeout.html 因为最近遇到一些超时的问题，正好就... ]]></description>
			<content:encoded><![CDATA[<p><span style="color: #888888;">本文内容遵从<a href="http://creativecommons.org/licenses/by-nc-sa/3.0/deed.zh" target="_blank">CC版权协议</a>, 可以随意转载, 但必须以超链接形式标明文章原始出处和作者信息及版权声明</br>网址: http://www.penglixun.com/tech/database/mysql_timeout.html </p>
<p></span>因为最近遇到一些超时的问题，正好就把所有的timeout参数都理一遍，首先数据库里查一下看有哪些超时：</p>

<div class="wp_codebox"><table><tr id="p122731"><td class="code" id="p1227code31"><pre class="sql" style="font-family:monospace;">root@localhost : test <span style="color: #cc66cc;">12</span>:<span style="color: #cc66cc;">55</span>:<span style="color: #cc66cc;">50</span><span style="color: #66cc66;">&gt;</span> <span style="color: #993333; font-weight: bold;">show</span> global <span style="color: #993333; font-weight: bold;">variables</span> <span style="color: #993333; font-weight: bold;">like</span> <span style="color: #ff0000;">&quot;%timeout%&quot;</span>;
<span style="color: #66cc66;">+</span><span style="color: #808080; font-style: italic;">----------------------------+--------+</span>
<span style="color: #66cc66;">|</span> Variable_name              <span style="color: #66cc66;">|</span> Value  <span style="color: #66cc66;">|</span>
<span style="color: #66cc66;">+</span><span style="color: #808080; font-style: italic;">----------------------------+--------+</span>
<span style="color: #66cc66;">|</span> connect_timeout            <span style="color: #66cc66;">|</span> <span style="color: #cc66cc;">10</span>     <span style="color: #66cc66;">|</span>
<span style="color: #66cc66;">|</span> delayed_insert_timeout     <span style="color: #66cc66;">|</span> <span style="color: #cc66cc;">300</span>    <span style="color: #66cc66;">|</span>
<span style="color: #66cc66;">|</span> innodb_lock_wait_timeout   <span style="color: #66cc66;">|</span> <span style="color: #cc66cc;">120</span>    <span style="color: #66cc66;">|</span>
<span style="color: #66cc66;">|</span> innodb_rollback_on_timeout <span style="color: #66cc66;">|</span> <span style="color: #993333; font-weight: bold;">ON</span>     <span style="color: #66cc66;">|</span>
<span style="color: #66cc66;">|</span> interactive_timeout        <span style="color: #66cc66;">|</span> <span style="color: #cc66cc;">172800</span> <span style="color: #66cc66;">|</span>
<span style="color: #66cc66;">|</span> net_read_timeout           <span style="color: #66cc66;">|</span> <span style="color: #cc66cc;">30</span>     <span style="color: #66cc66;">|</span>
<span style="color: #66cc66;">|</span> net_write_timeout          <span style="color: #66cc66;">|</span> <span style="color: #cc66cc;">60</span>     <span style="color: #66cc66;">|</span>
<span style="color: #66cc66;">|</span> slave_net_timeout          <span style="color: #66cc66;">|</span> <span style="color: #cc66cc;">3600</span>   <span style="color: #66cc66;">|</span>
<span style="color: #66cc66;">|</span> table_lock_wait_timeout    <span style="color: #66cc66;">|</span> <span style="color: #cc66cc;">50</span>     <span style="color: #66cc66;">|</span> # 这个参数已经没用了
<span style="color: #66cc66;">|</span> wait_timeout               <span style="color: #66cc66;">|</span> <span style="color: #cc66cc;">172800</span> <span style="color: #66cc66;">|</span>
<span style="color: #66cc66;">+</span><span style="color: #808080; font-style: italic;">----------------------------+--------+</span></pre></td></tr></table></div>

<p>我们一个个来看</p>
<h2>connect_timeout</h2>
<p><strong>手册描述:</strong><br />
The number of seconds that the mysqld server waits for a connect packet before responding with Bad handshake. The default value is 10 seconds as of MySQL 5.1.23 and 5 seconds before that.<br />
Increasing the connect_timeout value might help if clients frequently encounter errors of the form Lost connection to MySQL server at &#8216;XXX&#8217;, system error: errno.<br />
<strong>解释：在获取链接时，等待握手的超时时间，只在登录时有效，登录成功这个参数就不管事了。主要是为了防止网络不佳时应用重连导致连接数涨太快，一般默认即可。</strong><br />
<br/></p>
<h2>delayed_insert_timeout</h2>
<p><strong>手册描述：</strong><br />
How many seconds an INSERT DELAYED handler thread should wait for INSERT statements before terminating.<br />
<strong>解释：这是为MyISAM INSERT DELAY设计的超时参数，在INSERT DELAY中止前等待INSERT语句的时间。</strong><br />
<br/></p>
<h2>innodb_lock_wait_timeout</h2>
<p><strong>手册描述：</strong><br />
The timeout in seconds an InnoDB transaction may wait for a row lock before giving up. The default value is 50 seconds. A transaction that tries to access a row that is locked by another InnoDB transaction will hang for at most this many seconds before issuing the following error:</p>

<div class="wp_codebox"><table><tr id="p122732"><td class="code" id="p1227code32"><pre class="sql" style="font-family:monospace;">ERROR <span style="color: #cc66cc;">1205</span> <span style="color: #66cc66;">&#40;</span>HY000<span style="color: #66cc66;">&#41;</span>: <span style="color: #993333; font-weight: bold;">Lock</span> wait timeout exceeded; try restarting transaction</pre></td></tr></table></div>

<p>When a lock wait timeout occurs, the current statement is not executed. The current transaction is not rolled back. (To have the entire transaction roll back, start the server with the &#8211;innodb_rollback_on_timeout option, available as of MySQL 5.1.15. See also Section 13.6.12, “InnoDB Error Handling”.)<br />
innodb_lock_wait_timeout applies to InnoDB row locks only. A MySQL table lock does not happen inside InnoDB and this timeout does not apply to waits for table locks.<br />
InnoDB does detect transaction deadlocks in its own lock table immediately and rolls back one transaction. The lock wait timeout value does not apply to such a wait.<br />
For the built-in InnoDB, this variable can be set only at server startup. For InnoDB Plugin, it can be set at startup or changed at runtime, and has both global and session values.<br />
<strong>解释：描述很长，简而言之，就是事务遇到锁等待时的Query超时时间。跟死锁不一样，InnoDB一旦检测到死锁立刻就会回滚代价小的那个事务，锁等待是没有死锁的情况下一个事务持有另一个事务需要的锁资源，被回滚的肯定是请求锁的那个Query。</strong><br />
<br/></p>
<h2>innodb_rollback_on_timeout</h2>
<p><strong>手册描述：</strong><br />
In MySQL 5.1, InnoDB rolls back only the last statement on a transaction timeout by default. If &#8211;innodb_rollback_on_timeout is specified, a transaction timeout causes InnoDB to abort and roll back the entire transaction (the same behavior as in MySQL 4.1). This variable was added in MySQL 5.1.15.<br />
<strong>解释：这个参数关闭或不存在的话遇到超时只回滚事务最后一个Query，打开的话事务遇到超时就回滚整个事务。</strong><br />
<br/></p>
<h2>interactive_timeout/wait_timeout</h2>
<p><strong>手册描述：</strong><br />
The number of seconds the server waits for activity on an interactive connection before closing it. An interactive client is defined as a client that uses the CLIENT_INTERACTIVE option to mysql_real_connect(). See also<br />
<strong>解释：一个持续SLEEP状态的线程多久被关闭。线程每次被使用都会被唤醒为acrivity状态，执行完Query后成为interactive状态，重新开始计时。wait_timeout不同在于只作用于TCP/<acronym title="Internet Protocol">IP</acronym>和Socket链接的线程，意义是一样的。</strong><br />
<br/></p>
<h2>net_read_timeout / net_write_timeout</h2>
<p><strong>手册描述：</strong><br />
The number of seconds to wait for more data from a connection before aborting the read. Before MySQL 5.1.41, this timeout applies only to TCP/<acronym title="Internet Protocol">IP</acronym> connections, not to connections made through Unix socket files, named pipes, or shared memory. When the server is reading from the client, net_read_timeout is the timeout value controlling when to abort. When the server is writing to the client, net_write_timeout is the timeout value controlling when to abort. See also slave_net_timeout.<br />
On Linux, the NO_ALARM build flag affects timeout behavior as indicated in the description of the net_retry_count system variable.<br />
<strong>解释：这个参数只对TCP/<acronym title="Internet Protocol">IP</acronym>链接有效，分别是数据库等待接收客户端发送网络包和发送网络包给客户端的超时时间，这是在Activity状态下的线程才有效的参数</strong><br />
<br/></p>
<h2>slave_net_timeout</h2>
<p><strong>手册描述：</strong><br />
The number of seconds to wait for more data from the master before the slave considers the connection broken, aborts the read, and tries to reconnect. The first retry occurs immediately after the timeout. The interval between retries is controlled by the MASTER_CONNECT_RETRY option for the CHANGE MASTER TO statement or &#8211;master-connect-retry option, and the number of reconnection attempts is limited by the &#8211;master-retry-count option. The default is 3600 seconds (one hour).<br />
<strong>解释：这是Slave判断主机是否挂掉的超时设置，在设定时间内依然没有获取到Master的回应就人为Master挂掉了</strong></p><h2  class="related_post_title">类似的文章</h2><ul class="related_post"><li>2012年01月23日 -- <a href="http://www.penglixun.com/tech/database/case_about_innodb_faster_than_oracle.html" title="一个InnoDB性能超过Oracle的调优Case">一个InnoDB性能超过Oracle的调优Case</a> (1)</li><li>2011年12月23日 -- <a href="http://www.penglixun.com/tech/database/server_kill_idle_transaction.html" title="在Server层实现Kill Idle Transaction">在Server层实现Kill Idle Transaction</a> (1)</li><li>2011年11月29日 -- <a href="http://www.penglixun.com/tech/database/how_to_kill_idle_trx.html" title="如何杀掉空闲事务">如何杀掉空闲事务</a> (1)</li></ul>]]></content:encoded>
			<wfw:commentRss>http://www.penglixun.com/tech/database/mysql_timeout.html/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>MySQL中创建及优化索引组织结构的思路</title>
		<link>http://www.penglixun.com/tech/database/think_about_mysql_create_and_optimize_index.html</link>
		<comments>http://www.penglixun.com/tech/database/think_about_mysql_create_and_optimize_index.html#comments</comments>
		<pubDate>Thu, 02 Jun 2011 08:22:26 +0000</pubDate>
		<dc:creator>P.Linux</dc:creator>
				<category><![CDATA[数据库]]></category>
		<category><![CDATA[Index]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[Optimize]]></category>

		<guid isPermaLink="false">http://www.penglixun.com/?p=1220</guid>
		<description><![CDATA[本文内容遵从CC版权协议, 可以随意转载, 但必须以超链接形式标明文章原始出处和作者信息及版权声明网址: http://www.penglixun.com/tech/database/think_about_mysql_create_and_optimize_index.html 原文链接：http://w... ]]></description>
			<content:encoded><![CDATA[<p><span style="color: #888888;">本文内容遵从<a href="http://creativecommons.org/licenses/by-nc-sa/3.0/deed.zh" target="_blank">CC版权协议</a>, 可以随意转载, 但必须以超链接形式标明文章原始出处和作者信息及版权声明</br>网址: http://www.penglixun.com/tech/database/think_about_mysql_create_and_optimize_index.html </p>
<p></span>原文链接：<a href="http://www.mysqlops.com/2011/05/23/mysql%E4%B8%AD%E5%88%9B%E5%BB%BA%E5%8F%8A%E4%BC%98%E5%8C%96%E7%B4%A2%E5%BC%95%E7%BB%84%E7%BB%87%E7%BB%93%E6%9E%84%E7%9A%84%E6%80%9D%E8%B7%AF.html">http://www.mysqlops.com/2011/05/23/mysql%E4%B8%AD%E5%88%9B%E5%BB%BA%E5%8F%8A%E4%BC%98%E5%8C%96%E7%B4%A2%E5%BC%95%E7%BB%84%E7%BB%87%E7%BB%93%E6%9E%84%E7%9A%84%E6%80%9D%E8%B7%AF.html</a></p>
<p>【导读】<br />
通过一个实际生产环境中的数据存取需求，分析如何设计此存储结构，如何操纵存储的数据，以及如何使操作的成本或代价更低，系统开销最小。同时，让更多初学者明白数据存储的表上索引是如何一个思路组织起来的，希望起到一个参考模板的价值作用。</p>
<p><strong>测试用例描述</strong><br />
测试用例为B2C领域，一张用于存储用户选购物品而生成的产品订单信息表，不过去掉一些其他字段，以便用于测试，其表中的数据项也不特别描述，字段意思见表</p>

<div class="wp_codebox"><table><tr id="p122035"><td class="code" id="p1220code35"><pre class="sql" style="font-family:monospace;"><span style="color: #993333; font-weight: bold;">USE</span> <span style="color: #ff0000;">`test`</span>;
<span style="color: #993333; font-weight: bold;">DROP</span> <span style="color: #993333; font-weight: bold;">TABLE</span> <span style="color: #993333; font-weight: bold;">IF</span> <span style="color: #993333; font-weight: bold;">EXISTS</span> <span style="color: #ff0000;">`test`</span><span style="color: #66cc66;">.</span><span style="color: #ff0000;">`goods_order`</span>;
<span style="color: #993333; font-weight: bold;">CREATE</span> <span style="color: #993333; font-weight: bold;">TABLE</span> <span style="color: #ff0000;">`goods_order`</span><span style="color: #66cc66;">&#40;</span>
<span style="color: #ff0000;">`order_id`</span>        INT <span style="color: #993333; font-weight: bold;">UNSIGNED</span>      <span style="color: #993333; font-weight: bold;">NOT</span> <span style="color: #993333; font-weight: bold;">NULL</span>             COMMENT ‘订单单号’<span style="color: #66cc66;">,</span>
<span style="color: #ff0000;">`goods_id`</span>        INT <span style="color: #993333; font-weight: bold;">UNSIGNED</span>      <span style="color: #993333; font-weight: bold;">NOT</span> <span style="color: #993333; font-weight: bold;">NULL</span> <span style="color: #993333; font-weight: bold;">DEFAULT</span> ’<span style="color: #cc66cc;">0</span>′ COMMENT ‘商品款号’<span style="color: #66cc66;">,</span>
<span style="color: #ff0000;">`order_type`</span>      TINYINT <span style="color: #993333; font-weight: bold;">UNSIGNED</span>  <span style="color: #993333; font-weight: bold;">NOT</span> <span style="color: #993333; font-weight: bold;">NULL</span> <span style="color: #993333; font-weight: bold;">DEFAULT</span> ’<span style="color: #cc66cc;">0</span>′ COMMENT ‘订单类型’<span style="color: #66cc66;">,</span>
<span style="color: #ff0000;">`order_status`</span>    TINYINT <span style="color: #993333; font-weight: bold;">UNSIGNED</span>  <span style="color: #993333; font-weight: bold;">NOT</span> <span style="color: #993333; font-weight: bold;">NULL</span> <span style="color: #993333; font-weight: bold;">DEFAULT</span> ’<span style="color: #cc66cc;">0</span>′ COMMENT ‘订单状态’<span style="color: #66cc66;">,</span>
<span style="color: #ff0000;">`color_id`</span>        SMALLINT  <span style="color: #993333; font-weight: bold;">UNSIGNED</span> <span style="color: #993333; font-weight: bold;">NOT</span> <span style="color: #993333; font-weight: bold;">NULL</span> <span style="color: #993333; font-weight: bold;">DEFAULT</span> ’<span style="color: #cc66cc;">0</span>′ COMMENT ‘颜色id’<span style="color: #66cc66;">,</span>
<span style="color: #ff0000;">`size_id`</span>         SMALLINT  <span style="color: #993333; font-weight: bold;">UNSIGNED</span> <span style="color: #993333; font-weight: bold;">NOT</span> <span style="color: #993333; font-weight: bold;">NULL</span> <span style="color: #993333; font-weight: bold;">DEFAULT</span> ’<span style="color: #cc66cc;">0</span>′ COMMENT ‘尺寸id’<span style="color: #66cc66;">,</span>
<span style="color: #ff0000;">`goods_number`</span>    MEDIUMINT  <span style="color: #993333; font-weight: bold;">UNSIGNED</span> <span style="color: #993333; font-weight: bold;">NOT</span> <span style="color: #993333; font-weight: bold;">NULL</span> <span style="color: #993333; font-weight: bold;">DEFAULT</span> ’<span style="color: #cc66cc;">0</span>′ COMMENT ‘数量’<span style="color: #66cc66;">,</span>
<span style="color: #ff0000;">`depot_id`</span>        INT <span style="color: #993333; font-weight: bold;">UNSIGNED</span>  <span style="color: #993333; font-weight: bold;">NOT</span> <span style="color: #993333; font-weight: bold;">NULL</span> <span style="color: #993333; font-weight: bold;">DEFAULT</span> ’<span style="color: #cc66cc;">0</span>′ COMMENT ‘仓库id’<span style="color: #66cc66;">,</span>
<span style="color: #ff0000;">`packet_id`</span>       INT <span style="color: #993333; font-weight: bold;">UNSIGNED</span>  <span style="color: #993333; font-weight: bold;">NOT</span> <span style="color: #993333; font-weight: bold;">NULL</span> <span style="color: #993333; font-weight: bold;">DEFAULT</span> ’<span style="color: #cc66cc;">0</span>′ COMMENT ‘储位code’<span style="color: #66cc66;">,</span>
<span style="color: #ff0000;">`gmt_create`</span>      TIMESTAMP     <span style="color: #993333; font-weight: bold;">NOT</span> <span style="color: #993333; font-weight: bold;">NULL</span> <span style="color: #993333; font-weight: bold;">DEFAULT</span> ’0000<span style="color: #66cc66;">-</span>00<span style="color: #66cc66;">-</span>00 00:00:00′ COMMENT ‘添加时间’<span style="color: #66cc66;">,</span>
<span style="color: #ff0000;">`gmt_modify`</span>      TIMESTAMP     <span style="color: #993333; font-weight: bold;">NOT</span> <span style="color: #993333; font-weight: bold;">NULL</span> <span style="color: #993333; font-weight: bold;">DEFAULT</span> ’0000<span style="color: #66cc66;">-</span>00<span style="color: #66cc66;">-</span>00 00:00:00′ COMMENT ‘更新时间’<span style="color: #66cc66;">,</span>
<span style="color: #993333; font-weight: bold;">PRIMARY</span> <span style="color: #993333; font-weight: bold;">KEY</span><span style="color: #66cc66;">&#40;</span>order_id<span style="color: #66cc66;">,</span><span style="color: #ff0000;">`goods_id`</span><span style="color: #66cc66;">&#41;</span>
<span style="color: #66cc66;">&#41;</span>ENGINE<span style="color: #66cc66;">=</span>InnoDB <span style="color: #993333; font-weight: bold;">AUTO_INCREMENT</span><span style="color: #66cc66;">=</span><span style="color: #cc66cc;">1</span> CHARACTER <span style="color: #993333; font-weight: bold;">SET</span> ‘utf8′ COLLATE ‘utf8_general_ci’;</pre></td></tr></table></div>

<p>其中，主键信息：PRIMARY KEY(order_id,`goods_id`)，为何主键索引索引字段的顺序为：order_id,`goods_id`，而不是： `goods_id`, order_id呢？原因很简单，goods_id在订单信息表中的重复率会比order_id高，也即order_id的筛选率更高，可以减少扫描索引记录个数，从而达到更高的效率，同时，下面即将会列出的<acronym title="Structured Query Language">SQL</acronym>也告诉我们，有部分<acronym title="Structured Query Language">SQL</acronym>语句的WHERE字句中只出现order_id字段，为此更加坚定我们必须把字段：order_id作为联合主键索引的头部，`goods_id`为联合主键索引的尾部。</p>
<p>数据存储表设计的小结：<br />
设计用于存储数据的表结构，首先要知道有哪些数据项，也即行内常说的数据流，以及各个数据项的属性，比如存储的数据类型、值域范围及长度、数据完整性等要求，从而确定数据项的属性定义。存储的数据项信息确定之后，至少进行如下三步分析：<br />
l  首先，确定哪些数据项或组合，可以作为记录的唯一性标志；<br />
l  其次，要确定对数据记录有哪些操作，每个操作的频率如何，对网站等类型应用，还需要区分前台操作和后台操作，也即分外部用户的操作，还是内部用户的操作；<br />
l  最后，对作为数据记录操作的条件部分的数据项，分析其数据项的筛选率如何，也即数据项不同值占总数据记录数的比例关心，比例越接近1则是筛选率越好，以及各个值得分布率；<br />
综上所述，再让数据修改性操作优先级别高于只读性操作，就可以创建一个满足要求且性能较好的索引组织结构。<br />
数据的存取设计,就涉及一块非常重要的知识: 关系数据库的基础知识和关系数据理论的范式。对于范式的知识点，特别解释下，建议学到BCNF范式为止，1NF、2NF、3NF和BCNF之间的差别，各自规避的问题、存在的缺陷都要一清二楚，但是在真实的工作环境中，不要任何存取设计都想向范式靠，用一句佛语准确点表达：空即是色，色即是空。</p>
<p><strong>用于生成测试数据的存储过程代码</strong><br />
创建索引，就离不开表存储的真实数据，为此编写一个存储过程近可能模拟真实生产环境中的数据，同时也方便大家使用此存储过程，在自己的测试环境中，真实感受验证，<br />
存储过程代码：</p>

<div class="wp_codebox"><table><tr id="p122036"><td class="code" id="p1220code36"><pre class="sql" style="font-family:monospace;">DELIMITER $$
<span style="color: #993333; font-weight: bold;">DROP</span> PROCEDURE <span style="color: #993333; font-weight: bold;">IF</span> <span style="color: #993333; font-weight: bold;">EXISTS</span> <span style="color: #ff0000;">`usp_make_data`</span> $$
<span style="color: #993333; font-weight: bold;">CREATE</span> PROCEDURE <span style="color: #ff0000;">`usp_make_data`</span><span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span>
BEGIN
DECLARE iv_goods_id INT <span style="color: #993333; font-weight: bold;">UNSIGNED</span> <span style="color: #993333; font-weight: bold;">DEFAULT</span> <span style="color: #cc66cc;">0</span>;
DECLARE iv_depot_id INT <span style="color: #993333; font-weight: bold;">UNSIGNED</span> <span style="color: #993333; font-weight: bold;">DEFAULT</span> <span style="color: #cc66cc;">0</span>;
DECLARE iv_packet_id INT <span style="color: #993333; font-weight: bold;">UNSIGNED</span> <span style="color: #993333; font-weight: bold;">DEFAULT</span> <span style="color: #cc66cc;">0</span>;
&nbsp;
<span style="color: #993333; font-weight: bold;">SET</span> iv_goods_id<span style="color: #66cc66;">=</span><span style="color: #cc66cc;">5000</span>;
<span style="color: #993333; font-weight: bold;">SET</span> iv_depot_id<span style="color: #66cc66;">=</span><span style="color: #cc66cc;">10</span>;
<span style="color: #993333; font-weight: bold;">SET</span> iv_packet_id<span style="color: #66cc66;">=</span><span style="color: #cc66cc;">20</span>;
&nbsp;
WHILE iv_goods_id&amp;gt;<span style="color: #cc66cc;">0</span>
DO
START  TRANSACTION;
WHILE iv_depot_id&amp;gt;<span style="color: #cc66cc;">0</span>
DO
WHILE iv_packet_id&amp;gt;<span style="color: #cc66cc;">0</span>
DO
<span style="color: #993333; font-weight: bold;">INSERT</span> <span style="color: #993333; font-weight: bold;">INTO</span> goods_order<span style="color: #66cc66;">&#40;</span>order_id<span style="color: #66cc66;">,</span>goods_id<span style="color: #66cc66;">,</span>order_type<span style="color: #66cc66;">,</span>order_status<span style="color: #66cc66;">,</span>color_id<span style="color: #66cc66;">,</span>size_id<span style="color: #66cc66;">,</span>goods_number<span style="color: #66cc66;">,</span>depot_id<span style="color: #66cc66;">,</span>packet_id<span style="color: #66cc66;">,</span>gmt_create<span style="color: #66cc66;">,</span>gmt_modify<span style="color: #66cc66;">&#41;</span>
<span style="color: #993333; font-weight: bold;">VALUES</span><span style="color: #66cc66;">&#40;</span>SUBSTRING<span style="color: #66cc66;">&#40;</span>RAND<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">,</span><span style="color: #cc66cc;">3</span><span style="color: #66cc66;">,</span><span style="color: #cc66cc;">8</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">,</span>iv_goods_id<span style="color: #66cc66;">,</span>SUBSTRING<span style="color: #66cc66;">&#40;</span>RAND<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">,</span><span style="color: #cc66cc;">3</span><span style="color: #66cc66;">,</span><span style="color: #cc66cc;">1</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">,</span>SUBSTRING<span style="color: #66cc66;">&#40;</span>RAND<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">,</span><span style="color: #cc66cc;">5</span><span style="color: #66cc66;">,</span><span style="color: #cc66cc;">1</span><span style="color: #66cc66;">&#41;</span>%2<span style="color: #66cc66;">,</span>SUBSTRING<span style="color: #66cc66;">&#40;</span>RAND<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">,</span><span style="color: #cc66cc;">3</span><span style="color: #66cc66;">,</span><span style="color: #cc66cc;">3</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">,</span>SUBSTRING<span style="color: #66cc66;">&#40;</span>RAND<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">,</span><span style="color: #cc66cc;">4</span><span style="color: #66cc66;">,</span><span style="color: #cc66cc;">3</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">,</span>SUBSTRING<span style="color: #66cc66;">&#40;</span>RAND<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">,</span><span style="color: #cc66cc;">5</span><span style="color: #66cc66;">,</span><span style="color: #cc66cc;">2</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">,</span>
iv_depot_id<span style="color: #66cc66;">,</span>SUBSTRING<span style="color: #66cc66;">&#40;</span>RAND<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">,</span><span style="color: #cc66cc;">4</span><span style="color: #66cc66;">,</span><span style="color: #cc66cc;">2</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">*</span>iv_packet_id<span style="color: #66cc66;">,</span>DATE_ADD<span style="color: #66cc66;">&#40;</span>NOW<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">,</span>INTERVAL <span style="color: #66cc66;">-</span>SUBSTRING<span style="color: #66cc66;">&#40;</span>RAND<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">,</span><span style="color: #cc66cc;">2</span><span style="color: #66cc66;">,</span><span style="color: #cc66cc;">3</span><span style="color: #66cc66;">&#41;</span> DAY<span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">,</span>DATE_ADD<span style="color: #66cc66;">&#40;</span>NOW<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">,</span>INTERVAL <span style="color: #66cc66;">-</span>SUBSTRING<span style="color: #66cc66;">&#40;</span>RAND<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">,</span><span style="color: #cc66cc;">3</span><span style="color: #66cc66;">,</span><span style="color: #cc66cc;">2</span><span style="color: #66cc66;">&#41;</span> DAY<span style="color: #66cc66;">&#41;</span>
<span style="color: #66cc66;">&#41;</span>;
<span style="color: #993333; font-weight: bold;">SET</span> iv_packet_id<span style="color: #66cc66;">=</span>iv_packet_id<span style="color: #66cc66;">-</span><span style="color: #cc66cc;">1</span>;
END WHILE;
<span style="color: #993333; font-weight: bold;">SET</span> iv_packet_id<span style="color: #66cc66;">=</span><span style="color: #cc66cc;">20</span>;
<span style="color: #993333; font-weight: bold;">SET</span> iv_depot_id<span style="color: #66cc66;">=</span>iv_depot_id<span style="color: #66cc66;">-</span><span style="color: #cc66cc;">1</span>;
END WHILE ;
&nbsp;
COMMIT;
<span style="color: #993333; font-weight: bold;">SET</span> iv_depot_id<span style="color: #66cc66;">=</span><span style="color: #cc66cc;">10</span>;
<span style="color: #993333; font-weight: bold;">SET</span> iv_goods_id<span style="color: #66cc66;">=</span>iv_goods_id<span style="color: #66cc66;">-</span><span style="color: #cc66cc;">1</span>;
END WHILE ;
END $$
DELIMITER ;</pre></td></tr></table></div>

<p><strong>业务逻辑描述</strong><br />
l  非注册用户，或网站的注册用户不登陆，都能可选购买物品，生成订单号对应的用户UID为系统默认的；<br />
l  订单与用户UID关联、描述等信息，存储其它的表中，通过订单号的模式关联；<br />
l  用户的订单信息，在未付款之前都可以再修改，付款之后则无法修改；<br />
l  已经付费的订单信息，自动发送到物流部门，进行后续工序的操作。处理完毕之后，会更新订单中涉及物品的存储位置信息；<br />
l  定期读取部分数据到数据仓库分析系统，用于统计分析；<br />
l  个人订单查询，前后台都有；<br />
l  购物记录查询显示；</p>
<p><strong>根据业务规则描述需要使用操纵数据的<acronym title="Structured Query Language">SQL</acronym>语句</strong><br />
(1).      EXPLAIN SELECT * FROM goods_order WHERE `order_id`=40918986;<br />
(2).      SELECT * FROM goods_order WHERE `order_id` IN (40918986,40717328,30923040…) ORDER BY gmt_modify DESC;<br />
(3).      UPDATE goods_order SET gmt_modify=NOW(),…. WHERE  `order_id`=40717328 AND goods_id=4248;<br />
(4).      SELECT COUNT(*) FROM goods_order WHERE depot_id=0 ORDER BY gmt_modify DESC LIMIT 0,50;<br />
(5).      SELECT * FROM goods_order WHERE depot_id=6 AND packet_id=0 ORDER BY gmt_modify DESC LIMIT 0,50;<br />
(6).      SELECT COUNT(*) FROM goods_order WHERE goods_id=4248 AND order_status=0 AND order_type=1<br />
(7).      SELECT * FROM goods_order WHERE goods_id=4248 AND order_status=0 AND order_type=1 ORDER BY gmt_modify DESC LIMIT 0,50;<br />
(8).      SELECT * FROM goods_order WHERE gmt_modify&gt;=’ 2011-04-06’;<br />
8条<acronym title="Structured Query Language">SQL</acronym>语句按触发其执行的用户分类：<br />
l   前台用户点击触发的操作而会执行的<acronym title="Structured Query Language">SQL</acronym>语句为：(1)、(2)、(3)；<br />
l   后台内部用户点击触发的操作而会执行的<acronym title="Structured Query Language">SQL</acronym>语句为：(1)、(2)、(3)、(4)、(5)、(6)、(7)；<br />
l   后台系统自动定期执行：(4)、(5)、(6)、(7)，工作时间正常情况每隔15分钟执行一次，以检查是否有已付款而没有准备货物的订单、是否有收款而未发货的订单等;<br />
l  统计分析系统定期导出数据而执行的<acronym title="Structured Query Language">SQL</acronym>语句为：(8)，频率为每24小时一次；<br />
我们再分析上述列出来的<acronym title="Structured Query Language">SQL</acronym>，分为2类，一类是读操作的<acronym title="Structured Query Language">SQL</acronym>（备注：SELECT操作），另外一类为修改性操作（备注：UPDATE、DELETE操作），分别如下：<br />
SELECT 的WHERE子句、GROUP BY子、ORDER BY 子句和HAVING 子句中，出现的字段：<br />
(1).      order_id<br />
(2).      order_id+gmt_modify<br />
(3).      depot_id+gmt_modify<br />
(4).      depot_id+packet_id+gmt_modify<br />
(5).      goods_id+order_status+order_type<br />
(6).      goods_id+order_status+order_type+gmt_modify<br />
(7).      gmt_modify<br />
修改性操作的WHERE子句中出现的条件字段：<br />
(8).     order_id+ goods_id</p>
<p>我们已经存在主键索引：PRIMARY KEY(order_id,`goods_id`)，另外考虑到此表数据的操作以SELECT和INSERT为主，UPDATE的<acronym title="Structured Query Language">SQL</acronym>量其次，再根据上述<acronym title="Structured Query Language">SQL</acronym>语句，为此我们可以初步确定需要创建的索引：<br />
ALTER TABLE goods_order<br />
ADD INDEX idx_goodsID_orderType_orderStatus_gmtmodify(goods_id,order_type,order_status,gmt_modify),<br />
ADD INDEX idx_depotID_packetID_gmtmodify(depot_id,packet_id,gmt_modify);</p>
<p>总结：<br />
文章中也分析了为何联合主键索引的顺序为：order_id,`goods_id`，再补充下作为主键的联合索引的字段属性的其他特性：字段值写入之后不变化、字段值长度短且最好为数值类型；<br />
对于编号<acronym title="Structured Query Language">SQL</acronym>：(8)，每天按更新日期读取一次数据的操作，以采用全表扫描的方式实现，牺牲其数据读取的性能，以减少更新字段修改日期的值而带来的索引维护开销；<br />
对于编号<acronym title="Structured Query Language">SQL</acronym>：(4)、(5)，考虑到每次都是读取最新的５０条记录，以及读取的数据基本上可肯定为热数据，为此不得不牺牲其中一条<acronym title="Structured Query Language">SQL</acronym>的数据读取性能，而少创建一个联合索引，从而减少维护索引字段的IO量；<br />
对于编号<acronym title="Structured Query Language">SQL</acronym>：(6)、(7)，创建的联合索引，需要特别注意联合索引：idx_goodsID_orderType_orderStatus_gmtmodify(goods_id,order_type,order_status,gmt_modify)中的字段顺序，其中：<br />
l   goods_id字段的筛选率高于order_type,order_status，另外gmt_modify字段只出现在ORDER BY子句中，为此只有让goods_id字段作为联合索引的头部，以提高索引的筛选率，从而提高索引的效率，减少逻辑或物理的读。<br />
l   order_status字段只有0或1两种值，而order_type有多种，以及根据<acronym title="Structured Query Language">SQL</acronym>语句，必须order_type出现在联合中的位置要比order_status靠近头部；<br />
l   gmt_modify字段出现在ORDER BY子句中，为此必须放到联合索引字段的最后；</p>
<p>最后，再梳理一下从需求到设计存储结构，再到编写<acronym title="Structured Query Language">SQL</acronym>和创建索引结构，我们应该做的步骤：<br />
l   整理业务产生的数据流，读取数据的方式；<br />
l   整理清楚数据流中的每个数据项属性信息；<br />
l   分析业务指标，推测需要存储数据的规模（备注：一定要以多少<acronym title="Gigabyte">GB</acronym>作为容量单位）；<br />
l   选择可能用于支持业务的硬件设备和数据库架构；<br />
l   把所有可能操纵数据的条件和操作类型，都整理清楚；<br />
l   分析操纵数据条件字段各自的数据筛选率；<br />
l   权衡各个<acronym title="Structured Query Language">SQL</acronym>的性能和IO量，也即类似于哪个操作权重高一些，那些操作权重适当低一些；<br />
l   创建索引组织结构；<br />
l   收集测试和生产环境的反馈信息，优化索引组织结构；</p>
<p>备注：<br />
本想再用测试环境结合业务的方式，跑一套模拟测试脚本程序，让大家更加直观地看到不同索引组织情况下，相同的<acronym title="Structured Query Language">SQL</acronym>操作及频率，数据库服务器的处理能力和负载变化及对比信息，可惜唯一的服务器无法使用了，只好放弃。对于分析相同的<acronym title="Structured Query Language">SQL</acronym>，走不通索引，其需要的逻辑IO和物理IO量也是一个办法，此次就不分析了，有需要的朋友可以去玩玩，另外建议初学者一定要好好阅读下mysql 手册上的相关章节内容：7.2.6. Index Merge Optimization。</p><h2  class="related_post_title">类似的文章</h2><ul class="related_post"><li>2010年03月20日 -- <a href="http://www.penglixun.com/tech/database/mysql_index_store_perfomance_effect.html" title="MySQL索引与存储方式对性能的影响">MySQL索引与存储方式对性能的影响</a> (2)</li><li>2009年12月21日 -- <a href="http://www.penglixun.com/tech/database/mysql_virtual_function_index.html" title="给MySQL做虚拟的“函数索引”">给MySQL做虚拟的“函数索引”</a> (0)</li><li>2009年11月10日 -- <a href="http://www.penglixun.com/tech/database/mysql_index_check_script_preview.html" title="MySQL索引检查脚本预览">MySQL索引检查脚本预览</a> (0)</li></ul>]]></content:encoded>
			<wfw:commentRss>http://www.penglixun.com/tech/database/think_about_mysql_create_and_optimize_index.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>MySQL删除大表更快的DROP TABLE办法</title>
		<link>http://www.penglixun.com/tech/database/mysql_fast_drop_table_use_hard_lin.html</link>
		<comments>http://www.penglixun.com/tech/database/mysql_fast_drop_table_use_hard_lin.html#comments</comments>
		<pubDate>Thu, 02 Jun 2011 08:07:12 +0000</pubDate>
		<dc:creator>P.Linux</dc:creator>
				<category><![CDATA[数据库]]></category>
		<category><![CDATA[DROP]]></category>
		<category><![CDATA[MySQL]]></category>

		<guid isPermaLink="false">http://www.penglixun.com/?p=1215</guid>
		<description><![CDATA[本文内容遵从CC版权协议, 可以随意转载, 但必须以超链接形式标明文章原始出处和作者信息及版权声明网址: http://www.penglixun.com/tech/database/mysql_fast_drop_table_use_hard_lin.html 原文地址：http://www.mysqlo... ]]></description>
			<content:encoded><![CDATA[<p><span style="color: #888888;">本文内容遵从<a href="http://creativecommons.org/licenses/by-nc-sa/3.0/deed.zh" target="_blank">CC版权协议</a>, 可以随意转载, 但必须以超链接形式标明文章原始出处和作者信息及版权声明</br>网址: http://www.penglixun.com/tech/database/mysql_fast_drop_table_use_hard_lin.html </p>
<p></span>原文地址：<a href="http://www.mysqlops.com/2011/05/18/mysql%E5%88%A0%E9%99%A4%E5%A4%A7%E8%A1%A8%E6%9B%B4%E5%BF%AB%E7%9A%84drop-table%E5%8A%9E%E6%B3%95.html">http://www.mysqlops.com/2011/05/18/mysql%E5%88%A0%E9%99%A4%E5%A4%A7%E8%A1%A8%E6%9B%B4%E5%BF%AB%E7%9A%84drop-table%E5%8A%9E%E6%B3%95.html</a></p>
<p>&nbsp;</p>
<p>曾经发文介绍过，DROP table XXX ,特别是碰到大表时，<br />
<a href="http://www.mysqlops.com/2011/02/18/mysql-drop-table-%e5%a4%84%e7%90%86%e8%bf%87%e7%a8%8b.html">http://www.mysqlops.com/2011/02/18/mysql-drop-table-%e5%a4%84%e7%90%86%e8%bf%87%e7%a8%8b.html</a><br />
在DROP TABLE 过程中，所有操作都会被HANG住。<br />
这是因为INNODB会维护一个全局独占锁（在table cache上面），直到DROP TABLE完成才释放。<br />
在我们常用的ext3,ext4，ntfs文件系统，要删除一个大文件（几十G，甚至几百G）还是需要点时间的。<br />
下面我们介绍一个快速DROP table 的方法； 不管多大的表,INNODB 都可以很快返回，表删除完成；<br />
实现：巧用LINK（硬链接）</p>
<p>实测：</p>
<p><a href="mailto:root@127.0.0.1">root@127.0.0.1</a> : test 21:38:00&gt; show table status like ‘tt’ \G<br />
*************************** 1. row ***************************<br />
Name: tt<br />
Engine: InnoDB<br />
Version: 10<br />
Row_format: Compact<br />
Rows: 151789128<br />
Avg_row_length: 72<br />
Data_length: 11011096576<br />
Max_data_length: 0<br />
Index_length: 5206179840<br />
Data_free: 7340032<br />
Auto_increment: NULL<br />
Create_time: 2011-05-18 14:55:08<br />
Update_time: NULL<br />
Check_time: NULL<br />
Collation: utf8_general_ci<br />
Checksum: NULL<br />
Create_options:<br />
Comment:<br />
1 row in set (0.22 sec)</p>
<p><a href="mailto:root@127.0.0.1">root@127.0.0.1</a> : test 21:39:34&gt; drop table tt ;<br />
Query OK, 0 rows affected (25.01 sec)</p>
<p>删除一个11G的表用时25秒左右（硬件不同，时间不同）；</p>
<p>下面我们来对另一个更大的表进行删除；<br />
但之前，我们需要对这个表的数据文件做一个硬连接：</p>
<p>root@ # ln stock.ibd stock.id.hdlk<br />
root@ # ls stock.* -l<br />
-rw-rw—- 1 mysql mysql        9196 Apr 14 23:03 stock.frm<br />
-rw-r–r– 2 mysql mysql 19096666112 Apr 15 09:55 stock.ibd<br />
-rw-r–r– 2 mysql mysql 19096666112 Apr 15 09:55 stock.id.hdlk</p>
<p>你会发现stock.ibd的INODES属性变成了2；</p>
<p>下面我们继续来删表。</p>
<p><a href="mailto:root@127.0.0.1">root@127.0.0.1</a> : test 21:44:37&gt; show table status like ‘stock’ \G<br />
*************************** 1. row ***************************<br />
Name: stock<br />
Engine: InnoDB<br />
Version: 10<br />
Row_format: Compact<br />
Rows: 49916863<br />
Avg_row_length: 356<br />
Data_length: 17799577600<br />
Max_data_length: 0<br />
Index_length: 1025507328<br />
Data_free: 4194304<br />
Auto_increment: NULL<br />
Create_time: 2011-05-18 14:55:08<br />
Update_time: NULL<br />
Check_time: NULL<br />
Collation: utf8_general_ci<br />
Checksum: NULL<br />
Create_options:<br />
Comment:<br />
1 row in set (0.23 sec)</p>
<p><a href="mailto:root@127.0.0.1">root@127.0.0.1</a> : test 21:39:34&gt; drop table stock ;<br />
Query OK, 0 rows affected (0.99 sec)</p>
<p>1秒不到就删除完成； 也就是DROP TABLE不用再HANG这么久了。<br />
但table是删除了，数据文件还在，所以你还需要最后数据文件给删除。</p>
<p>root # ll<br />
total 19096666112<br />
-rw-r–r– 2 mysql mysql 19096666112 Apr 15 09:55 stock.id.hdlk<br />
root # rm stock.id.hdlk<br />
虽然DROP TABLE 多绕了几步。(如果你有一个比较可靠的自运行程序（自动为大表建立硬链接，并会自动删除过期的硬链接文件），就会显得不那么繁琐。)<br />
这样做能大大减少MYSQL HANG住的时间； 相信还是值得的。</p>
<p>至于原理: 就是利用<acronym title="Operating System">OS</acronym> HARD LINK的原理,<br />
当多个文件名同时指向同一个INODE时,这个INODE的引用数N&gt;1, 删除其中任何一个文件名都会很快.<br />
因为其直接的物理文件块没有被删除.只是删除了一个指针而已;<br />
当INODE的引用数N=1时, 删除文件需要去把这个文件相关的所有数据块清除,所以会比较耗时;</p>
<p>好了. 大家试试吧.</p><h2  class="related_post_title">类似的文章</h2><ul class="related_post"><li>2012年01月23日 -- <a href="http://www.penglixun.com/tech/database/case_about_innodb_faster_than_oracle.html" title="一个InnoDB性能超过Oracle的调优Case">一个InnoDB性能超过Oracle的调优Case</a> (1)</li><li>2011年12月23日 -- <a href="http://www.penglixun.com/tech/database/server_kill_idle_transaction.html" title="在Server层实现Kill Idle Transaction">在Server层实现Kill Idle Transaction</a> (1)</li><li>2011年11月29日 -- <a href="http://www.penglixun.com/tech/database/how_to_kill_idle_trx.html" title="如何杀掉空闲事务">如何杀掉空闲事务</a> (1)</li></ul>]]></content:encoded>
			<wfw:commentRss>http://www.penglixun.com/tech/database/mysql_fast_drop_table_use_hard_lin.html/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>自编译MySQL指南 2.0</title>
		<link>http://www.penglixun.com/tech/database/mysql_compile_reference.html</link>
		<comments>http://www.penglixun.com/tech/database/mysql_compile_reference.html#comments</comments>
		<pubDate>Wed, 13 Apr 2011 06:57:42 +0000</pubDate>
		<dc:creator>P.Linux</dc:creator>
				<category><![CDATA[数据库]]></category>
		<category><![CDATA[Compile]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[Reference]]></category>

		<guid isPermaLink="false">http://www.penglixun.com/?p=1211</guid>
		<description><![CDATA[本文内容遵从CC版权协议, 可以随意转载, 但必须以超链接形式标明文章原始出处和作者信息及版权声明网址: http://www.penglixun.com/tech/database/mysql_compile_reference.html 原文：http://www.mysqlops.com/2011/03/06... ]]></description>
			<content:encoded><![CDATA[<p><span style="color: #888888;">本文内容遵从<a href="http://creativecommons.org/licenses/by-nc-sa/3.0/deed.zh" target="_blank">CC版权协议</a>, 可以随意转载, 但必须以超链接形式标明文章原始出处和作者信息及版权声明</br>网址: http://www.penglixun.com/tech/database/mysql_compile_reference.html </p>
<p></span><strong>原文：<a href="http://www.mysqlops.com/2011/03/06/mysql_compile_reference.html">http://www.mysqlops.com/2011/03/06/mysql_compile_reference.html</a></strong></p>
<p>一般情况下，用户选择的MySQL安装方式为 RPM包 或 二进制压缩包，但是，通用安装包为了适应不同的软硬件平台，都会采用保守的编译方式，功能上也是选择最常用最稳定的功能编译入二进制版本。<br />
虽然这满足了大部分用户的需求，但是有时我们仅仅需要一部分功能（例如我们不需要Query Cache，但这个模块编译时不去掉的话，运行时依然会触发其代码清理Query Cache内存池，并引发过Bug），或者有性能更好的商业编译器（例如ICC），或者对源码做了修改时，就必须采用编译的方式来安装了。</p>
<p>下面我们就来介绍下如何从源码编译安装MySQL。<br />
<span id="more-1211"></span></p>
<p><strong>第一部分，选择编译参数</strong><br />
编译MySQL需要设置两种编译参数：GCC/ICC的编译参数，MySQL的编译参数。GCC/ICC编译参数是控制编译时编译器的优化动作，MySQL编译参数是控制MySQL功能模块的处理动作。</p>
<p>以Xeon 5520为例，55系列是Intel的Nehalem架构处理器，为了充分挖掘它的处理能力，我们做了很多的测试来尝试一些GCC的编译参数，如何获得更高的MySQL性能。</p>
<p>首先看处理器支持哪些flags：</p>
<blockquote><p>processor	: 15<br />
vendor_id	: GenuineIntel<br />
cpu family	: 6<br />
model		: 26<br />
model name	: Intel(R) Xeon(R) CPU           E5520  @ 2.27GHz<br />
stepping	: 5<br />
cpu <acronym title="Megahertz">MHz</acronym>		: 2261.088<br />
cache size	: 8192 <acronym title="Kilobyte">KB</acronym><br />
physical id	: 0<br />
siblings	: 8<br />
core id		: 3<br />
cpu cores	: 4<br />
apicid		: 7<br />
fpu		: yes<br />
fpu_exception	: yes<br />
cpuid level	: 11<br />
wp		: yes<br />
<strong>flags		: fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm syscall nx rdtscp lm constant_tsc ida pni monitor ds_cpl vmx est tm2 cx16 xtpr popcnt lahf_lm</strong><br />
bogomips	: 4521.98<br />
clflush size	: 64<br />
cache_alignment	: 64<br />
address sizes	: 40 bits physical, 48 bits virtual<br />
power management:</p></blockquote>
<p>从cupinfo的信息可以看出，支持sse/sse2/mmx这些GCC的flag，查看gcc的文档可以看到全部的优化选项：[<a href="http://gcc.gnu.org/onlinedocs/gcc/Optimize-Options.html">点我查看</a>]。</p>
<p>经过尝试，得到了如下编译参数，经过两周的压力测试，编译MySQL 5.1.46sp1企业版，比Percona 5.1.47 Server性能高出15%，目前也非常稳定的运行在开发测试库上。GCC版本为4.1.3，系统为RHEL 5.4 x64.</p>
<blockquote><p>CXX=gcc \<br />
CHOST=”x86_64-pc-linux-gnu” \<br />
CFLAGS=” -O3 \<br />
-fomit-frame-pointer \<br />
-pipe \<br />
-march=nocona \<br />
-mfpmath=sse \<br />
-m128bit-long-double \<br />
-mmmx \<br />
-msse \<br />
-msse2 \<br />
-maccumulate-outgoing-args \<br />
-m64 \<br />
-ftree-loop-linear \<br />
-fprefetch-loop-arrays \<br />
-freg-struct-return \<br />
-fgcse-sm \<br />
-fgcse-las \<br />
-frename-registers \<br />
-fforce-addr \<br />
-fivopts \<br />
-ftree-vectorize \<br />
-ftracer \<br />
-frename-registers \<br />
-minline-all-stringops \<br />
-fbranch-target-load-optimize2&#8243; \<br />
CXXFLAGS=”${CFLAGS}” \<br />
./configure &#8211;prefix=/usr/soft/install/mysql-ent-official-5.1.56 \<br />
&#8211;with-server-suffix=custom-mysql \<br />
&#8211;with-mysqld-user=mysql \<br />
&#8211;with-plugins=partition,blackhole,csv,heap,innobase,myisam,myisammrg \<br />
&#8211;with-charset=utf8 \<br />
&#8211;with-collation=utf8_general_ci \<br />
&#8211;with-extra-charsets=gbk,gb2312,utf8,ascii \<br />
&#8211;with-big-tables \<br />
&#8211;with-fast-mutexes \<br />
&#8211;with-zlib-dir=bundled \<br />
&#8211;enable-assembler \<br />
&#8211;enable-profiling \<br />
&#8211;enable-local-infile \<br />
&#8211;enable-thread-safe-client \<br />
&#8211;with-readline \<br />
&#8211;with-pthread \<br />
&#8211;with-embedded-server \<br />
&#8211;with-client-ldflags=-all-static \<br />
&#8211;with-mysqld-ldflags=-all-static \<br />
&#8211;without-query-cache \<br />
&#8211;without-geometry \<br />
&#8211;without-debug \<br />
&#8211;without-ndb-debug</p></blockquote>
<p>GCC参数的含义为：<br />
-fomit-frame-pointer<br />
对于不需要栈指针的函数就不在寄存器中保存指针，因此可以忽略存储和检索地址的代码，同时对许多函数提供一个额外的寄存器。所有”-O”级别都打开它，但仅在调试器可以不依靠栈指针运行时才有效。在AMD64平台上此选项默认打开，但是在x86平台上则默认关闭。建议显式的设置它。<br />
-pipe<br />
在编译过程的不同阶段之间使用管道而非临时文件进行通信，可以加快编译速度。建议使用。<br />
-march=nocona<br />
Xoen 55xx处理器在GCC 4.1.3<br />
-mfpmath=sse<br />
启用cpu支持”sse”标量浮点指令。<br />
m128bit-long-double<br />
指定long double为128位，pentium以上的cpu更喜欢这种标准，并且符合x86-64的ABI标准，但是却不附合i386的ABI标准。<br />
-mmmx -msse -msse2<br />
使用相应的扩展指令集以及内置函数<br />
-maccumulate-outgoing-args<br />
指定在函数引导段中计算输出参数所需最大空间，这在大部分现代cpu中是较快的方法；缺点是会明显增加二进制文件尺寸。<br />
-m64<br />
生成专门运行于64位环境的代码，不能运行于32位环境，仅用于x86_64[含EMT64]环境。<br />
-ftree-loop-linear<br />
在trees上进行线型循环转换。它能够改进缓冲性能并且允许进行更进一步的循环优化。<br />
-fprefetch-loop-arrays<br />
生成数组预读取指令，对于使用巨大数组的程序可以加快代码执行速度，适合数据库相关的大型软件等。具体效果如何取决于代码。<br />
-freg-struct-return<br />
如果struct和union足够小就通过寄存器返回，这将提高较小结构的效率。如果不够小，无法容纳在一个寄存器中，将使用内存返回。建议仅在完全使用GCC编译的系统上才使用。<br />
-fgcse-sm<br />
在全局公共子表达式消除之后运行存储移动，以试图将存储移出循环。<br />
-fgcse-las<br />
在全局公共子表达式消除之后消除多余的在存储到同一存储区域之后的加载操作。<br />
-frename-registers \<br />
-fforce-addr<br />
必须将地址复制到寄存器中才能对他们进行运算。由于所需地址通常在前面已经加载到寄存器中了，所以这个选项可以改进代码。<br />
-fivopts<br />
在trees上执行归纳变量优化。<br />
-ftree-vectorize<br />
在trees上执行循环向量化。<br />
-ftracer<br />
执行尾部复制以扩大超级块的尺寸，它简化了函数控制流，从而允许其它的优化措施做的更好。<br />
-frename-registers<br />
试图驱除代码中的假依赖关系，这个选项对具有大量寄存器的机器很有效。<br />
-minline-all-stringops<br />
默认时GCC只将确定目的地会被对齐在至少4字节边界的字符串操作内联进程序代码。该选项启用更多的内联并且增加二进制文件的体积，但是可以提升依赖于高速 memcpy, strlen, memset 操作的程序的性能。数据库系统使用这个参数可以显著提高内存操作性能。<br />
-fbranch-target-load-optimize2<br />
在执行序启动以及结尾之前执行分支目标缓存器加载最佳化。</p>
<p><strong>第二部分，使用TC-Malloc内存管理：</strong><br />
Linux下的malloc函数性能问题，想必大部分在Linux下写C的人都深有感受，纷纷利用内存池来改进内存分配效率。<br />
Google开源的tcmalloc则改进了malloc的一些效率问题，在大量malloc和free时，操作系统的内存曲线明显比Linux下malloc函数要平稳，在大并发情况下，提升程序稳定性和性能。<br />
一般网上都是把tcmalloc动态库加到mysqld_safe中启动，但是我们的MySQL都是静态编译的，这时候动态加载是否生效呢？所以还是静态编译入MySQL好。</p>
<p>编译tcmalloc先要编译libunwind：</p>
<blockquote><p>wget http://download.savannah.gnu.org/releases/libunwind/libunwind-0.99.tar.gz<br />
tar zxvf libunwind-0.99.tar.gz</p>
<p>CHOST=”x86_64-pc-linux-gnu” \<br />
CFLAGS=” -O3 -fPIC \<br />
-fomit-frame-pointer \<br />
-pipe \<br />
-march=nocona \<br />
-mfpmath=sse \<br />
-m128bit-long-double \<br />
-mmmx \<br />
-msse \<br />
-msse2 \<br />
-maccumulate-outgoing-args \<br />
-m64 \<br />
-ftree-loop-linear \<br />
-fprefetch-loop-arrays \<br />
-freg-struct-return \<br />
-fgcse-sm \<br />
-fgcse-las \<br />
-frename-registers \<br />
-fforce-addr \<br />
-fivopts \<br />
-ftree-vectorize \<br />
-ftracer \<br />
-frename-registers \<br />
-minline-all-stringops \<br />
-fbranch-target-load-optimize2&#8243; \<br />
CXXFLAGS=”${CFLAGS}” \<br />
./configure &amp;&amp; make &amp;&amp; make install</p></blockquote>
<p>然后编译tcmalloc：</p>
<blockquote><p>tar zxvf google-perftools-1.7.tar.gz</p>
<p>CHOST=”x86_64-pc-linux-gnu” \<br />
CFLAGS=” -O3 \<br />
-fomit-frame-pointer \<br />
-pipe \<br />
-march=nocona \<br />
-mfpmath=sse \<br />
-m128bit-long-double \<br />
-mmmx \<br />
-msse \<br />
-msse2 \<br />
-maccumulate-outgoing-args \<br />
-m64 \<br />
-ftree-loop-linear \<br />
-fprefetch-loop-arrays \<br />
-freg-struct-return \<br />
-fgcse-sm \<br />
-fgcse-las \<br />
-frename-registers \<br />
-fforce-addr \<br />
-fivopts \<br />
-ftree-vectorize \<br />
-ftracer \<br />
-frename-registers \<br />
-minline-all-stringops \<br />
-fbranch-target-load-optimize2&#8243; \<br />
CXXFLAGS=”${CFLAGS}” \<br />
./configure &#8211;disable-cpu-profiler \<br />
&#8211;disable-heap-profiler \<br />
&#8211;disable-heap-checker \<br />
&#8211;disable-debugalloc \<br />
&#8211;enable-minimal \<br />
&#8211;enable-frame-pointers &amp;&amp; make &amp;&amp; make install</p></blockquote>
<p>记得要把libtammloc加入系统路径，否则编译MySQL时找不到：</p>
<blockquote><p>echo “/usr/local/lib” &gt; /etc/ld.so.conf.d/usr_local_lib.conf<br />
/sbin/ldconfig</p></blockquote>
<p>最后就是编译MySQL了：</p>
<blockquote><p>CXX=gcc \<br />
CHOST=”x86_64-pc-linux-gnu” \<br />
CFLAGS=” -O3 \<br />
-fomit-frame-pointer \<br />
-pipe \<br />
-march=nocona \<br />
-mfpmath=sse \<br />
-m128bit-long-double \<br />
-mmmx \<br />
-msse \<br />
-msse2 \<br />
-maccumulate-outgoing-args \<br />
-m64 \<br />
-ftree-loop-linear \<br />
-fprefetch-loop-arrays \<br />
-freg-struct-return \<br />
-fgcse-sm \<br />
-fgcse-las \<br />
-frename-registers \<br />
-fforce-addr \<br />
-fivopts \<br />
-ftree-vectorize \<br />
-ftracer \<br />
-frename-registers \<br />
-minline-all-stringops \<br />
-felide-constructors \<br />
-fno-exceptions \<br />
-fno-rtti \<br />
-fbranch-target-load-optimize2&#8243; \<br />
CXXFLAGS=”${CFLAGS}” \<br />
LDFLAGS=” -lrt -lunwind -ltcmalloc_minimal -lstdc++ ” \<br />
./configure &#8211;prefix=/usr/soft/install/mysql-ent-custom-5.1.49sp1 \<br />
&#8211;with-server-suffix=-custom-edition \<br />
&#8211;with-mysqld-user=mysql \<br />
&#8211;with-plugins=partition,blackhole,csv,heap,innobase,myisam,myisammrg \<br />
&#8211;with-charset=utf8 \<br />
&#8211;with-collation=utf8_general_ci \<br />
&#8211;with-extra-charsets=gbk,gb2312,utf8,ascii \<br />
&#8211;with-big-tables \<br />
&#8211;with-fast-mutexes \<br />
&#8211;with-zlib-dir=bundled \<br />
&#8211;enable-assembler \<br />
&#8211;enable-profiling \<br />
&#8211;enable-local-infile \<br />
&#8211;enable-thread-safe-client \<br />
&#8211;with-readline \<br />
&#8211;with-pthread \<br />
&#8211;with-embedded-server \<br />
&#8211;with-mysqld-ldflags=-all-static \<br />
&#8211;without-query-cache \<br />
&#8211;without-geometry \<br />
&#8211;without-debug \<br />
&#8211;without-ndb-debug<br />
make &amp;&amp; make install</p></blockquote>
<p>经过试用，大并发下内存分配和释放曲线都比Linux原生的平稳。</p>
<p><strong>第三部分，尝试ICC：</strong><br />
ICC是Intel自己开发的多平台编译器，经过我的测试ICC在浮点运算，线程库和数学函数上的优势非常明显，原生SSE2指令集支持、Intel自己编写的线程库和数学函数库，性能没得说。<br />
我用同一份运算PI值的代码在ICC和GCC下编译，提升比例达<strong>20%</strong>，实际在数据库中比较同一条超级复杂的聚合<acronym title="Structured Query Language">SQL</acronym>，ICC提升达<strong>34%</strong>。<br />
下面给出TC-Malloc + ICC + Percona从源码编译的完整方案。</p>
<p>第一步：编译安装libunwind</p>
<blockquote><p>wget http://download.savannah.gnu.org/releases/libunwind/libunwind-0.99.tar.gz<br />
tar zxvf libunwind-0.99.tar.gz</p>
<p>CC=icc \<br />
CXX=icpc \<br />
LD=xild \<br />
AR=xiar \<br />
CFLAGS=”-O3 -no-prec-div -ip -fp-model fast=1 -xSSE2 -axSSE2 -fPIC” \<br />
CXXFLAGS=”${CFLAGS}” \<br />
CPPFLAGS=” -I/usr/alibaba/icc/include ” \<br />
./configure &amp;&amp; make &amp;&amp; make install</p></blockquote>
<p>第二布：编译安装tcmalloc</p>
<blockquote><p>wget http://google-perftools.googlecode.com/files/google-perftools-1.7.tar.gz<br />
tar zxvf google-perftools-1.7.tar.gz</p>
<p>CC=icc \<br />
CXX=icpc \<br />
LD=xild \<br />
AR=xiar \<br />
CFLAGS=”-O3 -no-prec-div -ip -fp-model fast=1 -xSSE2 -axSSE2 -fPIC” \<br />
CXXFLAGS=”${CFLAGS}” \<br />
CPPFLAGS=” -I/usr/alibaba/icc/include ” \<br />
./configure \<br />
&#8211;disable-cpu-profiler \<br />
&#8211;disable-heap-profiler \<br />
&#8211;disable-heap-checker \<br />
&#8211;disable-debugalloc \<br />
&#8211;enable-minimal \<br />
&#8211;enable-frame-pointers &amp;&amp; make &amp;&amp; make install</p>
<p>echo “/usr/local/lib” &gt; /etc/ld.so.conf.d/usr_local_lib.conf<br />
/sbin/ldconfig</p></blockquote>
<p>第三部：编译安装Percona</p>
<blockquote><p>CC=icc \<br />
CXX=icpc \<br />
LD=xild \<br />
AR=xiar \<br />
CFLAGS=”-O3 -fno-builtin-malloc -fno-builtin-calloc -fno-builtin-realloc -fno-builtin-free -unroll2 -ip -fp-model fast=1 -restrict -fno-exceptions -fno-rtti -no-prec-div -fno-implicit-templates -static-intel -static-libgcc -static -xSSE2 -axSSE2&#8243; \<br />
CXXFLAGS=”${CFLAGS}” \<br />
CPPFLAGS=” -I/usr/alibaba/icc/include ” \<br />
LDFLAGS=” -L/usr/alibaba/icc/lib/intel64/ -lrt -lunwind -ltcmalloc_minimal -lstdc++ ” \<br />
./configure &#8211;prefix=/usr/alibaba/install/percona-custom-5.1.55-12.6 \<br />
&#8211;with-server-suffix=-alibaba-edition \<br />
&#8211;with-mysqld-user=mysql \<br />
&#8211;with-plugins=heap,innodb_plugin,myisam,partition \<br />
&#8211;with-charset=utf8 \<br />
&#8211;with-collation=utf8_general_ci \<br />
&#8211;with-extra-charsets=gbk,utf8,ascii \<br />
&#8211;with-big-tables \<br />
&#8211;with-fast-mutexes \<br />
&#8211;with-zlib-dir=bundled \<br />
&#8211;with-readline \<br />
&#8211;with-pthread \<br />
&#8211;enable-assembler \<br />
&#8211;enable-profiling \<br />
&#8211;enable-local-infile \<br />
&#8211;enable-thread-safe-client \<br />
&#8211;without-embedded-server \<br />
&#8211;with-mysqld-ldflags=-all-static \<br />
&#8211;without-query-cache \<br />
&#8211;without-geometry \<br />
&#8211;without-debug \<br />
&#8211;without-ndb-binlog \<br />
&#8211;without-ndb-debug</p></blockquote>
<p>编译完成后make &amp;&amp; make install</p><h2  class="related_post_title">类似的文章</h2><ul class="related_post"><li>2012年01月23日 -- <a href="http://www.penglixun.com/tech/database/case_about_innodb_faster_than_oracle.html" title="一个InnoDB性能超过Oracle的调优Case">一个InnoDB性能超过Oracle的调优Case</a> (1)</li><li>2011年12月23日 -- <a href="http://www.penglixun.com/tech/database/server_kill_idle_transaction.html" title="在Server层实现Kill Idle Transaction">在Server层实现Kill Idle Transaction</a> (1)</li><li>2011年11月29日 -- <a href="http://www.penglixun.com/tech/database/how_to_kill_idle_trx.html" title="如何杀掉空闲事务">如何杀掉空闲事务</a> (1)</li></ul>]]></content:encoded>
			<wfw:commentRss>http://www.penglixun.com/tech/database/mysql_compile_reference.html/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>[译]InnoDB官方博客：InnoDB Plugin的性能和可伸缩性</title>
		<link>http://www.penglixun.com/tech/database/plug-in-for-performance-and-scalability.html</link>
		<comments>http://www.penglixun.com/tech/database/plug-in-for-performance-and-scalability.html#comments</comments>
		<pubDate>Thu, 27 Jan 2011 07:57:30 +0000</pubDate>
		<dc:creator>P.Linux</dc:creator>
				<category><![CDATA[数据库]]></category>
		<category><![CDATA[InnoDB]]></category>
		<category><![CDATA[MySQL]]></category>

		<guid isPermaLink="false">http://www.penglixun.com/?p=1191</guid>
		<description><![CDATA[本文内容遵从CC版权协议, 可以随意转载, 但必须以超链接形式标明文章原始出处和作者信息及版权声明网址: http://www.penglixun.com/tech/database/plug-in-for-performance-and-scalability.html 原文地址：http://blogs... ]]></description>
			<content:encoded><![CDATA[<p><span style="color: #888888;">本文内容遵从<a href="http://creativecommons.org/licenses/by-nc-sa/3.0/deed.zh" target="_blank">CC版权协议</a>, 可以随意转载, 但必须以超链接形式标明文章原始出处和作者信息及版权声明</br>网址: http://www.penglixun.com/tech/database/plug-in-for-performance-and-scalability.html </p>
<p></span>原文地址：<a href="http://blogs.innodb.com/wp/2009/03/plug-in-for-performance-and-scalability/">http://blogs.innodb.com/wp/2009/03/plug-in-for-performance-and-scalability/</a></p>
<p>Why should you care about             the latest “early adopter” release of the InnoDB Plugin,             version 1.0.3?   One word: <strong>performance!</strong> The release             introduces these features:<br />
<strong>为什么你应该关注最近的InnoDB Plugin 1.0.3版？一个词：性能！这个版本包括了这些特性</strong></p>
<ul>
<li>Enhanced concurrency               &amp; scalability: the “Google SMP patch” using atomic               instructions for mutexing</li>
<li><strong>增强的并发可可伸缩性：”Google                 多处理机 补丁” 为Mutext锁操作使用原子操作</strong></li>
<li>More efficient memory               allocation: ability to use more scalable platform memory               allocator</li>
<li><strong>更有效的内存分配：可以使用更多的可扩展内存                 分配器（例如tcmalloc）</strong></li>
<li>Improved out-of-the-box               scalability: unlimited concurrent thread execution by               default</li>
<li><strong>改进的即装即用扩展性：默认无限制的线程并发</strong></li>
<li>Dynamic tuning: at               run-time, enable or disable insert buffering and adaptive               hash indexing</li>
<li><strong>动态优化调整：在运行时，打开或者关闭插入缓                 存和自适应哈希索引</strong></li>
</ul>
<p>These new performance             features can yield <strong>up               to twice the throughput</strong> or more, depending             on your workload, platform and other tuning considerations.             In another post, we explore some details about these             changes, but first, what do these enhancements mean for             performance and scalability?<br />
<strong>这些新的性能特新可以提升多大两倍甚至更多的的吞吐量，这依赖于你的负载，平台和其他调整事项。在另一篇文章中，我们会探               讨这些改变的一些细节，但首先，我们现探讨这些性能和可扩展性的增强是什么意思，包括哪些内容</strong></p>
<p>In brief, we’ve tested             three different workloads (joins, DBT2 OLTP and a modified             sysbench) using a memory-resident database. In all cases,             the InnoDB Plugin scales significantly better than the             built-in InnoDB in MySQL 5.1. And in some cases, the             absolute level of performance is dramatically higher too!             The charts below illustrate the kinds of performance gains             we’ve measured with release 1.0.3 of the InnoDB Plugin. Your             mileage may vary, of course. See the <a href="http://www.innodb.com/wp/innodb_plugin/plugin-performance">InnoDB website</a> for all the details             on these tests.<br />
<strong>总之，我们已经使用内存驻留数据库（所有数据都载入在内存中）测试了三种不同的工作负载（关联，DBT2               OLTP和修改过的sysbench）。在所有的情况下，InnoDB Plugin的伸缩性明显优于MySQL               5.1内置的InnoDB。在一些场景中，性能提升的水平高的惊人。下面的图说明了InnoDB Plugin               1.0.3的性能提升。你的测试结果可能不同，当然可以在InnoDB网站看到所有测试的细节。</strong></p>
<p>This release of the InnoDB             Plugin incorporates a <a href="http://code.google.com/p/google-mysql-tools/wiki/SmpPerformance" target="new">patch               made by Ben Handy and Mark Callaghan at Google</a> to improve             multi-core scalability by using more efficient             synchronization methods (mutexing and rw-locks) to reduce             cpu utilization and contention. We’re grateful for this             contribution, and you will be too!<br />
<strong>这个InnoDB Plugin版本包含了Google的Ben Handy和Mark               Callaghan的补丁来提升多处理机扩展性，包括使用了更有效的同步机制（Mutexing和RW-Locks）来减少CPU利用和竞争。我们非常感               谢这个补丁的贡献，相信你也是。</strong></p>
<p>Now to our test results …<br />
<strong>现在来看我们的测试结果</strong>&#8230;</p>
<p><strong>Joins: </strong>The             following chart shows the performance gains in performing             joins, comparing the built-in InnoDB in MySQL (in blue) with the             InnoDB Plugin 1.0.3 (in red).<br />
<strong>关联：下图展示了执行Join操作时的性能提升，内置InnoDB（蓝）和InnoDB Plugin               1.0.3（红）的比较。</strong></p>
<div><a href="http://www.penglixun.com/wp-content/uploads/2011/01/1.png"><img class="alignnone size-full wp-image-1192" title="Case 1" src="http://www.penglixun.com/wp-content/uploads/2011/01/1.png" alt="" width="450" height="320" /></a></div>
<p>As you can see from the             blue bars in the above chart, with MySQL 5.1 using the             built-in InnoDB, the total number of joins the system can             execute declines as the number of concurrent users             increases. In contrast, the InnoDB Plugin slightly improves             performance even with one user, and maintains performance as             the number of users rises. This performance improvement is             due in large part to the use of atomics for mutexing in the             InnoDB Plugin.<br />
<strong>正如你在上面蓝柱上看到的，MySQL               5.1的内置InnoDB，随着并发数的增加系统的执行速度反而下降了。与此相反，InnoDB               Plugin随着并发的提升处理速度甚至略有提高，并且随着用户的增长保持着这种性能。这个性能改善很大程度上是因为对Mutexing使用了原子操作。</strong></p>
<p><strong>Transaction               Processing (DBT2):</strong> The following chart             illustrates a scalability improvement using the OLTP             read/write DBT2 benchmark, again comparing the performance             of the built-in               InnoDB in MySQL with             the performance of InnoDB Plugin               1.0.3.<br />
<strong>事务处理（DBT2）：下入展示了用DBT2测试OLTP读写性能的提升，再次比较了内置InnoDB和InnoDB               Plugin 1.0.3的性能。</strong></p>
<div><a href="http://www.penglixun.com/wp-content/uploads/2011/01/2.png"><img class="alignnone size-full wp-image-1193" title="2" src="http://www.penglixun.com/wp-content/uploads/2011/01/2.png" alt="" width="606" height="320" /></a></div>
<p>Here, the InnoDB Plugin             scales better than the built-in InnoDB from 16 to 32 users             and produces about 12% more throughput with 64 concurrent             users, as other bottlenecks are encountered or system             capacity is reached. This improvement is likewise due             primarily to the changes in mutexing.<br />
<strong>这里，InnoDB               Plugin伸缩性在16增加到32线程时表现更好，产生比64线程多大约12%的吞吐量。由于其他性能瓶颈或系统容量达到基线。这个提升依然主要依赖于               Mutexing的改变。</strong></p>
<p><strong>Modified Sysbench:</strong> This test uses a             version of the well-known sysbench workload, modified to             include queries based on a secondary index, <a href="http://mysqlha.blogspot.com/2009/02/update-for-sysbench.html">as suggested</a> by Mark Callaghan of             Google.<br />
<strong>修改过的sysbench：这个测试使用了著名的sysbench，修改包括基于非主键索引的查询，由Google的               Mark Callaghan建议。</strong></p>
<div><a href="http://www.penglixun.com/wp-content/uploads/2011/01/3.png"><img class="alignnone size-full wp-image-1194" title="3" src="http://www.penglixun.com/wp-content/uploads/2011/01/3.png" alt="" width="450" height="320" /></a></div>
<p>This time, the InnoDB             Plugin shows significantly better scalability from 8 to 64             users than the built-in InnoDB in MySQL, yielding as much as             60% more throughput at 64 users. Like the previous examples,             this improvement is largely due to the use of atomics for             mutexing.<br />
<strong>这次，InnoDB               Plugin在8~64线程都展示了明显优于内置InnoDB的可伸缩性。在64并发时多大60%的性能提升！像前一个例子，这个提升依然主要靠               Mutexing的原子性。</strong></p>
<p><strong>Modified Sysbench               with tcmalloc:</strong> This             test uses the same modified sysbench workload, but shows the             difference between the built-in InnoDB (which uses the             internal InnoDB memory allocator) and the InnoDB Plugin when             using a more scalable memory allocator, in this case <a href="http://google-perftools.googlecode.com/svn/trunk/doc/tcmalloc.html">tcmalloc</a>.<br />
<strong>使用tcmalloc的修改过的sysbench：这种测试使用相同的sysbench场景，但是不同于内置InnoDB               的是InnoDB Plugin使用了tcmalloc作为内存分配器。</strong></p>
<div><a href="http://www.penglixun.com/wp-content/uploads/2011/01/4.png"><img class="alignnone size-full wp-image-1195" title="4" src="http://www.penglixun.com/wp-content/uploads/2011/01/4.png" alt="" width="450" height="320" /></a></div>
<p>When the new configuration             parameter <code>innodb_use_sys_malloc</code> is set to enable use             of the memory allocator tcmalloc, the InnoDB Plugin really             shines! Transaction throughput continues to scale, and the             actual throughput with 64 users has nearly doubled!<br />
<strong>当设置innodb_user_sys_malloc变量为tcmalloc作为内存分配器时，InnoDB               Plugin依然是亮点！事务吞吐量继续扩展，在64并发时吞吐量提升接近1倍（相对没有tcmalloc的）。</strong></p><h2  class="related_post_title">类似的文章</h2><ul class="related_post"><li>2012年01月23日 -- <a href="http://www.penglixun.com/tech/database/case_about_innodb_faster_than_oracle.html" title="一个InnoDB性能超过Oracle的调优Case">一个InnoDB性能超过Oracle的调优Case</a> (1)</li><li>2011年12月23日 -- <a href="http://www.penglixun.com/tech/database/server_kill_idle_transaction.html" title="在Server层实现Kill Idle Transaction">在Server层实现Kill Idle Transaction</a> (1)</li><li>2011年01月19日 -- <a href="http://www.penglixun.com/tech/database/mysql_some_tips_part_1.html" title="MySQL小技巧问答(一)">MySQL小技巧问答(一)</a> (0)</li></ul>]]></content:encoded>
			<wfw:commentRss>http://www.penglixun.com/tech/database/plug-in-for-performance-and-scalability.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>MySQL小技巧问答(一)</title>
		<link>http://www.penglixun.com/tech/database/mysql_some_tips_part_1.html</link>
		<comments>http://www.penglixun.com/tech/database/mysql_some_tips_part_1.html#comments</comments>
		<pubDate>Tue, 18 Jan 2011 21:01:02 +0000</pubDate>
		<dc:creator>P.Linux</dc:creator>
				<category><![CDATA[数据库]]></category>
		<category><![CDATA[InnoDB]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[Tips]]></category>

		<guid isPermaLink="false">http://www.penglixun.com/?p=1189</guid>
		<description><![CDATA[本文内容遵从CC版权协议, 可以随意转载, 但必须以超链接形式标明文章原始出处和作者信息及版权声明网址: http://www.penglixun.com/tech/database/mysql_some_tips_part_1.html 抽空总结一下自己操作MySQL的一些... ]]></description>
			<content:encoded><![CDATA[<p><span style="color: #888888;">本文内容遵从<a href="http://creativecommons.org/licenses/by-nc-sa/3.0/deed.zh" target="_blank">CC版权协议</a>, 可以随意转载, 但必须以超链接形式标明文章原始出处和作者信息及版权声明</br>网址: http://www.penglixun.com/tech/database/mysql_some_tips_part_1.html </p>
<p></span>抽空总结一下自己操作MySQL的一些心得体会，做成MySQL小技巧问答系列，给大家作为一些案例参考，也为我自己做一些记录：</p>
<p><strong>1. 在基于ROW的双Master复制下，如何快速大批量订正？</strong><br />
在A&lt;-&gt;B的双Master结构下，假设只有一台提供服务，这是我们常用的架构，需要大批量订正数据，如何做最快？用存储过程一批批提交？这有很多的限制，有时候并不可以把一条或多条<acronym title="Structured Query Language">SQL</acronym>拆成几段，怎么办呢？binlog不是很好的工具嘛?! ROW格式的binlog，Slave在应用时是直接使用Handler <acronym title="Application Programming Interface">API</acronym>，并没有走<acronym title="Structured Query Language">SQL</acronym>解析，速度非常快，基本上是IO操作了，那么我们可以在备库上直接执行订正<acronym title="Structured Query Language">SQL</acronym>，产生的ROW binlog传到主机，就会很快订正完，基本上都比写存储过程快。</p>
<p><strong>2. ROW格式Replication如何实现不带库名的replicate-do-db？</strong><br />
虽然MySQL有replicate-do-db这个参数，但是在ROW格式的binlog下必须使用”db.table”的方式才能生效，USE对ROW格式是无效的。现在我有一个Instance，只需要复制Master的某几个库，但是是ROW格式，<acronym title="Structured Query Language">SQL</acronym>都没有使用db前缀，怎么办？可以这么做，把主库需要的库导出来，不需要的库导出结构即可，在Slave导入这些数据及结构，配置skip-slave-errors=all，这样Master复制过来的binlog，只要发现有库有表结构，就不会报找不到表，就不会阻塞复制，但是UPDATE/DELETE过来没有数据也会被跳过错误，间接的实现了replicate-do-db。</p>
<p><strong>3. 大批量乱序数据导入InnoDB很慢如何解决？</strong><br />
InnoDB因为主键聚集索引的关系，如果没有主键或者主键非序列的情况下，导入会越来越慢，如何快速的迁移数据到InnoDB？借助MyISAM的力量是很靠谱的，先关闭InnoDB的Buffer Pool，把内存空出来，建一张没有任何索引的MyISAM表，然后只管插入吧，concurrent_insert=2，在文件末尾并发插入，速度刚刚的，插入完成后，ALTER TABLE把索引加上，记得还有ENGINE=InnoDB，就把MyISAM转到InnoDB了，这样的速度远比直接往InnoDB里插乱序数据来得快。</p>
<p><strong>4. A&lt;&#8211;&gt;B&#8211;&gt;C&#8211;&gt;D结构切换到A&lt;&#8211;&gt;B, C&lt;&#8211;&gt;D结构出现Slave_lag一直增常如何避免？</strong><br />
这种情况常见与一个双Master集群分离出一套双Master集群，例如从原集群分离一部分库。过快的切换B&#8211;&gt;C到C&lt;&#8211;&gt;D容易导致主备出现slave_lag，并且一直增长，原因在于A&lt;&#8211;&gt;B集群产生的<acronym title="Structured Query Language">SQL</acronym>，随同server_id带到了C&#8211;&gt;D这个M-S中，当A,B产生的<acronym title="Structured Query Language">SQL</acronym>在C,D还没消化完成就CHANGE MASTER为C&lt;&#8211;&gt;D时，会导致这写<acronym title="Structured Query Language">SQL</acronym>在C,D之间来回传输，因为C,D都认为这个<acronym title="Structured Query Language">SQL</acronym>不是自己产生的，因而不销毁，自己执行后写入binlog，于是Slave_Lag就一直增长。<br />
避免的方法很简单，部分写切到C后，先断开B&#8211;&gt;C的复制，等一会，看D上已经没有Slave_Lag了，再CHANGE MASTER为C&lt;&#8211;&gt;D，这样A,B传过来的<acronym title="Structured Query Language">SQL</acronym>都消化完了。</p>
<p><strong>5. 表中存在很多重复数据时，如何删除这些重复数据最快？</strong><br />
在需要给表中某些字段加唯一索引时，而字段中又存在需要重复清理数据的问题，不少<acronym title="Database Administrator">DBA</acronym>都应该遇到过。一般在处理时总是想在数据库中只保留一条，其他的删除，但是这样的<acronym title="Structured Query Language">SQL</acronym>写出来总是效率不高，怎么办？其实可以转换思路，把重复的都选出一条出来，存到一张临时表，然后删除原表中所有存在重复的，再把临时表的数据库全部插入原库，这是比较通用并且高效的做法。</p><h2  class="related_post_title">类似的文章</h2><ul class="related_post"><li>2012年01月23日 -- <a href="http://www.penglixun.com/tech/database/case_about_innodb_faster_than_oracle.html" title="一个InnoDB性能超过Oracle的调优Case">一个InnoDB性能超过Oracle的调优Case</a> (1)</li><li>2011年12月23日 -- <a href="http://www.penglixun.com/tech/database/server_kill_idle_transaction.html" title="在Server层实现Kill Idle Transaction">在Server层实现Kill Idle Transaction</a> (1)</li><li>2011年01月27日 -- <a href="http://www.penglixun.com/tech/database/plug-in-for-performance-and-scalability.html" title="[译]InnoDB官方博客：InnoDB Plugin的性能和可伸缩性">[译]InnoDB官方博客：InnoDB Plugin的性能和可伸缩性</a> (0)</li></ul>]]></content:encoded>
			<wfw:commentRss>http://www.penglixun.com/tech/database/mysql_some_tips_part_1.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>MySQL Multi-Master实现方式</title>
		<link>http://www.penglixun.com/tech/program/how_to_mysql_multi_master.html</link>
		<comments>http://www.penglixun.com/tech/program/how_to_mysql_multi_master.html#comments</comments>
		<pubDate>Fri, 14 Jan 2011 09:35:01 +0000</pubDate>
		<dc:creator>P.Linux</dc:creator>
				<category><![CDATA[程序设计]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[mysqlbinlog]]></category>
		<category><![CDATA[Repliction]]></category>

		<guid isPermaLink="false">http://www.penglixun.com/?p=1188</guid>
		<description><![CDATA[本文内容遵从CC版权协议, 可以随意转载, 但必须以超链接形式标明文章原始出处和作者信息及版权声明网址: http://www.penglixun.com/tech/program/how_to_mysql_multi_master.html MySQL Mutil-Master Replication喊了很久... ]]></description>
			<content:encoded><![CDATA[<p><span style="color: #888888;">本文内容遵从<a href="http://creativecommons.org/licenses/by-nc-sa/3.0/deed.zh" target="_blank">CC版权协议</a>, 可以随意转载, 但必须以超链接形式标明文章原始出处和作者信息及版权声明</br>网址: http://www.penglixun.com/tech/program/how_to_mysql_multi_master.html </p>
<p></span>MySQL Mutil-Master Replication喊了很久了，但是MySQL一直没有去，虽然在MySQL源码中有注释将实现Multi-Master，mi结构体也为Multi-Master做好了准备，但是却一直不见MySQL发布。<br />
但是Multi-Master &#8211;> Slave的Repliction确实非常有用，例如一台集中备份机备份所有Master的数据。</p>
<p>实现Multi-Master有几种思路：<br />
1. 修改MySQL源码：修改sql_yacc.yy, sql_lex.cc支持多Master的CHANGE MASTER TO语法，然后修改slave相关的slave.cc，支持开启多个Slave, 将slave io/ slave thread线程扩展为一个slave_list。<br />
2. 利用mysqlbinlog之类的工具，远程注册到Master获取binlog，导入本地Slave服务器。</p>
<p>从效率看，肯定第一种方式效率高，但是风险太大了，并且MySQL版本更新，可能需要变动自己的代码以适应新的MySQL Source, MySQL官方的实现方式肯定是第一种，从源码中的注释可以看出他们的设计思路。但是他们考虑的问题可能是多个Master复制如何处理冲突等异常，因而迟迟不发布。</p>
<p>为了避免过多的入侵MySQL，我采用第二种方式，用一个脚本或者程序等等，去调用mysqlbinlog，用-R远程请求到&#8211;to-last-log，然后稍微修改一下啊mysqlbinlog的源码，在日志切换后计数一下，在输出文件末尾打上切换日志的个数，例如：</p>

<div class="wp_codebox"><table><tr id="p118841"><td class="code" id="p1188code41"><pre class="sql" style="font-family:monospace;"><span style="color: #993333; font-weight: bold;">insert</span> <span style="color: #993333; font-weight: bold;">into</span> a <span style="color: #993333; font-weight: bold;">values</span> <span style="color: #66cc66;">&#40;</span><span style="color: #cc66cc;">8</span><span style="color: #66cc66;">&#41;</span>
<span style="color: #808080; font-style: italic;">/*!*/</span>;
# at <span style="color: #cc66cc;">1070</span>
#<span style="color: #cc66cc;">110114</span> <span style="color: #cc66cc;">16</span>:<span style="color: #cc66cc;">16</span>:<span style="color: #cc66cc;">11</span> server id <span style="color: #cc66cc;">3</span>  end_log_pos <span style="color: #cc66cc;">1097</span> 	Xid <span style="color: #66cc66;">=</span> <span style="color: #cc66cc;">36</span>
COMMIT<span style="color: #808080; font-style: italic;">/*!*/</span>;
DELIMITER ;
# End of log file
ROLLBACK <span style="color: #808080; font-style: italic;">/* added by mysqlbinlog */</span>;
<span style="color: #808080; font-style: italic;">/*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/</span>;
<span style="color: #808080; font-style: italic;">-- Rorate binlog count: 1</span></pre></td></tr></table></div>

<p>&#8211; Rorate binlog count: 1就是日志切换信息，表示切换了一次日志（即传入Master的日志号没有用完）然后tail末尾的end_pos来查看本次同步到哪里了，写到*.info的文件中。</p>
<p>我的脚本需要配置一个multi_master.conf文件，配好每个Master的信息，例如：</p>

<div class="wp_codebox"><table><tr id="p118842"><td class="code" id="p1188code42"><pre class="sql" style="font-family:monospace;">#cat multi_master<span style="color: #66cc66;">.</span>conf 
<span style="color: #66cc66;">&#91;</span>master1<span style="color: #66cc66;">&#93;</span>
MASTER_HOST<span style="color: #66cc66;">=</span>1<span style="color: #66cc66;">.</span>2<span style="color: #66cc66;">.</span>3<span style="color: #66cc66;">.</span>4
MASTER_USER<span style="color: #66cc66;">=</span>plx
MASTER_PASSWORD<span style="color: #66cc66;">=</span>plx
MASTER_PORT<span style="color: #66cc66;">=</span><span style="color: #cc66cc;">3306</span>
MASTER_LOG_NAME<span style="color: #66cc66;">=</span>mysql<span style="color: #66cc66;">-</span>bin
MASTER_LOG_IDX<span style="color: #66cc66;">=</span>000002
MASTER_LOG_POS<span style="color: #66cc66;">=</span><span style="color: #cc66cc;">521</span>
RELAY_LOG_DIR<span style="color: #66cc66;">=/</span>tmp<span style="color: #66cc66;">/</span>
RELAY_LOG_NAME<span style="color: #66cc66;">=</span><span style="color: #cc66cc;">1</span><span style="color: #66cc66;">-</span>relay<span style="color: #66cc66;">-</span>bin
&nbsp;
<span style="color: #66cc66;">&#91;</span>master2<span style="color: #66cc66;">&#93;</span>
MASTER_HOST<span style="color: #66cc66;">=</span>2<span style="color: #66cc66;">.</span>3<span style="color: #66cc66;">.</span>4<span style="color: #66cc66;">.</span>5
MASTER_USER<span style="color: #66cc66;">=</span>plx
MASTER_PASSWORD<span style="color: #66cc66;">=</span>plx
MASTER_PORT<span style="color: #66cc66;">=</span><span style="color: #cc66cc;">3306</span>
MASTER_LOG_NAME<span style="color: #66cc66;">=</span>mysql<span style="color: #66cc66;">-</span>bin
MASTER_LOG_IDX<span style="color: #66cc66;">=</span>000002
MASTER_LOG_POS<span style="color: #66cc66;">=</span><span style="color: #cc66cc;">581</span>
RELAY_LOG_DIR<span style="color: #66cc66;">=/</span>tmp<span style="color: #66cc66;">/</span>
RELAY_LOG_NAME<span style="color: #66cc66;">=</span><span style="color: #cc66cc;">2</span><span style="color: #66cc66;">-</span>relay<span style="color: #66cc66;">-</span>bin
&nbsp;
<span style="color: #66cc66;">&#91;</span>slave<span style="color: #66cc66;">&#93;</span>
SLAVE_USER<span style="color: #66cc66;">=</span>plx
SLAVE_PASSWORD<span style="color: #66cc66;">=</span>plx</pre></td></tr></table></div>

<p>SLAVE默认导入本地，所以没有提供主机选项。<br />
配置文件的含义是，定义了master1和master2两个Master，名称其实只要不是slave都行，[slave]中定义了本地导入的用户名和密码。<br />
特有的参数我解释下，没解释的跟MySQL一样，<br />
MASTER_LOG_NAME和MASTER_LOG_IDX组成MySQL中的Master_log_file，RELAY_LOG_DIR表示取回的binlog文件放哪个目录，RELAY_LOG_NAME是Relay文件的文件名，会加上标号，跟MySQL一样，这个脚本会自动处理。<br />
一旦执行过一次，就会生成master1.info之类的文件，来表示当前同步到哪里了，例如下面这个例子：</p>

<div class="wp_codebox"><table><tr id="p118843"><td class="code" id="p1188code43"><pre class="sql" style="font-family:monospace;">MASTER_LOG_POS<span style="color: #66cc66;">=</span><span style="color: #cc66cc;">1482</span>
NAME<span style="color: #66cc66;">=</span>master1
MASTER_USER<span style="color: #66cc66;">=</span>plx
RELAY_LOG_NAME<span style="color: #66cc66;">=</span><span style="color: #cc66cc;">1</span><span style="color: #66cc66;">-</span>relay<span style="color: #66cc66;">-</span>bin
MASTER_LOG_IDX<span style="color: #66cc66;">=</span><span style="color: #cc66cc;">2</span>
MASTER_HOST<span style="color: #66cc66;">=</span>1<span style="color: #66cc66;">.</span>2<span style="color: #66cc66;">.</span>3<span style="color: #66cc66;">.</span>4
MASTER_LOG_NAME<span style="color: #66cc66;">=</span>mysql<span style="color: #66cc66;">-</span>bin
MASTER_PORT<span style="color: #66cc66;">=</span><span style="color: #cc66cc;">3306</span>
RELAY_LOG_DIR<span style="color: #66cc66;">=/</span>tmp<span style="color: #66cc66;">/</span>
MASTER_PASSWORD<span style="color: #66cc66;">=</span>plx
RELAY_LOG_IDX<span style="color: #66cc66;">=</span><span style="color: #cc66cc;">3</span></pre></td></tr></table></div>

<p>只有找不到*.info的时候，才会使用multi_master.conf。</p>
<p>现在每次调度multi_master_repl.pl都只会运行一次，可以不断的调度multi_master_repl.pl，因为还没有完全搞定KILL信号在<acronym title="Practical Extraction and Report Language">Perl</acronym>脚本的处理，用C重写后会解决，不能暴力kill -9，会导致不知道复制到哪里了。</p>
<p>这是下载地址，切勿用在生产环境，这只是个验证想法的程序。</p>
Note: There is a file embedded within this post, please visit this post to download the file.
<p>下一步我想用C重新实现，在mysqlbinlog源码基础上修改，获取到的日志直接写入到sock或直接导入远程mysql，避免多写一次文件，也欢迎提供新思路。</p>
<p>这是一次执行的日志：</p>

<div class="wp_codebox"><table><tr id="p118844"><td class="code" id="p1188code44"><pre class="shell" style="font-family:monospace;">#./multi_master_repl.pl 
(DEBUG) Enter: get_config()
	Info: begin
	(DEBUG) get_config --&gt; master1
	(DEBUG) get_config --&gt; multi_master.conf --&gt; master1:MASTER_HOST=1.2.3.4
	(DEBUG) get_config --&gt; multi_master.conf --&gt; master1:MASTER_USER=plx
	(DEBUG) get_config --&gt; multi_master.conf --&gt; master1:MASTER_PASSWORD=plx
	(DEBUG) get_config --&gt; multi_master.conf --&gt; master1:MASTER_PORT=3306
	(DEBUG) get_config --&gt; multi_master.conf --&gt; master1:MASTER_LOG_NAME=mysql-bin
	(DEBUG) get_config --&gt; multi_master.conf --&gt; master1:MASTER_LOG_IDX=000002
	(DEBUG) get_config --&gt; multi_master.conf --&gt; master1:MASTER_LOG_POS=521
	(DEBUG) get_config --&gt; multi_master.conf --&gt; master1:RELAY_LOG_DIR=/tmp/
	(DEBUG) get_config --&gt; multi_master.conf --&gt; master1:RELAY_LOG_NAME=1-relay-bin
	(DEBUG) get_config --&gt; Found master1.info, Read it
	(DEBUG) get_config --&gt; master1.info --&gt; master1:MASTER_LOG_POS=1097
	(DEBUG) get_config --&gt; master1.info --&gt; master1:NAME=master1
	(DEBUG) get_config --&gt; master1.info --&gt; master1:MASTER_USER=plx
	(DEBUG) get_config --&gt; master1.info --&gt; master1:RELAY_LOG_NAME=1-relay-bin
	(DEBUG) get_config --&gt; master1.info --&gt; master1:MASTER_LOG_IDX=2
	(DEBUG) get_config --&gt; master1.info --&gt; master1:MASTER_HOST=1.2.3.4
	(DEBUG) get_config --&gt; master1.info --&gt; master1:MASTER_LOG_NAME=mysql-bin
	(DEBUG) get_config --&gt; master1.info --&gt; master1:MASTER_PORT=3306
	(DEBUG) get_config --&gt; master1.info --&gt; master1:RELAY_LOG_DIR=/tmp/
	(DEBUG) get_config --&gt; master1.info --&gt; master1:MASTER_PASSWORD=plx
	(DEBUG) get_config --&gt; master1.info --&gt; master1:RELAY_LOG_IDX=2
	(DEBUG) get_config --&gt; Push[master1] to Master_Info_List
	(DEBUG) get_config --&gt; master2
	(DEBUG) get_config --&gt; multi_master.conf --&gt; master2:MASTER_HOST=2.3.4.5
	(DEBUG) get_config --&gt; multi_master.conf --&gt; master2:MASTER_USER=plx
	(DEBUG) get_config --&gt; multi_master.conf --&gt; master2:MASTER_PASSWORD=plx
	(DEBUG) get_config --&gt; multi_master.conf --&gt; master2:MASTER_PORT=3306
	(DEBUG) get_config --&gt; multi_master.conf --&gt; master2:MASTER_LOG_NAME=mysql-bin
	(DEBUG) get_config --&gt; multi_master.conf --&gt; master2:MASTER_LOG_IDX=000002
	(DEBUG) get_config --&gt; multi_master.conf --&gt; master2:MASTER_LOG_POS=581
	(DEBUG) get_config --&gt; multi_master.conf --&gt; master2:RELAY_LOG_DIR=/tmp/
	(DEBUG) get_config --&gt; multi_master.conf --&gt; master2:RELAY_LOG_NAME=2-relay-bin
	(DEBUG) get_config --&gt; Found master2.info, Read it
	(DEBUG) get_config --&gt; master2.info --&gt; master2:MASTER_LOG_POS=1541
	(DEBUG) get_config --&gt; master2.info --&gt; master2:NAME=master2
	(DEBUG) get_config --&gt; master2.info --&gt; master2:MASTER_USER=plx
	(DEBUG) get_config --&gt; master2.info --&gt; master2:RELAY_LOG_NAME=2-relay-bin
	(DEBUG) get_config --&gt; master2.info --&gt; master2:MASTER_LOG_IDX=2
	(DEBUG) get_config --&gt; master2.info --&gt; master2:MASTER_HOST=2.3.4.5
	(DEBUG) get_config --&gt; master2.info --&gt; master2:MASTER_LOG_NAME=mysql-bin
	(DEBUG) get_config --&gt; master2.info --&gt; master2:MASTER_PORT=3306
	(DEBUG) get_config --&gt; master2.info --&gt; master2:RELAY_LOG_DIR=/tmp/
	(DEBUG) get_config --&gt; master2.info --&gt; master2:MASTER_PASSWORD=plx
	(DEBUG) get_config --&gt; master2.info --&gt; master2:RELAY_LOG_IDX=2
	(DEBUG) get_config --&gt; Push[master2] to Master_Info_List
	(DEBUG) get_config --&gt; multi_master.conf --&gt; slave:SLAVE_USER=plx
	(DEBUG) get_config --&gt; multi_master.conf --&gt; slave:SLAVE_PASSWORD=plx
(DEBUG) Enter: get_config()
	Info: exit
(DEBUG) Enter: create_slave_threads()
	Info: begin
	(DEBUG) create_slave_threads --&gt; Creating run_slave Threads...
(DEBUG) Enter: run_slave()
	Info: begin [tid: 1]
	(DEBUG) run_slave(0) --&gt; NO KILL SIGNAL --&gt; g_is_killed =&gt;0
	(DEBUG) run_slave --&gt; mysqlbinlog: ./mysqlbinlog -h1.2.3.4 -uplx -pplx -R -t --start-position=1097 mysql-bin.000002 &gt; /tmp/1-relay-bin.000002
Warning: ./mysqlbinlog: unknown variable 'loose_default-character-set=utf8'
	(DEBUG) run_slave(0) --&gt; NO KILL SIGNAL --&gt; g_is_killed =&gt;0
(DEBUG) Enter: import_to_slave()
	Info: begin [Param: p_master_idx=&gt;0]
	(DEBUG) import_to_slave(0) --&gt; NO KILL SIGNAL --&gt; g_is_killed =&gt;0
	(DEBUG) import_to_slave(0) --&gt; Importing Relay Log /tmp/1-relay-bin.000002 To Slave...
	(DEBUG) create_slave_threads --&gt; Created 2 run_slave Threads
(DEBUG) Enter: run_slave()
	Info: begin [tid: 2]
	(DEBUG) run_slave(1) --&gt; NO KILL SIGNAL --&gt; g_is_killed =&gt;0
	(DEBUG) run_slave --&gt; mysqlbinlog: ./mysqlbinlog -h2.3.4.5 -uplx -pplx -R -t --start-position=1541 mysql-bin.000002 &gt; /tmp/2-relay-bin.000002
Warning: ./mysqlbinlog: unknown variable 'loose_default-character-set=utf8'
	(DEBUG) run_slave(1) --&gt; NO KILL SIGNAL --&gt; g_is_killed =&gt;0
(DEBUG) Enter: import_to_slave()
	Info: begin [Param: p_master_idx=&gt;1]
	(DEBUG) import_to_slave(1) --&gt; NO KILL SIGNAL --&gt; g_is_killed =&gt;0
	(DEBUG) import_to_slave(1) --&gt; Importing Relay Log /tmp/2-relay-bin.000002 To Slave...
(DEBUG) Enter: update_master_info()
	Info: begin [Param: p_master_idx=&gt;0]
(DEBUG) Enter: update_master_info()
	Info: begin [Param: p_master_idx=&gt;1]
	(DEBUG) update_master_info(0) --&gt; Now Master-Log is mysql-bin.000002 Pos is 1482
(DEBUG) Enter: update_master_info_file()
	Info: begin [Param: p_master_idx=&gt;0]
	(DEBUG) update_master_info_file(0) --&gt; NO KILL SIGNAL --&gt; g_is_killed =&gt;0
	(DEBUG) update_master_info_file(0) --&gt; Writing master1.info --&gt; MASTER_LOG_POS=1482
	(DEBUG) update_master_info_file(0) --&gt; Writing master1.info --&gt; NAME=master1
	(DEBUG) update_master_info_file(0) --&gt; Writing master1.info --&gt; MASTER_USER=plx
	(DEBUG) update_master_info_file(0) --&gt; Writing master1.info --&gt; RELAY_LOG_NAME=1-relay-bin
	(DEBUG) update_master_info_file(0) --&gt; Writing master1.info --&gt; MASTER_LOG_IDX=2
	(DEBUG) update_master_info_file(0) --&gt; Writing master1.info --&gt; MASTER_HOST=1.2.3.4
	(DEBUG) update_master_info_file(0) --&gt; Writing master1.info --&gt; MASTER_LOG_NAME=mysql-bin
	(DEBUG) update_master_info_file(0) --&gt; Writing master1.info --&gt; MASTER_PORT=3306
	(DEBUG) update_master_info_file(0) --&gt; Writing master1.info --&gt; RELAY_LOG_DIR=/tmp/
	(DEBUG) update_master_info_file(0) --&gt; Writing master1.info --&gt; MASTER_PASSWORD=plx
	(DEBUG) update_master_info_file(0) --&gt; Writing master1.info --&gt; RELAY_LOG_IDX=3
	(DEBUG) update_master_info_file(0) --&gt; Created master1.info
(DEBUG) Enter: update_master_info_file(0)
	Info: exit
(DEBUG) Enter: update_master_info(0)
	Info: exit
(DEBUG) Enter: import_to_slave(0)
	Info: exit
(DEBUG) Enter: run_slave(0)
	Info: exit
	(DEBUG) update_master_info(1) --&gt; Now Master-Log is mysql-bin.000002 Pos is 2120
(DEBUG) Enter: update_master_info_file()
	Info: begin [Param: p_master_idx=&gt;1]
	(DEBUG) update_master_info_file(1) --&gt; NO KILL SIGNAL --&gt; g_is_killed =&gt;0
	(DEBUG) update_master_info_file(1) --&gt; Writing master2.info --&gt; MASTER_LOG_POS=2120
	(DEBUG) update_master_info_file(1) --&gt; Writing master2.info --&gt; NAME=master2
	(DEBUG) update_master_info_file(1) --&gt; Writing master2.info --&gt; MASTER_USER=plx
	(DEBUG) update_master_info_file(1) --&gt; Writing master2.info --&gt; RELAY_LOG_NAME=2-relay-bin
	(DEBUG) update_master_info_file(1) --&gt; Writing master2.info --&gt; MASTER_LOG_IDX=2
	(DEBUG) update_master_info_file(1) --&gt; Writing master2.info --&gt; MASTER_HOST=2.3.4.5
	(DEBUG) update_master_info_file(1) --&gt; Writing master2.info --&gt; MASTER_LOG_NAME=mysql-bin
	(DEBUG) update_master_info_file(1) --&gt; Writing master2.info --&gt; MASTER_PORT=3306
	(DEBUG) update_master_info_file(1) --&gt; Writing master2.info --&gt; RELAY_LOG_DIR=/tmp/
	(DEBUG) update_master_info_file(1) --&gt; Writing master2.info --&gt; MASTER_PASSWORD=plx
	(DEBUG) update_master_info_file(1) --&gt; Writing master2.info --&gt; RELAY_LOG_IDX=3
	(DEBUG) update_master_info_file(1) --&gt; Created master2.info
(DEBUG) Enter: update_master_info_file(1)
	Info: exit
(DEBUG) Enter: update_master_info(1)
	Info: exit
(DEBUG) Enter: import_to_slave(1)
	Info: exit
(DEBUG) Enter: run_slave(1)
	Info: exit
(DEBUG) Enter: create_slave_threads()
	Info: exit</pre></td></tr></table></div>
<h2  class="related_post_title">类似的文章</h2><ul class="related_post"><li>2010年09月12日 -- <a href="http://www.penglixun.com/tech/database/backup_mysql_use_mysqlbinlog.html" title="利用mysqlbinlog进行集群备份的设想">利用mysqlbinlog进行集群备份的设想</a> (3)</li><li>2012年01月23日 -- <a href="http://www.penglixun.com/tech/database/case_about_innodb_faster_than_oracle.html" title="一个InnoDB性能超过Oracle的调优Case">一个InnoDB性能超过Oracle的调优Case</a> (1)</li><li>2011年12月23日 -- <a href="http://www.penglixun.com/tech/database/server_kill_idle_transaction.html" title="在Server层实现Kill Idle Transaction">在Server层实现Kill Idle Transaction</a> (1)</li></ul>]]></content:encoded>
			<wfw:commentRss>http://www.penglixun.com/tech/program/how_to_mysql_multi_master.html/feed</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>MySQL多个Slave同一server_id的冲突原因分析</title>
		<link>http://www.penglixun.com/tech/database/mysql_multi_slave_same_serverid.html</link>
		<comments>http://www.penglixun.com/tech/database/mysql_multi_slave_same_serverid.html#comments</comments>
		<pubDate>Fri, 07 Jan 2011 14:37:54 +0000</pubDate>
		<dc:creator>P.Linux</dc:creator>
				<category><![CDATA[数据库]]></category>
		<category><![CDATA[MySQL]]></category>

		<guid isPermaLink="false">http://www.penglixun.com/?p=1185</guid>
		<description><![CDATA[本文内容遵从CC版权协议, 可以随意转载, 但必须以超链接形式标明文章原始出处和作者信息及版权声明网址: http://www.penglixun.com/tech/database/mysql_multi_slave_same_serverid.html 今天分析一个诡异问题，... ]]></description>
			<content:encoded><![CDATA[<p><span style="color: #888888;">本文内容遵从<a href="http://creativecommons.org/licenses/by-nc-sa/3.0/deed.zh" target="_blank">CC版权协议</a>, 可以随意转载, 但必须以超链接形式标明文章原始出处和作者信息及版权声明</br>网址: http://www.penglixun.com/tech/database/mysql_multi_slave_same_serverid.html </p>
<p></span>今天分析一个诡异问题，一个模拟Slave线程的程序，不断的被Master Server给kill掉，最终发现是因为有两个Slave使用同样一个server id去连接Master Server，为什么两个Slave用同一个server id会被Master Server给Kill呢？分析了源码，这源于<strong>MySQL Replication的重连机制</strong>。</p>
<p>我们首先看看一个Slave注册到Master会发生什么，首先Slave需要向Master发送一个COM_REGISTER_SLAVE类型的请求（sql_parse.cc）命令请求，这里Master会使用register_slave函数注册一个Slave到slave_list。</p>

<div class="wp_codebox"><table><tr id="p118549"><td class="code" id="p1185code49"><pre class="cpp" style="font-family:monospace;">  <span style="color: #0000ff;">case</span> COM_REGISTER_SLAVE<span style="color: #008080;">:</span>
  <span style="color: #008000;">&#123;</span>
    <span style="color: #0000ff;">if</span> <span style="color: #008000;">&#40;</span><span style="color: #000040;">!</span>register_slave<span style="color: #008000;">&#40;</span>thd, <span style="color: #008000;">&#40;</span>uchar<span style="color: #000040;">*</span><span style="color: #008000;">&#41;</span>packet, packet_length<span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span>
      my_ok<span style="color: #008000;">&#40;</span>thd<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
    <span style="color: #0000ff;">break</span><span style="color: #008080;">;</span>
  <span style="color: #008000;">&#125;</span></pre></td></tr></table></div>

<p>在注册Slave线程的时候会发生什么呢？我们略去无用的代码直接看重点：（repl_failsafe.cc）</p>

<div class="wp_codebox"><table><tr id="p118550"><td class="code" id="p1185code50"><pre class="cpp" style="font-family:monospace;"><span style="color: #0000ff;">int</span> register_slave<span style="color: #008000;">&#40;</span>THD<span style="color: #000040;">*</span> thd, uchar<span style="color: #000040;">*</span> packet, uint packet_length<span style="color: #008000;">&#41;</span>
<span style="color: #008000;">&#123;</span>
  <span style="color: #0000ff;">int</span> res<span style="color: #008080;">;</span>
  SLAVE_INFO <span style="color: #000040;">*</span>si<span style="color: #008080;">;</span>
  uchar <span style="color: #000040;">*</span>p<span style="color: #000080;">=</span> packet, <span style="color: #000040;">*</span>p_end<span style="color: #000080;">=</span> packet <span style="color: #000040;">+</span> packet_length<span style="color: #008080;">;</span>
.... <span style="color: #666666;">//省略</span>
  <span style="color: #0000ff;">if</span> <span style="color: #008000;">&#40;</span><span style="color: #000040;">!</span><span style="color: #008000;">&#40;</span>si<span style="color: #000040;">-</span><span style="color: #000080;">&gt;</span>master_id<span style="color: #000080;">=</span> uint4korr<span style="color: #008000;">&#40;</span>p<span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span>
    si<span style="color: #000040;">-</span><span style="color: #000080;">&gt;</span>master_id<span style="color: #000080;">=</span> server_id<span style="color: #008080;">;</span>
  si<span style="color: #000040;">-</span><span style="color: #000080;">&gt;</span>thd<span style="color: #000080;">=</span> thd<span style="color: #008080;">;</span>
  pthread_mutex_lock<span style="color: #008000;">&#40;</span><span style="color: #000040;">&amp;</span>LOCK_slave_list<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
  unregister_slave<span style="color: #008000;">&#40;</span>thd,<span style="color: #0000dd;">0</span>,<span style="color: #0000dd;">0</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> <span style="color: #666666;">//关键在这里，先取消注册server_id相同的Slave线程</span>
  res<span style="color: #000080;">=</span> my_hash_insert<span style="color: #008000;">&#40;</span><span style="color: #000040;">&amp;</span>slave_list, <span style="color: #008000;">&#40;</span>uchar<span style="color: #000040;">*</span><span style="color: #008000;">&#41;</span> si<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> <span style="color: #666666;">//把新的Slave线程注册到slave_list</span>
  pthread_mutex_unlock<span style="color: #008000;">&#40;</span><span style="color: #000040;">&amp;</span>LOCK_slave_list<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
  <span style="color: #0000ff;">return</span> res<span style="color: #008080;">;</span>
.....
<span style="color: #008000;">&#125;</span></pre></td></tr></table></div>

<p>这是什么意思呢？这就是重连机制，slave_list是一个Hash表，server_id是Key，每一个线程注册上来，需要删掉同样server_id的Slave线程，再把新的Slave线程加到slave_list表中。</p>
<p>线程注册上来后，请求Binlog，发送COM_BINLOG_DUMP请求，Master会发送binlog给Slave，代码如下：</p>

<div class="wp_codebox"><table><tr id="p118551"><td class="code" id="p1185code51"><pre class="cpp" style="font-family:monospace;">  <span style="color: #0000ff;">case</span> COM_BINLOG_DUMP<span style="color: #008080;">:</span>
    <span style="color: #008000;">&#123;</span>
      ulong pos<span style="color: #008080;">;</span>
      ushort flags<span style="color: #008080;">;</span>
      uint32 slave_server_id<span style="color: #008080;">;</span>
&nbsp;
      status_var_increment<span style="color: #008000;">&#40;</span>thd<span style="color: #000040;">-</span><span style="color: #000080;">&gt;</span>status_var.<span style="color: #007788;">com_other</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
      thd<span style="color: #000040;">-</span><span style="color: #000080;">&gt;</span>enable_slow_log<span style="color: #000080;">=</span> opt_log_slow_admin_statements<span style="color: #008080;">;</span>
      <span style="color: #0000ff;">if</span> <span style="color: #008000;">&#40;</span>check_global_access<span style="color: #008000;">&#40;</span>thd, REPL_SLAVE_ACL<span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span>
        <span style="color: #0000ff;">break</span><span style="color: #008080;">;</span>
&nbsp;
      <span style="color: #ff0000; font-style: italic;">/* TODO: The following has to be changed to an 8 byte integer */</span>
      pos <span style="color: #000080;">=</span> uint4korr<span style="color: #008000;">&#40;</span>packet<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
      flags <span style="color: #000080;">=</span> uint2korr<span style="color: #008000;">&#40;</span>packet <span style="color: #000040;">+</span> <span style="color: #0000dd;">4</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
      thd<span style="color: #000040;">-</span><span style="color: #000080;">&gt;</span>server_id<span style="color: #000080;">=</span><span style="color: #0000dd;">0</span><span style="color: #008080;">;</span> <span style="color: #ff0000; font-style: italic;">/* avoid suicide */</span>
      <span style="color: #0000ff;">if</span> <span style="color: #008000;">&#40;</span><span style="color: #008000;">&#40;</span>slave_server_id<span style="color: #000080;">=</span> uint4korr<span style="color: #008000;">&#40;</span>packet<span style="color: #000040;">+</span><span style="color: #0000dd;">6</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span> <span style="color: #666666;">// mysqlbinlog.server_id==0</span>
        kill_zombie_dump_threads<span style="color: #008000;">&#40;</span>slave_server_id<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
      thd<span style="color: #000040;">-</span><span style="color: #000080;">&gt;</span>server_id <span style="color: #000080;">=</span> slave_server_id<span style="color: #008080;">;</span>
&nbsp;
      general_log_print<span style="color: #008000;">&#40;</span>thd, command, <span style="color: #FF0000;">&quot;Log: '%s'  Pos: %ld&quot;</span>, packet<span style="color: #000040;">+</span><span style="color: #0000dd;">10</span>,
                      <span style="color: #008000;">&#40;</span><span style="color: #0000ff;">long</span><span style="color: #008000;">&#41;</span> pos<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
      mysql_binlog_send<span style="color: #008000;">&#40;</span>thd, thd<span style="color: #000040;">-</span><span style="color: #000080;">&gt;</span>strdup<span style="color: #008000;">&#40;</span>packet <span style="color: #000040;">+</span> <span style="color: #0000dd;">10</span><span style="color: #008000;">&#41;</span>, <span style="color: #008000;">&#40;</span>my_off_t<span style="color: #008000;">&#41;</span> pos, flags<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> <span style="color: #666666;">//不断的发送日志给slave端</span>
      unregister_slave<span style="color: #008000;">&#40;</span>thd,<span style="color: #0000dd;">1</span>,<span style="color: #0000dd;">1</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> <span style="color: #666666;">//发送完成后清理Slave线程，因为执行到这一步肯定是binlog dump线程被kill了</span>
      <span style="color: #ff0000; font-style: italic;">/*  fake COM_QUIT -- if we get here, the thread needs to terminate */</span>
      error <span style="color: #000080;">=</span> TRUE<span style="color: #008080;">;</span>
      <span style="color: #0000ff;">break</span><span style="color: #008080;">;</span>
    <span style="color: #008000;">&#125;</span></pre></td></tr></table></div>

<p>mysql_binlog_send函数在sql_repl.cc，里面是轮询Master binlog，发送给Slave。</p>
<p>再来简单看看unregister_slave做了什么（repl_failsafe.cc）：</p>

<div class="wp_codebox"><table><tr id="p118552"><td class="code" id="p1185code52"><pre class="cpp" style="font-family:monospace;"><span style="color: #0000ff;">void</span> unregister_slave<span style="color: #008000;">&#40;</span>THD<span style="color: #000040;">*</span> thd, <span style="color: #0000ff;">bool</span> only_mine, <span style="color: #0000ff;">bool</span> need_mutex<span style="color: #008000;">&#41;</span>
<span style="color: #008000;">&#123;</span>
  <span style="color: #0000ff;">if</span> <span style="color: #008000;">&#40;</span>thd<span style="color: #000040;">-</span><span style="color: #000080;">&gt;</span>server_id<span style="color: #008000;">&#41;</span>
  <span style="color: #008000;">&#123;</span>
    <span style="color: #0000ff;">if</span> <span style="color: #008000;">&#40;</span>need_mutex<span style="color: #008000;">&#41;</span>
      pthread_mutex_lock<span style="color: #008000;">&#40;</span><span style="color: #000040;">&amp;</span>LOCK_slave_list<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
&nbsp;
    SLAVE_INFO<span style="color: #000040;">*</span> old_si<span style="color: #008080;">;</span>
    <span style="color: #0000ff;">if</span> <span style="color: #008000;">&#40;</span><span style="color: #008000;">&#40;</span>old_si <span style="color: #000080;">=</span> <span style="color: #008000;">&#40;</span>SLAVE_INFO<span style="color: #000040;">*</span><span style="color: #008000;">&#41;</span>hash_search<span style="color: #008000;">&#40;</span><span style="color: #000040;">&amp;</span>slave_list,
                                           <span style="color: #008000;">&#40;</span>uchar<span style="color: #000040;">*</span><span style="color: #008000;">&#41;</span><span style="color: #000040;">&amp;</span>thd<span style="color: #000040;">-</span><span style="color: #000080;">&gt;</span>server_id, <span style="color: #0000dd;">4</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span> <span style="color: #000040;">&amp;&amp;</span>
        <span style="color: #008000;">&#40;</span><span style="color: #000040;">!</span>only_mine <span style="color: #000040;">||</span> old_si<span style="color: #000040;">-</span><span style="color: #000080;">&gt;</span>thd <span style="color: #000080;">==</span> thd<span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span> <span style="color: #666666;">//拿到slave值</span>
    hash_delete<span style="color: #008000;">&#40;</span><span style="color: #000040;">&amp;</span>slave_list, <span style="color: #008000;">&#40;</span>uchar<span style="color: #000040;">*</span><span style="color: #008000;">&#41;</span>old_si<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> <span style="color: #666666;">//从slave_list中拿掉</span>
&nbsp;
    <span style="color: #0000ff;">if</span> <span style="color: #008000;">&#40;</span>need_mutex<span style="color: #008000;">&#41;</span>
      pthread_mutex_unlock<span style="color: #008000;">&#40;</span><span style="color: #000040;">&amp;</span>LOCK_slave_list<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
  <span style="color: #008000;">&#125;</span>
<span style="color: #008000;">&#125;</span></pre></td></tr></table></div>

<p>这就可以解释同样的server_id为什么会被kill，因为一旦注册上去，就会现删除相同server_id的Slave线程，然后把当前的Slave加入，这是因为有时Slave断开了，重新请求上来，当然需要踢掉原来的线程，这就是线程重连机制。</p>
<p>切记，一个MySQL集群中，绝不可以出现相同server_id的实例，否则各种诡异的问题可是接踵而来。</p><h2  class="related_post_title">类似的文章</h2><ul class="related_post"><li>2012年01月23日 -- <a href="http://www.penglixun.com/tech/database/case_about_innodb_faster_than_oracle.html" title="一个InnoDB性能超过Oracle的调优Case">一个InnoDB性能超过Oracle的调优Case</a> (1)</li><li>2011年12月23日 -- <a href="http://www.penglixun.com/tech/database/server_kill_idle_transaction.html" title="在Server层实现Kill Idle Transaction">在Server层实现Kill Idle Transaction</a> (1)</li><li>2011年11月29日 -- <a href="http://www.penglixun.com/tech/database/how_to_kill_idle_trx.html" title="如何杀掉空闲事务">如何杀掉空闲事务</a> (1)</li></ul>]]></content:encoded>
			<wfw:commentRss>http://www.penglixun.com/tech/database/mysql_multi_slave_same_serverid.html/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>ICC静态编译Percona</title>
		<link>http://www.penglixun.com/tech/database/icc_static_compile_percona.html</link>
		<comments>http://www.penglixun.com/tech/database/icc_static_compile_percona.html#comments</comments>
		<pubDate>Thu, 06 Jan 2011 13:37:47 +0000</pubDate>
		<dc:creator>P.Linux</dc:creator>
				<category><![CDATA[数据库]]></category>
		<category><![CDATA[ICC]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[Percona]]></category>
		<category><![CDATA[XtraDB]]></category>

		<guid isPermaLink="false">http://www.penglixun.com/?p=1182</guid>
		<description><![CDATA[本文内容遵从CC版权协议, 可以随意转载, 但必须以超链接形式标明文章原始出处和作者信息及版权声明网址: http://www.penglixun.com/tech/database/icc_static_compile_percona.html 经过我的测试ICC在浮点运算，... ]]></description>
			<content:encoded><![CDATA[<p><span style="color: #888888;">本文内容遵从<a href="http://creativecommons.org/licenses/by-nc-sa/3.0/deed.zh" target="_blank">CC版权协议</a>, 可以随意转载, 但必须以超链接形式标明文章原始出处和作者信息及版权声明</br>网址: http://www.penglixun.com/tech/database/icc_static_compile_percona.html </p>
<p></span>经过我的测试ICC在浮点运算，线程库和数学函数上的优势非常明显，原生SSE2指令集支持、Intel自己编写的线程库和数学函数库，性能没得说。<br />
我用同一份运算PI值的代码在ICC和GCC下编译，提升比例达<strong>20%</strong>，实际在数据库中比较同一条超级复杂的聚合<acronym title="Structured Query Language">SQL</acronym>，ICC提升达<strong>34%</strong>。</p>
<p>第一步：编译安装libunwind<br />
wget http://download.savannah.gnu.org/releases/libunwind/libunwind-0.99.tar.gz<br />
tar zxvf libunwind-0.99.tar.gz</p>
<p>CC=icc \<br />
CXX=icpc \<br />
LD=xild \<br />
AR=xiar \<br />
CFLAGS=”-O3 -no-prec-div -ip -xSSE2 -axSSE2&#8243; \<br />
CXXFLAGS=”${CFLAGS}” \<br />
./configure &#038;&#038; make &#038;&#038; make install</p>
<p>第二布：编译安装tcmalloc<br />
wget http://google-perftools.googlecode.com/files/google-perftools-1.6.tar.gz<br />
tar zxvf google-perftools-1.6.tar.gz</p>
<p>CC=icc \<br />
CXX=icpc \<br />
LD=xild \<br />
AR=xiar \<br />
CFLAGS=”-O3 -no-prec-div -ip -xSSE2 -axSSE2&#8243; \<br />
CXXFLAGS=”${CFLAGS}” \<br />
./configure &#8211;disable-debugalloc &#8211;enable-frame-pointers &#038;&#038; make &#038;&#038; make install</p>
<p>echo “/usr/local/lib” > /etc/ld.so.conf.d/usr_local_lib.conf<br />
/sbin/ldconfig</p>
<p>第三部：编译安装Percona<br />
CC=icc \<br />
CXX=icpc \<br />
LD=xild \<br />
AR=xiar \<br />
CFLAGS=”-O3 -unroll2 -ip -mp -restrict -fno-exceptions -fno-rtti -no-prec-div -fno-implicit-templates -static-intel -static-libgcc -xSSE2 -axSSE2&#8243; \<br />
CXXFLAGS=”${CFLAGS}” \<br />
CPPFLAGS=” -I/usr/alibaba/icc/include ” \<br />
LDFLAGS=” -L/usr/alibaba/icc/lib -lrt ” \<br />
./configure &#8211;prefix=/usr/alibaba/install/percona-custom-5.1.53-12.4 \<br />
&#8211;with-server-suffix=-alibaba-edition \<br />
&#8211;with-mysqld-user=mysql \<br />
&#8211;with-plugins=heap,innodb_plugin,myisam,partition \<br />
&#8211;with-charset=utf8 \<br />
&#8211;with-collation=utf8_general_ci \<br />
&#8211;with-extra-charsets=gbk,utf8,ascii \<br />
&#8211;with-big-tables \<br />
&#8211;with-fast-mutexes \<br />
&#8211;with-zlib-dir=bundled \<br />
&#8211;with-readline \<br />
&#8211;with-pthread \<br />
&#8211;with-mysqld-ldflags=&#8217;-all-static -ltcmalloc&#8217; \<br />
&#8211;enable-assembler \<br />
&#8211;enable-profiling \<br />
&#8211;enable-local-infile \<br />
&#8211;enable-thread-safe-client \<br />
&#8211;without-embedded-server \<br />
&#8211;with-client-ldflags=-all-static \<br />
&#8211;with-mysqld-ldflags=-all-static \<br />
&#8211;with-mysqld-ldflags=-ltcmalloc \<br />
&#8211;without-query-cache \<br />
&#8211;without-geometry \<br />
&#8211;without-debug \<br />
&#8211;without-ndb-binlog \<br />
&#8211;without-ndb-debug<br />
编译完成后make &#038;&#038; make install</p><h2  class="related_post_title">类似的文章</h2><ul class="related_post"><li>2012年01月23日 -- <a href="http://www.penglixun.com/tech/database/case_about_innodb_faster_than_oracle.html" title="一个InnoDB性能超过Oracle的调优Case">一个InnoDB性能超过Oracle的调优Case</a> (1)</li><li>2011年12月23日 -- <a href="http://www.penglixun.com/tech/database/server_kill_idle_transaction.html" title="在Server层实现Kill Idle Transaction">在Server层实现Kill Idle Transaction</a> (1)</li><li>2010年12月6日 -- <a href="http://www.penglixun.com/tech/database/percona_vs_mysql.html" title="Percona对MySQL标准版本的改进">Percona对MySQL标准版本的改进</a> (3)</li></ul>]]></content:encoded>
			<wfw:commentRss>http://www.penglixun.com/tech/database/icc_static_compile_percona.html/feed</wfw:commentRss>
		<slash:comments>9</slash:comments>
		</item>
		<item>
		<title>PostgreSQL和MySQL的对比，第1部分：表组织</title>
		<link>http://www.penglixun.com/tech/database/mysql-vs-postgresql-part-1-table-organization.html</link>
		<comments>http://www.penglixun.com/tech/database/mysql-vs-postgresql-part-1-table-organization.html#comments</comments>
		<pubDate>Mon, 27 Dec 2010 12:36:04 +0000</pubDate>
		<dc:creator>P.Linux</dc:creator>
				<category><![CDATA[数据库]]></category>
		<category><![CDATA[InnoDB]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[PostgreSQL]]></category>

		<guid isPermaLink="false">http://www.penglixun.com/?p=1181</guid>
		<description><![CDATA[本文内容遵从CC版权协议, 可以随意转载, 但必须以超链接形式标明文章原始出处和作者信息及版权声明网址: http://www.penglixun.com/tech/database/mysql-vs-postgresql-part-1-table-organization.html 翻译自：http://bl... ]]></description>
			<content:encoded><![CDATA[<p><span style="color: #888888;">本文内容遵从<a href="http://creativecommons.org/licenses/by-nc-sa/3.0/deed.zh" target="_blank">CC版权协议</a>, 可以随意转载, 但必须以超链接形式标明文章原始出处和作者信息及版权声明</br>网址: http://www.penglixun.com/tech/database/mysql-vs-postgresql-part-1-table-organization.html </p>
<p></span>翻译自：http://blogs.enterprisedb.com/2010/11/29/mysql-vs-postgresql-part-1-table-organization/<br />
翻译不正确之处请指正。</p>
<p>I&#8217;m going to be starting an occasional series of blog postings comparing MySQL&#8217;s architecture to PostgreSQL&#8217;s architecture.  Regular readers of this blog will already be aware that I know PostgreSQL far better than MySQL, having last used MySQL a very long time ago when both products were far less mature than they are today.  So, my discussion of how PostgreSQL works will be based on first-hand knowledge, but discussion of how MySQL works will be based on research and – insofar as I&#8217;m can make it happen – discussion with people who know it better than I do.  (Note: If you&#8217;re a person who knows MySQL better than I do and would like to help me avoid making stupid mistakes, drop me an email.)<br />
我将要开始一个比较MySQL和PostgreSQL架构系列的博客。本博客的长期读者都已经知道，我最后一次使用MySQL是在很久很久以前两款产品都远不如今天的时候，所以我认为PostgreSQL远好于MySQL。因此，我讨论PostgreSQL如何工作是基于第一手资料，而对于MySQL则是基于很久以前的情况，看博客的同学有很多比我更了解MySQL。如果你是一个比我更了解MySQL的人，发现了我愚蠢的错误请给我一个邮件。</p>
<p>In writing these posts, I&#8217;m going to try to avoid making value judgments about which system is “better”, and instead focus on describing how the architecture differs, and maybe a bit about the advantages of each architecture.  I can&#8217;t promise that it will be entirely unbiased (after all, I am a PostgreSQL committer, not a MySQL committer!) but I&#8217;m going to try to make it as unbiased as I can.  Also, bearing in mind what I&#8217;ve recently been told by Baron Schwartz and Rob Wultsch, I&#8217;m going to focus completely on InnoDB and ignore MyISAM and all other storage engines.  Finally, I&#8217;m going to focus on architectural differences.  People might choose to use PostgreSQL because they hate Oracle, or MySQL because it&#8217;s easier to find hosting, or either product because they know it better, and that&#8217;s totally legitimate and perhaps worth talking about, but – partly in the interests of harmony among communities that ought to be allies – it&#8217;s not what I&#8217;m going to talk about here.<br />
写这些文章，我要尽量避免作出哪个系统更好的判断，而是侧重于介绍他们架构的不同，也许是一些各种架构的优势。我不能保证这些观点是完全不带偏见的（毕竟，我是一个PostgreSQL代码的提交者，而不是MySQL的提交者），但是我会尽量做到不偏重某一个。此外，考虑到我最近已经跟Baron Schwartz和Rob Wultsch说的内容，我将完全忽略MyISAM和所有其他存储引擎，而重点关注InnoDB。最后，我将专注于架构的差异。人们有时选择使用PostgreSQL是因为他们恨甲骨文，或者选择MySQL因为它更容易找到托管服务，或其他一些产品因为他们知道它更好，并且这是完全符合授权的。这些但这不是我想要谈的。（译者注：最后一段话太绕口，翻译不了，只翻译大意）</p>
<p>So, all that having been said, what I&#8217;d like to talk about in this post is the way that MySQL and PostgreSQL store tables and indexes on disk.  In PostgreSQL, table data and index data are stored in completely separate structures.  When a new row is inserted, or when an existing row is updated, the new row is stored in any convenient place in the table.  In the case of an update, we try to store the new row on the same page as the old row if there&#8217;s room; if there isn&#8217;t room or if it&#8217;s an insert, we pick a page that has adequate free space and use that, or failing all else extend the table by one page and add the new row there.  Once the table row is added, we cycle through all the indexes defined for the table and add an index entry to each one pointing at the physical position of the table row.  One index may happen to be the primary key, but that&#8217;s a fairly nominal distinction – all indexes are basically the same.<br />
因此，我将说的内容是，MySQL和PostgreSQL的表和索引存储在磁盘上的方式。在 PostgreSQL，表数据和索引数据是完全分开存储的。当新行插入，或现有的行被更新，新行是表中的任何方便保存的地方保存。在更新的场景下，我们尝试在页内还有空间的情况下存储新行与旧行在同一个页上。如果没有空间，或者如果它是一个插入操作，我们将选择一个有足够空闲空间的页，使用它，或者扩展一个新页把新行放入。我们轮训表上定义的所有索引，并添加一个索引项指针指向表中新行的物理位置。这个索引也许是主键，也许是一般的索引，但是所有的所有索引都是基于一样的操作。</p>
<p>Under MySQL&#8217;s InnoDB, the table data and the primary key index are stored in the same data structure.  As I understand it, this is what Oracle calls an index-organized table.  Any additional (”secondary”) indexes refer to the primary key value of the tuple to which they point, not the physical position, which can change as leaf pages in the primary key index are split.  Since this architecture requires every table to have a primary key, an internal row ID field is used as the primary key if no explicit primary key is specified.<br />
在InnoDB中，表数据和主键索引是存在同样的数据结构中（译者注：主键聚集索引）。据我的理解，这就像Oracle的索引组织表（译者注：还是有一些区别，索引组织表完全按索引排序，但是InnoDB只按主键排序）。任何非主键索引指向主键索引的位置，而不是物理位置，所以主键索引页的页节点分裂不会导致数据改变。由于这种架构要求每个表都有一个主键，所以如果没有定义主键内部将隐含定义一个主键（译者注，内部定义的主键为6字节）。</p>
<p>Since Oracle supports both options, they are probably both useful.  An index-organized table seems particularly likely to be useful when most lookups are by primary key, and most of the data in each row is part of the primary key anyway, either because the primary key columns are long compared with the remaining columns, or because the rows, overall, are short.  Storing the whole row in the index avoids storing the same data twice (once in the index and once in the table), and the gain will be larger when the primary key is a substantial percentage of the total data.  Furthermore, in this situation, the index page still holds as many, or almost as many, keys as it would if only a pointer were stored in lieu of the whole row, so one fewer random I/Os will be needed to access a given row.<br />
由于Oracle支持两种选择（索引组织表和堆表），他们可能都非常有用。一个索引组织表似乎在多数<acronym title="Structured Query Language">SQL</acronym>是通过主键查找，以及每行的大部分数据是主键的一部分的时候非常有用。要么因为主键列比其余的列长，或因为行总体而言是比较短的。存储整行数据在索引上避免了同样的数据存两分（一份在索引，一份在表中），但是如果主键占数据行的比例较大时，数据增益（译者注：数据+表的重复数据量）将更大。此外，在这种情况下，索引页将保存很多或几乎一样多的数据，访问数据时在索引页中就可能得到整行需要的列，所以这可以减少随机IO（译者注：覆盖索引扫描，Index Scan）。</p>
<p>When accessing an index-organized table via a secondary index, it may be necessary to traverse both the B-tree in the secondary-index, and the B-tree in the primary index.  As a result, queries involving secondary indexes might be slower.  However, since MySQL has index-only scans ( PostgreSQL does not ), it can sometimes avoid traversing the secondary index.  So in MySQL, adding additional columns to an index might very well make it run faster, if it causes the index to function as a covering index for the query being executed.  But in PostgreSQL, we frequently find ourselves telling users to pare down the columns in the index to the minimum set that is absolutely necessary, often resulting in dramatic performance gains.  This is an interesting example of how the tuning that is right for one database may be completely wrong for another database.<br />
当通过非主键索引访问一个索引组织表，可能需要遍历非主键索引的B树和主键索引的B树。因此，查询涉及非主键索引可能会变慢。然而，由于MySQL有Index-Scan方式（译者注：访问索引即可获得数据） 而PostgreSQL没有，它有时访问非主键索引就能拿到数据。因此，在MySQL中，添加额外的列索引如果带来覆盖索引的查询计划，则很可能使<acronym title="Structured Query Language">SQL</acronym>运行得更快（译者注：这个不完全对，索引多的话索引页分裂时的物理IO操作还是比较多的，推荐满足需求的情况下减少索引，除非你能保证覆盖索引经常被用到）。但是在PostgreSQL里，我们经常发现自己告诉用户减少索引到满足要求的最低限度时往往能带来巨大的性能提升。这是一个有趣的例子，如何调整数据库在不同的数据库中是完全相反的方法。</p>
<p>I&#8217;ve recently learned that neither InnoDB nor PostgreSQL supports traversing an index in physical order, only in key order.  For InnoDB, this means that ALL scans are performed in key order, since the table itself is, in essence, also an index.  As I understand it, this can make a large sequential scan quite slow, by defeating the operating system&#8217;s prefetch logic.  In PostgreSQL, however, because tables are not index-organized, sequential scans are always performed in physical order, and don&#8217;t require looking at the indexes at all; this also means we can skip any I/O or CPU cost associated with examining non-leaf index pages.  Traversing in physical order is apparently difficult from a locking perspective, although it must be possible, because Oracle supports it.  It would be very useful to see this support in MySQL, and once PostgreSQL has index-only scans, it would be a useful improvement for PostgreSQL, too.<br />
我最近获悉，PostgreSQL跟InnoDB一样也支持通过主键索引顺序遍历（译者注：InnoDB访问全表返回数据按主键顺序排列）。对于 InnoDB，这意味着所有的全表扫描是在扫描主键索引，主键索引本身就是表。据我了解，这可能导致大的顺序扫描慢很多（译者注：这个比较扯淡，在数据静止的情况下，PostgreSQL一样要通过block的指针访问下一个block，InnoDB通过页的指针访问下一个页）。在PostgreSQL，因为表不是按（主键）索引组织，顺序扫描总是按物理顺序进行，并且完全不需要访问索引，这也意味着我们可以跳过任何访问索引非叶子节点的IO或CPU开销（译者注：这位兄台应该忘记了什么是B+树）。显然按物理顺序访问是很困难的，但是肯定可以实现，因为Oracle支持。这是MySQL一个非常有用的功能，PostgreSQL一旦有了覆盖索引扫描功能，对PostgreSQL也将是非常有用的提升。</p>
<p>One final difficulty with an index-organized table is that you can&#8217;t add, drop, or change the primary key definition without a full-table rewrite.  In PostgreSQL, on the other hand, this can be done – even while allow concurrent read and write activity.  This is a fairly nominal advantage for most use cases since the primary key of a table rarely changes – I think it&#8217;s happened to me only once or twice in the last ten years – but it is useful when it does comes up.<br />
使用索引组织表的最后一个问题是不能在不重建全表的情况下添加，删除或变更主键索引定义。反而在PostgreSQL里，这是可以做到的——即使当允许并发读写活动时。在大多数情况下（InnoDB）具有优势，因为在大多数场景下一旦定义主键不太可能更改 。在我最近十年内这只碰到一次或两次——但是它真的发生时，（PostgreSQL）还是很有用的。</p>
<p>I hope that the above is a fair and accurate summary of the topic, but I&#8217;m sure I&#8217;ve missed a few things and covered others incompletely or in less detail than might be helpful.  Please feel free to respond with a comment below or a blog post of your own if I&#8217;ve missed something.<br />
我希望以上是这个专题比较公正和准确的总结，但我敢肯定，我已经错过了一些东西，或者覆盖一些内容不完全，缺少一些可能会有所帮助的细节。请随时反馈在下面的评论中评论您对我遗漏的一些内容的看法。</p><h2  class="related_post_title">类似的文章</h2><ul class="related_post"><li>2012年01月23日 -- <a href="http://www.penglixun.com/tech/database/case_about_innodb_faster_than_oracle.html" title="一个InnoDB性能超过Oracle的调优Case">一个InnoDB性能超过Oracle的调优Case</a> (1)</li><li>2011年12月23日 -- <a href="http://www.penglixun.com/tech/database/server_kill_idle_transaction.html" title="在Server层实现Kill Idle Transaction">在Server层实现Kill Idle Transaction</a> (1)</li><li>2011年01月27日 -- <a href="http://www.penglixun.com/tech/database/plug-in-for-performance-and-scalability.html" title="[译]InnoDB官方博客：InnoDB Plugin的性能和可伸缩性">[译]InnoDB官方博客：InnoDB Plugin的性能和可伸缩性</a> (0)</li></ul>]]></content:encoded>
			<wfw:commentRss>http://www.penglixun.com/tech/database/mysql-vs-postgresql-part-1-table-organization.html/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>InnoDB的Master Thread调度流程</title>
		<link>http://www.penglixun.com/tech/database/innodb_master_thread.html</link>
		<comments>http://www.penglixun.com/tech/database/innodb_master_thread.html#comments</comments>
		<pubDate>Tue, 14 Dec 2010 17:22:03 +0000</pubDate>
		<dc:creator>P.Linux</dc:creator>
				<category><![CDATA[数据库]]></category>
		<category><![CDATA[InnoDB]]></category>
		<category><![CDATA[Master Thread]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[XtraDB]]></category>

		<guid isPermaLink="false">http://www.penglixun.com/?p=1180</guid>
		<description><![CDATA[本文内容遵从CC版权协议, 可以随意转载, 但必须以超链接形式标明文章原始出处和作者信息及版权声明网址: http://www.penglixun.com/tech/database/innodb_master_thread.html InnoDB的主要IO操作都是在Master Thread... ]]></description>
			<content:encoded><![CDATA[<p><span style="color: #888888;">本文内容遵从<a href="http://creativecommons.org/licenses/by-nc-sa/3.0/deed.zh" target="_blank">CC版权协议</a>, 可以随意转载, 但必须以超链接形式标明文章原始出处和作者信息及版权声明</br>网址: http://www.penglixun.com/tech/database/innodb_master_thread.html </p>
<p></span>InnoDB的主要IO操作都是在<strong>Master Thread</strong>（srv0srv.c）中完成的，所以分析InnoDB的IO调度，就一定要分析Master Thread线程。</p>
<p>下面是我画的一张流程图，标识了整个Master Thread的调度流程。红色部分是InnoDB Plugin/XtraDB对原有InnoDB引擎的改进。<br />
每个Process文字中最下面的括号是进行这个操作的具体函数，可以参照源代码阅读本图。</p>
<p>顺便解释一下“<strong>插入缓冲</strong>”（Insert Buffer）：InnoDB为了避免更新数据时更新索引损失太多性能，使用了这种称为Insert Buffer的方法来缓冲索引更新，对于非聚集索引（主键索引）、唯一索引的修改，不是每次都直接插入索引页，而是先判断要更新的这一页在不在内存中，如果不在则存入Insert Buffer，按照Master Thread的调度规则来合并非唯一索引和索引页中的叶子结点，这样经常能减少更新索引的代价。<strong>为什么要求是非唯一索引</strong>（排除主键索引和唯一索引）呢？因为唯一索引要检查记录是不是存在，所以必须把修改的记录影响的索引页读出来才知道是不是唯一，这样Insert Buffer就没意义了，反正要读出来，所以只对非唯一索引有效。<br />
show innodb status中的“INSERT BUFFER AND ADAPITIVE HASH INDEX”里面显示了Insert Buffer的效果。</p>
<p><strong>更正一部分，发现在刷新100个赃页后，InnoDB认为刷新耗时已经超过一秒了，无需等待，设置skip_sleep=TRUE，直接跳过os_pthread_sleep，进行下一次判断。</strong></p>
<p><img src="http://file.penglixun.com/InnoDB_Master_Thread.png" alt="InnoDB Master Thread" /></p><h2  class="related_post_title">类似的文章</h2><ul class="related_post"><li>2012年01月23日 -- <a href="http://www.penglixun.com/tech/database/case_about_innodb_faster_than_oracle.html" title="一个InnoDB性能超过Oracle的调优Case">一个InnoDB性能超过Oracle的调优Case</a> (1)</li><li>2011年12月23日 -- <a href="http://www.penglixun.com/tech/database/server_kill_idle_transaction.html" title="在Server层实现Kill Idle Transaction">在Server层实现Kill Idle Transaction</a> (1)</li><li>2010年12月6日 -- <a href="http://www.penglixun.com/tech/database/percona_vs_mysql.html" title="Percona对MySQL标准版本的改进">Percona对MySQL标准版本的改进</a> (3)</li></ul>]]></content:encoded>
			<wfw:commentRss>http://www.penglixun.com/tech/database/innodb_master_thread.html/feed</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>Slave SQL线程阻塞时执行Slave相关命令的风险</title>
		<link>http://www.penglixun.com/tech/database/slave_sql_locked_bug.html</link>
		<comments>http://www.penglixun.com/tech/database/slave_sql_locked_bug.html#comments</comments>
		<pubDate>Sun, 12 Dec 2010 08:39:53 +0000</pubDate>
		<dc:creator>P.Linux</dc:creator>
				<category><![CDATA[数据库]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[Slave]]></category>

		<guid isPermaLink="false">http://www.penglixun.com/?p=1179</guid>
		<description><![CDATA[本文内容遵从CC版权协议, 可以随意转载, 但必须以超链接形式标明文章原始出处和作者信息及版权声明网址: http://www.penglixun.com/tech/database/slave_sql_locked_bug.html 今天做一批备机加主键的工作时，... ]]></description>
			<content:encoded><![CDATA[<p><span style="color: #888888;">本文内容遵从<a href="http://creativecommons.org/licenses/by-nc-sa/3.0/deed.zh" target="_blank">CC版权协议</a>, 可以随意转载, 但必须以超链接形式标明文章原始出处和作者信息及版权声明</br>网址: http://www.penglixun.com/tech/database/slave_sql_locked_bug.html </p>
<p></span>今天做一批备机加主键的工作时，意外发现，如果有一个线程阻塞了Slave <acronym title="Structured Query Language">SQL</acronym>线程应用日志，导致Slave <acronym title="Structured Query Language">SQL</acronym>在Locked状态，再试图执行Slave Stop命令时，必定导致show slave status/master status等语句执行Hang死。<br />
解决方法是只能等待锁定Slave <acronym title="Structured Query Language">SQL</acronym>的线程结束，或者重启数据库，还没试出其他方法可以解决。已经在MySQL 5.0.68、5.1.30/34/40上重现。<br />
搜索了Bug库，确实找到了这个bug，http://bugs.mysql.com/bug.php?id=56676，至少在5.1.50之前都会有这个问题。</p>
<p>查看了源码，主要是由于<strong>mi-&gt;run_lock</strong>和<strong>LOCK_active_mi</strong>两个锁导致的问题。<br />
slave的运行流程是 start_slave_thread函数创建handler_slave_sql线程去轮询日志，handler_slave_sql调用exec_relay_log_event去应用日志事件，exec_relay_log_event又调用apply_event_and_update_pos来具体读取一个日志事件应用日志到存储引擎并更新relay-log的pos信息，最后根据读取的日志类型，调用不同类重载的XXX_log_event::do_apply_event去真正使用解出来的日志。</p>
<p>导致Hang住的原因是这样的：<br />
slave_sql一旦启动成功，就会持有mi-&gt;run_lock锁，mi是Master_info的实例，记录主机信息，就是master.info的内容，mi-&gt;run_lock被持有表示mi的Slave正在运行（mi定义为Master_info *，注释里也说了，Multi Master写完后，mi是个数组，可以有每个Master分别持有锁，所以MySQL也在做这个事了），由于目前只支持单Master，所以mi的锁是全局的，即LOCK_active_mi。当一条<acronym title="Structured Query Language">SQL</acronym>被Locked的时候，Slave <acronym title="Structured Query Language">SQL</acronym>持有mi-&gt;run_lock，cond_wait等待不到继续进行的条件，于是运行不到if (!sql_slave_killed(thd,rli))这条语句。所以stop_slave发出kill无法被判断到，于是slave stop就Hang住了。由于stop slave持有LOCK_active_mi（关闭Slave需要保存master.info），而show slave status/show status都会先做pthread_mutex_lock(&amp;LOCK_active_mi);因而全部堵住。<br />
还有一个可能存在的风险，Relay_log_info类的tables_to_lock链表存了Slave要锁住的表，如果Slave不能及时继续，tables_to_lock链表就不能及时清理，会带来很多锁问题，可能引起大面积阻塞。上次有个故障，MySQL Hang死，很可能就是我们一个跳过复制错误的脚本show slave status和slave start/stop执行频率很高，突然切换主备需要建立大量连接的时候CPU上下文切换较多，释放LOCK_active_mi锁的速度就跟不上，另一些show slave status采集监控的脚本迅速阻塞，导致tables_to_lock链表不能及时释放，进而导致正常<acronym title="Structured Query Language">SQL</acronym>执行被锁阻塞，由于变更量非常大，阻塞迅速蔓延，锁等待几乎把数据库Hang死。</p>
<p>所以我提醒各位，在Slave中有长<acronym title="Structured Query Language">SQL</acronym>或Locked的<acronym title="Structured Query Language">SQL</acronym>执行时，除show processlist;外千万不要做show slave/master status以及slave stop等slave相关命令。</p>
<p>handler_slave_sql循环执行：<br />
03058   while (!<span style="color: #ff0000;">sql_slave_killed(thd,rli)</span>)<br />
03059   {<br />
03060     thd_proc_info(thd, “Reading event from the relay log”);<br />
03061     DBUG_ASSERT(rli-&gt;sql_thd == thd);<br />
03062     THD_CHECK_SENTRY(thd);<br />
03063<br />
03064     if (saved_skip &amp;&amp; rli-&gt;slave_skip_counter == 0)<br />
03065     {省略<br />
03076     }<br />
03077<br />
03078     if (<span style="color: #ff0000;">exec_relay_log_event(thd,rli)</span>)<br />
03079     {<br />
03080       DBUG_PRINT(“info”, (“exec_relay_log_event() failed”));<br />
03081       // do not scare the user if <acronym title="Structured Query Language">SQL</acronym> thread was simply killed or stopped<br />
03082       if (!sql_slave_killed(thd,rli))<br />
03083       {省略<br />
03144       }<br />
03145       goto err;<br />
03146     }<br />
03147   }</p>
<p>show slave status命令<br />
07409 static int show_slave_running(THD *thd, SHOW_VAR *var, char *buff)<br />
07410 {<br />
07411   var-&gt;type= SHOW_MY_BOOL;<br />
07412   pthread_mutex_lock(&amp;<span style="color: #ff0000;">LOCK_active_mi</span>);<br />
07413   var-&gt;value= buff;<br />
07414   *((my_bool *)buff)= (my_bool) (active_mi &amp;&amp;<br />
07415                                  active_mi-&gt;slave_running == MYSQL_SLAVE_RUN_CONNECT &amp;&amp;<br />
07416                                  active_mi-&gt;rli.slave_running);<br />
07417   pthread_mutex_unlock(&amp;LOCK_active_mi);<br />
07418   return 0;<br />
07419 }</p>
<p>清除锁定表的clear_tables_to_lcok<br />
01222 void Relay_log_info::clear_tables_to_lock()<br />
01223 {<br />
01224   while (tables_to_lock)<br />
01225   {<br />
01226     uchar* to_free= reinterpret_cast(tables_to_lock);<br />
01227     if (tables_to_lock-&gt;m_tabledef_valid)<br />
01228     {<br />
01229       tables_to_lock-&gt;m_tabledef.table_def::~table_def();<br />
01230       tables_to_lock-&gt;m_tabledef_valid= FALSE;<br />
01231     }<br />
01232     tables_to_lock=<br />
01233       static_cast(tables_to_lock-&gt;next_global);<br />
01234     tables_to_lock_count&#8211;;<br />
01235     my_free(to_free, MYF(MY_WME));<br />
01236   }<br />
01237   DBUG_ASSERT(tables_to_lock == NULL &amp;&amp; tables_to_lock_count == 0);<br />
01238 }</p><h2  class="related_post_title">类似的文章</h2><ul class="related_post"><li>2012年01月23日 -- <a href="http://www.penglixun.com/tech/database/case_about_innodb_faster_than_oracle.html" title="一个InnoDB性能超过Oracle的调优Case">一个InnoDB性能超过Oracle的调优Case</a> (1)</li><li>2011年12月23日 -- <a href="http://www.penglixun.com/tech/database/server_kill_idle_transaction.html" title="在Server层实现Kill Idle Transaction">在Server层实现Kill Idle Transaction</a> (1)</li><li>2011年11月29日 -- <a href="http://www.penglixun.com/tech/database/how_to_kill_idle_trx.html" title="如何杀掉空闲事务">如何杀掉空闲事务</a> (1)</li></ul>]]></content:encoded>
			<wfw:commentRss>http://www.penglixun.com/tech/database/slave_sql_locked_bug.html/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Percona对MySQL标准版本的改进</title>
		<link>http://www.penglixun.com/tech/database/percona_vs_mysql.html</link>
		<comments>http://www.penglixun.com/tech/database/percona_vs_mysql.html#comments</comments>
		<pubDate>Mon, 06 Dec 2010 08:08:41 +0000</pubDate>
		<dc:creator>P.Linux</dc:creator>
				<category><![CDATA[数据库]]></category>
		<category><![CDATA[InnoDB]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[Percona]]></category>
		<category><![CDATA[XtraDB]]></category>

		<guid isPermaLink="false">http://www.penglixun.com/?p=1176</guid>
		<description><![CDATA[本文内容遵从CC版权协议, 可以随意转载, 但必须以超链接形式标明文章原始出处和作者信息及版权声明网址: http://www.penglixun.com/tech/database/percona_vs_mysql.html 周末有空读了下Percona XtraDB对MySQL InnoDB... ]]></description>
			<content:encoded><![CDATA[<p><span style="color: #888888;">本文内容遵从<a href="http://creativecommons.org/licenses/by-nc-sa/3.0/deed.zh" target="_blank">CC版权协议</a>, 可以随意转载, 但必须以超链接形式标明文章原始出处和作者信息及版权声明</br>网址: http://www.penglixun.com/tech/database/percona_vs_mysql.html </p>
<p></span>周末有空读了下Percona XtraDB对MySQL InnoDB的改进点，这里给大家分享下。</p>
<p><strong>一、对可扩展性的改进： </strong><br />
1. 提升Buffer Pool的扩展性<br />
InnoDB Buffer Pool一个众所周知的问题是大并发查询执行的争用，XtraDB将Buffer Pool的全局Mutex拆成了多个Mutex以减少争用。</p>
<p>2. 提高InnoDB IO扩展性<br />
XtraDB增加了许多变量去调整IO到最佳状态，包括调整checkpoint、后台读写数据文件线程数等等的参数。</p>
<p>3. 多个回滚段<br />
为提供一直读，InnoDB将事务修改的数据写到回滚段。回滚段被一个独立的Mutex保护，这直接导致了写密集型的工作并发不高。在 XtraDB可以改变回滚段的数目（innodb_extra_rsegments），在写密集型操作中可以大幅度提高性能。</p>
<p>4. 可以更高的并发数<br />
InnoDB在回滚段只提供了1024个回滚槽（春哥就遇到过这个瓶颈），如果回滚槽用完，新的事务将不能开始，直到有回滚槽被释放。</p>
<p><strong>二、性能上的提升 </strong><br />
1. 专用的Purge线程<br />
在InnoDB一个事务修改的数据被写到共享表空间的undo space，所以InnoDB能提供读一致。到一个事务结束了，undo space的相应区域被释放。但是如果有很多事务，Purge线程清理空间不够快，共享表空间将急剧增长（BRMMS共享表空间巨大应该是这个原因）。这 将导致性能严重下降，甚至可能用完所有的磁盘空间。XtraDB使用了一个专用的线程来清理undo space，这对undo space的清理速度可以提升很多。尽管这可能使整体的性能降低，但是可以大大提高稳定性，因而整体性能略微降低是值得的。</p>
<p>2. 可配置的Doublewrite缓冲<br />
InnoDB使用了double write功能来防止数据损坏，double write的意思是，是写数据到文件前，先顺序写到到共享表空间。如果遇到一个损坏的写，InnoDB将使用这个buffer去恢复数据。尽管数据被写了 两次但对性能影响通常较小，但是在一些高负载环境，doublewrite就成了瓶颈。XtraDB提供了一个选项将doublewrite buffer放在一个独立的磁盘来提升并发性能。</p>
<p>3. Query Cache增强<br />
Percona提供了额外的参数来配置Query Cache，例如忽略<acronym title="Structured Query Language">SQL</acronym>中的注释性语句来检查是否可以命中。</p>
<p>4. Fast InnoDB Checksum<br />
InnoDB可以checksum所有从磁盘上读取的页，以提供防止数据损坏的额外安全保障。在XtraDB中，Percona改进算了 checksum算法，可以提供更好的性能。</p>
<p>5. 删除过多的函数调用<br />
当MySQL从socket读数据时，将产生很多fcntl（针对描述符提供控制的函数）调用，导致并发性能下降。Percona移出了多于 的调用。</p>
<p>6. 减少了Buffer Pool Mutex竞争<br />
在InnoDB内核操作时减少了Buffer Pool之间的Mutex争用（拆分Mutex变量）</p>
<p><strong>三、灵活性改进 </strong><br />
1. 支持多种页大小<br />
尽管InnoDB支持多种页大小，但是默认的页大小16K无法在不重新编译的情况下改变。XtraDB提供一个系统变量 （innodb_page_size）来改变这个值。更小的页大小可以提升大多数OLTP系统的工作性能，更大的页通常可以提供更好的 OLAP性能。</p>
<p>2. 禁止Replication警告<br />
默认的基于Statement的复制，例如NOW(),RAND()，call存储过程/函数等一些语句，或者UPDATE没有ORDER BY而使用LIMIT，可能是不安全的。在这种情况下，MySQL会发出1592警告（声明语句在Statement日志下是不安全的）。不 幸的是，MySQL 5.1的一个Bug导致Server发出这个警告在一些安全的情况下。索然他不会导致任何与复制相关的问题，但是这会导致Error Log里面存在没必要的报警。这个改进可以避免这些警告。</p>
<p>3. 处理BLOB中的行结束符<br />
Percona(5.1.x-12.x开始，5.1.x-11.x不支持)为MySQL客户端提供一个新的选项（no-remove- eol-carret）来处理Blob字段含\r字符的情况。</p>
<p>4. 复制停止恢复<br />
当使用sql_slave_skip_counter参数时，如果一个事件组的中间某条出错了，slave将跳过所有剩余的时间操作直到这个 事件组结束。表述比较困难，直接看Percona给的使用例子就明白了。<br />
<a href="http://www.percona.com/docs/wiki/percona-server:features:replication_skip_single_statement" target="_blank">http://www.percona.com/docs/wiki/percona-server:features:replication_skip_single_statement</a></p>
<p>5. 可固定的预读区<br />
在InnoDB中，预读（read-ahead区域）的大小是动态计算的，但是它经常是一个同样的值。XtraDB(5.1.x-12.x开 始，5.1.x-11.x不支持)可以让这个这个区域的大小固定，避免无用的计算。<br />
这是Facebook放出的补丁：<a href="http://bazaar.launchpad.net/~mysqlatfacebook/mysqlatfacebook/5.1/revision/3538">http://bazaar.launchpad.net/~mysqlatfacebook/mysqlatfacebook/5.1/revision/3538</a></p>
<p><strong>四、可靠性的改进</strong><br />
1. Crash后同步日志<br />
在InnoDB中，slave复制状态存储在两个不同步的文件中(relay.index和relay.info)。如果slave因为错误 状态而停止，文件将不同步，最后的事务将重新执行。Percona在XtraDB事务日志中增加了复制状态：当重启事务时，slave可以使 用这个信息来实现一致性。<br />
来自Google的补丁：<a href="http://code.google.com/p/google-mysql-tools/wiki/TransactionalReplication">http://code.google.com/p/google-mysql-tools/wiki/TransactionalReplication</a><br />
这个缺陷可能导致的Bug：<a href="http://bugs.mysql.com/bug.php?id=34058" target="_blank">http://bugs.mysql.com/bug.php?id=34058</a></p>
<p>2. Too Many Connections的警告<br />
Percona将“Too Many Connections”这个警告写入Server端的error_log，而不只是客户端报这个错。</p>
<p>3. 错误代码的兼容性<br />
Percona(5.1.x-12.x开始，5.1.x-11.x不支持)提供与MySQL 5.5错误代码的兼容性，避免因为升级到5.5而带来错误码不一样的问题。</p>
<p>4. 文件句柄损坏的表（InnoDB）<br />
MySQL在InnoDB有表损坏之后，所有的InnoDB表都不可用。XtraDB改进了这一点，只是disable损坏的表，数据库依然 可以使用其他的表，损坏的表被锁定。</p>
<p><strong>五、可管理性的提升</strong><br />
1. Fast InnoDB Recovery<br />
InnoDB一直以来有个很麻烦的事情，在crash后回复InnoDB的表非常的缓慢。Percona/XtraDB因为是基于 InnoDB Plugin 1.0.8+的，也具备InnoDB Plugin快速恢复的功能。（早期的Percona版本也能看到XtraDB恢复速度比InnoDB快很多，因为XtraDB早期使用了自己开发的 Fast Revcovery）<br />
一些测试：<a href="http://www.mysqlperformanceblog.com/2009/07/07/improving-innodb-recovery-time/">http://www.mysqlperformanceblog.com/2009/07/07/improving-innodb-recovery-time/</a></p>
<p>2. InnoDB 数据字段大小限制<br />
InnoDB在自己的表缓存（Table Cache）中分配存储表定义（Table Definitions）的内存称为数据字典。默认情况下，一旦打开表，字典中表示它的内部对象将一直保存在内存中，直到表被删除或者服务器重启。如果存 在很多表（例如 10万张或更多，Dubbo就有这种情况，logstat库），可能导致消耗巨大的内存有时可能达到G级别。Percona修改了这种策略，可以设置参数 （innodb_dict_size_limit）来限制数据字典的大小，使InnoDB使用LRU算法来限制数据字典大小，而不是一直存在 内存中，避免因为表太多而内存耗尽。</p>
<p>3. 展开表导入<br />
InnoDB不像MyISAM那样可以在服务器之间拷贝单表定义文件。如果配合Xtrabackup导出，一张表可以在另一个XtraDB导 入。</p>
<p>4. Buffer Pool使用共享内存<br />
当Buffer Pool非常大时，重启后Warn up需要大量磁盘读写，这会消耗很多时间。通过将Buffer Pool存储在Shared Memory中，这些非是耗时的IO将会节省掉。主机重启就没办法了，得用下面的功能。</p>
<p>5. 导出/恢复Buffer Pool<br />
对于使用了很大Buffer Pool的InnoDB，重启数据库很痛苦。通常需要InnoDB Buffer Pool先Warn Up再提供服务，这可能需要很久。XtraDB(5.1.x-12.x开始，5.1.x-11.x不支持)提供了命令可以把Buffer Pool的内容导入或导出，从而可以提高重启提供服务的速度。<br />
使用方法：<a href="http://www.percona.com/docs/wiki/percona-server:features:innodb_lru_dump_restore?redirect=1">http://www.percona.com/docs/wiki/percona-server:features:innodb_lru_dump_restore?redirect=1</a></p>
<p>6. Fast Index Creation<br />
快速索引创建是InnoDB Plugin的功能，只要不是主键变动，修改索引的速度比之前快很多。但是在一些场景下，这可能导致损坏。XtraDB提供参数 （innodb_fast_index_creation）来选择Fast Index Creation功能是否启用，如果关闭，则使用原来的创建方法。</p>
<p>7. Fast Index Renaming<br />
XtraDB（(5.1.x-12.x开始，5.1.x-11.x不支持)）扩展了ALTER TABLE命令，提供在线重命名索引功能，这样不会导致重建索引。（这对我们调整不规范索引名称非常有用）</p>
<p>8. 防止缓存Flashcache<br />
Flashcache通过在SSD上缓存数据来提升性能。它工作时应该让更热的数据缓存才能能提高更好的性能，XtraDB提供了注释提示来 忽略不必缓存的数据。</p>
<p><strong>六、诊断问题方面的提升</strong><br />
1. 额外的INFORMATION_SCHEMA表<br />
Percona/XtraDB提供额外的INFORMATION_SCHEMA表以获得数据库内部更详尽的信息，例如内部缓冲池的内容或统计 信息。</p>
<p>2. 慢查日志扩展<br />
Percona提供了额外的统计数据，可以通过参数启用。它可以帮助我们捕捉需要的事件尽可能详细的信息，简化了慢查分析的难度。</p>
<p>3. InnoDB状态显示<br />
XtraDB整理了InnoDB Status的显示量，提供更好的可读性，状态由24个上升到48个，并且打印了被内部哈希表使用的内存量。通过新的参数可以配置的输出。</p>
<p>4. 计算InnoDB死锁数<br />
当运行一饿事务性的应用程序，总会不同程度的出现死锁，只要不经常出现这并不是大的问题。InnoDB中Show InnoDB Status命令只给出了最后一次死锁额信息，当我们需要知道总的死锁数或一个单位时间的死锁量这里并不能给出。XtraDB增加了一个保存死锁量的状态 变量，通过这个变量可以更好的了解我们数据库上发生的死锁。</p>
<p>5. 可以记录所有Server端命令（syslog）<br />
Percona可以在syslog中记录所有运行在Server端的命令。</p>
<p>6. 响应时间分布<br />
Percona提供了一份报告表明在一定间隔内在服务器上执行Query数。这个信息可以用于监控数据库性能是否稳定。</p>
<p>7. Show Storage Engines<br />
Percona改变了Show Storage Egnines的输出，以表名XtraDB是不是启用。（以前XtraDB也使用InnoDB的名称输出）</p>
<p>8. Query Cache Mutex状态<br />
Query Cache可能导致一些很难被检测出来的问题，Percona修改了show processlist命令，可以输出“Waiting on query cache mutex”状态。</p>
<p>9. 显示锁名称<br />
“show mutex status”命令可以显示当前发生的锁定名称和os_wait值。</p><h2  class="related_post_title">类似的文章</h2><ul class="related_post"><li>2012年01月23日 -- <a href="http://www.penglixun.com/tech/database/case_about_innodb_faster_than_oracle.html" title="一个InnoDB性能超过Oracle的调优Case">一个InnoDB性能超过Oracle的调优Case</a> (1)</li><li>2011年12月23日 -- <a href="http://www.penglixun.com/tech/database/server_kill_idle_transaction.html" title="在Server层实现Kill Idle Transaction">在Server层实现Kill Idle Transaction</a> (1)</li><li>2010年01月14日 -- <a href="http://www.penglixun.com/tech/database/xtradb_compile_error.html" title="XtraDB 1.0.6-9编译错误的解决">XtraDB 1.0.6-9编译错误的解决</a> (0)</li></ul>]]></content:encoded>
			<wfw:commentRss>http://www.penglixun.com/tech/database/percona_vs_mysql.html/feed</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Repair with keycache产生的原因和解决方法</title>
		<link>http://www.penglixun.com/tech/database/slove_repair_with_keycache.html</link>
		<comments>http://www.penglixun.com/tech/database/slove_repair_with_keycache.html#comments</comments>
		<pubDate>Fri, 26 Nov 2010 14:01:43 +0000</pubDate>
		<dc:creator>P.Linux</dc:creator>
				<category><![CDATA[数据库]]></category>
		<category><![CDATA[Key Buffer]]></category>
		<category><![CDATA[myisam]]></category>
		<category><![CDATA[MySQL]]></category>

		<guid isPermaLink="false">http://www.penglixun.com/?p=1175</guid>
		<description><![CDATA[本文内容遵从CC版权协议, 可以随意转载, 但必须以超链接形式标明文章原始出处和作者信息及版权声明网址: http://www.penglixun.com/tech/database/slove_repair_with_keycache.html 今天给一个MyISAM的大表加索引... ]]></description>
			<content:encoded><![CDATA[<p><span style="color: #888888;">本文内容遵从<a href="http://creativecommons.org/licenses/by-nc-sa/3.0/deed.zh" target="_blank">CC版权协议</a>, 可以随意转载, 但必须以超链接形式标明文章原始出处和作者信息及版权声明</br>网址: http://www.penglixun.com/tech/database/slove_repair_with_keycache.html </p>
<p></span>今天给一个MyISAM的大表加索引，临时表MYD文件的大小增长非常慢，到了MYD文件创建完成后，却发现MYI文件很小，ALTER TABLE语句始终不能结束，登录MYSQL查看show processlist;发现，ALTER TABLE语句在“<strong>Repair with keycache</strong>”状态。<br />
于是想到，myisam_max_sort_file_size参数我们设置的是10G，但是现在这个文件正好>10G一点点，于是不能用tmpdir指定的目录排序索引。于是增加myisam_max_sort_file_size参数到20G，再次ALTER TABLE，首先MYD文件的创建速度就快了非常多，MYD文件创建结束后，MYI文件开始增长，查看processlist，发现在“<strong>Repair by sorting</strong>”状态，很快表创建完成。<br />
如果遇到类似的情况，你可以一试。</p><h2  class="related_post_title">类似的文章</h2><ul class="related_post"><li>2010年03月20日 -- <a href="http://www.penglixun.com/tech/database/mysql_index_store_perfomance_effect.html" title="MySQL索引与存储方式对性能的影响">MySQL索引与存储方式对性能的影响</a> (2)</li><li>2009年09月30日 -- <a href="http://www.penglixun.com/tech/database/mysql_parameter_tuning.html" title="MySQL参数调优">MySQL参数调优</a> (0)</li><li>2012年01月23日 -- <a href="http://www.penglixun.com/tech/database/case_about_innodb_faster_than_oracle.html" title="一个InnoDB性能超过Oracle的调优Case">一个InnoDB性能超过Oracle的调优Case</a> (1)</li></ul>]]></content:encoded>
			<wfw:commentRss>http://www.penglixun.com/tech/database/slove_repair_with_keycache.html/feed</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>静态编译TCMalloc到MySQL</title>
		<link>http://www.penglixun.com/tech/database/static_compile_mysql_with_tcmalloc.html</link>
		<comments>http://www.penglixun.com/tech/database/static_compile_mysql_with_tcmalloc.html#comments</comments>
		<pubDate>Sat, 30 Oct 2010 14:59:20 +0000</pubDate>
		<dc:creator>P.Linux</dc:creator>
				<category><![CDATA[数据库]]></category>
		<category><![CDATA[libtcmalloc]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[tcmalloc]]></category>

		<guid isPermaLink="false">http://www.penglixun.com/?p=1172</guid>
		<description><![CDATA[本文内容遵从CC版权协议, 可以随意转载, 但必须以超链接形式标明文章原始出处和作者信息及版权声明网址: http://www.penglixun.com/tech/database/static_compile_mysql_with_tcmalloc.html Linux下的malloc函数性能问... ]]></description>
			<content:encoded><![CDATA[<p><span style="color: #888888;">本文内容遵从<a href="http://creativecommons.org/licenses/by-nc-sa/3.0/deed.zh" target="_blank">CC版权协议</a>, 可以随意转载, 但必须以超链接形式标明文章原始出处和作者信息及版权声明</br>网址: http://www.penglixun.com/tech/database/static_compile_mysql_with_tcmalloc.html </p>
<p></span>Linux下的malloc函数性能问题，想必大部分在Linux下写C的人都深有感受，纷纷利用内存池来改进内存分配效率。<br />
Google开源的tcmalloc则改进了malloc的一些效率问题，在大量malloc和free时，操作系统的内存曲线明显比Linux下malloc函数要平稳，在大并发情况下，提升程序稳定性和性能。<br />
一般网上都是把tcmalloc动态库加到mysqld_safe中启动，但是我们的MySQL都是静态编译的，这时候动态加载是否生效呢？所以还是静态编译入MySQL好。</p>
<p>编译tcmalloc先要编译libunwind：</p>
<blockquote><p>
wget http://download.savannah.gnu.org/releases/libunwind/libunwind-0.99.tar.gz<br />
tar zxvf libunwind-0.99.tar.gz</p>
<p>CHOST=”x86_64-pc-linux-gnu” \<br />
CFLAGS=” -O3 -fPIC \<br />
-fomit-frame-pointer \<br />
-pipe \<br />
-march=nocona \<br />
-mfpmath=sse \<br />
-m128bit-long-double \<br />
-mmmx \<br />
-msse \<br />
-msse2 \<br />
-maccumulate-outgoing-args \<br />
-m64 \<br />
-ftree-loop-linear \<br />
-fprefetch-loop-arrays \<br />
-freg-struct-return \<br />
-fgcse-sm \<br />
-fgcse-las \<br />
-frename-registers \<br />
-fforce-addr \<br />
-fivopts \<br />
-ftree-vectorize \<br />
-ftracer \<br />
-frename-registers \<br />
-minline-all-stringops \<br />
-fbranch-target-load-optimize2&#8243; \<br />
CXXFLAGS=”${CFLAGS}” \<br />
./configure &#038;&#038; make &#038;&#038; make install
</p></blockquote>
<p>然后编译tcmalloc：</p>
<blockquote><p>
tar zxvf google-perftools-1.6.tar.gz</p>
<p>CHOST=”x86_64-pc-linux-gnu” \<br />
CFLAGS=” -O3 \<br />
-fomit-frame-pointer \<br />
-pipe \<br />
-march=nocona \<br />
-mfpmath=sse \<br />
-m128bit-long-double \<br />
-mmmx \<br />
-msse \<br />
-msse2 \<br />
-maccumulate-outgoing-args \<br />
-m64 \<br />
-ftree-loop-linear \<br />
-fprefetch-loop-arrays \<br />
-freg-struct-return \<br />
-fgcse-sm \<br />
-fgcse-las \<br />
-frename-registers \<br />
-fforce-addr \<br />
-fivopts \<br />
-ftree-vectorize \<br />
-ftracer \<br />
-frename-registers \<br />
-minline-all-stringops \<br />
-fbranch-target-load-optimize2&#8243; \<br />
CXXFLAGS=”${CFLAGS}” \<br />
./configure &#038;&#038; make &#038;&#038; make install
</p></blockquote>
<p>记得要把libtammloc加入系统路径，否则编译MySQL时找不到：</p>
<blockquote><p>
echo “/usr/local/lib” > /etc/ld.so.conf.d/usr_local_lib.conf<br />
/sbin/ldconfig
</p></blockquote>
<p>最后就是编译MySQL了：</p>
<blockquote><p>
CXX=gcc \<br />
CHOST=”x86_64-pc-linux-gnu” \<br />
CFLAGS=” -O3 \<br />
-fomit-frame-pointer \<br />
-pipe \<br />
-march=nocona \<br />
-mfpmath=sse \<br />
-m128bit-long-double \<br />
-mmmx \<br />
-msse \<br />
-msse2 \<br />
-maccumulate-outgoing-args \<br />
-m64 \<br />
-ftree-loop-linear \<br />
-fprefetch-loop-arrays \<br />
-freg-struct-return \<br />
-fgcse-sm \<br />
-fgcse-las \<br />
-frename-registers \<br />
-fforce-addr \<br />
-fivopts \<br />
-ftree-vectorize \<br />
-ftracer \<br />
-frename-registers \<br />
-minline-all-stringops \<br />
-felide-constructors \<br />
-fno-exceptions \<br />
-fno-rtti \<br />
-fbranch-target-load-optimize2&#8243; \<br />
CXXFLAGS=”${CFLAGS}” \<br />
./configure &#8211;prefix=/usr/alibaba/install/mysql-ent-custom-5.1.49sp1 \<br />
&#8211;with-server-suffix=-alibaba-edition \<br />
&#8211;with-mysqld-user=mysql \<br />
&#8211;with-plugins=partition,blackhole,csv,heap,innobase,myisam,myisammrg \<br />
&#8211;with-charset=utf8 \<br />
&#8211;with-collation=utf8_general_ci \<br />
&#8211;with-extra-charsets=gbk,gb2312,utf8,ascii \<br />
&#8211;with-big-tables \<br />
&#8211;with-fast-mutexes \<br />
&#8211;with-zlib-dir=bundled \<br />
&#8211;enable-assembler \<br />
&#8211;enable-profiling \<br />
&#8211;enable-local-infile \<br />
&#8211;enable-thread-safe-client \<br />
&#8211;with-readline \<br />
&#8211;with-pthread \<br />
&#8211;with-embedded-server \<br />
&#8211;with-client-ldflags=-all-static \<br />
&#8211;with-mysqld-ldflags=-all-static \<br />
<strong>&#8211;with-mysqld-ldflags=-ltcmalloc \</strong><br />
&#8211;without-query-cache \<br />
&#8211;without-geometry \<br />
&#8211;without-debug \<br />
&#8211;without-ndb-debug<br />
make &#038;&#038; make install
</p></blockquote>
<p>经过试用，大并发下内存分配和释放曲线都比Linux原生的平稳。</p><h2  class="related_post_title">类似的文章</h2><ul class="related_post"><li>2009年09月29日 -- <a href="http://www.penglixun.com/tech/database/opt_mysql_using_tcmalloc.html" title="使用tcmalloc优化MySQL">使用tcmalloc优化MySQL</a> (0)</li><li>2009年12月8日 -- <a href="http://www.penglixun.com/tech/database/database_schema_design_traning_2009_12.html" title="今天的数据库设计培训">今天的数据库设计培训</a> (4)</li><li>2012年01月23日 -- <a href="http://www.penglixun.com/tech/database/case_about_innodb_faster_than_oracle.html" title="一个InnoDB性能超过Oracle的调优Case">一个InnoDB性能超过Oracle的调优Case</a> (1)</li></ul>]]></content:encoded>
			<wfw:commentRss>http://www.penglixun.com/tech/database/static_compile_mysql_with_tcmalloc.html/feed</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>数据分布对MySQL执行计划的影响</title>
		<link>http://www.penglixun.com/tech/database/data_distribution_on_mysql_explain.html</link>
		<comments>http://www.penglixun.com/tech/database/data_distribution_on_mysql_explain.html#comments</comments>
		<pubDate>Sat, 09 Oct 2010 13:00:56 +0000</pubDate>
		<dc:creator>P.Linux</dc:creator>
				<category><![CDATA[数据库]]></category>
		<category><![CDATA[EXPLAIN]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[执行计划]]></category>

		<guid isPermaLink="false">http://www.penglixun.com/?p=1168</guid>
		<description><![CDATA[本文内容遵从CC版权协议, 可以随意转载, 但必须以超链接形式标明文章原始出处和作者信息及版权声明网址: http://www.penglixun.com/tech/database/data_distribution_on_mysql_explain.html 以前我一直以为，MySQL优... ]]></description>
			<content:encoded><![CDATA[<p><span style="color: #888888;">本文内容遵从<a href="http://creativecommons.org/licenses/by-nc-sa/3.0/deed.zh" target="_blank">CC版权协议</a>, 可以随意转载, 但必须以超链接形式标明文章原始出处和作者信息及版权声明</br>网址: http://www.penglixun.com/tech/database/data_distribution_on_mysql_explain.html </p>
<p></span>以前我一直以为，MySQL优化器只会根据数据的基数来判断执行计划的优化，在5.0时，基本上只要基数达不到要求，MySQL就不会选择索引。不过从今天优化一组<acronym title="Structured Query Language">SQL</acronym>的情况来看，5.1早已不是这样，MySQL优化器考虑了数据分布的影响，使用不同的值，对同一条<acronym title="Structured Query Language">SQL</acronym>可能产生完全不同的执行计划。可以做如下测试。</p>
<p>有一张表 A (id,c1)，假设采用“SELECT c1,count(*) FROM table GROUP BY c1”的方式来查看每一列每个值的数据量的结果如下：</p>
<table style="width: 66px; height: 104px;" border="0">
<tbody>
<tr>
<td>c1</td>
<td>count(*)</td>
</tr>
<tr>
<td>1</td>
<td>100</td>
</tr>
<tr>
<td>2</td>
<td>1000</td>
</tr>
<tr>
<td>3</td>
<td>10000</td>
</tr>
<tr>
<td>4</td>
<td>100000</td>
</tr>
</tbody>
</table>
<p>假设现在c1上有个索引 idx_1 (c1)。<br />
当我采用只有100个值的1作为条件的筛选值查看执行计划时，<br />
MySQL会毫不犹豫的走 idx_1 索引。<br />
但是改为4作为筛选值，基本上都可以看到全表扫描的执行计划。</p>

<div class="wp_codebox"><table><tr id="p116854"><td class="code" id="p1168code54"><pre class="sql" style="font-family:monospace;"><span style="color: #993333; font-weight: bold;">EXPLAIN</span> <span style="color: #993333; font-weight: bold;">SELECT</span> <span style="color: #66cc66;">*</span> <span style="color: #993333; font-weight: bold;">FROM</span> A <span style="color: #993333; font-weight: bold;">WHERE</span> c1<span style="color: #66cc66;">=</span><span style="color: #cc66cc;">1</span>;
<span style="color: #993333; font-weight: bold;">EXPLAIN</span> <span style="color: #993333; font-weight: bold;">SELECT</span> <span style="color: #66cc66;">*</span> <span style="color: #993333; font-weight: bold;">FROM</span> A <span style="color: #993333; font-weight: bold;">WHERE</span> c1<span style="color: #66cc66;">=</span><span style="color: #cc66cc;">4</span>;</pre></td></tr></table></div>

<p>虽然从源码目录的 sql/sql_select.cc 中并未找到具体的优化代码，但是从sql/opt_range.cc来看，至少RANGE查询的优化已经通过蒙特卡罗方法来估算要选择的值的出现概率，那么有理由相信，如此简单的选择查询，MYSQL肯定也估算了要查询的值出现的概率，然后以此为依据计算访问路径。<br />
所以，一条<acronym title="Structured Query Language">SQL</acronym>优化时，不仅要看数据的离散度，还得看经常被当作筛选值的数值唯一性是否够好，如果被筛选的值唯一性不好，建立索引依然是没有什么意义的，因为MySQL根本不会选择这个索引。</p><h2  class="related_post_title">类似的文章</h2><ul class="related_post"><li>2009年10月16日 -- <a href="http://www.penglixun.com/tech/database/mysql_explain_detail.html" title="MySQL EXPLAIN 详解">MySQL EXPLAIN 详解</a> (1)</li><li>2012年01月23日 -- <a href="http://www.penglixun.com/tech/database/case_about_innodb_faster_than_oracle.html" title="一个InnoDB性能超过Oracle的调优Case">一个InnoDB性能超过Oracle的调优Case</a> (1)</li><li>2011年12月23日 -- <a href="http://www.penglixun.com/tech/database/server_kill_idle_transaction.html" title="在Server层实现Kill Idle Transaction">在Server层实现Kill Idle Transaction</a> (1)</li></ul>]]></content:encoded>
			<wfw:commentRss>http://www.penglixun.com/tech/database/data_distribution_on_mysql_explain.html/feed</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>利用mysqlbinlog进行集群备份的设想</title>
		<link>http://www.penglixun.com/tech/database/backup_mysql_use_mysqlbinlog.html</link>
		<comments>http://www.penglixun.com/tech/database/backup_mysql_use_mysqlbinlog.html#comments</comments>
		<pubDate>Sat, 11 Sep 2010 21:40:17 +0000</pubDate>
		<dc:creator>P.Linux</dc:creator>
				<category><![CDATA[数据库]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[mysqlbinlog]]></category>
		<category><![CDATA[备份]]></category>

		<guid isPermaLink="false">http://www.penglixun.com/?p=1166</guid>
		<description><![CDATA[本文内容遵从CC版权协议, 可以随意转载, 但必须以超链接形式标明文章原始出处和作者信息及版权声明网址: http://www.penglixun.com/tech/database/backup_mysql_use_mysqlbinlog.html 实现MySQL热备份的最好方法，... ]]></description>
			<content:encoded><![CDATA[<p><span style="color: #888888;">本文内容遵从<a href="http://creativecommons.org/licenses/by-nc-sa/3.0/deed.zh" target="_blank">CC版权协议</a>, 可以随意转载, 但必须以超链接形式标明文章原始出处和作者信息及版权声明</br>网址: http://www.penglixun.com/tech/database/backup_mysql_use_mysqlbinlog.html </p>
<p></span>实现MySQL热备份的最好方法，我一直都认为是Replication，xtrabackup等各种热备脚本，都没有Replication安全方便。<br />
面对一个大规模集群的备份，由于实例太对，没办法创建这么多实例去Replication。之前我的想法一直是通过修改MySQL的源码，扩展MySQL Replication可以创建多个M-S复制，这对MySQL本身有入侵，没办法保证我的代码能有非常高的可靠性，更严重的是要改变MySQL的语法，来支持多Master的Change语句，对.yy文件的修改风险就更大了。</p>
<p>在这条路不断的碰壁之时，突然想到，mysqlbinlog不是一个很好的工具吗，为什么还要靠修改源码，一个利用mysqlbinlog进行大规模备份的想法就诞生了，但是是否可靠还要去验证下。</p>
<p>怎么做呢，首先了解下MySQL Replication怎么做的，首先一个Slave IO线程从Master读取binlog，然后解析到Relay-log，另一个Slave <acronym title="Structured Query Language">SQL</acronym>线程异步的从Relay-log中读取<acronym title="Structured Query Language">SQL</acronym>应用到本地。<br />
mysqlbinlog有一个参数read-from-remote-server，可以从远程读取binlog，只要创建一个有Replication Client权限的用户即可，这就模拟了Slave IO线程的作用。<br />
<strong>mysqlbinglog &#8211;read-from-remote-server -u repl -p -h target_node &#8211;start-datetime=&#8217;2010-09-01 00:00:00&#8242; &#8211;stop-datetime=&#8217;2010-09-01 23:59:59&#8242; </strong><br />
通过这条命令就可以获取到2010-09-01这一天的全部<acronym title="Structured Query Language">SQL</acronym>，这些<acronym title="Structured Query Language">SQL</acronym>可以直接导入到数据库，也可以写到Relaylog，让SLave <acronym title="Structured Query Language">SQL</acronym>线程去执行。</p>
<p>假设我们原来是每5分钟备份一次新产生的binlog，每天一次全备，所有备份都在一个备份机上，利用上述方法，就可以如下操作：</p>
<blockquote><p>1. 在备份机启动一个实例，指向任意一个没有操作的Master，使Relay-log文件生成。<br />
2. 每个要备份的实例从备份机每5分钟发起一次mysqlbinlog请求，获取上5分钟的binlog，写入到一个临时文件，然后等临时文件写完了，去touch一个锁，写Relaylog。<br />
3. 每天Slave Start一次，Slave Start之前touch一个锁，让Relay-log的写阻塞，等待Slave start执行完毕，删除Relay-log的写锁。<br />
4. 删除前一天产生的临时文件。</p></blockquote>
<p>这样操作就可以保证，每五分钟产生的<acronym title="Structured Query Language">SQL</acronym>都被分开记录，方便查找，每天的Slave start则消化掉这些<acronym title="Structured Query Language">SQL</acronym>。<br />
如果想方便一点，不写Relay-log也是可以的，直接每天把<acronym title="Structured Query Language">SQL</acronym>丢给MySQL执行一次就好，效果也一样。</p>
<p>具体这种方法靠谱不靠谱，我会去实践一下看看。</p><h2  class="related_post_title">类似的文章</h2><ul class="related_post"><li>2011年01月14日 -- <a href="http://www.penglixun.com/tech/program/how_to_mysql_multi_master.html" title="MySQL Multi-Master实现方式">MySQL Multi-Master实现方式</a> (6)</li><li>2012年01月23日 -- <a href="http://www.penglixun.com/tech/database/case_about_innodb_faster_than_oracle.html" title="一个InnoDB性能超过Oracle的调优Case">一个InnoDB性能超过Oracle的调优Case</a> (1)</li><li>2011年12月23日 -- <a href="http://www.penglixun.com/tech/database/server_kill_idle_transaction.html" title="在Server层实现Kill Idle Transaction">在Server层实现Kill Idle Transaction</a> (1)</li></ul>]]></content:encoded>
			<wfw:commentRss>http://www.penglixun.com/tech/database/backup_mysql_use_mysqlbinlog.html/feed</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
	</channel>
</rss>

