<?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>OurMySQL</title>
	<atom:link href="http://ourmysql.com/feed" rel="self" type="application/rss+xml" />
	<link>http://ourmysql.com</link>
	<description>我们致力于一个MySQL知识的分享网站</description>
	<lastBuildDate>Fri, 22 Jul 2011 05:49:35 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.2.1</generator>
		<item>
		<title>“ERROR 1235 (42000): skip-innodb is defined”的误导</title>
		<link>http://ourmysql.com/archives/956</link>
		<comments>http://ourmysql.com/archives/956#comments</comments>
		<pubDate>Fri, 22 Jul 2011 05:49:35 +0000</pubDate>
		<dc:creator>OurMySQL</dc:creator>
				<category><![CDATA[MySQL解错方案]]></category>
		<category><![CDATA[error-1235]]></category>
		<category><![CDATA[InnoDB]]></category>
		<category><![CDATA[skip-innodb]]></category>

		<guid isPermaLink="false">http://ourmysql.com/?p=956</guid>
		<description><![CDATA[发现监控数据库的my.cnf中的关于Innodb的配置都保持默认状态，而之前只运行cacti倒是没有什么影响，它的表都是MyISAM的。因为前段采用了zabbix监控，而它的表都采用Innodb的表结构。其实，很多参数都可以在线调整，之后将变化的添加到my.cnf即可，无需修改my.cnf再重启mysqld，因为zabbix的信息收集量不小，导致binlog增长很快，磁盘容量报警，之前expire_log_days又设置为0。我觉得监控系统没必要开启binlog日志功能，所以想将log-bin注释掉不记录二进制日志，所以，必须要重启mysqld。在改动的这些参数里面，我调整了redo log的大小，将默认的10M增大到256M，也就是这么一改，重启后，扑哧让我惆怅了好一会。]]></description>
			<content:encoded><![CDATA[<p><strong>ERROR 1235 (42000): Cannot call SHOW <a href="http://ourmysql.com/archives/tag/innodb" class="st_tag internal_tag" rel="tag" title="标签 InnoDB 下的日志">INNODB</a> <a href="http://ourmysql.com/archives/tag/status" class="st_tag internal_tag" rel="tag" title="标签 status 下的日志">STATUS</a> because <a href="http://ourmysql.com/archives/tag/skip-innodb" class="st_tag internal_tag" rel="tag" title="标签 skip-innodb 下的日志">skip-innodb</a> is defined</strong></p>
<p>以上这个醒目错误提示，如果你是一个细心专业的DBA的话，可能这辈子你也遇到这样的问题，而我不是，毛躁马虎加上不专业，已经成了我的标签，所以，“幸运的”本人才遭遇到这个Error。究竟怎么一个动作导致出现这样的错误呢，下面简单描述下。</p>
<p>发现监控数据库的my.cnf中的关于Innodb的配置都保持默认状态，而之前只运行cacti倒是没有什么影响，它的表都是MyISAM的。因为前段采用了zabbix监控，而它的表都采用Innodb的表结构。其实，很多参数都可以在线调整，之后将变化的添加到my.cnf即可，无需修改my.cnf再重启mysqld，因为zabbix的信息收集量不小，导致binlog增长很快，磁盘容量报警，之前expire_log_days又设置为0。我觉得监控系统没必要开启binlog日志功能，所以想将log-bin注释掉不记录二进制日志，所以，必须要重启mysqld。在改动的这些参数里面，我调整了redo log的大小，将默认的10M增大到256M，也就是这么一改，重启后，扑哧让我惆怅了好一会。</p>
<p>当我执行show engine innodb status\G（现在我很喜欢看它的输出信息:-）之后，Error 1235就出现了，突然有点惊慌。刚开始我并没去查看error-log（这是一个非常不好的习惯，重启关闭mysqld是必须要tail -f error-log，确定正常关闭正常启动，是否有异常发生），而是跟着上面那个错误提示去找问题。风风火火的就去查看my.cnf里面是否有加skip-innodb，但是不可能呀，如果有那么之前zabbix的表也不会被创建为innodb类型的呀，后来查看error log才发现，是下面的原因导致的错误：</p>
<p>InnoDB: Error: log file /data/db/mysql/ib_logfile0 is of different size 0 10485760 bytes</p>
<p>InnoDB: than specified in the .cnf file 0 134217728 bytes!</p>
<p>这下明白了吧，接着我又执行show engines，发现Innodb的选项是disable的。怎么回事呢？我认为，当mysqld启动时，Innodb检查发现当前iblogfileX大小和配置文件中设置的不一致时，就会报错，但是mysqld仍然能够正常启动，但是Innodb会被自动skip掉。正常的操作应该是，首先正常关闭mysqld，然后将之前的iblogfile文件移走，最后在启动mysqld，初始化期间，如果发现iblogfile不存在会按照配置文件中指定大小重新创建一组新的。有时，以上这个错误的发生，不iblogfile的大小导致的，还可能是你的ibdata的大小问题导致的，Baron也遇到过上面的错误提示，就因为<a href="http://www.xaprb.com/blog/?s=ERROR+1235+%2842000%29">ibdata大小的设置问题</a>。Innodb的加载是一个十分细致的过程，我们必须要谨慎小心。</p>
<p>这些都是不细心和操作不规范造成的；先想，记录，测试，线上，这才是一个专业负责任的做法，其实，这些田老师一开始就这么教给我，可我…都快一年了，还是没有养成这个良好的工作方式。</p>
<p>继续努力吧，我以不再年轻，差距还是很大。</p>
<h3  class="related_post_title">相关文章</h3><ul class="related_post"><li>2011-03-30 -- <a href="http://ourmysql.com/archives/920" title="InnoDB的多版本一致性读的实现 ">InnoDB的多版本一致性读的实现 </a></li><li>2011-01-10 -- <a href="http://ourmysql.com/archives/902" title="InnoDB的Master Thread调度流程">InnoDB的Master Thread调度流程</a></li><li>2010-09-29 -- <a href="http://ourmysql.com/archives/857" title="MySQL锁机制/管理(并发锁,行锁,表锁,预加锁,全局锁等等)">MySQL锁机制/管理(并发锁,行锁,表锁,预加锁,全局锁等等)</a></li><li>2010-09-27 -- <a href="http://ourmysql.com/archives/852" title="InnoDB Adaptive Flush">InnoDB Adaptive Flush</a></li><li>2010-08-04 -- <a href="http://ourmysql.com/archives/845" title="InnoDB主键设计">InnoDB主键设计</a></li><li>2010-04-13 -- <a href="http://ourmysql.com/archives/825" title="InnoDB Double write">InnoDB Double write</a></li><li>2010-03-09 -- <a href="http://ourmysql.com/archives/817" title="Innodb 表和索引结构">Innodb 表和索引结构</a></li><li>2010-03-09 -- <a href="http://ourmysql.com/archives/811" title="InnoDB线程并发检查机制">InnoDB线程并发检查机制</a></li><li>2009-12-20 -- <a href="http://ourmysql.com/archives/805" title="Innodb如何使用内存">Innodb如何使用内存</a></li><li>2009-12-20 -- <a href="http://ourmysql.com/archives/801" title="Innodb文件表空间结构">Innodb文件表空间结构</a></li></ul>
	标签：<a href="http://ourmysql.com/archives/tag/error-1235" title="error-1235" rel="tag">error-1235</a>, <a href="http://ourmysql.com/archives/tag/innodb" title="InnoDB" rel="tag">InnoDB</a>, <a href="http://ourmysql.com/archives/category/debug" title="MySQL解错方案" rel="tag">MySQL解错方案</a>, <a href="http://ourmysql.com/archives/tag/skip-innodb" title="skip-innodb" rel="tag">skip-innodb</a><br />
]]></content:encoded>
			<wfw:commentRss>http://ourmysql.com/archives/956/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Heartbeat+DRBD+MySQL Replication故障处理</title>
		<link>http://ourmysql.com/archives/954</link>
		<comments>http://ourmysql.com/archives/954#comments</comments>
		<pubDate>Fri, 22 Jul 2011 05:46:51 +0000</pubDate>
		<dc:creator>OurMySQL</dc:creator>
				<category><![CDATA[MySQL解错方案]]></category>
		<category><![CDATA[DRBD]]></category>
		<category><![CDATA[Heartbeat]]></category>
		<category><![CDATA[replication]]></category>

		<guid isPermaLink="false">http://ourmysql.com/?p=954</guid>
		<description><![CDATA[不久前的一次机房网络故障，再一次对我们在Heartbeat+DRBD+MySQL数据库架构运维水平的一个考验，之前不止一次的测试与线上部署，还有之后大言不惭的关于该架构组件的所谓深入理解，在这一次不经意的意外面前又是“很囧”的收场，慌张呀！这次断网导致H-D-M全线异常，真是千载难逢，都让我们赶上啦lol: 下面就把这次的小幸运小幸福和大家分享下，以下是按照问题处理的先后顺序依次讲述。]]></description>
			<content:encoded><![CDATA[<p>不久前的一次机房网络故障，再一次对我们在Heartbeat+<a href="http://ourmysql.com/archives/tag/drbd" class="st_tag internal_tag" rel="tag" title="标签 DRBD 下的日志">DRBD</a>+MySQL数据库架构运维水平的一个考验，之前不止一次的测试与线上<a href="http://www.mysqlsystems.com/2010/11/drbd-heartbeat-make-mysql-ha.html">部署</a>，还有之后大言不惭的关于该架构组件的所谓<a href="http://www.mysqlsystems.com/2010/11/thinking-on-drbd-heartbeat-faq.html">深入理解</a>，在这一次不经意的意外面前又是“很囧”的收场，慌张呀！这次断网导致H-D-M全线异常，真是千载难逢，都让我们赶上啦lol: 下面就把这次的小幸运小幸福和大家分享下，以下是按照问题处理的先后顺序依次讲述。</p>
<p><strong>- MySQL Replication同步异常</strong></p>
<p>当发生网络故障一个小时后，从库io_thread和主库的连接被中断，抛出错误提示：[ERROR] Error reading packet from server: Client requested master to start <a href="http://ourmysql.com/archives/tag/replication" class="st_tag internal_tag" rel="tag" title="标签 replication 下的日志">replication</a> from impossible position ( server_errno=1236)，没想到竟遇到了一个古董级的<a href="http://bugs.mysql.com/bug.php?id=30223">Bug</a>，有点喜出望外了（心想，我也能遇到bug）。最后解决办法，只能拿备份重新做一遍主从。后来，好奇想查查，究竟是怎么导致这个问题，竟发现，从库relay log中的记录比主库binlog中的记录多了2条insert和1条update（0_0!!!…不合逻辑呀？！！）。</p>
<p><strong>- DRBD状态异常</strong></p>
<p>处理完数据库同步问题后，当时并没有去查看DRBD的状态，直到周一才发现出问题了，简单地通过命令cat /proc/drbd就可以查看，DRBD的状态是否正常。查看/var/log/messages知道网络故障导致DRBD发生脑裂，彼此都认为对方已经死了，然后自己都将角色作为Primary，并积极获取资源，当时的两端的连接状态都为StandAlone，角色都为Primary。在发生脑裂不久后原active node被heartbeat强制将系统重启，最后，原active node角色变为Secondary/Unknown，原standby node角色依然是脑裂时的Primary/Unknown，两端的连接状态，分别为WFConnection和StandAlone。解决方法如下：</p>
<p>Step 1 - On New Secondary:</p>
<p># service <a href="http://ourmysql.com/archives/tag/heartbeat" class="st_tag internal_tag" rel="tag" title="标签 Heartbeat 下的日志">heartbeat</a> stop</p>
<p># service drbd stop</p>
<p># drbdadm create-md r0</p>
<p># service drbd start</p>
<p># service heartbeat start</p>
<p>Step 2 &#8211; On New Primary:</p>
<p># service drbd reload</p>
<p>之后就进入漫长数据同步阶段，重新将Primary上的数据块文件拷贝到Secondary上，最后完成同步。</p>
<p><strong>- Heartbeat通信异常</strong></p>
<p>通过查看/var/log/ha-dug日志，发现在出现网络故障后4分钟内，Heartbeat服务在active node与standby node间反复做资源释放与获取的操作，最后资源被之前的standby node获得，而之前的active node因为DRBD资源的问题，请求系统重启“CRIT: Resource STOP failure. Reboot required!”。系统重启后，Heartbeat服务并没有被开启，chkconfig里面没有把heartbeat设置为开机自启动，drbd是被设置开启自启的。其实，周日在处理问题时，没有考虑到heartbeat问题，理所当然的人为，资源是被正常切换，而认为heartbeat当时是正常（~脸红~:&lt;太业余了…），更不好意思的是，周一发现heartbeat没有开启，我手动开启后，“习惯性”地依旧没有查看日志，就默认它了（唉…鄙视我吧！）。最后是在第3天，田老师检查整个系统，发现ha-dug里面警示异常提示。折腾了半天，最后等到晚上访问低谷的时候，采取了看上去不是方法的办法，解决如下：</p>
<p># less /var/log/ha-dug      — 发现问题</p>
<p>On Active Node（之前的standby–&gt;切换后active）:</p>
<p>WARN: Gmain_timeout_dispatch: Dispatch function for retransmit request took too long to execute: 390 ms (&gt; 10 ms)</p>
<p>ERROR: Message hist queue is filling up (500 messages in queue)</p>
<p>On Standby Node（之前的active–&gt;切换后standby）:</p>
<p>WARN: Rexmit of seq 17224382 requested. 41 is max.</p>
<p>在当前的active node上执行如下命令：</p>
<p># top  — 注意有4个僵尸进程（zombie），同时会发现heartbeat的cpu使用达到100%左右</p>
<p>Tasks: 245 total,   2 running, 239 sleeping,   0 stopped,   4 zombie</p>
<p>PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND</p>
<p>2106 root      -2   0  422m 376m 4788 R 100.1  1.6   5002:17 heartbeat</p>
<p># ps aux |grep defunct |grep -v grep   — 找出是哪4个僵尸进程</p>
<p>root     15678  0.0  0.0      0     0 ?        Z    10:57   0:00 [heartbeat] &lt;defunct&gt;</p>
<p>root     17932  0.0  0.0      0     0 ?        Z    13:48   0:00 [heartbeat] &lt;defunct&gt;</p>
<p>root     19176  0.0  0.0      0     0 ?        Z    Jul11   0:00 [<a href="http://ourmysql.com/archives/tag/status" class="st_tag internal_tag" rel="tag" title="标签 status 下的日志">status</a>] &lt;defunct&gt;</p>
<p>root     19626  0.0  0.0      0     0 ?        Z    Jul11   0:00 [heartbeat] &lt;defunct&gt;</p>
<div>既然，heartbeat服务有问题，那么很自然的就想到重启该服务，重启heartbeat是也会释放掉所有的资源的，会影响到正常业务，所以，选择到晚上闲时操作。出于安全为了不让资源切换到standby node上（其实，当时的情况heartbeat以及不能工作），我先停掉了standby node上的heartbeat，接着去停止active node上的服务，但是过了几分钟都没有相应，事实上，heartbeat的主进程已经僵死了，最后我“鼓足勇气”—kill -9 heartbeat-PID，然后先重启active node，再重启standby node，最后，查看日志一切都恢复正常了。之前，在做kill操作后，active node上的资源并没有释放，依然正常运行。</div>
<div><strong>– — – END — – –</strong></div>
<div>即便这次飞不小的劲，看似把问题都依依解决了，但心里依然没谱，对于之后可能发生的问题还是没有十足的把握；事实上，还是对于Heartbeat和DRBD技术本身，理解的不够透彻，Heartbeat对于资源的切换、检测后的判断以及对于日志输出的理解都还有很多疑惑，DRBD发生脑裂时资源争夺，会对数据块有多大影响，等等，所以就像田老师的感慨说的，我们之前做的仅仅就是能够把这个架构简单的打起来而已，根本谈不上专业的运维。</div>
<h3  class="related_post_title">相关文章</h3><ul class="related_post"><li>2009-02-11 -- <a href="http://ourmysql.com/archives/448" title="Mysql + DRBD + Heartbeat(v1)基本配置笔记及切换测试">Mysql + DRBD + Heartbeat(v1)基本配置笔记及切换测试</a></li><li>2010-12-14 -- <a href="http://ourmysql.com/archives/895" title="DRBD+Heartbeat让MySQL提供的服务更加稳定">DRBD+Heartbeat让MySQL提供的服务更加稳定</a></li><li>2010-12-02 -- <a href="http://ourmysql.com/archives/889" title="MySQL5.5复制/同步的新特性及改进">MySQL5.5复制/同步的新特性及改进</a></li><li>2010-11-15 -- <a href="http://ourmysql.com/archives/876" title="mysql replication 报告">mysql replication 报告</a></li><li>2009-02-17 -- <a href="http://ourmysql.com/archives/458" title="配置MySQL远程复制">配置MySQL远程复制</a></li><li>2009-02-16 -- <a href="http://ourmysql.com/archives/456" title="MySQL双向复制简单配置步骤">MySQL双向复制简单配置步骤</a></li><li>2009-02-06 -- <a href="http://ourmysql.com/archives/408" title="Mysql测试：DRBD+Mysql 高可用方案设置测试">Mysql测试：DRBD+Mysql 高可用方案设置测试</a></li><li>2008-11-08 -- <a href="http://ourmysql.com/archives/264" title="MySQL数据库自动恢复的简单操作过程">MySQL数据库自动恢复的简单操作过程</a></li><li>2008-11-08 -- <a href="http://ourmysql.com/archives/259" title="MySQL主从服务器配置">MySQL主从服务器配置</a></li><li>2008-11-08 -- <a href="http://ourmysql.com/archives/257" title="mysql 数据库的同步问题 ">mysql 数据库的同步问题 </a></li></ul>
	标签：<a href="http://ourmysql.com/archives/tag/drbd" title="DRBD" rel="tag">DRBD</a>, <a href="http://ourmysql.com/archives/tag/heartbeat" title="Heartbeat" rel="tag">Heartbeat</a>, <a href="http://ourmysql.com/archives/category/debug" title="MySQL解错方案" rel="tag">MySQL解错方案</a>, <a href="http://ourmysql.com/archives/tag/replication" title="replication" rel="tag">replication</a><br />
]]></content:encoded>
			<wfw:commentRss>http://ourmysql.com/archives/954/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>探索MYSQL源代码–添加一个函数</title>
		<link>http://ourmysql.com/archives/947</link>
		<comments>http://ourmysql.com/archives/947#comments</comments>
		<pubDate>Tue, 19 Jul 2011 15:50:29 +0000</pubDate>
		<dc:creator>OurMySQL</dc:creator>
				<category><![CDATA[MySQL高级应用]]></category>
		<category><![CDATA[函数]]></category>
		<category><![CDATA[源代码]]></category>

		<guid isPermaLink="false">http://ourmysql.com/?p=947</guid>
		<description><![CDATA[探索MYSQL源代码–添加一个函数]]></description>
			<content:encoded><![CDATA[<p>我们来为MySQL添加一个函数，名为show disk_usage</p>
<pre>mysql&gt; show disk_usage;
+----------+-----------+
| Database | Size (Kb) |
+----------+-----------+
| test_row | 120400      |
+----------+-----------+
1 row in set (0.00 sec)</pre>
<p>要修改新的函数，涉及到词法分析，我们先来修改sql/lex.h文件。<br />
找到static SYMBOL symbols[] 这个结构体，添加一个”DISK_USAGE”这个词法，效果如下</p>
<pre>{ "DISK",             SYM(DISK_SYM)},
/*start*/
{ "DISK_USAGE",       SYM(DISK_USAGE_SYM)},
/*end */
{ "DISTINCT",         SYM(DISTINCT)}</pre>
<p>于是词法分析的时候会DISK_USAGE这个词法当做一个token转化为内部枚举DISK_USAGE_SYM。</p>
<p>有新的词法，我们为新词法添加新语法，我们来修改sql/yacc.yy文件。<br />
来到token区域，添加一个token，名字于lex.h一样，这样语法分析器bison才能知晓词法分析器flex传过来的token对应的枚举。</p>
<pre>%token  DISK_SYM
/*start*/
%token  DISK_USAGE_SYM
/*end*/
%token  DISTINCT</pre>
<p>继续添加发现show disk_usage()语法匹配之后的行为<br />
搜索关键字show: 添加新的行为</p>
<pre>show:
        /*start*/
        SHOW DISK_USAGE_SYM
        {
                LEX *lex = Lex;
                <a href="http://ourmysql.com/archives/tag/sql" class="st_tag internal_tag" rel="tag" title="标签 sql 下的日志">sql</a>_command = SQLCOM_SHOW_DISK_USAGE;
        }
        | /*end*/
        SHOW</pre>
<p>到这里为止词法语法部分添加完毕。</p>
<p>SQLCOM_SHOW_DISK_USAGE产生什么效果呢，需要指向具体的函数。<br />
在添加具体函数之前，还需要让SQLCOM_SHOW_DISK_USAGE成为一个合法的sql_command，我们需要修改sql/sql_lex.h。找到关键字enum enum_sql_command, 把SQLCOM_SHOW_DISK_USAGE作为一个enum添加进去</p>
<pre>  SQLCOM_SHOW_PROFILE,
  SQLCOM_SHOW_PROFILES,
  /*start*/
  SQLCOM_SHOW_DISK_USAGE,
  /*end*/
  /*
    When a command is added here, be sure it's also added in mysqld.cc
    in "struct show_var_st <a href="http://ourmysql.com/archives/tag/status" class="st_tag internal_tag" rel="tag" title="标签 status 下的日志">status</a>_vars[]= {" ...
  */
  /* This should be the last !!! */
  SQLCOM_END
};</pre>
<p>&nbsp;</p>
<p>接着还要在sql/mysqld.cc 里再添加一遍， 找到关键字SHOW_VAR com_status_vars[]= {</p>
<pre>  {"show_authors",         (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_AUTHORS]), SHOW_LONG_STATUS},
/*start*/
  {"show_disk_usage",      (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_DISK_USAGE]), SHOW_LONG_STATUS},
