<?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>潘锦的空间 &#187; 大数据量</title>
	<atom:link href="https://www.phppan.com/tag/%e5%a4%a7%e6%95%b0%e6%8d%ae%e9%87%8f/feed/" rel="self" type="application/rss+xml" />
	<link>https://www.phppan.com</link>
	<description>SaaS SaaS架构 团队管理 技术管理 技术架构 PHP 内核 扩展 项目管理</description>
	<lastBuildDate>Sun, 10 May 2026 02:26:45 +0000</lastBuildDate>
	<language>zh-CN</language>
		<sy:updatePeriod>hourly</sy:updatePeriod>
		<sy:updateFrequency>1</sy:updateFrequency>
	<generator>https://wordpress.org/?v=3.9.40</generator>
	<item>
		<title>在线修改MySQL大表的表结构</title>
		<link>https://www.phppan.com/2012/05/online-schema-change/</link>
		<comments>https://www.phppan.com/2012/05/online-schema-change/#comments</comments>
		<pubDate>Thu, 10 May 2012 00:57:51 +0000</pubDate>
		<dc:creator><![CDATA[admin]]></dc:creator>
				<category><![CDATA[程序相关]]></category>
		<category><![CDATA[mysql]]></category>
		<category><![CDATA[OSC]]></category>
		<category><![CDATA[大数据量]]></category>

		<guid isPermaLink="false">http://www.phppan.com/?p=1674</guid>
		<description><![CDATA[问题描述 由于某个临时需求，需要给在线MySQL的某个超过千万的表增加一个字段。此表在设计之时完全按照需求实现 [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>问题描述</p>
<p>由于某个临时需求，需要给在线MySQL的某个超过千万的表增加一个字段。此表在设计之时完全按照需求实现，并没有多余的保留字段。</p>
<p>我们知道在MySQL中如果要执行ALTER TABLE操作，MySQL会通过制作原来表的一个临时副本来工作。对于表结构的修改在副本上施行，然后将新表替换原始表，此时会产生锁表，用户可以从原始表读取数据，而用户的更新和写入操作都会被lock，待新表准备好后写入新表。<br />
这对于在线的数据量较大的表来说是绝对无法容忍的，并且由于这种在线操作时间会很长，此时如果show processlist，会发现有若干的MySQL进程处于lock状态，当这种进程太多超过单台服务器允许的MySQL进程数，其它进程可能会被拒绝连接。</p>
<p>有哪些方案可以处理这个问题呢？<br />
<br />
<strong>方案1、直接ALTER TABLE</strong><br />
这个方案只能说这仅仅是一种方案，在某些非实时在线或数据量较小时有较好的表现。<br />
<br />
<strong>方案２、模拟数据库修改表结构的操作，在非数据库层实现整个过程。</strong></p>
<ol>
<li>实现业务中对于数据的读写分离</li>
<li>创建一个已经按需求修改好结构的新表</li>
<li>修改业务逻辑，将读操作指向旧表，将写操作指向新表。如果读旧表没有，再读新表，并将旧的数据写入到新表，当然这一步写入操作我们可以不用，我们可以在后台做一个定时任务将旧数据同步到新表。</li>
</ol>
<p>这种方案有一个较大的缺点，需要业务逻辑层配合实现数据的迁移，对于业务逻辑有修改，并且如果有多台机器的话，需要一台一台的修改，较费时间，但是对于MySQL的两种主要存储引擎都适用。</p>
<p> <br />
<strong>方案３、facebook <a href="http://bazaar.launchpad.net/~mysqlatfacebook/mysqlatfacebook/tools/files/head:/osc/">online schema change</a></strong><br />
facebook的OSC在整体流程上与方案2没有较大的区别，只是它在这里引入了触发器，从而不需要修改业务逻辑，在数据库层就实现了新数据的两个表的同步问题。其大概步骤如下：</p>
<ol>
<li>按需求创建新表</li>
<li>针对原始表创建触发器</li>
<li>对于原始表的更新操作都会被触发器更新到新表中</li>
<li>把原始表中的数据复制到新表中</li>
<li>将新表替换旧表</li>
</ol>
<p>fb的osc方案从数据库层解决了方案2的问题，但是它仅支持InnoDB存储引擎。</p>
<p> <br />
<strong>方案４、换一个思路，保留字段。</strong><br />
假设一切可以从头再来，我们也许可以加多一些冗余字段，各个类型都加一些，备用。只是，回不去了！<br />
<br />
<strong>方案5、再换一个思路，增加扩展表。</strong><br />
我们不在原有的表的基础上修改了，以增加扩展表的方式，将新字段的数据写入到扩展表中，修改业务逻辑，这些字段从新表中读取。<br />
<a href="http://liuzhiqiangruc.iteye.com/">志强同学</a>说这是典型的维表结构设计。<br />
暂时解决了问题，如果这些字段后续使用频率高的话，可能会有对后期维护或业务有一定的影响。<br />
<br />
<strong>后记</strong><br />
基于现有的需求，只是需要记录新的字段，所以采用了扩展表的方案。</p>
]]></content:encoded>
			<wfw:commentRss>https://www.phppan.com/2012/05/online-schema-change/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