/*end*/
  {"show_<a href="http://ourmysql.com/archives/tag/binlog" class="st_tag internal_tag" rel="tag" title="标签 binlog 下的日志">binlog</a>_events",   (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_<a href="http://ourmysql.com/archives/tag/binlog" class="st_tag internal_tag" rel="tag" title="标签 binlog 下的日志">BINLOG</a>_EVENTS]), SHOW_LONG_STATUS},</pre>
<p>不添加这部会出现编译时的ASSERT错误。</p>
<p>接着把SQLCOM_DISK_USAGE指向具体函数， 修改sql/sql_parse.cc，关键字mysql_execute_command</p>
<pre>  switch (lex-&gt;sql_command) {
/*start*/
  case SQLCOM_SHOW_DISK_USAGE:
        res = show_disk_usage_command(thd);
        break;
/*end*/
  case SQLCOM_SHOW_EVENTS:</pre>
<p>好了终于指向了具体的函数show_disk_usage_command()，我们接着来实现这个函数。</p>
<p>在sql/mysql_priv.h添加一个申明</p>
<pre>bool mysqld_help (THD *thd, const char *text);
/*start*/
bool show_disk_usage_command(THD *thd);
/* end */
void calc_sum_of_all_status(STATUS_VAR *to);</pre>
<p>&nbsp;</p>
<p>在sql/sql_show.cc添加一个具体的实现</p>
<pre>bool show_disk_usage_command(THD *thd)
{
  DBUG_ENTER("show_disk_usage");
  List field_list;
  List dbs;
  Protocol *protocol = thd-&gt;protocol;

  /*set fields*/
  field_list.push_back(new Item_empty_string("Database", 50));
  field_list.push_back(new Item_empty_string("Size (Kb)", 30));

  if (protocol-&gt;send_fields(&amp;field_list, Protocol::SEND_NUM_ROWS|Protocol::SEND_EOF))
    DBUG_RETURN(TRUE);

  /*set data*/
  protocol-&gt;prepare_for_resend();
  protocol-&gt;store("test_row", system_charset_info);
  protocol-&gt;store("1024000", system_charset_info);
  if (protocol-&gt;write())
    DBUG_RETURN(TRUE);

  my_eof(thd);
  DBUG_RETURN(FALSE);
}
/*end*/
bool mysqld_show_authors(THD *thd)</pre>
<p>&nbsp;</p>
<p>make clean; make;make install<br />
好了，效果就可以看到了</p>
<pre>mysql&gt; show disk_usage;
+----------+-----------+
| Database | Size (Kb) |
+----------+-----------+
| test_row | 1024      |
+----------+-----------+
1 row in set (0.00 sec)</pre>
<p>ps : 部分参考expert mysql<br />
for douban: doubanclaimfdd64e647e42d240</p>
<p>&nbsp;</p>
<h3  class="related_post_title">相关文章</h3><ul class="related_post"><li>2011-07-19 -- <a href="http://ourmysql.com/archives/945" title="探索MYSQL源代码–添加一个VARIABLE">探索MYSQL源代码–添加一个VARIABLE</a></li><li>2011-07-19 -- <a href="http://ourmysql.com/archives/943" title="探索MYSQL源代码–准备工作">探索MYSQL源代码–准备工作</a></li><li>2011-07-19 -- <a href="http://ourmysql.com/archives/941" title="探索MYSQL源代码–SQL历险记">探索MYSQL源代码–SQL历险记</a></li><li>2011-07-19 -- <a href="http://ourmysql.com/archives/939" title="探索MYSQL源代码-BINLOG里的时间">探索MYSQL源代码-BINLOG里的时间</a></li><li>2011-07-18 -- <a href="http://ourmysql.com/archives/934" title="DROP TABLE AND LOCK_OPEN MUTEX">DROP TABLE AND LOCK_OPEN MUTEX</a></li><li>2011-07-18 -- <a href="http://ourmysql.com/archives/930" title="探索MYSQL源代码-在SHOW PROCESSLIST里添加字段">探索MYSQL源代码-在SHOW PROCESSLIST里添加字段</a></li><li>2011-07-18 -- <a href="http://ourmysql.com/archives/928" title="探索MYSQL源代码-客户端连接过程和用户认证体系">探索MYSQL源代码-客户端连接过程和用户认证体系</a></li><li>2009-11-10 -- <a href="http://ourmysql.com/archives/777" title="教你写MySQL UDF ">教你写MySQL UDF </a></li></ul>
	标签：<a href="http://ourmysql.com/archives/category/advanced" title="MySQL高级应用" rel="tag">MySQL高级应用</a>, <a href="http://ourmysql.com/archives/tag/%e5%87%bd%e6%95%b0" title="函数" rel="tag">函数</a>, <a href="http://ourmysql.com/archives/tag/%e6%ba%90%e4%bb%a3%e7%a0%81" title="源代码" rel="tag">源代码</a><br />
]]></content:encoded>
			<wfw:commentRss>http://ourmysql.com/archives/947/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>探索MYSQL源代码–添加一个VARIABLE</title>
		<link>http://ourmysql.com/archives/945</link>
		<comments>http://ourmysql.com/archives/945#comments</comments>
		<pubDate>Tue, 19 Jul 2011 15:48:25 +0000</pubDate>
		<dc:creator>OurMySQL</dc:creator>
				<category><![CDATA[MySQL高级应用]]></category>
		<category><![CDATA[variable]]></category>
		<category><![CDATA[源代码]]></category>

		<guid isPermaLink="false">http://ourmysql.com/?p=945</guid>
		<description><![CDATA[mysql里的variable 有一部分是来自于my.cnf里的option。为了添加一个可配置的variale, 我们先来添加一个option, 名字是options_hoterran，没有s。]]></description>
			<content:encoded><![CDATA[<p>我们来为mysql添加一个variable, 名字是options_hoterrans，要达到的效果如下</p>
<pre>mysql&gt; show variables like '%hoterrans%';
+------------------+-------+
| <a href="http://ourmysql.com/archives/tag/variable" class="st_tag internal_tag" rel="tag" title="标签 variable 下的日志">Variable</a>_name    | Value |
+------------------+-------+
| options_hoterrans | 4     |
+------------------+-------+
1 row in set (0.00 sec)</pre>
<p>&nbsp;</p>
<p>mysql里的variable 有一部分是来自于my.cnf里的option。为了添加一个可配置的variale, 我们先来添加一个option, 名字是options_hoterran，没有s。</p>
<p><a href="http://ourmysql.com/archives/tag/sql" class="st_tag internal_tag" rel="tag" title="标签 sql 下的日志">sql</a>/mysqld.cc 查找关键字 my_long_options， 会找到一个很大的类型为my_options的结构体，这个结构体用于存储所有的long_options。<br />
我们调到这个结构体的尾部，可以利用vim的{键。<br />
在结构体的尾部有个哨兵，我们的选项就添加到哨兵的前面</p>
<pre>struct my_option my_long_options[] =
....
  {"wait_timeout", OPT_WAIT_TIMEOUT,
   "The number of seconds the server waits for activity on a connection before closing it.",
   (uchar**) &amp;global_system_variables.net_wait_timeout,
   (uchar**) &amp;max_system_variables.net_wait_timeout, 0, GET_ULONG,
   REQUIRED_ARG, NET_WAIT_TIMEOUT, 1, IF_WIN(INT_MAX32/1000, LONG_TIMEOUT),
   0, 1, 0},
   /* start*/
  {"options_hoterran", OPT_HOTERRAN,
        "This is option just for test",
        (uchar**)  &amp;global_system_variables.opt_hoterran,
        NULL,
        0, GET_ULONG,
        REQUIRED_ARG, 2, 1, 1000,
        0, 1, 0
  },                                        

   /* end */
  {0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
};</pre>
<p>/*start*/ /*end*/ 之间的就是我们所添加的代码，下同。</p>
<p>简单介绍一下my_option这个结构体</p>
<pre>struct my_option
{
  const char *name;                     /* Name of the option */
  int        id;                        /* unique id or short option */
  const char *comment;                  /* option comment, for autom. --help */
  uchar      **value;                   /* The variable value */
  uchar      **u_max_value;             /* The user def. max variable value */
  struct st_typelib *typelib;           /* Pointer to possible values */
  ulong     var_type;
  enum get_opt_arg_type arg_type;
  longlong   def_value;                 /* Default value */
  longlong   min_value;                 /* Min allowed value */
  longlong   max_value;                 /* Max allowed value */
  longlong   sub_size;                  /* Subtract this from given value */
  long       block_size;                /* Value should be a mult. of this */
  void       *app_type;                 /* To be used by an application */
};</pre>
<p>我们要注意其中2个字段， id：option的内部序列号; typelib:option的值指向了一个地址。<br />
所以我们还需要添加这2个变量。</p>
<p>sql/mysqld.cc 里查找关键字enum options_mysqld，在这个枚举中我们添加一个枚举类型</p>
<pre>   OPT_SLOW_QUERY_LOG_FILE,
+  /*rry start*/
+  OPT_HOTERRAN,
+  /*rry end*/
   OPT_IGNORE_BUILTIN_<a href="http://ourmysql.com/archives/tag/innodb" class="st_tag internal_tag" rel="tag" title="标签 InnoDB 下的日志">INNODB</a>
 };</pre>
<p>转到global_system_variables的类型system_variables定义处，sql/sql_class.h里。<br />
在system_variables最末尾添加一个变量</p>
<pre>  my_bool sysdate_is_now;
/*start*/
  u_long opt_hoterran;
/*end*/
};</pre>
<p>目前为止，我们已经添加一个option, 你可以在my.cnf 添加</p>
<pre>[mysqld]
....
options_hoterran=4</pre>
<p>这个参数会被mysqld采用。</p>
<p>继续添加variable, 只要把上面的option与variable关联上即可。<br />
打开sql/set_var.cc 文件，找到关键字net_wait_timeout, 修改后效果如下</p>
<pre> static sys_var_thd_ulong       sys_net_wait_timeout(&amp;vars, "wait_timeout",
                                             &amp;SV::net_wait_timeout);
+/*start*/
+static sys_var_thd_ulong        sys_opt_hoterran(&amp;vars, "options_hoterrans",
+                                             &amp;SV::opt_hoterran);
+/*end*/</pre>
<p>这里是创建一个名为sys_opt_hoterran 的 sys_var_thd_ulong类，这个类的构造函数实际上就是在vars这个全局变量chain中添加一个名为options_hoterrans的variable。<br />
SV就是上面options里的global_system_variables。</p>
<p>我们来看效果。</p>
<pre>make&amp;&amp;make install</pre>
<p>这里会比较慢，因为sql/sql_class.h 这个文件被修改了，而reference这个文件的target很多。</p>
<p>重启mysqld，mysql登上去</p>
<pre>mysql&gt; show variables like '%hoterrans%';
+-------------------+-------+
| Variable_name     | Value |
+-------------------+-------+
| options_hoterrans | 5     |
+-------------------+-------+
1 row in set (0.00 sec)</pre>
<p>&nbsp;</p>
<h3  class="related_post_title">相关文章</h3><ul class="related_post"><li>2011-07-19 -- <a href="http://ourmysql.com/archives/947" title="探索MYSQL源代码–添加一个函数">探索MYSQL源代码–添加一个函数</a></li><li>2011-07-19 -- <a href="http://ourmysql.com/archives/943" title="探索MYSQL源代码–准备工作">探索MYSQL源代码–准备工作</a></li><li>2011-07-19 -- <a href="http://ourmysql.com/archives/941" title="探索MYSQL源代码–SQL历险记">探索MYSQL源代码–SQL历险记</a></li><li>2011-07-19 -- <a href="http://ourmysql.com/archives/939" title="探索MYSQL源代码-BINLOG里的时间">探索MYSQL源代码-BINLOG里的时间</a></li><li>2011-07-18 -- <a href="http://ourmysql.com/archives/934" title="DROP TABLE AND LOCK_OPEN MUTEX">DROP TABLE AND LOCK_OPEN MUTEX</a></li><li>2011-07-18 -- <a href="http://ourmysql.com/archives/930" title="探索MYSQL源代码-在SHOW PROCESSLIST里添加字段">探索MYSQL源代码-在SHOW PROCESSLIST里添加字段</a></li><li>2011-07-18 -- <a href="http://ourmysql.com/archives/928" title="探索MYSQL源代码-客户端连接过程和用户认证体系">探索MYSQL源代码-客户端连接过程和用户认证体系</a></li></ul>
	标签：<a href="http://ourmysql.com/archives/category/advanced" title="MySQL高级应用" rel="tag">MySQL高级应用</a>, <a href="http://ourmysql.com/archives/tag/variable" title="variable" rel="tag">variable</a>, <a href="http://ourmysql.com/archives/tag/%e6%ba%90%e4%bb%a3%e7%a0%81" title="源代码" rel="tag">源代码</a><br />
]]></content:encoded>
			<wfw:commentRss>http://ourmysql.com/archives/945/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>探索MYSQL源代码–准备工作</title>
		<link>http://ourmysql.com/archives/943</link>
		<comments>http://ourmysql.com/archives/943#comments</comments>
		<pubDate>Tue, 19 Jul 2011 15:46:20 +0000</pubDate>
		<dc:creator>OurMySQL</dc:creator>
				<category><![CDATA[MySQL高级应用]]></category>
		<category><![CDATA[源代码]]></category>

		<guid isPermaLink="false">http://ourmysql.com/?p=943</guid>
		<description><![CDATA[探索MYSQL源代码–准备工作]]></description>
			<content:encoded><![CDATA[<p>mysql源代码，编译的时候要注意添加如下选项，增加symbol</p>
<pre>./configure --with-debug</pre>
<p>&nbsp;</p>
<p>使用git来查看自己对源代码做过的改动，方便发现代码的变化</p>
<pre>sudo apt-get install  git-doc
sudo  apt-get install git-core</pre>
<p>把mysql代码加入到git里</p>
<pre>cd mysql-source
git init
git add *.h
git add *.c
git add *.cc</pre>
<p>&nbsp;</p>
<p>安装cscope，方便快速切换。<br />
具体的步骤见<a href="http://cscope.sourceforge.net/cscope_vim_tutorial.html">这篇文章</a>。<br />
愿意的话可修改一下cscope.vim 文件里的nmap</p>
<pre>nmap s :vert scs find s =expand("")
nmap g :vert scs find g =expand("")
nmap c :vert scs find c =expand("")
nmap t :vert scs find t =expand("")
nmap e :vert scs find e =expand("")
nmap f :vert scs find f =expand("")
nmap i :vert scs find i ^=expand("")$
nmap d :vert scs find d =expand("")</pre>
<p>这样的好处就是ctrl+] 调到函数内部，ctrl+n+g 跳出垂直窗口显示代码</p>
<p>gdb调试会涉及到重复set args，我们可以利用gdb的macro-file来避免重复的输入。</p>
<p>涉及到多线程编程，为了让其他线程继续运行，需要设置<br />
set scheduler-locking off</p>
<p>另外mysql对SIGINT设置了sigprocmask。启动mysqld时需设置参数–gdb</p>
<p>于是我们的macro-file就是</p>
<pre>b main
r --user=mysql --gdb
set scheduler-locking off</pre>
<p>&nbsp;</p>
<p>开始debug</p>
<pre>gdb mysqld -x macro-file</pre>
<p>&nbsp;</p>
<h3  class="related_post_title">相关文章</h3><ul class="related_post"><li>2011-07-19 -- <a href="http://ourmysql.com/archives/947" title="探索MYSQL源代码–添加一个函数">探索MYSQL源代码–添加一个函数</a></li><li>2011-07-19 -- <a href="http://ourmysql.com/archives/945" title="探索MYSQL源代码–添加一个VARIABLE">探索MYSQL源代码–添加一个VARIABLE</a></li><li>2011-07-19 -- <a href="http://ourmysql.com/archives/941" title="探索MYSQL源代码–SQL历险记">探索MYSQL源代码–SQL历险记</a></li><li>2011-07-19 -- <a href="http://ourmysql.com/archives/939" title="探索MYSQL源代码-BINLOG里的时间">探索MYSQL源代码-BINLOG里的时间</a></li><li>2011-07-18 -- <a href="http://ourmysql.com/archives/934" title="DROP TABLE AND LOCK_OPEN MUTEX">DROP TABLE AND LOCK_OPEN MUTEX</a></li><li>2011-07-18 -- <a href="http://ourmysql.com/archives/930" title="探索MYSQL源代码-在SHOW PROCESSLIST里添加字段">探索MYSQL源代码-在SHOW PROCESSLIST里添加字段</a></li><li>2011-07-18 -- <a href="http://ourmysql.com/archives/928" title="探索MYSQL源代码-客户端连接过程和用户认证体系">探索MYSQL源代码-客户端连接过程和用户认证体系</a></li></ul>
	标签：<a href="http://ourmysql.com/archives/category/advanced" title="MySQL高级应用" rel="tag">MySQL高级应用</a>, <a href="http://ourmysql.com/archives/tag/%e6%ba%90%e4%bb%a3%e7%a0%81" title="源代码" rel="tag">源代码</a><br />
]]></content:encoded>
			<wfw:commentRss>http://ourmysql.com/archives/943/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>探索MYSQL源代码–SQL历险记</title>
		<link>http://ourmysql.com/archives/941</link>
		<comments>http://ourmysql.com/archives/941#comments</comments>
		<pubDate>Tue, 19 Jul 2011 15:44:21 +0000</pubDate>
		<dc:creator>OurMySQL</dc:creator>
				<category><![CDATA[MySQL高级应用]]></category>
		<category><![CDATA[sql]]></category>
		<category><![CDATA[源代码]]></category>

		<guid isPermaLink="false">http://ourmysql.com/?p=941</guid>
		<description><![CDATA[本文从一个select语句的执行过程出发, 遍历MySQL的多个几子系统.]]></description>
			<content:encoded><![CDATA[<p>本文从一个select语句的执行过程出发, 遍历MySQL的多个几子系统.</p>
<p>先放图一张, 按图索骥开始我们的历险.<br />
<a href="https://picasaweb.google.com/lh/photo/spjceuML7iFZdRjND4lSEg?feat=embedwebsite"><img src="https://lh3.googleusercontent.com/_UkB3qlLgBXE/TWU2B-iK1vI/AAAAAAAAB3c/SiX9ghG5pEo/s288/sql_adventure1.jpg" alt="" width="288" height="176" /></a></p>
<p>当客户端连接上MySQL服务端之后,发出请求之前,服务端的线程是阻塞在do_command（<a href="http://ourmysql.com/archives/tag/sql" class="st_tag internal_tag" rel="tag" title="标签 sql 下的日志">sql</a>/parse.cc）里的my_net_read函数中(就是socket里的read).</p>
<p>当客户端键入sql语句(本文例子select * from zzz)发送到服务端之后, my_net_read返回, 并从tcpbuffer中读取数据写入到packet这个字符串.</p>
<div>
<div>
<pre>packet_length= my_net_read(net);</pre>
</div>
</div>
<p>packet的第一个字节是个标志位, 决定数据包是查询还是命令,成功,或者出错。<br />
接下来就进入dispatch_command(sql/sql/parse.cc)这个函数, 数据类型不再需要.</p>
<div>
<div>
<pre>return_value= dispatch_command(command, thd, packet+1, (uint) (packet_length-1));</pre>
</div>
</div>
<p>进入dispatch_command, 我们可见</p>
<div>
<div>
<pre>statistic_increment(thd-&gt;<a href="http://ourmysql.com/archives/tag/status" class="st_tag internal_tag" rel="tag" title="标签 status 下的日志">status</a>_var.questions, &amp;amp;LOCK_<a href="http://ourmysql.com/archives/tag/status" class="st_tag internal_tag" rel="tag" title="标签 status 下的日志">status</a>);</pre>
</div>
</div>
<p>这个就是show status questions的值累加.</p>
<p>接下的mysql_parse（sql/sql_parse.cc）, 该函数是sql语句解析的总路口.</p>
<p>进入该函数后首先碰到的是query_cache_send_result_to_client,故名思义这个函数是在QCache里查询是否有相同的语句, 有则立即从QCache返回结果, 于是整个sql就结束了.</p>
<p>QCache里不存在的sql则继续前进来到parse_sql(sql/sql_parse.cc),这个函数主要就是调用了MYSQLparse. 而MYSQLparse其实就是bison/yacc里的yyparse(^_^),</p>
<pre>#define yyparse         MYSQLparse</pre>
<p>是的开始解析sql了. 关于词法分析和语法匹配简单说几下.</p>
<p>对于一条像select * from zzz的语句首先进入词法分析,找到2个token(select, from), 然后根据token进行语法匹配, 规则在sql/yacc.yy里, 我把几个匹配到的pattern和action贴出来.</p>
<div>
<div>
<pre>select:
          select_init
          {
            LEX *lex= Lex;
            lex-&gt;sql_command= SQLCOM_SELECT;
          }
        ;

/* Need select_init2 for subselects. */
select_init:
          SELECT_SYM select_init2
        | '(' select_paren ')' union_opt
        ;

select_paren:
          SELECT_SYM select_part2
          {
            LEX *lex= Lex;
            SELECT_LEX * sel= lex-&gt;current_select;
.....

select_from:
          FROM join_table_list where_clause group_clause having_clause
          opt_order_clause opt_limit_clause procedure_clause
          {
            Select-&gt;context.table_list=
              Select-&gt;context.first_name_resolution_table=
                (TABLE_LIST *) Select-&gt;table_list.first;
          }
....
select_item_list:
          select_item_list ',' select_item
        | select_item
        | '*'
          {
            THD *thd= YYTHD;
            Item *item= new (thd-&gt;mem_root)
                          Item_field(&amp;amp;thd-&gt;lex-&gt;current_select-&gt;context,
                                     NULL, NULL, "*");
            if (item == NULL)
              MYSQL_YYABORT;
            if (add_item_to_list(thd, item))
              MYSQL_YYABORT;
            (thd-&gt;lex-&gt;current_select-&gt;with_wild)++;
          }
        ;    

select_item:
          remember_name select_item2 remember_end select_alias
          {
            THD *thd= YYTHD;
            DBUG_ASSERT($1 &amp;lt; $3);

            if (add_item_to_list(thd, $2))
              MYSQL_YYABORT;
            if ($4.str)
...</pre>
</div>
</div>
<p>可以看到action里最关键的就是add_item_to_list 和table_list的赋值.<br />
解析后对于需要查询的表(zzz)和字段(*)这些信息都写入到thd-&gt;lex这个结构体里了.</p>
<p>例如其中thd-&gt;lex-&gt;query_tables就是表(zzz)的状况, thd-&gt;lex-&gt;current_select-&gt;with_wild 是表示该语句是否使用了*等等.</p>
<div>
<div>
<pre>(gdb) p *thd-&gt;lex-&gt;query_tables
$7 = {next_local = 0x0, next_global = 0x0, prev_global = 0x855a458, db = 0x85a16b8 "test", alias = 0x85a16e0 "zzz",
  table_name = 0x85a16c0 "zzz", schema_table_name = 0x0, option = 0x0, on_expr = 0x0, prep_on_expr = 0x0, cond_equal = 0x0,</pre>
</div>
</div>
<p>&nbsp;</p>
<p>sql解析完了, 优化呢? 别急接着往下看.<br />
接着进入mysql_execute_command函数，这个函数是所有sql命令的总入口.<br />
由于是这个sql是一个select, 于是execute_sqlcom_select就是我们下个要执行的函数,又然后进入了mysql_select(^_^怒了如此复杂).</p>
<p>mysql_select 就是优化器的模块, 这个模块代码比较复杂. 我们可以清楚看到创建优化器，优化，执行的3个步骤, 优化细节不表.</p>
<div>
<div>
<pre>if (!(join= new JOIN(thd, fields, select_options, result)))
...
if ((err= join-&gt;optimize()))
...
join-&gt;exec();</pre>
</div>
</div>
<p>&nbsp;</p>
<p>结束了优化，我们要具体执行join-&gt;exec()，该函数实际进入的是JOIN::exec()(sql_select.cc)。</p>
<p>exec()首先向客户端发送字段title的函数send_fields, 没数据但字段也是要的。</p>
<p>然后再进入do_select()，根据表的存储引擎跳入到引擎具体的实现(zzz是myisam表)。<br />
这里mi_scan就是myisam引擎扫描文件的函数，再看到</p>
<pre>(gdb) p info-&gt;filename
./test/zzz</pre>
<p>这不就是zzz表对应的物理文件吗。</p>
<p>通过一系列的mi函数访问磁盘拿到数据之后，会通过send_data发送数据给client，并从dispatch_command返回.最后在net_end_statement结束整个sql。</p>
<p>一个简单的select语句背后的执行过程是非常复杂的，上面的步骤都只是点到就止。</p>
<p>ps: 在sql_yacc.yy可见MySQL对于Oracle中常用的dual表的嘲讽。</p>
<h3  class="related_post_title">相关文章</h3><ul class="related_post"><li>2011-07-19 -- <a href="http://ourmysql.com/archives/947" title="探索MYSQL源代码–添加一个函数">探索MYSQL源代码–添加一个函数</a></li><li>2011-07-19 -- <a href="http://ourmysql.com/archives/945" title="探索MYSQL源代码–添加一个VARIABLE">探索MYSQL源代码–添加一个VARIABLE</a></li><li>2011-07-19 -- <a href="http://ourmysql.com/archives/943" title="探索MYSQL源代码–准备工作">探索MYSQL源代码–准备工作</a></li><li>2011-07-19 -- <a href="http://ourmysql.com/archives/939" title="探索MYSQL源代码-BINLOG里的时间">探索MYSQL源代码-BINLOG里的时间</a></li><li>2011-07-18 -- <a href="http://ourmysql.com/archives/934" title="DROP TABLE AND LOCK_OPEN MUTEX">DROP TABLE AND LOCK_OPEN MUTEX</a></li><li>2011-07-18 -- <a href="http://ourmysql.com/archives/930" title="探索MYSQL源代码-在SHOW PROCESSLIST里添加字段">探索MYSQL源代码-在SHOW PROCESSLIST里添加字段</a></li><li>2011-07-18 -- <a href="http://ourmysql.com/archives/928" title="探索MYSQL源代码-客户端连接过程和用户认证体系">探索MYSQL源代码-客户端连接过程和用户认证体系</a></li></ul>
	标签：<a href="http://ourmysql.com/archives/category/advanced" title="MySQL高级应用" rel="tag">MySQL高级应用</a>, <a href="http://ourmysql.com/archives/tag/sql" title="sql" rel="tag">sql</a>, <a href="http://ourmysql.com/archives/tag/%e6%ba%90%e4%bb%a3%e7%a0%81" title="源代码" rel="tag">源代码</a><br />
]]></content:encoded>
			<wfw:commentRss>http://ourmysql.com/archives/941/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>探索MYSQL源代码-BINLOG里的时间</title>
		<link>http://ourmysql.com/archives/939</link>
		<comments>http://ourmysql.com/archives/939#comments</comments>
		<pubDate>Tue, 19 Jul 2011 15:42:17 +0000</pubDate>
		<dc:creator>OurMySQL</dc:creator>
				<category><![CDATA[MySQL高级应用]]></category>
		<category><![CDATA[binlog]]></category>
		<category><![CDATA[源代码]]></category>

		<guid isPermaLink="false">http://ourmysql.com/?p=939</guid>
		<description><![CDATA[set timestamp 就是修改start_time, 而从上面的now()可以看到，now()取的就是start_time。
replication就是依靠存储在event里的set timestamp 来保证now函数的时间一致的。]]></description>
			<content:encoded><![CDATA[<p>今天在代码的时候无意中看到</p>
<div>
<div>
<pre>void Item_func_now_local::store_now_in_TIME(MYSQL_TIME *now_time)
{
  THD *thd= current_thd;
  thd-&gt;variables.time_zone-&gt;gmt_sec_to_TIME(now_time,
                                             (my_time_t)thd-&gt;query_start());
  thd-&gt;time_zone_used= 1;
}

tem_func_sysdate_local::store_now_in_TIME(MYSQL_TIME *now_time)
{
  THD *thd= current_thd;
  thd-&gt;variables.time_zone-&gt;gmt_sec_to_TIME(now_time, (my_time_t) my_time(0));
  thd-&gt;time_zone_used= 1;
}</pre>
</div>
</div>
<p>可以看到now()函数取的是这个语句执行开始时的时间</p>
<div>
<div>
<pre>inline time_t query_start() { query_start_used=1; return start_time; }</pre>
</div>
</div>
<p>而sysdate取得是执行到这个函数点的时间。</p>
<div>
<div>
<pre>time_t my_time(myf flags __attribute__((unused)))
{
.....
  while ((t= time(0)) == (time_t) -1)
.....
}</pre>
</div>
</div>
<p>所以就有了这个现象（当然别设置–sysdate-is-now ）</p>
<div>
<div>
<pre>mysql&gt; select sysdate(), sleep(3), sysdate();
+---------------------+----------+---------------------+
| sysdate()           | sleep(3) | sysdate()           |
+---------------------+----------+---------------------+
| 2011-03-07 15:02:48 |        0 | 2011-03-07 15:02:51 |
+---------------------+----------+---------------------+</pre>
</div>
</div>
<p>基于statement <a href="http://ourmysql.com/archives/tag/replication" class="st_tag internal_tag" rel="tag" title="标签 replication 下的日志">replication</a>，源端的now(), sysdate() 等函数都是原封不动的传递到对端。<br />
对端应用binlog的时候，sysdate()自然就会使用本地的时间，所以用sysdate()除了检测slave lag，没有别的用处， 还容易误用。</p>
<p>那么now() 是如何保证与源节点的时间一样呢？</p>
<p>通过mysqlbinlog可看到大量的set timestamp 语句。<br />
每个event group 的最开始都会使用set timestamp来决定这次查询的开始点，而这个设置影响到group内的now()。</p>
<p>我们来看看set timestamp 的函数实现，从sql/<a href="http://ourmysql.com/archives/tag/sql" class="st_tag internal_tag" rel="tag" title="标签 sql 下的日志">sql</a>_yacc.yy 的关键字set:出发，跳到sql/<a href="http://ourmysql.com/archives/tag/sql" class="st_tag internal_tag" rel="tag" title="标签 sql 下的日志">sql</a>_parse.cc<br />
的sql_set_variables, 再来到sql/set_var.cc的实现类</p>
<div>
<div>
<pre>bool sys_var_timestamp::update(THD *thd,  set_var *var)
{
  thd-&gt;set_time((time_t) var-&gt;save_result.ulonglong_value);
  return 0;
}</pre>
</div>
</div>
<p>转到set_time的实现sql/sql_class.h</p>
<div>
<div>
<pre>class THD :public Statement,
           public Open_tables_state
{
.......
  inline void   set_time(time_t t)
  {
    start_time= user_time= t;
........</pre>
</div>
</div>
<p>可以看到set timestamp 就是修改start_time, 而从上面的now()可以看到，now()取的就是start_time。<br />
replication就是依靠存储在event里的set timestamp 来保证now函数的时间一致的。</p>
<p>ps: sysdate函数应该是源自于Oracle， dataguard是基于data block，进入block之前sysdate已经计算出写入，所以不存在这个问题。</p>
<p>&nbsp;</p>
<h3  class="related_post_title">相关文章</h3><ul class="related_post"><li>2011-07-19 -- <a href="http://ourmysql.com/archives/947" title="探索MYSQL源代码–添加一个函数">探索MYSQL源代码–添加一个函数</a></li><li>2011-07-19 -- <a href="http://ourmysql.com/archives/945" title="探索MYSQL源代码–添加一个VARIABLE">探索MYSQL源代码–添加一个VARIABLE</a></li><li>2011-07-19 -- <a href="http://ourmysql.com/archives/943" title="探索MYSQL源代码–准备工作">探索MYSQL源代码–准备工作</a></li><li>2011-07-19 -- <a href="http://ourmysql.com/archives/941" title="探索MYSQL源代码–SQL历险记">探索MYSQL源代码–SQL历险记</a></li><li>2011-07-18 -- <a href="http://ourmysql.com/archives/934" title="DROP TABLE AND LOCK_OPEN MUTEX">DROP TABLE AND LOCK_OPEN MUTEX</a></li><li>2011-07-18 -- <a href="http://ourmysql.com/archives/930" title="探索MYSQL源代码-在SHOW PROCESSLIST里添加字段">探索MYSQL源代码-在SHOW PROCESSLIST里添加字段</a></li><li>2011-07-18 -- <a href="http://ourmysql.com/archives/928" title="探索MYSQL源代码-客户端连接过程和用户认证体系">探索MYSQL源代码-客户端连接过程和用户认证体系</a></li><li>2009-11-30 -- <a href="http://ourmysql.com/archives/788" title="mysql audit-访问日志记录 ">mysql audit-访问日志记录 </a></li><li>2009-04-08 -- <a href="http://ourmysql.com/archives/508" title="利用binlog来恢复数据库">利用binlog来恢复数据库</a></li><li>2008-11-18 -- <a href="http://ourmysql.com/archives/293" title="删除MYSQL BIN-LOG 日志">删除MYSQL BIN-LOG 日志</a></li></ul>
	标签：<a href="http://ourmysql.com/archives/tag/binlog" title="binlog" rel="tag">binlog</a>, <a href="http://ourmysql.com/archives/category/advanced" title="MySQL高级应用" rel="tag">MySQL高级应用</a>, <a href="http://ourmysql.com/archives/tag/%e6%ba%90%e4%bb%a3%e7%a0%81" title="源代码" rel="tag">源代码</a><br />
]]></content:encoded>
			<wfw:commentRss>http://ourmysql.com/archives/939/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>DROP TABLE AND LOCK_OPEN MUTEX</title>
		<link>http://ourmysql.com/archives/934</link>
		<comments>http://ourmysql.com/archives/934#comments</comments>
		<pubDate>Mon, 18 Jul 2011 15:55:47 +0000</pubDate>
		<dc:creator>OurMySQL</dc:creator>
				<category><![CDATA[MySQL解错方案]]></category>
		<category><![CDATA[drop]]></category>
		<category><![CDATA[源代码]]></category>

		<guid isPermaLink="false">http://ourmysql.com/?p=934</guid>
		<description><![CDATA[在Oracle中直接删除一张大表，会导致free extent 的enqueue，会导致buffer cache 的object purge，所以我们要有很多步骤，让删表变得不影响性能。这方面MySQL目前没有好的方法。MySQL中在对表进行drop table 命令，实际上调度的是mysql_rm_table_part2(sql/sql_table.cc)函数。]]></description>
			<content:encoded><![CDATA[<p>在Oracle中直接删除一张大表，会导致free extent 的enqueue，会导致buffer cache 的object purge，所以我们要有很多步骤，让删表变得不影响性能。</p>
<p>这方面MySQL目前没有好的方法。</p>
<p>MySQL中在对表进行drop table 命令，实际上调度的是mysql_rm_table_part2(<a href="http://ourmysql.com/archives/tag/sql" class="st_tag internal_tag" rel="tag" title="标签 sql 下的日志">sql</a>/sql_table.cc)<a href="http://ourmysql.com/archives/tag/%e5%87%bd%e6%95%b0" class="st_tag internal_tag" rel="tag" title="标签 函数 下的日志">函数</a>，其中有一段代码。</p>
<div>
<div>
<pre>pthread_mutex_lock(&amp;LOCK_open);
…..
error= ha_delete_table(thd, table_type, path, db, table-&gt;table_name,
….
pthread_mutex_unlock(&amp;LOCK_open);</pre>
</div>
</div>
<p>ha_delete_table 实际调用的是每个存储引擎对应的删除表的函数，这个函数不返回，LOCK_open 这个全局的mutex 要一直持有。</p>
<p>要知道LOCK_open是table_cache 的全局mutex，而任何和表相关的sql都会在open_table 这个函数中锁住这个全局的mutex，于是一个删表的操作会阻塞了所有的sql语句，碰到大表删除，show processlist 看到一堆的opening tables state。</p>
<p>同样的alter table 也会阻塞实例中所有的sql。</p>
<p>个人认为LOCK_open 这个全局的mutex粒度太粗了，应该细到每个表的table_cache上，这样drop、alter仅仅影响到该表的sql。</p>
<p>PS： MySQL 的worklog也提到了<a href="http://forge.mysql.com/worklog/task.php?id=3983" target="_blank">这个问题</a>，说会在6.x改进。</p>
<p>&nbsp;</p>
<h3  class="related_post_title">相关文章</h3><ul class="related_post"><li>2011-07-19 -- <a href="http://ourmysql.com/archives/947" title="探索MYSQL源代码–添加一个函数">探索MYSQL源代码–添加一个函数</a></li><li>2011-07-19 -- <a href="http://ourmysql.com/archives/945" title="探索MYSQL源代码–添加一个VARIABLE">探索MYSQL源代码–添加一个VARIABLE</a></li><li>2011-07-19 -- <a href="http://ourmysql.com/archives/943" title="探索MYSQL源代码–准备工作">探索MYSQL源代码–准备工作</a></li><li>2011-07-19 -- <a href="http://ourmysql.com/archives/941" title="探索MYSQL源代码–SQL历险记">探索MYSQL源代码–SQL历险记</a></li><li>2011-07-19 -- <a href="http://ourmysql.com/archives/939" title="探索MYSQL源代码-BINLOG里的时间">探索MYSQL源代码-BINLOG里的时间</a></li><li>2011-07-18 -- <a href="http://ourmysql.com/archives/930" title="探索MYSQL源代码-在SHOW PROCESSLIST里添加字段">探索MYSQL源代码-在SHOW PROCESSLIST里添加字段</a></li><li>2011-07-18 -- <a href="http://ourmysql.com/archives/928" title="探索MYSQL源代码-客户端连接过程和用户认证体系">探索MYSQL源代码-客户端连接过程和用户认证体系</a></li><li>2009-06-23 -- <a href="http://ourmysql.com/archives/579" title="缓慢的drop table 操作">缓慢的drop table 操作</a></li><li>2009-02-17 -- <a href="http://ourmysql.com/archives/460" title="MySQL优化 &#8212; 频繁创建临时表">MySQL优化 &#8212; 频繁创建临时表</a></li><li>2008-10-14 -- <a href="http://ourmysql.com/archives/151" title="SQL中drop,delete和truncate的异同">SQL中drop,delete和truncate的异同</a></li></ul>
	标签：<a href="http://ourmysql.com/archives/tag/drop" title="drop" rel="tag">drop</a>, <a href="http://ourmysql.com/archives/category/debug" title="MySQL解错方案" rel="tag">MySQL解错方案</a>, <a href="http://ourmysql.com/archives/tag/%e6%ba%90%e4%bb%a3%e7%a0%81" title="源代码" rel="tag">源代码</a><br />
]]></content:encoded>
			<wfw:commentRss>http://ourmysql.com/archives/934/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>给PYTHON的MYSQLDB模块加功能</title>
		<link>http://ourmysql.com/archives/932</link>
		<comments>http://ourmysql.com/archives/932#comments</comments>
		<pubDate>Mon, 18 Jul 2011 15:53:03 +0000</pubDate>
		<dc:creator>OurMySQL</dc:creator>
				<category><![CDATA[MySQL高级应用]]></category>
		<category><![CDATA[MYSQLDB]]></category>
		<category><![CDATA[python]]></category>
		<category><![CDATA[模块]]></category>

		<guid isPermaLink="false">http://ourmysql.com/?p=932</guid>
		<description><![CDATA[使用Python操作MySQL数据库的时候常使用MySQLdb这个模块。今天在开发的过程发现MySQLdb.connect有些参数没法设置。通过这个页面我们可以看到在connect的时候，可以设置的option和client_flags和MySQL c api相比差不少。一个很重要的参数 MYSQL_OPT_READ_TIMEOUT没法设置，这个参数如果不设置，极致状况MySQL处于hang住，自动切换IP漂移，客户端无法重连到新MySQL。]]></description>
			<content:encoded><![CDATA[<div>
<p>使用Python操作MySQL数据库的时候常使用<a href="http://mysql-python.sourceforge.net/">MySQLdb</a>这个模块。</p>
<p>今天在开发的过程发现MySQLdb.connect有些参数没法设置。通过<a href="http://mysql-python.sourceforge.net/MySQLdb-1.2.2/public/MySQLdb.connections.Connection-class.html#__init__">这个页面</a>我们可以看到在connect的时候，可以设置的option和client_flags和MySQL c api相比差不少。</p>
<p>一个很重要的参数 MYSQL_OPT_READ_TIMEOUT没法设置，这个参数如果不设置，极致状况MySQL处于hang住，自动切换IP漂移，客户端无法重连到新MySQL。</p>
<p>给MySQLdb加Option很简单，只要修改_mysql.c这个把Python对象映射到MySQL操作的文件，添加参数，再加一段mysql_option即可。</p>
<p>下面是修改后的git diff 文件</p>

<div class="wp_codebox_msgheader"><span class="right"><sup><a href="http://www.ericbess.com/ericblog/2008/03/03/wp-codebox/#examples" target="_blank" title="WP-CodeBox HowTo?"><span style="color: #99cc00">?</span></a></sup></span><span class="left"><a href="javascript:;" onclick="javascript:showCodeTxt('p932code1'); return false;">View Code</a> BASH</span><div class="codebox_clear"></div></div><div class="wp_codebox"><table><tr id="p9321"><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
</pre></td><td class="code" id="p932code1"><pre class="bash" style="font-family:monospace;"><span style="color: #c20cb9; font-weight: bold;">diff</span> <span style="color: #660033;">--git</span> a<span style="color: #000000; font-weight: bold;">/</span>_mysql.c b<span style="color: #000000; font-weight: bold;">/</span>_mysql.c
index d42cc54..61a9b34 <span style="color: #000000;">100644</span>
<span style="color: #660033;">---</span> a<span style="color: #000000; font-weight: bold;">/</span>_mysql.c
+++ b<span style="color: #000000; font-weight: bold;">/</span>_mysql.c
<span style="color: #000000; font-weight: bold;">@@</span> -<span style="color: #000000;">489</span>,<span style="color: #000000;">9</span> +<span style="color: #000000;">489</span>,<span style="color: #000000;">10</span> <span style="color: #000000; font-weight: bold;">@@</span> _mysql_ConnectionObject_Initialize<span style="color: #7a0874; font-weight: bold;">&#40;</span>
<span style="color: #ff0000;">&quot;named_pipe&quot;</span>, <span style="color: #ff0000;">&quot;init_command&quot;</span>,
<span style="color: #ff0000;">&quot;read_default_file&quot;</span>, <span style="color: #ff0000;">&quot;read_default_group&quot;</span>,
<span style="color: #ff0000;">&quot;client_flag&quot;</span>, <span style="color: #ff0000;">&quot;ssl&quot;</span>,
-                                 <span style="color: #ff0000;">&quot;local_infile&quot;</span>,
+                                 <span style="color: #ff0000;">&quot;local_infile&quot;</span>, <span style="color: #ff0000;">&quot;read_timeout&quot;</span>,
NULL <span style="color: #7a0874; font-weight: bold;">&#125;</span> ;
int connect_timeout = <span style="color: #000000;">0</span>;
+       int read_timeout = <span style="color: #000000;">0</span>;
int compress = -<span style="color: #000000;">1</span>, named_pipe = -<span style="color: #000000;">1</span>, local_infile = -<span style="color: #000000;">1</span>;
char <span style="color: #000000; font-weight: bold;">*</span><span style="color: #007800;">init_command</span>=NULL,
<span style="color: #000000; font-weight: bold;">*</span><span style="color: #007800;">read_default_file</span>=NULL,
<span style="color: #000000; font-weight: bold;">@@</span> -<span style="color: #000000;">500</span>,<span style="color: #000000;">7</span> +<span style="color: #000000;">501</span>,<span style="color: #000000;">7</span> <span style="color: #000000; font-weight: bold;">@@</span> _mysql_ConnectionObject_Initialize<span style="color: #7a0874; font-weight: bold;">&#40;</span>
self-<span style="color: #000000; font-weight: bold;">&amp;</span>gt;converter = NULL;
self-<span style="color: #000000; font-weight: bold;">&amp;</span>gt;open = <span style="color: #000000;">0</span>;
check_server_init<span style="color: #7a0874; font-weight: bold;">&#40;</span>-<span style="color: #000000;">1</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>;
-       <span style="color: #000000; font-weight: bold;">if</span> <span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #000000; font-weight: bold;">!</span>PyArg_ParseTupleAndKeywords<span style="color: #7a0874; font-weight: bold;">&#40;</span>args, kwargs, <span style="color: #ff0000;">&quot;|ssssisOiiisssiOi:connect&quot;</span>,
+       <span style="color: #000000; font-weight: bold;">if</span> <span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #000000; font-weight: bold;">!</span>PyArg_ParseTupleAndKeywords<span style="color: #7a0874; font-weight: bold;">&#40;</span>args, kwargs, <span style="color: #ff0000;">&quot;|ssssisOiiisssiOii:connect&quot;</span>,
kwlist,
<span style="color: #000000; font-weight: bold;">&amp;</span>amp;host, <span style="color: #000000; font-weight: bold;">&amp;</span>amp;user, <span style="color: #000000; font-weight: bold;">&amp;</span>amp;<span style="color: #c20cb9; font-weight: bold;">passwd</span>, <span style="color: #000000; font-weight: bold;">&amp;</span>amp;db,
<span style="color: #000000; font-weight: bold;">&amp;</span>amp;port, <span style="color: #000000; font-weight: bold;">&amp;</span>amp;unix_socket, <span style="color: #000000; font-weight: bold;">&amp;</span>amp;conv,
<span style="color: #000000; font-weight: bold;">@@</span> -<span style="color: #000000;">509</span>,<span style="color: #000000;">7</span> +<span style="color: #000000;">510</span>,<span style="color: #000000;">8</span> <span style="color: #000000; font-weight: bold;">@@</span> _mysql_ConnectionObject_Initialize<span style="color: #7a0874; font-weight: bold;">&#40;</span>
<span style="color: #000000; font-weight: bold;">&amp;</span>amp;init_command, <span style="color: #000000; font-weight: bold;">&amp;</span>amp;read_default_file,
<span style="color: #000000; font-weight: bold;">&amp;</span>amp;read_default_group,
<span style="color: #000000; font-weight: bold;">&amp;</span>amp;client_flag, <span style="color: #000000; font-weight: bold;">&amp;</span>amp;ssl,
-                                        <span style="color: #000000; font-weight: bold;">&amp;</span>amp;local_infile <span style="color: #000000; font-weight: bold;">/*</span> DO NOT PATCH FOR RECONNECT, IDIOTS
+                                        <span style="color: #000000; font-weight: bold;">&amp;</span>amp;local_infile, <span style="color: #000000; font-weight: bold;">&amp;</span>amp;read_timeout
+                                        <span style="color: #000000; font-weight: bold;">/*</span> DO NOT PATCH FOR RECONNECT, IDIOTS
IF YOU DO THIS, I WILL NOT SUPPORT YOUR PACKAGES. <span style="color: #000000; font-weight: bold;">*/</span>
<span style="color: #7a0874; font-weight: bold;">&#41;</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>
<span style="color: #7a0874; font-weight: bold;">return</span> -<span style="color: #000000;">1</span>;
<span style="color: #000000; font-weight: bold;">@@</span> -<span style="color: #000000;">540</span>,<span style="color: #000000;">6</span> +<span style="color: #000000;">542</span>,<span style="color: #000000;">12</span> <span style="color: #000000; font-weight: bold;">@@</span> _mysql_ConnectionObject_Initialize<span style="color: #7a0874; font-weight: bold;">&#40;</span>
mysql_options<span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #000000; font-weight: bold;">&amp;</span>amp;<span style="color: #7a0874; font-weight: bold;">&#40;</span>self-<span style="color: #000000; font-weight: bold;">&amp;</span>gt;connection<span style="color: #7a0874; font-weight: bold;">&#41;</span>, MYSQL_OPT_CONNECT_TIMEOUT,
<span style="color: #7a0874; font-weight: bold;">&#40;</span>char <span style="color: #000000; font-weight: bold;">*</span><span style="color: #7a0874; font-weight: bold;">&#41;</span><span style="color: #000000; font-weight: bold;">&amp;</span>amp;timeout<span style="color: #7a0874; font-weight: bold;">&#41;</span>;
<span style="color: #7a0874; font-weight: bold;">&#125;</span>
+
+        <span style="color: #000000; font-weight: bold;">if</span> <span style="color: #7a0874; font-weight: bold;">&#40;</span>read_timeout<span style="color: #7a0874; font-weight: bold;">&#41;</span> <span style="color: #7a0874; font-weight: bold;">&#123;</span>
+                unsigned int timeout = read_timeout;
+                mysql_options<span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #000000; font-weight: bold;">&amp;</span>amp;<span style="color: #7a0874; font-weight: bold;">&#40;</span>self-<span style="color: #000000; font-weight: bold;">&amp;</span>gt;connection<span style="color: #7a0874; font-weight: bold;">&#41;</span>, MYSQL_OPT_READ_TIMEOUT, <span style="color: #7a0874; font-weight: bold;">&#40;</span>char <span style="color: #000000; font-weight: bold;">*</span><span style="color: #7a0874; font-weight: bold;">&#41;</span><span style="color: #000000; font-weight: bold;">&amp;</span>amp;timeout<span style="color: #7a0874; font-weight: bold;">&#41;</span>;
+        <span style="color: #7a0874; font-weight: bold;">&#125;</span>
+
<span style="color: #000000; font-weight: bold;">if</span> <span style="color: #7a0874; font-weight: bold;">&#40;</span>compress <span style="color: #000000; font-weight: bold;">!</span>= -<span style="color: #000000;">1</span><span style="color: #7a0874; font-weight: bold;">&#41;</span> <span style="color: #7a0874; font-weight: bold;">&#123;</span>
mysql_options<span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #000000; font-weight: bold;">&amp;</span>amp;<span style="color: #7a0874; font-weight: bold;">&#40;</span>self-<span style="color: #000000; font-weight: bold;">&amp;</span>gt;connection<span style="color: #7a0874; font-weight: bold;">&#41;</span>, MYSQL_OPT_COMPRESS, <span style="color: #000000;">0</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>;
client_flag <span style="color: #000000; font-weight: bold;">|</span>= CLIENT_COMPRESS;</pre></td></tr></table></div>

<p>代码修改完毕，<a href="http://ourmysql.com/archives/tag/python" class="st_tag internal_tag" rel="tag" title="标签 python 下的日志">python</a> setup.py install 即可，如果出现mysql_config找不到的问题。你还要修改setup_posix.py文件。</p>
<div>
<div>
<pre>hoterran@hoterran-laptop:~/Projects/MySQL-python-1.2.3$ git diff setup_posix.py
diff --git a/setup_posix.py b/setup_posix.py
index 86432f5..f4f08f1 100644
--- a/setup_posix.py
+++ b/setup_posix.py
@@ -23,7 +23,7 @@ def mysql_config(what):
         if ret/256 &amp;gt; 1:
             raise EnvironmentError("%s not found" % (mysql_config.path,))
     return data
-mysql_config.path = "mysql_config"
+mysql_config.path = "/usr/local/mysql/bin/mysql_config"

 def get_config():
     import os, sys</pre>
</div>
</div>
<p>编译通过，我们来试试添加的read_timeout这个参数。</p>
<div>
<div>
<pre>conn = <a href="http://ourmysql.com/archives/tag/mysqldb" class="st_tag internal_tag" rel="tag" title="标签 MYSQLDB 下的日志">MySQLdb</a>.connect(host = DB_SERVER,user = DB_USERNAME,passwd = DB_PASSWORD,db = DB_NAME, port=int(DB_PORT), client_flag = 2, read_timeout = 10)</pre>
</div>
</div>
<p>然后执行语句前，你试着把mysql用gdb hang住10s后，python就会异常抛错</p>
<div>
<div>
<pre>OperationalError: (2013, 'Lost connection to MySQL server during query')
 &gt;/home/hoterran/Projects/dbaas/trunk/dbtest.py(18)()
 &gt;mydb.execute_<a href="http://ourmysql.com/archives/tag/sql" class="st_tag internal_tag" rel="tag" title="标签 sql 下的日志">sql</a>(conn, <a href="http://ourmysql.com/archives/tag/sql" class="st_tag internal_tag" rel="tag" title="标签 sql 下的日志">sql</a>)
(Pdb)
--Return--
&gt; /home/hoterran/Projects/dbaas/trunk/dbtest.py(18)()-&amp;gt;None
&gt; mydb.execute_<a href="http://ourmysql.com/archives/tag/sql" class="st_tag internal_tag" rel="tag" title="标签 sql 下的日志">sql</a>(conn, <a href="http://ourmysql.com/archives/tag/sql" class="st_tag internal_tag" rel="tag" title="标签 sql 下的日志">sql</a>)
(Pdb)
OperationalError: (2013, 'Lost connection to MySQL server during query')
&gt; &lt;string&gt;(1)&lt;module&gt;()-&gt;None</pre>
</div>
</div>
<p>ps: 在_mysql.c找到一句很搞的话</p>
<div>
<div>
<pre>/* DO NOT PATCH FOR RECONNECT, IDIOTS
IF YOU DO THIS, I WILL NOT SUPPORT YOUR PACKAGES. */</pre>
</div>
</div>
</div>
<p>&nbsp;</p>
<h3  class="related_post_title">相关文章</h3><ul class="related_post"><li>2010-11-18 -- <a href="http://ourmysql.com/archives/883" title="mysql 的模块不能安装的解决方法">mysql 的模块不能安装的解决方法</a></li></ul>
	标签：<a href="http://ourmysql.com/archives/tag/mysqldb" title="MYSQLDB" rel="tag">MYSQLDB</a>, <a href="http://ourmysql.com/archives/category/advanced" title="MySQL高级应用" rel="tag">MySQL高级应用</a>, <a href="http://ourmysql.com/archives/tag/python" title="python" rel="tag">python</a>, <a href="http://ourmysql.com/archives/tag/%e6%a8%a1%e5%9d%97" title="模块" rel="tag">模块</a><br />
]]></content:encoded>
			<wfw:commentRss>http://ourmysql.com/archives/932/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>探索MYSQL源代码-在SHOW PROCESSLIST里添加字段</title>
		<link>http://ourmysql.com/archives/930</link>
		<comments>http://ourmysql.com/archives/930#comments</comments>
		<pubDate>Mon, 18 Jul 2011 15:50:50 +0000</pubDate>
		<dc:creator>OurMySQL</dc:creator>
				<category><![CDATA[MySQL高级应用]]></category>
		<category><![CDATA[mysql_sourcecode]]></category>
		<category><![CDATA[源代码]]></category>

		<guid isPermaLink="false">http://ourmysql.com/?p=930</guid>
		<description><![CDATA[show processlist是诊断MySQL常用的命令，它会列出THD对象里所有的线程当前状况。下面将为show processlist添加一个新的列，表示当前连接查询之后返回的行数，字段名为my_row_count。]]></description>
			<content:encoded><![CDATA[<p>show processlist是诊断MySQL常用的命令，它会列出THD对象里所有的线程当前状况。</p>
<p>下面将为show processlist添加一个新的列，表示当前连接查询之后返回的行数，字段名为my_row_count。</p>
<p>当你要修改一个命令的时候，最好从sql/<a href="http://ourmysql.com/archives/tag/sql" class="st_tag internal_tag" rel="tag" title="标签 sql 下的日志">sql</a>_yacc.yy出发，根据命令的关键字语法匹配到后续的动作。打开sql/<a href="http://ourmysql.com/archives/tag/sql" class="st_tag internal_tag" rel="tag" title="标签 sql 下的日志">sql</a>_yacc.yy后搜索关键字show:，就找到了所有show命令的语法规则。继续往下找就能看到，</p>
<div>
<div>
<pre>| opt_full PROCESSLIST_SYM
{ Lex-&gt;sql_command= SQLCOM_SHOW_PROCESSLIST;}
| ....</pre>
</div>
</div>
<p>找到了相应的sql命令SQLCOM_SHOW_PROCESSLIST，命令对应的行为呢？</p>
<p>我们来到sql/sql_parse.cc的dispatch_command函数，这是所有命令和查询的总路口，搜索关键字SQLCOM_SHOW_PROCESSLIST会发现，</p>
<div>
<div>
<pre>case SQLCOM_SHOW_PROCESSLIST:
if (!thd-&gt;security_ctx-&gt;priv_user[0] &amp;&amp; check_global_access(thd,PROCESS_ACL))
    break;
mysqld_list_processes(thd, (thd-&gt;security_ctx-&gt;master_access &amp; PROCESS_ACL ? NullS :
thd-&gt;security_ctx-&gt;priv_user), lex-&gt;verbose);
break;</pre>
</div>
</div>
<p>是的msyqld_list_processes就是服务端处理show processlist 的函数。如果你配置好<a href="http://www.hoterran.info/ems_prepare">cscope和ctag</a>，这里就可以很方便的快速切换进入这个函数。</p>
<p>进入mysqld_list_processes（sql/sql_show.cc）之后，可以看到这个函数还是比较简单，先是往field_list插入一些item，这些item就是show processlist的字段title， 很熟悉把。这里我们添加一个字段名my_row_count。</p>
<div>
<div>
<pre>field_list.push_back(field=new Item_empty_string("Info",max_query_length));
field-&gt;maybe_null=1;
/* start */
field_list.push_back(field=new Item_int("my_row_count", MY_INT32_NUM_DECIMAL_DIGITS));
field-&gt;maybe_null=1;
/* end */
if (protocol-&gt;send_fields(&amp;field_list,
Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
DBUG_VOID_RETURN;</pre>
</div>
</div>
<p>可以看到上面代码最后的send_fields就是把字段名发送给客户端。<br />
接下来就是从tmp对象（THD）把内容复制给thd_info对象（thread_info）。</p>
<div>
<div>
<pre>thd_info-&gt;query=(char*) thd-&gt;strmake(tmp-&gt;query,length);
}
/* start */
thd_info-&gt;my_row_count = tmp-&gt;my_row_count;
/* end */
pthread_mutex_unlock(&amp;tmp-&gt;LOCK_thd_data);</pre>
</div>
</div>
<p>接下来把thd_info 打包到protocol，随后就发送出去了。</p>
<div>
<div>
<pre>protocol-&gt;store(thd_info-&gt;query, system_charset_info);
/*start*/
protocol-&gt;store((ulonglong) thd_info-&gt;my_row_count);
/*end*/
if (protocol-&gt;write())
 ....</pre>
</div>
</div>
<p>好了show processlist 函数添加的新列就结束了。接下来我们要填充my_row_count的值， 这就涉及到为THD类的添加新的成员。</p>
<p>打开sql/sql_class.h,查找关键字sent_row_count，然后添加一个my_row_count成员。</p>
<div>
<div>
<pre>ha_rows    sent_row_count;
/* start */
ha_rows  my_row_count;
/* end */</pre>
</div>
</div>
<p>再打开sql/sql_class.cc 为my_row_count赋初值。</p>
<div>
<div>
<pre>cuted_fields= sent_row_count= row_count=my_row_count =  0L;</pre>
</div>
</div>
<p>接着在sql/sql_class.cc 为每次select进行累加，找到函数 bool select_send::send_data(List &amp;items)</p>
<div>
<div>
<pre>thd-&gt;sent_row_count++;
/* start */
thd-&gt;my_row_count++;
/* end */</pre>
</div>
</div>
<p>好了，重新make &amp;&amp;sudo make install，这里花费时间比较长，因为sql_class被修改，很多lib、binary需要重新编译。</p>
<p>编译后就可以看到</p>
<pre>mysql&gt; show processlist;
+----+------+-----------------+------+---------+------+-------+------------------+--------------+
| Id | User | Host            | db   | Command | Time | State | Info             | my_row_count |
+----+------+-----------------+------+---------+------+-------+------------------+--------------+
|  3 | root | localhost:39325 | NULL | Query   |    0 | NULL  | show processlist |            3 |
+----+------+-----------------+------+---------+------+-------+------------------+--------------+
1 row in set (0.00 sec)

mysql&gt; insert into test.dddd values(1);
Query OK, 1 row affected (0.10 sec)

mysql&gt; select * from test.dddd;
+------+
| a    |
+------+
|    1 |
|    1 |
|    1 |
+------+
3 rows in set (0.00 sec)

mysql&gt; show processlist;
+----+------+-----------------+------+---------+------+-------+------------------+--------------+
| Id | User | Host            | db   | Command | Time | State | Info             | my_row_count |
+----+------+-----------------+------+---------+------+-------+------------------+--------------+
|  3 | root | localhost:39325 | NULL | Query   |    0 | NULL  | show processlist |            6 |
+----+------+-----------------+------+---------+------+-------+------------------+--------------+
1 row in set (0.00 sec)</pre>
<p>&nbsp;</p>
<h3  class="related_post_title">相关文章</h3><ul class="related_post"><li>2011-07-18 -- <a href="http://ourmysql.com/archives/928" title="探索MYSQL源代码-客户端连接过程和用户认证体系">探索MYSQL源代码-客户端连接过程和用户认证体系</a></li><li>2011-07-19 -- <a href="http://ourmysql.com/archives/947" title="探索MYSQL源代码–添加一个函数">探索MYSQL源代码–添加一个函数</a></li><li>2011-07-19 -- <a href="http://ourmysql.com/archives/945" title="探索MYSQL源代码–添加一个VARIABLE">探索MYSQL源代码–添加一个VARIABLE</a></li><li>2011-07-19 -- <a href="http://ourmysql.com/archives/943" title="探索MYSQL源代码–准备工作">探索MYSQL源代码–准备工作</a></li><li>2011-07-19 -- <a href="http://ourmysql.com/archives/941" title="探索MYSQL源代码–SQL历险记">探索MYSQL源代码–SQL历险记</a></li><li>2011-07-19 -- <a href="http://ourmysql.com/archives/939" title="探索MYSQL源代码-BINLOG里的时间">探索MYSQL源代码-BINLOG里的时间</a></li><li>2011-07-18 -- <a href="http://ourmysql.com/archives/934" title="DROP TABLE AND LOCK_OPEN MUTEX">DROP TABLE AND LOCK_OPEN MUTEX</a></li></ul>
	标签：<a href="http://ourmysql.com/archives/tag/mysql_sourcecode" title="mysql_sourcecode" rel="tag">mysql_sourcecode</a>, <a href="http://ourmysql.com/archives/category/advanced" title="MySQL高级应用" rel="tag">MySQL高级应用</a>, <a href="http://ourmysql.com/archives/tag/%e6%ba%90%e4%bb%a3%e7%a0%81" title="源代码" rel="tag">源代码</a><br />
]]></content:encoded>
			<wfw:commentRss>http://ourmysql.com/archives/930/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>探索MYSQL源代码-客户端连接过程和用户认证体系</title>
		<link>http://ourmysql.com/archives/928</link>
		<comments>http://ourmysql.com/archives/928#comments</comments>
		<pubDate>Mon, 18 Jul 2011 15:48:50 +0000</pubDate>
		<dc:creator>OurMySQL</dc:creator>
				<category><![CDATA[MySQL高级应用]]></category>
		<category><![CDATA[mysql_sourcecode]]></category>
		<category><![CDATA[源代码]]></category>
		<category><![CDATA[认证]]></category>
		<category><![CDATA[连接]]></category>

		<guid isPermaLink="false">http://ourmysql.com/?p=928</guid>
		<description><![CDATA[本文从源代码角度详细解释使用mysql客户端连上MySQL的服务端的过程以及通过用户认证的过程。]]></description>
			<content:encoded><![CDATA[<p>本文从源代码角度详细解释使用mysql客户端连上MySQL的服务端的过程以及通过用户认证的过程。</p>
<p>用户在客户端键入</p>
<pre>mysql -h a.b.c.d -u root -pxxxx</pre>
<p>最终都会调用到mysql_real_connect(<a href="http://ourmysql.com/archives/tag/sql" class="st_tag internal_tag" rel="tag" title="标签 sql 下的日志">sql</a>/client.c的1856行的宏CLI_MYSQL_REAL_CONNECT)，我们从这个函数出发。</p>
<p>先上图</p>
<table>
<tbody>
<tr>
<td><a href="https://picasaweb.google.com/lh/photo/WeWAF-SeWNVPu1brCHJjpw?feat=embedwebsite"><img src="https://lh5.googleusercontent.com/_UkB3qlLgBXE/TXnkMq8N8ZI/AAAAAAAAB4o/P8_e4tqSKLY/s288/mysql_connect_and_user_auth.png" alt="" width="185" height="288" /></a></td>
</tr>
<tr>
<td>发件人 <a href="https://picasaweb.google.com/musicode/MySQL?feat=embedwebsite">MySQL</a></td>
</tr>
</tbody>
</table>
<ol>
<li>客户端发起socket连接，等待三次握手的通过。</li>
<li>三次握手通过之后，客户端进入client_safe_read阻塞，同时服务端从handle_connection_sockets函数的select处返回，获知有新的连接。</li>
<li>服务端创建线程（这里就不说thread cache了），然后开始对这个连接进行校验。</li>
<li>login_connection（sql/sql_connect.c）下的check_connection为的主校验函数。</li>
<li>check_connection首先回调用acl_check_host(sql/sql_acl.cc) 判断该ip是否能够连接。</li>
<li>acl_check_host依次查找2个对象来做判断：一个是动态数组acl_wild_hosts，另一个是hash表acl_check_hosts。</li>
<div>
<div>
<pre>VOID(my_init_dynamic_array(&amp;amp;acl_wild_hosts,sizeof(struct acl_host_and_ip), acl_users.elements,1));
VOID(hash_init(&amp;amp;acl_check_hosts,system_charset_info,acl_users.elements,0,0, (hash_get_key) check_get_key,0,0));</pre>
</div>
</div>
<p>这2个对象都是在mysqld启动的时候，通过init_check_host函数从mysq.users表里读出并加载的。<br />
其中acl_wild_hosts用于存放有统配符的主机，acl_check_hosts存放具体的主机。</p>
<li>通过acl_check_host校验后，来到create_random_string(sql/sql_connect.c)<a href="http://ourmysql.com/archives/tag/%e5%87%bd%e6%95%b0" class="st_tag internal_tag" rel="tag" title="标签 函数 下的日志">函数</a>。这个函数随机的产生一个20字节的scramble串，用于接下来密码SHA1加密。</li>
<div>
<div>
<pre>(gdb) p thd-&amp;gt;scramble
$3 = "p}DwPf4kCJ+8vk5cuD3q</pre>
</div>
</div>
<li>服务端通过net_write_command函数把这个scramble以及当前的服务端版本发送给客户端，然后自己阻塞在my_net_read里，等待客户端的命令，这里的阻塞有个最小握手时间MIN_HANDSHAKE_SIZE。</li>
<li>客户端从cli_safe_read阻塞中返回，获知版本和scramble。进行版本匹配后，对输入的密码进行sha1加密（加密的公司后面详细说明），然后再发送给服务端。</li>
<li>服务端从my_net_read返回来，拿到登录的用户名和密码。</li>
<li>来到check_user(sql/sql_connect.c)函数，其中的acl_getroot是对密码进行了校验，关键函数是check_scramble。下面详细说明密码比较过程，伪代码方便理解。</li>
<p>===客户端的 scrabmle======<br />
password 来自于用户键入的密码<br />
scramble 来自于create_random_string 产生的20字节的随机字符<br />
reply 就是发送给服务端的加密密码</p>
<pre>scramble(password, scramble)
{
        hash_stage1 = sha1(password) 

        hash_stage2 = sha1(hash_stage1)

        to = sha1(scramble, hash_stage2)

        reply = xor(to, hash_stage1)
}</pre>
<p>===服务端的check_scramble =====<br />
reply 来自于客户端发送的加密密码<br />
scramble create_random_string 产生的随机字符<br />
store_password 就是mysql.user 表的password的字段（password函数实际上进行了两次的sha1加密）</p>
<pre>check_scramble(reply, scramble, store_password)
{
        to = sha1(scramble, store_password)

        my_hash_stage1 = xor(to, reply)

        return store_password == sha1(my_hash_stage1)
}</pre>
<p>拿reply进行异或的逆运算得到sha1加密的密码，然后与数据库内的做比较。<br />
关键点就是异或的特点 A XOR B XOR B = A</p>
<li>acl_getroot通过后，连接就通过了用户认证。</li>
<li>告知客户端认证正常，接下来的sql执行步骤可见我以前的<a href="http://www.hoterran.info/sql_adventure">博文</a></li>
</ol>
<p>&nbsp;</p>
<h3  class="related_post_title">相关文章</h3><ul class="related_post"><li>2011-07-18 -- <a href="http://ourmysql.com/archives/930" title="探索MYSQL源代码-在SHOW PROCESSLIST里添加字段">探索MYSQL源代码-在SHOW PROCESSLIST里添加字段</a></li><li>2011-07-19 -- <a href="http://ourmysql.com/archives/947" title="探索MYSQL源代码–添加一个函数">探索MYSQL源代码–添加一个函数</a></li><li>2011-07-19 -- <a href="http://ourmysql.com/archives/945" title="探索MYSQL源代码–添加一个VARIABLE">探索MYSQL源代码–添加一个VARIABLE</a></li><li>2011-07-19 -- <a href="http://ourmysql.com/archives/943" title="探索MYSQL源代码–准备工作">探索MYSQL源代码–准备工作</a></li><li>2011-07-19 -- <a href="http://ourmysql.com/archives/941" title="探索MYSQL源代码–SQL历险记">探索MYSQL源代码–SQL历险记</a></li><li>2011-07-19 -- <a href="http://ourmysql.com/archives/939" title="探索MYSQL源代码-BINLOG里的时间">探索MYSQL源代码-BINLOG里的时间</a></li><li>2011-07-18 -- <a href="http://ourmysql.com/archives/934" title="DROP TABLE AND LOCK_OPEN MUTEX">DROP TABLE AND LOCK_OPEN MUTEX</a></li><li>2009-05-14 -- <a href="http://ourmysql.com/archives/558" title="mysql连接过多的处理">mysql连接过多的处理</a></li><li>2009-02-07 -- <a href="http://ourmysql.com/archives/420" title="php环境配置时出现无法访问MYSQL数据库的解决办法汇总">php环境配置时出现无法访问MYSQL数据库的解决办法汇总</a></li></ul>
	标签：<a href="http://ourmysql.com/archives/tag/mysql_sourcecode" title="mysql_sourcecode" rel="tag">mysql_sourcecode</a>, <a href="http://ourmysql.com/archives/category/advanced" title="MySQL高级应用" rel="tag">MySQL高级应用</a>, <a href="http://ourmysql.com/archives/tag/%e6%ba%90%e4%bb%a3%e7%a0%81" title="源代码" rel="tag">源代码</a>, <a href="http://ourmysql.com/archives/tag/%e8%ae%a4%e8%af%81" title="认证" rel="tag">认证</a>, <a href="http://ourmysql.com/archives/tag/%e8%bf%9e%e6%8e%a5" title="连接" rel="tag">连接</a><br />
]]></content:encoded>
			<wfw:commentRss>http://ourmysql.com/archives/928/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>MYSQL DAEMON PLUGIN EXAMPLE</title>
		<link>http://ourmysql.com/archives/925</link>
		<comments>http://ourmysql.com/archives/925#comments</comments>
		<pubDate>Mon, 18 Jul 2011 15:44:18 +0000</pubDate>
		<dc:creator>OurMySQL</dc:creator>
				<category><![CDATA[MySQL高级应用]]></category>
		<category><![CDATA[plugin]]></category>

		<guid isPermaLink="false">http://ourmysql.com/?p=925</guid>
		<description><![CDATA[5.1 版本开始MySQL开始支持plugin API，允许在mysqld运行时载入或者卸载组件，而不需要重启mysqld。plugin API涵盖了UDF、full-text、advanced schema等功能，其中的daemon plugin个人认为是非常的有用。其功能是在plugin载入后可以创建额外的后台线程于mysqld主线程一同协同工作。]]></description>
			<content:encoded><![CDATA[<p>5.1 版本开始MySQL开始支持plugin API，允许在mysqld运行时载入或者卸载组件，而不需要重启mysqld。</p>
<p><a href="http://ourmysql.com/archives/tag/plugin" class="st_tag internal_tag" rel="tag" title="标签 plugin 下的日志">plugin</a> API涵盖了UDF、full-text、advanced schema等功能，其中的daemon plugin个人认为是非常的有用。其功能是在plugin载入后可以创建额外的后台线程于mysqld主线程一同协同工作。</p>
<p>plugin API的具体实现在sql/<a href="http://ourmysql.com/archives/tag/sql" class="st_tag internal_tag" rel="tag" title="标签 sql 下的日志">sql</a>_plugin.h 和sql/<a href="http://ourmysql.com/archives/tag/sql" class="st_tag internal_tag" rel="tag" title="标签 sql 下的日志">sql</a>_plugin.cc两个文件中。载入plugin使用dl_open系的动态加载共享库的方法打开so文件，获得需要执行的加载函数和卸载函数的指针。daemon plugin 的启动和storage plugin 启动一样，由init_server_components(<a href="http://ourmysql.com/archives/tag/sql" class="st_tag internal_tag" rel="tag" title="标签 sql 下的日志">sql</a>/mysqld.cc) 里的plugin_init函数来启动。</p>
<p>开发的plugin的时候，只需要关心API接口文件include/plugin.h（我把mysql安装在/usr/local/mysql，所以这个文件在/usr/local/mysql/include/mysql/plugin.h），里面可以看到一些API函数和宏。</p>
<p><strong>plugin的几个相关命令</strong></p>
<p>show plugins 可查询系统内所有的激活的plugin，也包括storage plugin。</p>
<pre>mysql&gt;show plugins;
+------------+--------+----------------+--------------+---------+
| Name       | <a href="http://ourmysql.com/archives/tag/status" class="st_tag internal_tag" rel="tag" title="标签 status 下的日志">Status</a> | Type           | Library      | License |
+------------+--------+----------------+--------------+---------+
| <a href="http://ourmysql.com/archives/tag/binlog" class="st_tag internal_tag" rel="tag" title="标签 binlog 下的日志">binlog</a>     | ACTIVE | STORAGE ENGINE | NULL         | GPL     |
| CSV        | ACTIVE | STORAGE ENGINE | NULL         | GPL     |
| MEMORY     | ACTIVE | STORAGE ENGINE | NULL         | GPL     |
| <a href="http://ourmysql.com/archives/tag/innodb" class="st_tag internal_tag" rel="tag" title="标签 InnoDB 下的日志">InnoDB</a>     | ACTIVE | STORAGE ENGINE | NULL         | GPL     |
| MyISAM     | ACTIVE | STORAGE ENGINE | NULL         | GPL     |
| MRG_MYISAM | ACTIVE | STORAGE ENGINE | NULL         | GPL     |
+------------+--------+----------------+--------------+---------+</pre>
<p>mysql.plugin 表也可以获得目前的plugin，但不包括storage plugin，加载错误的plugin也会包含在内，例如so不存在。</p>
<p>plugin_dir参数用于告知系统plugin的目录，这个参数必须在mysqld启动前指定，如果不设置，默认目录为/usr/local/mysql/lib/mysql/plugin/（/usr/local/mysql是我的MySQL安装目录）。</p>

<div class="wp_codebox_msgheader"><span class="right"><sup><a href="http://www.ericbess.com/ericblog/2008/03/03/wp-codebox/#examples" target="_blank" title="WP-CodeBox HowTo?"><span style="color: #99cc00">?</span></a></sup></span><span class="left"><a href="javascript:;" onclick="javascript:showCodeTxt('p925code2'); return false;">View Code</a> BASH</span><div class="codebox_clear"></div></div><div class="wp_codebox"><table><tr id="p9252"><td class="line_numbers"><pre>1
2
3
4
5
6
</pre></td><td class="code" id="p925code2"><pre class="bash" style="font-family:monospace;">mysql<span style="color: #000000; font-weight: bold;">&amp;</span>gt; show variables like <span style="color: #ff0000;">'plugin_dir'</span>;
+---------------+-------------------------+
<span style="color: #000000; font-weight: bold;">|</span> Variable_name <span style="color: #000000; font-weight: bold;">|</span> Value                   <span style="color: #000000; font-weight: bold;">|</span>
+---------------+-------------------------+
<span style="color: #000000; font-weight: bold;">|</span> plugin_dir    <span style="color: #000000; font-weight: bold;">|</span> <span style="color: #000000; font-weight: bold;">/</span>usr<span style="color: #000000; font-weight: bold;">/</span>local<span style="color: #000000; font-weight: bold;">/</span>mysql<span style="color: #000000; font-weight: bold;">/</span>plugin <span style="color: #000000; font-weight: bold;">|</span>
+---------------+------------------------</pre></td></tr></table></div>

<p>加载plugin</p>

<div class="wp_codebox_msgheader"><span class="right"><sup><a href="http://www.ericbess.com/ericblog/2008/03/03/wp-codebox/#examples" target="_blank" title="WP-CodeBox HowTo?"><span style="color: #99cc00">?</span></a></sup></span><span class="left"><a href="javascript:;" onclick="javascript:showCodeTxt('p925code3'); return false;">View Code</a> BASH</span><div class="codebox_clear"></div></div><div class="wp_codebox"><table><tr id="p9253"><td class="line_numbers"><pre>1
</pre></td><td class="code" id="p925code3"><pre class="bash" style="font-family:monospace;">mysql<span style="color: #000000; font-weight: bold;">&amp;</span>gt;INSTALL PLUGIN plugin_name SONAME <span style="color: #ff0000;">'plugin_library'</span></pre></td></tr></table></div>

<p>这里的plugin_name后面会讲到，plugin_library即为要加载的共享库so文件的名字，目录必须是上面的plugin_dir。</p>
<p>加载插件后，通过前面的show plugins、mysql.plugin 可以看到你的plugin。</p>
<p>卸载plugin</p>

<div class="wp_codebox_msgheader"><span class="right"><sup><a href="http://www.ericbess.com/ericblog/2008/03/03/wp-codebox/#examples" target="_blank" title="WP-CodeBox HowTo?"><span style="color: #99cc00">?</span></a></sup></span><span class="left"><a href="javascript:;" onclick="javascript:showCodeTxt('p925code4'); return false;">View Code</a> BASH</span><div class="codebox_clear"></div></div><div class="wp_codebox"><table><tr id="p9254"><td class="line_numbers"><pre>1
</pre></td><td class="code" id="p925code4"><pre class="bash" style="font-family:monospace;">mysql<span style="color: #000000; font-weight: bold;">&amp;</span>gt;UNINSTALL PLUGIN plugin_name</pre></td></tr></table></div>

<p><strong>编写plugin</strong></p>
<p>plugin模式的软件领域分明是oop继承、重载的用武之地，MySQL却使用了预编译宏和函数指针不是那么优雅的完成了这个任务（个人很喜欢这种方法，虽然代码丑陋了点）。另外说几句MySQL虽然看起来是c++写的，但实际上较少的使用c++的一些特性，只在内部几个模块用到模板类。跑题了，开始写plugin。</p>
<p>下面编写一个plugin，作用是加载后创建一个线程在后台持续的把MySQL内的一些信息打印到err.log日志。</p>
<p>首先介绍一下include/plugin.h里的st_mysql_plugin这个结构体，所有的plugin 都必须是基于这个结构体，填充必须的内容。</p>
<div>
<div>
<pre>struct st_mysql_plugin
{
    int type;                    /* 插件类型，这里填MYSQL_DAEMON_PLUGIN 即可 */
    void *info;                 /* 插件类型描述符，对于daemon类来说没用，指向一个常量即可   */
    const char *name;          /* 插件名，这个就是前面的install 命令里的plugin_name  */
    const char *author;       /* 插件作者，随意 */
    const char *descr;        /* 插件描述，随意  */
    int license;                /* PLUGIN_LICENSE_GPL */
    int (*init)(void);           /* install 命令之后调用的函数 */
    int (*deinit)(void);       /* uninstall 命令之后调用的函数 */
    unsigned int version;     /* 插件版本，随意*/
    struct st_mysql_show_var   /* 指向的show_var，可不填*/
    struct st_mysql_sys_var     /* 指向的sys_var，可不填*/
    void * __reserved1;        /* 不填*/
};</pre>
</div>
</div>
<p>声明plugin需要使用2个预编译宏，你可以在include/plugin.h 查看mysql_declare_plugin，mysql_declare_plugin_end两个宏的具体内容。</p>
<div>
<div>
<pre>struct st_mysql_daemon monitor_plugin =
{
    MYSQL_DAEMON_INTERFACE_VERSION
};

mysql_declare_plugin(monitor_plugin)
{
    MYSQL_DAEMON_PLUGIN,
    &amp;monitor_plugin,
    "monitor",
    "hoterran",
    "test",
    PLUGIN_LICENSE_GPL,
    monitor_plugin_init,
    monitor_plugin_deinit,
    0x0100,
    NULL,
    NULL,
    NULL,
}
mysql_declare_plugin_end;</pre>
</div>
</div>
<p>结构体中的monitor_plugin_init和monitor_plugin_deinit就是接下来要编写的加载和卸载对应的函数。</p>
<p>下面是全部代码monitor.c</p>
<div>
<div>
<pre>#include &lt;string.h&gt;
#include &lt;unistd.h&gt;
#include &lt;stdio.h&gt;
#include &lt;plugin.h&gt;
#include &lt;mysql_version.h&gt;
#include &lt;my_global.h&gt;
#include &lt;my_sys.h&gt;
#include &lt;pthread.h&gt;

extern ulong		thread_id;
extern uint		thread_count;
extern ulong		max_connections;

static pthread_t	G_thread;

pthread_handler_t func(void *p)
{
    while(1) {
         sleep(5);
         fprintf(stderr, "Thread id [%ld] Thread_count: %u Max_connections:%lu\n",
             thread_id, thread_count, max_connections);
         }
}

static int monitor_plugin_init(void *p)
{
    if (pthread_create(&amp;amp;G_thread, NULL, func, NULL) != 0) {
        fprintf(stderr, "Monitor plugin init failure");
        return 1;
    }

    fprintf(stderr, "%s", "Monitor plugin init\n");
    return 0;
}

static int monitor_plugin_deinit(void *p)
{
    pthread_cancel(G_thread);
    pthread_join(G_thread, NULL);
    fprintf(stderr, "%s", "Monitor_plugin deinit\n");

    return 0;
}

struct st_mysql_daemon monitor_plugin =
{
    MYSQL_DAEMON_INTERFACE_VERSION
};

mysql_declare_plugin(monitor_plugin)
{
    MYSQL_DAEMON_PLUGIN,
    &amp;monitor_plugin,
    "monitor",
    "hoterran",
    "test",
    PLUGIN_LICENSE_GPL,
    monitor_plugin_init,
    monitor_plugin_deinit,
    0x0100,
    NULL,
    NULL,
    NULL,
}
mysql_declare_plugin_end;</pre>
</div>
</div>
<p><strong>编译</strong></p>

<div class="wp_codebox_msgheader"><span class="right"><sup><a href="http://www.ericbess.com/ericblog/2008/03/03/wp-codebox/#examples" target="_blank" title="WP-CodeBox HowTo?"><span style="color: #99cc00">?</span></a></sup></span><span class="left"><a href="javascript:;" onclick="javascript:showCodeTxt('p925code5'); return false;">View Code</a> BASH</span><div class="codebox_clear"></div></div><div class="wp_codebox"><table><tr id="p9255"><td class="line_numbers"><pre>1
2
3
</pre></td><td class="code" id="p925code5"><pre class="bash" style="font-family:monospace;"><span style="color: #c20cb9; font-weight: bold;">gcc</span> <span style="color: #660033;">-g</span> <span style="color: #660033;">-Wall</span> -I<span style="color: #000000; font-weight: bold;">/</span>usr<span style="color: #000000; font-weight: bold;">/</span>local<span style="color: #000000; font-weight: bold;">/</span>mysql<span style="color: #000000; font-weight: bold;">/</span>include<span style="color: #000000; font-weight: bold;">/</span>mysql -DMYSQL_DYNAMIC_PLUGIN   <span style="color: #660033;">-c</span> <span style="color: #660033;">-o</span> monitor.o monitor.c
<span style="color: #c20cb9; font-weight: bold;">gcc</span> <span style="color: #660033;">-shared</span> <span style="color: #660033;">-o</span> libmonitor.so monitor.o
<span style="color: #c20cb9; font-weight: bold;">sudo</span> <span style="color: #c20cb9; font-weight: bold;">cp</span> libmonitor.so <span style="color: #000000; font-weight: bold;">/</span>usr<span style="color: #000000; font-weight: bold;">/</span>local<span style="color: #000000; font-weight: bold;">/</span>mysql<span style="color: #000000; font-weight: bold;">/</span>plugin<span style="color: #000000; font-weight: bold;">/</span></pre></td></tr></table></div>

<p><strong>加载</strong></p>

<div class="wp_codebox_msgheader"><span class="right"><sup><a href="http://www.ericbess.com/ericblog/2008/03/03/wp-codebox/#examples" target="_blank" title="WP-CodeBox HowTo?"><span style="color: #99cc00">?</span></a></sup></span><span class="left"><a href="javascript:;" onclick="javascript:showCodeTxt('p925code6'); return false;">View Code</a> BASH</span><div class="codebox_clear"></div></div><div class="wp_codebox"><table><tr id="p9256"><td class="line_numbers"><pre>1
2
</pre></td><td class="code" id="p925code6"><pre class="bash" style="font-family:monospace;">mysql<span style="color: #000000; font-weight: bold;">&amp;</span>gt;<span style="color: #c20cb9; font-weight: bold;">install</span> plugin monitor soname <span style="color: #ff0000;">'libmonitor.so'</span>;
Query OK, <span style="color: #000000;">0</span> rows affected <span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #000000;">0.01</span> sec<span style="color: #7a0874; font-weight: bold;">&#41;</span></pre></td></tr></table></div>

<p>观察日志可以看到具体的输出。</p>

<div class="wp_codebox_msgheader"><span class="right"><sup><a href="http://www.ericbess.com/ericblog/2008/03/03/wp-codebox/#examples" target="_blank" title="WP-CodeBox HowTo?"><span style="color: #99cc00">?</span></a></sup></span><span class="left"><a href="javascript:;" onclick="javascript:showCodeTxt('p925code7'); return false;">View Code</a> BASH</span><div class="codebox_clear"></div></div><div class="wp_codebox"><table><tr id="p9257"><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
</pre></td><td class="code" id="p925code7"><pre class="bash" style="font-family:monospace;">....
<span style="color: #7a0874; font-weight: bold;">&#91;</span>New Thread 0xb4296b70 <span style="color: #7a0874; font-weight: bold;">&#40;</span>LWP <span style="color: #000000;">3895</span><span style="color: #7a0874; font-weight: bold;">&#41;</span><span style="color: #7a0874; font-weight: bold;">&#93;</span>
<span style="color: #7a0874; font-weight: bold;">&#91;</span>New Thread 0xb1e34b70 <span style="color: #7a0874; font-weight: bold;">&#40;</span>LWP <span style="color: #000000;">4042</span><span style="color: #7a0874; font-weight: bold;">&#41;</span><span style="color: #7a0874; font-weight: bold;">&#93;</span>
Monitor plugin init
Thread <span style="color: #c20cb9; font-weight: bold;">id</span> <span style="color: #7a0874; font-weight: bold;">&#91;</span><span style="color: #000000;">2</span><span style="color: #7a0874; font-weight: bold;">&#93;</span> Thread_count: <span style="color: #000000;">1</span> Max_connections:<span style="color: #000000;">151</span>
Thread <span style="color: #c20cb9; font-weight: bold;">id</span> <span style="color: #7a0874; font-weight: bold;">&#91;</span><span style="color: #000000;">2</span><span style="color: #7a0874; font-weight: bold;">&#93;</span> Thread_count: <span style="color: #000000;">1</span> Max_connections:<span style="color: #000000;">151</span>
Thread <span style="color: #c20cb9; font-weight: bold;">id</span> <span style="color: #7a0874; font-weight: bold;">&#91;</span><span style="color: #000000;">2</span><span style="color: #7a0874; font-weight: bold;">&#93;</span> Thread_count: <span style="color: #000000;">1</span> Max_connections:<span style="color: #000000;">151</span>
....</pre></td></tr></table></div>


<div class="wp_codebox_msgheader"><span class="right"><sup><a href="http://www.ericbess.com/ericblog/2008/03/03/wp-codebox/#examples" target="_blank" title="WP-CodeBox HowTo?"><span style="color: #99cc00">?</span></a></sup></span><span class="left"><a href="javascript:;" onclick="javascript:showCodeTxt('p925code8'); return false;">View Code</a> BASH</span><div class="codebox_clear"></div></div><div class="wp_codebox"><table><tr id="p9258"><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
</pre></td><td class="code" id="p925code8"><pre class="bash" style="font-family:monospace;">mysql<span style="color: #000000; font-weight: bold;">&amp;</span>gt;show plugins;
+------------+--------+----------------+---------------+---------+
<span style="color: #000000; font-weight: bold;">|</span> Name       <span style="color: #000000; font-weight: bold;">|</span> Status <span style="color: #000000; font-weight: bold;">|</span> Type           <span style="color: #000000; font-weight: bold;">|</span> Library       <span style="color: #000000; font-weight: bold;">|</span> License <span style="color: #000000; font-weight: bold;">|</span>
+------------+--------+----------------+---------------+---------+
<span style="color: #000000; font-weight: bold;">|</span> monitor    <span style="color: #000000; font-weight: bold;">|</span> ACTIVE <span style="color: #000000; font-weight: bold;">|</span> DAEMON         <span style="color: #000000; font-weight: bold;">|</span> libmonitor.so <span style="color: #000000; font-weight: bold;">|</span> GPL     <span style="color: #000000; font-weight: bold;">|</span>
+------------+--------+----------------+---------------+---------+
&nbsp;
mysql<span style="color: #000000; font-weight: bold;">&amp;</span>gt; <span style="color: #000000; font-weight: bold;">select</span> <span style="color: #000000; font-weight: bold;">*</span> from mysql.plugin;
+------------+---------------+
<span style="color: #000000; font-weight: bold;">|</span> name       <span style="color: #000000; font-weight: bold;">|</span> dl            <span style="color: #000000; font-weight: bold;">|</span>
+------------+---------------+
....
<span style="color: #000000; font-weight: bold;">|</span> monitor    <span style="color: #000000; font-weight: bold;">|</span> libmonitor.so <span style="color: #000000; font-weight: bold;">|</span>
+------------+---------------+</pre></td></tr></table></div>

<p>好了，插件的编写工作就完成了，够简单吧。</p>
<p>在MySQL的附带demo里有个heartbeat的例子，MySQL的ref里面也有另外一个full-text的例子。</p>
<p>&nbsp;</p>
<p>如何使用daemon plugin ，时还没想好，淘宝的同事 @ningoo有把zookeeper client 作为deamon plugin 想法。</p>
<p>&nbsp;</p>
<h3  class="related_post_title">相关文章</h3><ul class="related_post"><li>2011-07-18 -- <a href="http://ourmysql.com/archives/923" title="利用PLUGIN更快的添加STATUS VARIABLES">利用PLUGIN更快的添加STATUS VARIABLES</a></li></ul>
	标签：<a href="http://ourmysql.com/archives/category/advanced" title="MySQL高级应用" rel="tag">MySQL高级应用</a>, <a href="http://ourmysql.com/archives/tag/plugin" title="plugin" rel="tag">plugin</a><br />
]]></content:encoded>
			<wfw:commentRss>http://ourmysql.com/archives/925/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>利用PLUGIN更快的添加STATUS VARIABLES</title>
		<link>http://ourmysql.com/archives/923</link>
		<comments>http://ourmysql.com/archives/923#comments</comments>
		<pubDate>Mon, 18 Jul 2011 15:39:10 +0000</pubDate>
		<dc:creator>OurMySQL</dc:creator>
				<category><![CDATA[MySQL高级应用]]></category>
		<category><![CDATA[plugin]]></category>
		<category><![CDATA[status]]></category>

		<guid isPermaLink="false">http://ourmysql.com/?p=923</guid>
		<description><![CDATA[在MySQL里添加一个system、status variables的比较复杂的，需要修改sql/sql_show.cc，sql/mysqld.cc, 还要修改sql/sql_yacc.yy，然后重新编译等等，前面的文章可见其复杂度，很容易出错。daemon plugin 除了允许添加后台线程，也允许添加status，且不需要修改mysqld的代码。]]></description>
			<content:encoded><![CDATA[<p>在MySQL里添加一个system、<a href="http://ourmysql.com/archives/tag/status" class="st_tag internal_tag" rel="tag" title="标签 status 下的日志">status</a> variables的比较复杂的，需要修改sql/<a href="http://ourmysql.com/archives/tag/sql" class="st_tag internal_tag" rel="tag" title="标签 sql 下的日志">sql</a>_show.cc，<a href="http://ourmysql.com/archives/tag/sql" class="st_tag internal_tag" rel="tag" title="标签 sql 下的日志">sql</a>/mysqld.cc, 还要修改sql/<a href="http://ourmysql.com/archives/tag/sql" class="st_tag internal_tag" rel="tag" title="标签 sql 下的日志">sql</a>_yacc.yy，然后重新编译等等，<a href="http://www.hoterran.info/ems_add_variable">前面的文章</a>可见其复杂度，很容易出错。</p>
<p>daemon <a href="http://ourmysql.com/archives/tag/plugin" class="st_tag internal_tag" rel="tag" title="标签 plugin 下的日志">plugin</a> 除了允许添加后台线程，也允许添加status，且不需要修改mysqld的代码。</p>
<div>
<div>
<pre>#include &lt;string.h&gt;
#include &lt;unistd.h&gt;
#include &lt;stdio.h&gt;
#include &lt;plugin.h&gt;
#include &lt;mysql_version.h&gt;
#include &lt;my_global.h&gt;
#include &lt;my_sys.h&gt;
#include &lt;pthread.h&gt;

static int get_value(MYSQL_THD thd, struct st_mysql_show_var* var, char *buff) {
	struct st_mysql_show_var *status = (struct st_mysql_show_var*) buff;

	var-&gt;type = SHOW_ARRAY;
	var-&gt;value= (char* )status;

	status-&gt;value = "aaa";
	status-&gt;type = SHOW_CHAR;
	status-&gt;name = "test1";

	status++;
	status-&gt;name = 0;

	return 0;

}

struct st_mysql_daemon sys_status =
{
	MYSQL_DAEMON_INTERFACE_VERSION
};

static struct st_mysql_show_var sys_status_var[] =
{
	{"plugin_test", (char *)&amp;get_value, SHOW_FUNC},
	{0, 0, 0}
};

mysql_declare_plugin(sys_status)
{
	MYSQL_DAEMON_PLUGIN,
	&amp;sys_status,
	"sys_status",
	"hoterran",
	"test",
	PLUGIN_LICENSE_GPL,
	NULL,
	NULL,
	0x0100,
	sys_status_var,
	NULL,
	NULL,
}
mysql_declare_plugin_end;</pre>
</div>
</div>
<p>上面添加了一个名字叫做plugin_test的status组，第一个status叫 plugin_test_test1，第二个status-&gt;name=0是个哨兵。</p>
<p>get_value(MYSQL_THD *thd, struct st_mysql_show_var* var, char* buff)，其中thd为线程THD类， var就是你要填充的内容， buff是预先分配好的1024字节的一个变量，你不需要另外malloc了。先把status的内容填充到buff里，再把status赋值到var-&gt;value，就算结束了。</p>
<p>例子里status-&gt;value只是简单赋值为”aaaa”，你要加工获得想获得你想要的信息。</p>
<p>编译、安装、加载同上<a href="http://www.hoterran.info/mysql-daemon-plugin-example">一篇文章</a>。最后的效果如下</p>
<pre>mysql&gt; show status like '%plugin_test_test1%';
+-------------------+-------+
| <a href="http://ourmysql.com/archives/tag/variable" class="st_tag internal_tag" rel="tag" title="标签 variable 下的日志">Variable</a>_name     | Value |
+-------------------+-------+
| plugin_test_test1 | aaa   |
+-------------------+-------+
1 row in set (0.00 sec)</pre>
<p>&nbsp;</p>
<h3  class="related_post_title">相关文章</h3><ul class="related_post"><li>2011-07-18 -- <a href="http://ourmysql.com/archives/925" title="MYSQL DAEMON PLUGIN EXAMPLE">MYSQL DAEMON PLUGIN EXAMPLE</a></li><li>2009-07-10 -- <a href="http://ourmysql.com/archives/610" title="show engine innodb status显示信息不全?">show engine innodb status显示信息不全?</a></li></ul>
	标签：<a href="http://ourmysql.com/archives/category/advanced" title="MySQL高级应用" rel="tag">MySQL高级应用</a>, <a href="http://ourmysql.com/archives/tag/plugin" title="plugin" rel="tag">plugin</a>, <a href="http://ourmysql.com/archives/tag/status" title="status" rel="tag">status</a><br />
]]></content:encoded>
			<wfw:commentRss>http://ourmysql.com/archives/923/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>InnoDB的多版本一致性读的实现</title>
		<link>http://ourmysql.com/archives/920</link>
		<comments>http://ourmysql.com/archives/920#comments</comments>
		<pubDate>Wed, 30 Mar 2011 05:56:37 +0000</pubDate>
		<dc:creator>OurMySQL</dc:creator>
				<category><![CDATA[MySQL高级应用]]></category>
		<category><![CDATA[InnoDB]]></category>
		<category><![CDATA[一致性]]></category>

		<guid isPermaLink="false">http://ourmysql.com/?p=920</guid>
		<description><![CDATA[InnoDB是支持MVCC多版本一致性读的，因此和其他实现了MVCC的系统如Oracle，PostgreSQL一样，读不会阻塞写，写也不会阻塞读。虽然同样是MVCC，各家的实现是不太一样的。Oracle通过在block头部的事务列表，和记录中的锁标志位，加上回滚段，个人认为实现上是最优雅的方式。 而PostgreSQL则更是将多个版本的数据都放在表中，而没有单独的回滚段，导致的一个结果是回滚非常快，却付出了查询性能降低的代价。]]></description>
			<content:encoded><![CDATA[<div class="entry">
<p>InnoDB是支持MVCC多版本一致性读的，因此和其他实现了MVCC的系统如Oracle，PostgreSQL一样，读不会阻塞写，写也不会阻塞读。虽然同样是MVCC，各家的实现是不太一样的。Oracle通过在block头部的事务列表，和记录中的锁标志位，加上回滚段，个人认为实现上是最优雅的方式。  而<a href="http://www.ningoo.net/html/2010/introduce_to_postgresql.html">PostgreSQL</a>则更是将多个版本的数据都放在表中，而没有单独的回滚段，导致的一个结果是回滚非常快，却付出了查询性能降低的代价。</p>
<p>InnoDB的实现更像Oracle，同样是将数据的旧版本存放在单独的回滚段中，但是也有不同。之前还以为整体实现都会跟Oracle不会有太大的出入，也一直没有太在意去看具体实现。今晚晚上下班准备回家时，刚好路过几个同事在交流分享这个问题，遇到一个疑问：</p>
<p>我们知道，InnoDB表会有三个隐藏字段，6字节的DB_ROW_ID，6字节的DB_TX_ID，7字节的DB_ROLL_PTR（指向对应回滚段的地址），这个可以通过<a href="http://www.ningoo.net/html/2009/an_introduce_of_innodb_monitor.html">innodb monitor</a>看到，当然如果你熟悉innodb文件结构，也可以直接od  ibd文件来验证。一致性读主要跟后两者有关系。InnoDB内部维护了一个递增的tx id counter，其当前值可以通过show engine <a href="http://ourmysql.com/archives/tag/innodb" class="st_tag internal_tag" rel="tag" title="标签 InnoDB 下的日志">innodb</a>  status获得</p>
<pre>echo "show engine innodb <a href="http://ourmysql.com/archives/tag/status" class="st_tag internal_tag" rel="tag" title="标签 status 下的日志">status</a>\G" | mysql -uroot | grep "Trx id counter"</pre>
<p>假设有一个表，当前已经有两条记录。这时候我们开始一个实验，开启两个session，A和B，都设置autocommit=0</p>
<pre>MySQL&gt;set global autocommit=0;</pre>
<p>T1时间：<br />
A开始一个事务，执行一条select，可以看到已有的两条记录，show engine innodb status可以知道A的tx  id，假设为7430<br />
T2时间：<br />
B开始一个事务，执行一条select，可以看到已有的两条记录，可以知道B的tx  id，为7431<br />
T3时间：<br />
A中insert一条记录，此时A再select能看到，所以返回三条记录，而B无法看到，还是返回两条记录。<br />
T4时间：<br />
A中执行commit提交事务，分别在A和B中select，得到的结果和T3时间相同。</p>
<p>Ok，假设一致性读是根据事务先后，也就是tx id来比较的话，如果B事务的一致性读是通过B的tx id即7431来和A事务中insert的这条记录的tx  id即7430来比较的话，由于A.tx_id &lt; B.tx_id，那么B应该能都到A的记录（tx  id是递增的，所以越小说明事务越早开始），但如果能读到，则显然不符合多版本一致性。</p>
<p>因此结果是正确的，那么就是InnoDB的一致性读的实现方式不是像我们按照经验来测试的那样了。通过google和察看代码，原来InnoDB还真是有一个感觉上很山寨的设计，由于tx  id是事务一开始就分配的，事务中的变化也没有记录一个类似于Oracle的SCN的逻辑时钟，于是由了如下的实现：</p>
<p>InnoDB每个事务在开始的时候，会将当前系统中的活跃事务列表（trx_sys-&gt;trx_list）创建一个副本（read  view），然后一致性读去比较记录的tx id的时候，并不是根据当前事务的tx id，而是根据read view最早一个事务的tx id（read  view-&gt;up_limit_id）来做比较的，这样就能确保在事务B之前没有提交的所有事务的变更，B事务都是看不到的。当然，这里还有个小问题要处理一下，就是当前事务自身的变更还是需要看到的。</p>
<p>有兴趣的可以去仔细看看代码的实现，在storage/innobase/read/read0read.c中实现了创建read  view的函数read_view_open_now，在storage/innobase/include/read0read.ic中实现了判断一致性读是否可见的read_view_sees_trx_id。以下代码摘自5.5.8：</p>
<pre>UNIV_INTERN
read_view_t*
read_view_open_now(
/*===============*/
	trx_id_t	cr_trx_id,	/*!&lt; in: trx_id of creating
					transaction, or 0 used in purge */
	mem_heap_t*	heap)		/*!&lt; in: memory heap from which
					allocated */
{
	read_view_t*	view;
	trx_t*		trx;
	ulint		n;
	ut_ad(mutex_own(&amp;kernel_mutex));
	view = read_view_create_low(UT_LIST_GET_LEN(trx_sys-&gt;trx_list), heap);
	view-&gt;creator_trx_id = cr_trx_id;
	view-&gt;type = VIEW_NORMAL;
	view-&gt;undo_no = 0;
	/* No future transactions should be visible in the view */
	view-&gt;low_limit_no = trx_sys-&gt;max_trx_id;
	view-&gt;low_limit_id = view-&gt;low_limit_no;
	n = 0;
	trx = UT_LIST_GET_FIRST(trx_sys-&gt;trx_list);
	/* No active transaction should be visible, except cr_trx */
	while (trx) {
		if (trx-&gt;id != cr_trx_id
		    &amp;&amp; (trx-&gt;conc_state == TRX_ACTIVE
			|| trx-&gt;conc_state == TRX_PREPARED)) {
			read_view_set_nth_trx_id(view, n, trx-&gt;id);
			n++;
			/* NOTE that a transaction whose trx number is &lt;
			trx_sys-&gt;max_trx_id can still be active, if it is
			in the middle of its commit! Note that when a
			transaction starts, we initialize trx-&gt;no to
			IB_ULONGLONG_MAX. */
			if (view-&gt;low_limit_no &gt; trx-&gt;no) {
				view-&gt;low_limit_no = trx-&gt;no;
			}
		}
		trx = UT_LIST_GET_NEXT(trx_list, trx);
	}
	view-&gt;n_trx_ids = n;
	if (n &gt; 0) {
		/* The last active transaction has the smallest id: */
		view-&gt;up_limit_id = read_view_get_nth_trx_id(view, n - 1);
	} else {
		view-&gt;up_limit_id = view-&gt;low_limit_id;
	}
	UT_LIST_ADD_FIRST(view_list, trx_sys-&gt;view_list, view);
	return(view);
}</pre>
<pre>UNIV_INLINE
ibool
read_view_sees_trx_id(
/*==================*/
	const read_view_t*	view,	/*!&lt; in: read view */
	trx_id_t		trx_id)	/*!&lt; in: trx id */
{
	ulint	n_ids;
	ulint	i;
	if (trx_id &lt; view-&gt;up_limit_id) {
		return(TRUE);
	}
	if (trx_id &gt;= view-&gt;low_limit_id) {
		return(FALSE);
	}
	/* We go through the trx ids in the array smallest first: this order
	may save CPU time, because if there was a very long running
	transaction in the trx id array, its trx id is looked at first, and
	the first two comparisons may well decide the visibility of trx_id. */
	n_ids = view-&gt;n_trx_ids;
	for (i = 0; i &lt; n_ids; i++) {
		trx_id_t	view_trx_id
			= read_view_get_nth_trx_id(view, n_ids - i - 1);
		if (trx_id &lt;= view_trx_id) {
			return(trx_id != view_trx_id);
		}
	}
	return(TRUE);
}</pre>
<p>参考：<br />
<a href="http://dev.mysql.com/doc/refman/5.1/en/innodb-multi-versioning.html">http://dev.mysql.com/doc/refman/5.1/en/innodb-multi-versioning.html</a><br />
<a href="http://wangyuanzju.blog.163.com/blog/static/130292009107101544125/">http://wangyuanzju.blog.163.com/blog/static/130292009107101544125/</a><br />
<a href="http://bbs.chinaunix.net/thread-1773206-1-1.html">http://bbs.chinaunix.net/thread-1773206-1-1.html</a></div>
<h3  class="related_post_title">相关文章</h3><ul class="related_post"><li>2011-07-22 -- <a href="http://ourmysql.com/archives/956" title="“ERROR 1235 (42000): skip-innodb is defined”的误导">“ERROR 1235 (42000): skip-innodb is defined”的误导</a></li><li>2011-01-10 -- <a href="http://ourmysql.com/archives/902" title="InnoDB的Master Thread调度流程">InnoDB的Master Thread调度流程</a></li><li>2010-09-29 -- <a href="http://ourmysql.com/archives/857" title="MySQL锁机制/管理(并发锁,行锁,表锁,预加锁,全局锁等等)">MySQL锁机制/管理(并发锁,行锁,表锁,预加锁,全局锁等等)</a></li><li>2010-09-27 -- <a href="http://ourmysql.com/archives/852" title="InnoDB Adaptive Flush">InnoDB Adaptive Flush</a></li><li>2010-08-04 -- <a href="http://ourmysql.com/archives/845" title="InnoDB主键设计">InnoDB主键设计</a></li><li>2010-04-13 -- <a href="http://ourmysql.com/archives/825" title="InnoDB Double write">InnoDB Double write</a></li><li>2010-03-09 -- <a href="http://ourmysql.com/archives/817" title="Innodb 表和索引结构">Innodb 表和索引结构</a></li><li>2010-03-09 -- <a href="http://ourmysql.com/archives/811" title="InnoDB线程并发检查机制">InnoDB线程并发检查机制</a></li><li>2009-12-20 -- <a href="http://ourmysql.com/archives/805" title="Innodb如何使用内存">Innodb如何使用内存</a></li><li>2009-12-20 -- <a href="http://ourmysql.com/archives/801" title="Innodb文件表空间结构">Innodb文件表空间结构</a></li></ul>
	标签：<a href="http://ourmysql.com/archives/tag/innodb" title="InnoDB" rel="tag">InnoDB</a>, <a href="http://ourmysql.com/archives/category/advanced" title="MySQL高级应用" rel="tag">MySQL高级应用</a>, <a href="http://ourmysql.com/archives/tag/%e4%b8%80%e8%87%b4%e6%80%a7" title="一致性" rel="tag">一致性</a><br />
]]></content:encoded>
			<wfw:commentRss>http://ourmysql.com/archives/920/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>PHP查询MySQL大量数据的内存占用分析</title>
		<link>http://ourmysql.com/archives/917</link>
		<comments>http://ourmysql.com/archives/917#comments</comments>
		<pubDate>Thu, 24 Feb 2011 05:32:58 +0000</pubDate>
		<dc:creator>OurMySQL</dc:creator>
				<category><![CDATA[MySQL解错方案]]></category>
		<category><![CDATA[主从同步]]></category>
		<category><![CDATA[内存]]></category>
		<category><![CDATA[缓冲]]></category>

		<guid isPermaLink="false">http://ourmysql.com/?p=917</guid>
		<description><![CDATA[ 这篇文章主要是从原理, 手册和源码分析在PHP中查询MySQL返回大量结果时, 内存占用的问题, 同时对使用MySQL C API也有涉及.]]></description>
			<content:encoded><![CDATA[<p>这篇文章主要是从原理, 手册和源码分析在PHP中查询MySQL返回大量结果时, 内存占用的问题, 同时对使用MySQL C API也有涉及.</p>
<p>昨天, 有同事在PHP讨论群里提到, 他做的一个项目由于MySQL查询返回的结果太多(达10万条), 从而导致PHP内存不够用. 所以, 他问, 在执行下面的代码遍历返回的MySQL结果之前, 数据是否已经在内存中了? -</p>
<pre>while ($row = mysql_fetch_assoc($result)) {
    // ...
}</pre>
<p>当然, 这种问题有许多优化的方法. 不过, 就这个问题来讲, 我首先想到, MySQL是经典的C/S(Client/Server, 客户端/服务器)模型, 在遍历结果集之前, 底层的实现可能已经把所有的数据通过网络(假设使用TCP/IP)读到了Client的缓冲区, 也有另一种可能, 就是数据还在Server端的发送缓冲区里, 并没有传给Client.</p>
<p>在查看PHP和MySQL的源码之前, 我注意到PHP手册里有两个功能相近的函数:</p>
<pre>mysql_query()
mysql_unbuffered_query()</pre>
<p>两个函数的字面意思和说明证实了我的想法, 前一个函数执行时, 会把所有的结果集从Server端读到Client端的缓冲区中, 而后一个则没有, 这就是”unbuffered(未缓冲)”的意思.</p>
<p>那就是说, 如果用mysql_unbuffered_query()执行了一条返回大量结果集的SQL语句, 在遍历结果之前, PHP的内存是没有被结果集占用的. 而用mysql_query()来执行同样的语句的话, 函数返回时, PHP的内存占用便会急剧增加, 立即耗光内存.</p>
<p>如果阅读PHP的相关代码, 可以看到这两个函数的实现上的异同:</p>
<pre>/* {{{ proto resource mysql_query(string query [, int link_identifier])
   Sends an <a href="http://ourmysql.com/archives/tag/sql" class="st_tag internal_tag" rel="tag" title="标签 sql 下的日志">SQL</a> query to MySQL */
PHP_FUNCTION(mysql_query)
{
    php_mysql_do_query(INTERNAL_FUNCTION_PARAM_PASSTHRU, <strong>MYSQL_STORE_RESULT</strong>);
}
/* }}} */

/* {{{ proto resource mysql_unbuffered_query(string query [, int link_identifier])
   Sends an SQL query to MySQL, without fetching and buffering the result rows */
PHP_FUNCTION(mysql_unbuffered_query)
{
    php_mysql_do_query(INTERNAL_FUNCTION_PARAM_PASSTHRU, <strong>MYSQL_USE_RESULT</strong>);
}
/* }}} */</pre>
<p>两个函数都调用了php_mysql_do_query(), 只差了第2个参数的不同, MYSQL_STORE_RESULT和MYSQL_USE_RESULT. 再看php_mysql_do_query()的实现:</p>
<pre>if(use_store == MYSQL_USE_RESULT) {
    mysql_result=mysql_use_result(&amp;mysql-&gt;conn);
} else {
    mysql_result=mysql_store_result(&amp;mysql-&gt;conn);
}</pre>
<p>mysql_use_result()和mysql_store_result()是MySQL的C API函数, 这两个C API函数的区别就是后者把结果集从MySQL Server端全部读取到了Client端, 前者只是读取了结果集的元信息.</p>
<p>回到PHP, 使用mysql_unbuffered_query(), 可以避免内存的立即占用. 如果在遍历的过程不对结果进行”PHP缓存”(如放到某数组中), 则整个执行过程虽然操作了十万条或者百万条或者更多的数据, 但PHP占用的内存始终是非常小的.</p>
<h3  class="related_post_title">相关文章</h3><ul class="related_post"><li>2011-01-28 -- <a href="http://ourmysql.com/archives/908" title="处理Mysql的MySql-bin.0000X日志文件">处理Mysql的MySql-bin.0000X日志文件</a></li><li>2010-11-15 -- <a href="http://ourmysql.com/archives/876" title="mysql replication 报告">mysql replication 报告</a></li><li>2009-12-20 -- <a href="http://ourmysql.com/archives/805" title="Innodb如何使用内存">Innodb如何使用内存</a></li><li>2009-04-26 -- <a href="http://ourmysql.com/archives/545" title="MySQL内存使用 &#8211; 全局共享">MySQL内存使用 &#8211; 全局共享</a></li><li>2009-04-20 -- <a href="http://ourmysql.com/archives/537" title="MySQL内存使用-线程独享">MySQL内存使用-线程独享</a></li><li>2009-02-17 -- <a href="http://ourmysql.com/archives/458" title="配置MySQL远程复制">配置MySQL远程复制</a></li><li>2009-02-16 -- <a href="http://ourmysql.com/archives/456" title="MySQL双向复制简单配置步骤">MySQL双向复制简单配置步骤</a></li><li>2008-11-18 -- <a href="http://ourmysql.com/archives/293" title="删除MYSQL BIN-LOG 日志">删除MYSQL BIN-LOG 日志</a></li><li>2008-11-08 -- <a href="http://ourmysql.com/archives/264" title="MySQL数据库自动恢复的简单操作过程">MySQL数据库自动恢复的简单操作过程</a></li><li>2008-11-08 -- <a href="http://ourmysql.com/archives/259" title="MySQL主从服务器配置">MySQL主从服务器配置</a></li></ul>
	标签：<a href="http://ourmysql.com/archives/category/debug" title="MySQL解错方案" rel="tag">MySQL解错方案</a>, <a href="http://ourmysql.com/archives/tag/%e4%b8%bb%e4%bb%8e%e5%90%8c%e6%ad%a5" title="主从同步" rel="tag">主从同步</a>, <a href="http://ourmysql.com/archives/tag/%e5%86%85%e5%ad%98" title="内存" rel="tag">内存</a>, <a href="http://ourmysql.com/archives/tag/%e7%bc%93%e5%86%b2" title="缓冲" rel="tag">缓冲</a><br />
]]></content:encoded>
			<wfw:commentRss>http://ourmysql.com/archives/917/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>数据库设计范式的理解</title>
		<link>http://ourmysql.com/archives/915</link>
		<comments>http://ourmysql.com/archives/915#comments</comments>
		<pubDate>Mon, 21 Feb 2011 02:49:04 +0000</pubDate>
		<dc:creator>OurMySQL</dc:creator>
				<category><![CDATA[MySQL基础知识]]></category>
		<category><![CDATA[范式]]></category>

		<guid isPermaLink="false">http://ourmysql.com/?p=915</guid>
		<description><![CDATA[范式是符合某一种级别的关系模式的集合。关系数据库中的关系必须满足一定的要求，即满足不同的范式。目前关系数据库有六种范式：第一范式（1NF）、第二范式（2NF）、第三范式（3NF）、第四范式（4NF）、第五范式（5NF）和第六范式（6NF）。满足最低要求的范式是第一范式（1NF）。在第一范式的基础上进一步满足更多要求的称为第二范式（2NF），其余范式以次类推。一般说来，数据库只需满足第三范式（3NF）就行了。]]></description>
			<content:encoded><![CDATA[<p><strong>前言</strong><br />
为什么要写这篇文章呢，从去年年底开始，就和很多做技术的朋友交流过，从数据库设计到数据库架构各个方面的内容。有一些朋友执着于ORM，执着于所谓的数据库设计，却忘记了一切技术是要为业务服务这个基石。当然这文章里也有一些自己的理解，想向大家表达。</p>
<p><strong>范式是什么</strong><br />
范式是符合某一种级别的关系模式的集合。关系数据库中的关系必须满足一定的要求，即满足不同的范式。目前关系数据库有六种范式：第一范式（1NF）、第二范式（2NF）、第三范式（3NF）、第四范式（4NF）、第五范式（5NF）和第六范式（6NF）。满足最低要求的范式是第一范式（1NF）。在第一范式的基础上进一步满足更多要求的称为第二范式（2NF），其余范式以次类推。一般说来，数据库只需满足第三范式（3NF）就行了。</p>
<p><strong>范式的原理</strong></p>
<ul>
<li><strong>第一范式（1NF）无重复的列</strong>所谓第一范式（1NF）是指数据库表的每一列都是不可分割的基本数据项，同一列中不能有多个值，即实体中的某个属性不能有多个值或者不能有重复的属性。如果出现重复的属性，就可能需要定义一个新的实体，新的实体由重复的属性构成，新实体与原实体之间为一对多关系。在第一范式（1NF）中表的每一行只包含一个实例的信息。简而言之，第一范式就是无重复的列。
<p>说明：在任何一个关系数据库中，第一范式（1NF）是对关系模式的基本要求，不满足第一范式（1NF）的数据库就不是关系数据库。</li>
<li><strong>第二范式（2NF）属性完全依赖于主键</strong>[消除部分子函数依赖]第二范式（2NF）是在第一范式（1NF）的基础上建立起来的，即满足第二范式（2NF）必须先满足第一范式（1NF）。第二范式（2NF）要求数据库表中的每个实例或行必须可以被惟一地区分。为实现区分通常需要为表加上一个列，以存储各个实例的惟一标识。
<p>例如员工信息表中加上了员工编号（emp_id）列，因为每个员工的员工编号是惟一的，因此每个员工可以被惟一区分。这个惟一属性列被称为主关键字或主键、主码。</p>
<p>第二范式（2NF）要求实体的属性完全依赖于主关键字。所谓完全依赖是指不能存在仅依赖主关键字一部分的属性，如果存在，那么这个属性和主关键字的这一部分应该分离出来形成一个新的实体，新实体与原实体之间是一对多的关系。为实现区分通常需要为表加上一个列，以存储各个实例的惟一标识。简而言之，第二范式就是属性完全依赖于主键。</li>
<li><strong>第三范式（3NF）属性不依赖于其它非主属性</strong>[消除传递依赖]满足第三范式（3NF）必须先满足第二范式（2NF）。简而言之，第三范式（3NF）要求一个数据库表中不包含已在其它表中已包含的非主关键字信息。例如，存在一个部门信息表，其中每个部门有部门编号（dept_id）、部门名称、部门简介等信息。
<p>那么在的员工信息表中列出部门编号后就不能再将部门名称、部门简介等与部门有关的信息再加入员工信息表中。如果不存在部门信息表，则根据第三范式（3NF）也应该构建它，否则就会有大量的数据冗余。简而言之，第三范式就是属性不依赖于其它非主属性。</li>
</ul>
<p><strong>范式的说明</strong></p>
<ul>
<li>第一范式：1NF是对属性的原子性约束，要求属性具有原子性，不可再分解；通俗的理解是字段还可以再分吗？如过不能，则是符合1NF的设计。</li>
<li>第二范式：2NF是对记录的惟一性约束，要求记录有惟一标识，即实体的惟一性；简单的解释，比如你和一个女生约会建立一张表，不用每条约会记录都记录她的身高、体重，将身高体重单独的存在一张表中供查询即可。</li>
<li>第三范式：3NF是对字段冗余性的约束，即任何字段不能由其他字段派生出来，它要求字段没有冗余。<br />
打个比方，比如评论表，如果你将用户ID，用户头像都放在这留言表中，就是不合适的了。用户头像是依赖于用户ID，而不依赖该评论。</li>
</ul>
<p><strong>我对范式的理解</strong><br />
一个严格恪守数据库设计范式来进行数据库设计的人，必定是个傻球；<br />
一个没有研究过数据库设计范式就进行数据库设计的人，必定也是个傻球；</p>
<p>在现代数据库设计中，尤其是web 2.0的系统中的数据库设计，我可以断言，大多数都是违反2NF、3NF的，少数设计甚至是违反1NF的。数据库设计范式只是对数据库惯用设计的一些说明，并不能定性为标准。</p>
<p>而从数据库的发展来看，以MySQL举例，随着MySQL实现越来越多的功能，它的宣传材料上会越来越多的出现以前被MySQL所摒弃的复杂设计理念，并且宣称这是MySQL所独创或一贯倡导的。这是一个数据库系统发展所必然经历的过程。而这却会给MySQL的使用者以极大的误导，从而忽视了是否新特性是业务所真正需要的。</p>
<p>数据库设计不是一种编程语言这么简单，与面向对象、面向过程无关。数据库设计代表的是一种与应用开发语言完全不同的思想。现在绝大多数的程序，无论任何人采用什么方式进行程序开发，其最终还是会回归到对数据库的操作上（当然如果你的程序只是个教学演示则不在此范围内）。</p>
<p><strong>数据库发展</strong><br />
各种缓存方案，说到底是以key为基础的数据解决方案，而数据库与应用层之间的中间件，为了实现逻辑的简单和高性能，更多的也会是基于key的实现。比如我所使用过的腾讯的TTC。</p>
<p>从下面的列表可以看出当前SNS的网站对于高并发、高性能的数据库解决方案有多么渴求，Facebook贡献了Cassandra、Linkedin贡献了Voldemort、mixi.jp贡献了Tokyo Cabinet和Tokoy Tyrant、green.jp贡献了Flare、甚至包括Google的BigTable。</p>
<p><strong>总结</strong><br />
写到这里，我发现单单是这些新的数据库解决方案就有太多可写的内容，而这些已经超过了本文所要说明的主要内容，而现在所写的内容就全当是个引子吧，我写的很意犹未尽。后面会就反范式设计实例，内存缓存方案、NoSQL数据库等逐渐展开。</p>
<p>PS：这篇文章写的很杂乱，尤其是后面两端，见谅！</p>
<h3  class="related_post_title">相关文章</h3><ul class="related_post"><li>目前没有相关的文章</li></ul>
	标签：<a href="http://ourmysql.com/archives/category/basic" title="MySQL基础知识" rel="tag">MySQL基础知识</a>, <a href="http://ourmysql.com/archives/tag/%e8%8c%83%e5%bc%8f" title="范式" rel="tag">范式</a><br />
]]></content:encoded>
			<wfw:commentRss>http://ourmysql.com/archives/915/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>MySQL延时备份之实现</title>
		<link>http://ourmysql.com/archives/912</link>
		<comments>http://ourmysql.com/archives/912#comments</comments>
		<pubDate>Mon, 21 Feb 2011 02:42:05 +0000</pubDate>
		<dc:creator>OurMySQL</dc:creator>
				<category><![CDATA[MySQL高级应用]]></category>
		<category><![CDATA[备份]]></category>
		<category><![CDATA[延时备份]]></category>

		<guid isPermaLink="false">http://ourmysql.com/?p=912</guid>
		<description><![CDATA[在实际工作中,经常有一不小心误删除数据库或表而后悔莫及的事件发生,这有没有后悔药可吃呢？今天介绍的延时备份就可以做到。延时备份让slave滞后于master一段时间,当你误操作时只要立即停止slave的同步,即可轻松地从延时备份库中找回你误删的数据。]]></description>
			<content:encoded><![CDATA[<p>在实际工作中,经常有一不小心误删除数据库或表而后悔莫及的事件发生,这有没有后悔药可吃呢？今天介绍的延时备份就可以做到。</p>
<p>延时备份让slave滞后于master一段时间,当你误操作时只要立即停止slave的同步,即可轻松地从延时备份库中找回你误删的数据。</p>
<p>下面介绍使用maatkit工具集中mk-slave-delay来实现延时备份。</p>
<h2>1、     maatkit工具集简介</h2>
<p>官方:http://www.maatkit.org/doc/</p>
<p>maatkit是一个包括多个实用MySQL的工具集，使用它们，可以让你的MySQL服务器使用起来更加方便也更加安全。maatkit是开源的软件,你可以自由的改进软件并将自己作出的改进版本向社会发行传播。</p>
<p>maatkit工具目前包含26个不同功能的工具。</p>
<p>主要有：</p>
<p>mk-archiver,mk-audit,mk-find,mk-kill,mk-<a href="http://ourmysql.com/archives/tag/heartbeat" class="st_tag internal_tag" rel="tag" title="标签 Heartbeat 下的日志">heartbeat</a>,mk-query-digest,mk-parallel-dump,mk-parallel-restore,mk-show-grants ,mk-slave-delay,mk-slave-move,mk-slave-restart等工具。</p>
<p>顾名思义mk-slave-delay是延时备份工具。mk-slave-delay控制MySQL slave端，使它滞后于其master。</p>
<h2>2、     maatkit安装</h2>
<p>下载:http://code.google.com/p/maatkit/</p>
<p>安装步骤：</p>
<p>tar -zxf maatkit-&lt;version&gt;.tar.gz</p>
<p>cd maatkit-&lt;version&gt;</p>
<p>perl Makefile.PL</p>
<p>make install</p>
<p>###</p>
<p># make install</p>
<p>&#8230;.</p>
<p>Installing /usr/bin/mk-index-usage</p>
<p>Installing /usr/bin/mk-slave-delay</p>
<p>Installing /usr/bin/mk-archiver</p>
<p>Installing /usr/bin/mk-checksum-filter</p>
<p>Installing /usr/bin/mk-slave-prefetch</p>
<p>Installing /usr/bin/mk-log-player</p>
<p>Installing /usr/bin/mk-query-profiler</p>
<p>Installing /usr/bin/mk-slave-move</p>
<p>Installing /usr/bin/mk-query-digest</p>
<p>Installing /usr/bin/mk-show-grants</p>
<p>Installing /usr/bin/mk-parallel-restore</p>
<p>Installing /usr/bin/mk-profile-compact</p>
<p>Installing /usr/bin/mk-find</p>
<p>Installing /usr/bin/mk-table-checksum</p>
<p>Installing /usr/bin/mk-fifo-split</p>
<p>Installing /usr/bin/mk-error-log</p>
<p>Installing /usr/bin/mk-visual-explain</p>
<p>Installing /usr/bin/mk-<a href="http://ourmysql.com/archives/tag/variable" class="st_tag internal_tag" rel="tag" title="标签 variable 下的日志">variable</a>-advisor</p>
<p>Installing /usr/bin/mk-kill</p>
<p>Installing /usr/bin/mk-heartbeat</p>
<p>Installing /usr/bin/mk-purge-logs</p>
<p>Installing /usr/bin/mk-query-advisor</p>
<p>Installing /usr/bin/mk-parallel-dump</p>
<p>Installing /usr/bin/mk-merge-mqd-results</p>
<p>Installing /usr/bin/mk-duplicate-key-checker</p>
<p>Installing /usr/bin/mk-upgrade</p>
<p>Installing /usr/bin/mk-deadlock-logger</p>
<p>Installing /usr/bin/mk-slave-restart</p>
<p>Installing /usr/bin/mk-slave-find</p>
<p>Installing /usr/bin/mk-loadavg</p>
<p>Installing /usr/bin/mk-table-sync</p>
<h2>3、     文档帮助</h2>
<p>man /usr/bin/mk-slave-delay</p>
<p>/usr/bin/mk-slave-delay &#8211;help</p>
<h2>4、     mk-slave-delay使用</h2>
<p><strong>示例：</strong></p>
<p>mk-slave-delay &#8211;delay 1m &#8211;interval 15s &#8211;run-time 10m slavehost</p>
<p>延时运行10分钟，slave滞后master1分钟,15秒检查下次延时情况。</p>
<p><strong>详细参数说明：</strong></p>
<p>Usage: mk-slave-delay [OPTION...] SLAVE-HOST [MASTER-HOST]</p>
<p>Options:</p>
<p>&#8211;ask-pass            Prompt for a password when connecting to MySQL</p>
<p>&#8211;charset=s       -A  Default character set</p>
<p>&#8211;config=A            Read this comma-separated list of config files; if</p>
<p>specified, this must be the first option on the command</p>
<p>line</p>
<p>&#8211;[no]continue        Continue <a href="http://ourmysql.com/archives/tag/replication" class="st_tag internal_tag" rel="tag" title="标签 replication 下的日志">replication</a> normally on exit (default yes)</p>
<p>&#8211;daemonize           Fork to the background and detach from the shell</p>
<p>&#8211;defaults-file=s -F  Only read mysql options from the given file</p>
<p>&#8211;delay=m             How far the slave should lag its master (default 1h).</p>
<p>Optional suffix s=seconds, m=minutes, h=hours, d=days;</p>
<p>if no suffix, s is used.</p>
<p>&#8211;help                Show help and exit</p>
<p>&#8211;host=s          -h  Connect to host</p>
<p>&#8211;interval=m          How frequently mk-slave-delay should check whether the</p>
<p>slave needs to be started or stopped (default 1m).</p>
<p>Optional suffix s=seconds, m=minutes, h=hours, d=days;</p>
<p>if no suffix, s is used.</p>
<p>&#8211;log=s               Print all output to this file when daemonized</p>
<p>&#8211;password=s      -p  Password to use when connecting</p>
<p>&#8211;pid=s               Create the given PID file when daemonized</p>
<p>&#8211;port=i          -P  Port number to use for connection</p>
<p>&#8211;quiet           -q  Don&#8217;t print informational messages about operation</p>
<p>&#8211;run-time=m          How long mk-slave-delay should run before exiting.</p>
<p>Optional suffix s=seconds, m=minutes, h=hours, d=days;</p>
<p>if no suffix, s is used.</p>
<p>&#8211;set-vars=s          Set these MySQL variables (default wait_timeout=10000)</p>
<p>&#8211;socket=s        -S  Socket file to use for connection</p>
<p>&#8211;use-master          Get <a href="http://ourmysql.com/archives/tag/binlog" class="st_tag internal_tag" rel="tag" title="标签 binlog 下的日志">binlog</a> positions from master, not slave</p>
<p>&#8211;user=s          -u  User for login if not current user</p>
<p>&#8211;version             Show version and exit</p>
<h2>5、     延时原理</h2>
<p>mk-slave-delay 定时地 starts /stops slave的sql_thread,以使其达到滞后master的目的。</p>
<p>2011-02-15T14:46:19 START SLAVE until master 2011-02-15T06:46:17 apollo226-bin.000290/779116659</p>
<p>2011-02-15T14:46:19 START SLAVE until master 2011-02-15T06:46:18 apollo226-bin.000290/781852897</p>
<h2>6、     应用布署</h2>
<p>脚本my_slave_delay.sh集中控制延时备份DB服务器.</p>
<p>服务器信息以host_ip port 的格式存在delay_host配置文件中。</p>
<p>head delay_host.txt</p>
<p>10.xx.xx.xxx 3601</p>
<p>usage1: sh my_slave_delay.sh</p>
<p>usage2: sh my_slave_delay.sh [delay_host] [delay] [interval]</p>
<p><strong>my_slave_delay</strong><strong>核心代码：</strong></p>
<p>delay_host=$1</p>
<p>delay_host=${delay_host:-”delay_host.txt”}</p>
<p>delay=$2</p>
<p>delay=${delay:-”8h”}</p>
<p>interval=$3</p>
<p>interval=${interval:-”2m”}</p>
<p>log_file=”my_slave_delay.log”</p>
<p>my_slave_delay(){</p>
<p>cat $delay_host |grep -v &#8216;#&#8217; | while read host port</p>
<p>do</p>
<p>echo ” /usr/bin/mk-slave-delay  -h $host -P $port &#8211;interval=$interval  &#8211;delay=$delay &amp;”</p>
<p>echo ” /usr/bin/mk-slave-delay  -h $host -P $port &#8211;interval=$interval  &#8211;delay=$delay &amp;”&gt;&gt;$log_file</p>
<p>/usr/bin/mk-slave-delay  -h $host -P $port &#8211;interval=$interval  &#8211;delay=$delay &amp;</p>
<p>sleep 1</p>
<p>done</p>
<p>}</p>
<p>### 取消延时</p>
<p>my_slave_start(){</p>
<p>echo “my_slave_start”</p>
<p>ps aux |grep “mk-slave-delay -h” -i |grep -v “grep” |  awk &#8216;{print $2,$14,$16}&#8217; | while read pid host port ;</p>
<p>do</p>
<p>echo “stop slave delay &lt;$host:$port&gt;”;</p>
<p>kill  -9 $pid</p>
<p>echo “slave start <a href="http://ourmysql.com/archives/tag/sql" class="st_tag internal_tag" rel="tag" title="标签 sql 下的日志">sql</a>_thread &lt;$host:$port&gt;”</p>
<p>echo “slave start sql_thread;” | mysql -h $host -P$port -N</p>
<p>done;</p>
<p>echo “my_slave_start done.”</p>
<p>}</p>
<h2>7、     参考</h2>
<p>http://www.maatkit.org/doc/mk-slave-delay.html</p>
<h3  class="related_post_title">相关文章</h3><ul class="related_post"><li>2010-11-15 -- <a href="http://ourmysql.com/archives/881" title="AutoMySQLBackup &#8212; 轻量级MySQL备份方案">AutoMySQLBackup &#8212; 轻量级MySQL备份方案</a></li><li>2009-08-16 -- <a href="http://ourmysql.com/archives/705" title="mysql数据库备份脚本">mysql数据库备份脚本</a></li><li>2009-07-08 -- <a href="http://ourmysql.com/archives/608" title="使用Xtrabackup备份MySQL数据库(续)">使用Xtrabackup备份MySQL数据库(续)</a></li><li>2009-04-16 -- <a href="http://ourmysql.com/archives/533" title="使用Amanda ZRM备份远程MySQL数据库">使用Amanda ZRM备份远程MySQL数据库</a></li><li>2009-03-05 -- <a href="http://ourmysql.com/archives/488" title="备份MySQL需要知道的十件事">备份MySQL需要知道的十件事</a></li><li>2009-02-23 -- <a href="http://ourmysql.com/archives/463" title="改良版本mysqldump来备份MYSQL数据库">改良版本mysqldump来备份MYSQL数据库</a></li><li>2009-02-08 -- <a href="http://ourmysql.com/archives/428" title="再谈“MySQL 数据库的备份和恢复问题” ">再谈“MySQL 数据库的备份和恢复问题” </a></li><li>2008-12-25 -- <a href="http://ourmysql.com/archives/356" title="mysql数据库自动备份">mysql数据库自动备份</a></li><li>2008-12-25 -- <a href="http://ourmysql.com/archives/353" title="用MySQL-zrm来备份和恢复MySQL数据库">用MySQL-zrm来备份和恢复MySQL数据库</a></li><li>2008-11-04 -- <a href="http://ourmysql.com/archives/239" title="MySQL 备份和恢复">MySQL 备份和恢复</a></li></ul>
	标签：<a href="http://ourmysql.com/archives/category/advanced" title="MySQL高级应用" rel="tag">MySQL高级应用</a>, <a href="http://ourmysql.com/archives/tag/%e5%a4%87%e4%bb%bd" title="备份" rel="tag">备份</a>, <a href="http://ourmysql.com/archives/tag/%e5%bb%b6%e6%97%b6%e5%a4%87%e4%bb%bd" title="延时备份" rel="tag">延时备份</a><br />
]]></content:encoded>
			<wfw:commentRss>http://ourmysql.com/archives/912/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>SQL到NOSQL的思维转变</title>
		<link>http://ourmysql.com/archives/910</link>
		<comments>http://ourmysql.com/archives/910#comments</comments>
		<pubDate>Sun, 30 Jan 2011 03:00:44 +0000</pubDate>
		<dc:creator>OurMySQL</dc:creator>
				<category><![CDATA[MySQL高级应用]]></category>
		<category><![CDATA[NoSQL]]></category>

		<guid isPermaLink="false">http://ourmysql.com/?p=910</guid>
		<description><![CDATA[NOSQL系统一般都会宣传一个特性，那就是性能好，然后为什么呢？关系型数据库发展了这么多年，各种优化工作已经做得很深了，NOSQL系统一般都是吸收关系型数据库的技术，然后，到底是什么因素束缚了关系型数据库的性能呢？我们从系统设计的角度看这个问题。]]></description>
			<content:encoded><![CDATA[<p>NOSQL系统一般都会宣传一个特性，那就是性能好，然后为什么呢？关系型数据库发展了这么多年，各种优化工作已经做得很深了，NOSQL系统一般都是吸收关系型数据库的技术，然后，到底是什么因素束缚了关系型数据库的性能呢？我们从系统设计的角度看这个问题。</p>
<p>1, 索引支持。关系型数据库创立之初没有想到今天的互联网应用对可扩展性提出如此高的要求，因此，设计时主要考虑的是简化用户的工作，SQL语言的产生促成数据库接口的标准化，从而形成了Oracle这样的数据库公司并带动了上下游产业链的发展。关系型数据库在单机存储引擎支持索引，比如Mysql的Innodb存储引擎需要支持索引，而NOSQL系统的单机存储引擎是纯粹的，只需要支持基于主键的随机读取和范围查询。NOSQL系统在系统层面提供对索引的支持，比如有一个用户表，主键为user_id，每个用户有很多属性，包括用户名，照片ID(photo_id)，照片URL，在NOSQL系统中如果需要对photo_id建立索引，可以维护一张分布式表，表的主键为&lt;photo_id, user_id&gt;形成的二元组。关系型数据库由于需要在单机存储引擎层面支持索引，大大降低了系统的可扩展性，使得单机存储引擎的设计变得很复杂。</p>
<p>2, 事务并发处理。关系型数据库有一整套的关于事务并发处理的理论，比如锁的粒度是表级，页级还是行级，多版本并发控制机制MVCC，事务的隔离级别，死锁检测，回滚，等等。然而，互联网应用大多数的特点都是多读少些，比如读和写的比例是10 : 1，并且很少有复杂事务需求，因此，一般可以采用更为简单的copy-on-write技术：单线程写，多线程读，写的时候执行copy-on-write，写不影响读服务。NOSQL系统这样的假设简化了系统的设计，减少了很多操作的overhead，提高了性能。</p>
<p>3, 动态还是静态的数据结构。关系型数据库的存储引擎总是一颗磁盘B+树，为了提高性能，可能需要有insert buffer聚合写，query cache缓存读，经常需要实现类似Linux page cache的缓存管理机制。数据库中的读和写是互相影响的，写操作也因为时不时需要将数据flush到磁盘而性能不高。简而言之，关系型数据库存储引擎的数据结构是通用的动态更新的B+树，然而，在NOSQL系统中，比如Bigtable中采用SSTable + MemTable的数据结构，数据先写入到内存的MemTable，达到一定大小或者超过一定时间才会dump到磁盘生成SSTable文件，SSTable是只读的。如果说关系型数据库存储引擎的数据结构是一颗动态的B+树，那么SSTable就是一个排好序的有序数组。很明显，实现一个有序数据比实现一个动态B+树且包含复杂的并发控制机制要简单高效地多。</p>
<p>4, Join操作。关系型数据库需要在存储引擎层面支持Join，而NOSQL系统一般根据应用来决定Join实现的方式。举个例子，有两张表：用户表和商品表，每个用户下可能有若干个商品，用户表的主键为&lt;user_id, item_id&gt;，用户和商品的关联属性存放在用户表中，商品表的主键为item_id，商品属性包括商品名，商品URL，等等。假设应用需要查询一个用户的所有商品并显示商品的详细信息，普通的做法是先从用户表查找指定用户的所有item_id，然后对每个item_id去商品表查询详细信息，即执行一次数据库Join操作，这必然带来了很多的磁盘随机读，并且由于Join带来的随机读的局部性不好，缓存的效果往往也是有限的。在NOSQL系统中，我们往往可以将用户表和商品表集成到一张宽表中，这样虽然冗余存储了商品的详细信息，却换来了查询的高效。</p>
<p>关系型数据库的性能瓶颈往往不在SQL语句解析上，而是在于需要支持完备的SQL特性。互联网公司面临的问题是应用对性能和可扩展性要求很高，并且DBA和开发工程师水平比较高，可以通过牺牲一些接口友好性来换取更好的性能。NOSQL系统的一些设计，比如通过宽表实现Join操作，互联网公司的DBA和开发工程师也做过，NOSQL系统只是加强了这种约束。从长远来看，可以总结一套约束集合，并且定义一个SQL子集，只需要支持这个SQL子集就可以在不牺牲可扩展性的前提下支持比如90%以上的互联网应用。我想，NOSQL技术发展到这一步的时候就算是比较成熟了，这也是我们最终想做的事情。我们在设计和使用NOSQL系统的时候也可以适当转化一下思维，如下：</p>
<p>1, 更大的数据量。很多人在使用Mysql的过程遇到记录条数超过一定值，比如2000W的时候，数据库性能开始下降，这个值的得出往往需要经过大量的测试。然而，大多数的NOSQL系统可扩展性都比较好，能够支持更大的数据量，因此也可以采用一些空间换时间的做法，比如通过宽表的方式实现Join。</p>
<p>2, 性能预估更加容易。关系型数据库由于复杂的并发控制，insert buffer及类似page cache的读写优化机制，性能估算相对较难，很多时候需要凭借经验或者经过测试才能得出系统的性能。然后，NOSQL系统由于存储引擎实现，并发控制机制等相对简单，可以通过硬件的性能指标在系统设计之处大致预估系统的性能，性能预估可操作性相对更强。</p>
<h3  class="related_post_title">相关文章</h3><ul class="related_post"><li>2010-12-14 -- <a href="http://ourmysql.com/archives/897" title="Handler-Socket Plugin for MySQL – SQL的功能、NoSQL的性能">Handler-Socket Plugin for MySQL – SQL的功能、NoSQL的性能</a></li><li>2010-09-27 -- <a href="http://ourmysql.com/archives/854" title="我对技术方向的一些反思">我对技术方向的一些反思</a></li></ul>
	标签：<a href="http://ourmysql.com/archives/category/advanced" title="MySQL高级应用" rel="tag">MySQL高级应用</a>, <a href="http://ourmysql.com/archives/tag/nosql" title="NoSQL" rel="tag">NoSQL</a><br />
]]></content:encoded>
			<wfw:commentRss>http://ourmysql.com/archives/910/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>处理Mysql的MySql-bin.0000X日志文件</title>
		<link>http://ourmysql.com/archives/908</link>
		<comments>http://ourmysql.com/archives/908#comments</comments>
		<pubDate>Fri, 28 Jan 2011 08:30:09 +0000</pubDate>
		<dc:creator>OurMySQL</dc:creator>
				<category><![CDATA[MySQL解错方案]]></category>
		<category><![CDATA[mysql-bin]]></category>
		<category><![CDATA[主从同步]]></category>
		<category><![CDATA[日志]]></category>

		<guid isPermaLink="false">http://ourmysql.com/?p=908</guid>
		<description><![CDATA[mysql运行一段时间后，在mysql目录下出现一堆类似 mysql-bin.000***，从mysql-bin.000001开始一直排列下来，而且占用了大量硬盘空间，高达几十个G.  对于这些超大空间 占用量的文件我们应该怎么办呢?]]></description>
			<content:encoded><![CDATA[<p>mysql运行一段时间后，在mysql目录下出现一堆类似 <a href="http://ourmysql.com/archives/tag/mysql-bin" class="st_tag internal_tag" rel="tag" title="标签 mysql-bin 下的日志">mysql-bin</a>.000***，从mysql-bin.000001开始一直排列下来，而且占用了大量硬盘空间，高达几十个G.  对于这些超大空间 占用量的文件我们应该怎么办呢?<br />
首先咱们来分析下mysql数据库文件夹中的mysql-bin.00001是什么文件？</p>
<p>mysql-bin.000001、mysql- bin.000002等文件是数据库的操作日志，例如UPDATE一个表，或者DELETE一些数据，即使该语句没有匹配的数据，这个命令也会存储到日志 文件中，还包括每个语句执行的时间，也会记录进去的。</p>
<p>任何处理呢？</p>
<p>/usr/local/mysql/bin/mysql -u root -p</p>
<p>输入密码登陆mysql后,运行命令:<br />
reset master;</p>
<h3  class="related_post_title">相关文章</h3><ul class="related_post"><li>2011-02-24 -- <a href="http://ourmysql.com/archives/917" title="PHP查询MySQL大量数据的内存占用分析">PHP查询MySQL大量数据的内存占用分析</a></li><li>2010-11-15 -- <a href="http://ourmysql.com/archives/876" title="mysql replication 报告">mysql replication 报告</a></li><li>2009-11-30 -- <a href="http://ourmysql.com/archives/788" title="mysql audit-访问日志记录 ">mysql audit-访问日志记录 </a></li><li>2009-09-07 -- <a href="http://ourmysql.com/archives/734" title="使用mysqldumpslow和mysqlsla分析mysql慢查询日志">使用mysqldumpslow和mysqlsla分析mysql慢查询日志</a></li><li>2009-08-05 -- <a href="http://ourmysql.com/archives/668" title="MySQL的日志文件">MySQL的日志文件</a></li><li>2009-06-07 -- <a href="http://ourmysql.com/archives/568" title="mysql-bin.000001文件是怎么产生的及处理方法">mysql-bin.000001文件是怎么产生的及处理方法</a></li><li>2009-02-26 -- <a href="http://ourmysql.com/archives/473" title="mysql的日志">mysql的日志</a></li><li>2009-02-17 -- <a href="http://ourmysql.com/archives/458" title="配置MySQL远程复制">配置MySQL远程复制</a></li><li>2009-02-16 -- <a href="http://ourmysql.com/archives/456" title="MySQL双向复制简单配置步骤">MySQL双向复制简单配置步骤</a></li><li>2008-11-18 -- <a href="http://ourmysql.com/archives/293" title="删除MYSQL BIN-LOG 日志">删除MYSQL BIN-LOG 日志</a></li></ul>
	标签：<a href="http://ourmysql.com/archives/tag/mysql-bin" title="mysql-bin" rel="tag">mysql-bin</a>, <a href="http://ourmysql.com/archives/category/debug" title="MySQL解错方案" rel="tag">MySQL解错方案</a>, <a href="http://ourmysql.com/archives/tag/%e4%b8%bb%e4%bb%8e%e5%90%8c%e6%ad%a5" title="主从同步" rel="tag">主从同步</a>, <a href="http://ourmysql.com/archives/tag/%e6%97%a5%e5%bf%97" title="日志" rel="tag">日志</a><br />
]]></content:encoded>
			<wfw:commentRss>http://ourmysql.com/archives/908/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>mysql unknown command ‘\”‘问题解决办法</title>
		<link>http://ourmysql.com/archives/906</link>
		<comments>http://ourmysql.com/archives/906#comments</comments>
		<pubDate>Mon, 24 Jan 2011 08:22:13 +0000</pubDate>
		<dc:creator>OurMySQL</dc:creator>
				<category><![CDATA[MySQL解错方案]]></category>
		<category><![CDATA[字符集]]></category>

		<guid isPermaLink="false">http://ourmysql.com/?p=906</guid>
		<description><![CDATA[经过多是导出导入发现，原来默认安装的mysql使用的是utf8编码，而我本机安装的是mysql gbk数据库。这样一来，备份文件恢复的时候可能就出现了格式错误。]]></description>
			<content:encoded><![CDATA[<p>在还原备份数据库的时候，遇到一个问题。</p>
<p>原来的服务器环境使用的windows，然后使用mysqldump备份出来的数据库怎么也不能在linux下的数据库中导入。导入的时候总是出现：</p>
<p>unknown command ‘\”‘</p>
<p>于是将 \’ 全部替换成 ‘  结果还是不行，导入不了。</p>
<p>但是直接将数据库文件copy过去就可以用的。copy过去后在dump出来。结果还是一样的效果</p>
<p>unknown command ‘\”‘</p>
<p>郁闷至极。</p>
<p>经过多是导出导入发现，原来默认安装的mysql使用的是utf8编码，而我本机安装的是mysql gbk数据库。这样一来，备份文件恢复的时候可能就出现了格式错误。</p>
<p>后来在dump的时候指定字符集 mysqldump加个参数： -default-character-set=gbk，再次导入备份文件，一切顺利。</p>
<p>mysqldump -u root -p  –opt –allow-keywords –default-character-set=gbk databases &gt; /PATH/XXX.<a href="http://ourmysql.com/archives/tag/sql" class="st_tag internal_tag" rel="tag" title="标签 sql 下的日志">sql</a></p>
<p>非默认字符集，在导入导出注意指定相应的字符集</p>
<h3  class="related_post_title">相关文章</h3><ul class="related_post"><li>2010-12-14 -- <a href="http://ourmysql.com/archives/893" title="Perl DBI操作MySQL的Tips">Perl DBI操作MySQL的Tips</a></li><li>2010-06-01 -- <a href="http://ourmysql.com/archives/834" title="mysql latin1转utf8 的两种方法">mysql latin1转utf8 的两种方法</a></li><li>2010-02-07 -- <a href="http://ourmysql.com/archives/808" title="MySQL库目录下db.opt文件的作用">MySQL库目录下db.opt文件的作用</a></li><li>2009-07-15 -- <a href="http://ourmysql.com/archives/625" title="数据库字符集修改">数据库字符集修改</a></li><li>2008-12-15 -- <a href="http://ourmysql.com/archives/342" title="调用存储过程时报错:Illegal mix of collations">调用存储过程时报错:Illegal mix of collations</a></li><li>2008-12-03 -- <a href="http://ourmysql.com/archives/314" title="深入Mysql字符集设置">深入Mysql字符集设置</a></li><li>2008-09-21 -- <a href="http://ourmysql.com/archives/53" title="如何更改MySQL的默认字符集">如何更改MySQL的默认字符集</a></li><li>2008-09-21 -- <a href="http://ourmysql.com/archives/49" title="小谈MySQL字符集">小谈MySQL字符集</a></li><li>2008-09-18 -- <a href="http://ourmysql.com/archives/44" title="mysql连接通道中的字符集和校验规则">mysql连接通道中的字符集和校验规则</a></li><li>2008-09-18 -- <a href="http://ourmysql.com/archives/41" title="mysql字符集与校验规则的设置">mysql字符集与校验规则的设置</a></li></ul>
	标签：<a href="http://ourmysql.com/archives/category/debug" title="MySQL解错方案" rel="tag">MySQL解错方案</a>, <a href="http://ourmysql.com/archives/tag/%e5%ad%97%e7%ac%a6%e9%9b%86" title="字符集" rel="tag">字符集</a><br />
]]></content:encoded>
			<wfw:commentRss>http://ourmysql.com/archives/906/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

