<?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>Thu, 27 May 2021 08:04:30 +0000</lastBuildDate>
	<language>zh-CN</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.4.1</generator>
		<item>
		<title>美团MySQL数据库巡检系统的设计与应用</title>
		<link>http://ourmysql.com/archives/1472</link>
		<comments>http://ourmysql.com/archives/1472#comments</comments>
		<pubDate>Thu, 27 May 2021 08:04:30 +0000</pubDate>
		<dc:creator>OurMySQL</dc:creator>
				<category><![CDATA[MySQL高级应用]]></category>
		<category><![CDATA[巡检]]></category>

		<guid isPermaLink="false">http://ourmysql.com/?p=1472</guid>
		<description><![CDATA[本文介绍了美团MySQL数据库巡检系统的框架和巡检内容，希望能够帮助大家了解什么是数据库巡检，美团的巡检系统架构是如何设计的，以及巡检系统是如何保障MySQL服务稳定运行的。 <a href="http://ourmysql.com/archives/1472"><br /><br />继续阅读全文 <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>巡检工作是保障系统平稳有效运行必不可少的一个环节，目的是能及时发现系统中存在的隐患。我们生活中也随处可见各种巡检，比如电力巡检、消防检查等，正是这些巡检工作，我们才能在稳定的环境下进行工作、生活。巡检对于数据库或者其他IT系统来说也同样至关重要，特别是在降低风险、提高服务稳定性方面起到了非常关键作用。</p>
<p>本文介绍了美团MySQL数据库巡检系统的框架和巡检内容，希望能够帮助大家了解什么是数据库巡检，美团的巡检系统架构是如何设计的，以及巡检系统是如何保障MySQL服务稳定运行的。</p>
<h2 id="一-背景" style="box-sizing:border-box;font-family:&quot;pingfang sc&quot;, verdana, &quot;helvetica neue&quot;, &quot;microsoft yahei&quot;, &quot;hiragino sans gb&quot;, &quot;microsoft sans serif&quot;, &quot;wenquanyi micro hei&quot;, sans-serif;font-weight:500;line-height:1.1;color:#2a2935;margin:0.8em 0px 1rem;font-size:24px;padding:0px;text-shadow:0px 1px 0px;background-color:#fdfdfd;">一、背景</h2>
<p>为了保障数据库的稳定运行，以下核心功能组件必不可少：</p>
<p><img src="https://p0.meituan.net/travelcube/3a0153c26b23d36896b868ed1700561c299217.png" alt="图1 数据库运维保障核心功能组件" style="box-sizing:border-box;border:0px;vertical-align:middle;display:block;margin:2rem auto 0.2rem;max-width:75%;cursor:pointer;" /></p>
<div class="img-figure" style="box-sizing:border-box;margin:0.5rem 0px 1.5rem;text-align:center;"><span style="box-sizing:border-box;padding:0.4rem 1rem;color:#777777;font-size:1.2rem;font-family:serif;">图1 数据库运维保障核心功能组件</span></div>
<p></p>
<p>其中，数据库巡检作为运维保障体系最重要的环节之一，能够帮助我们发现数据库存在的隐患，提前治理，做到防患于未然。对于大规模集群而言，灵活健壮的自动化巡检能力，至关重要。</p>
<p>任何系统都会经历一个原始的阶段，最早的巡检是由中控机+定时巡检脚本+前端展示构成的。但是，随着时间的推移，老巡检方案逐渐暴露出了一些问题：</p>
<ul>
<li>
<p>巡检定时任务执行依赖中控机，存在单点问题；</p>
</li>
<li>
<p>巡检结果分散在不同的库表，无法进行统计；</p>
</li>
<li>
<p>巡检脚本没有统一开发标准，不能保证执行的成功率；</p>
</li>
<li>
<p>每个巡检项都需要单独写接口取数据，并修改前端用于巡检结果展示，比较繁琐；</p>
</li>
<li>
<p>巡检发现的隐患需要DBA主动打开前端查看，再进行处理，影响整体隐患的治理速度；</p>
</li>
<li>
<p>……</p>
</li>
</ul>
<p>所以我们需要一个灵活、稳定的巡检系统来帮助我们解决这些痛点，保障数据库的稳定。</p>
<h2 id="二-设计原则" style="box-sizing:border-box;font-family:&quot;pingfang sc&quot;, verdana, &quot;helvetica neue&quot;, &quot;microsoft yahei&quot;, &quot;hiragino sans gb&quot;, &quot;microsoft sans serif&quot;, &quot;wenquanyi micro hei&quot;, sans-serif;font-weight:500;line-height:1.1;color:#2a2935;margin:0.8em 0px 1rem;font-size:24px;padding:0px;text-shadow:0px 1px 0px;background-color:#fdfdfd;">二、设计原则</h2>
<p>巡检系统的设计原则，我们从以下三个方面进行考虑：</p>
<p><span style="box-sizing:border-box;font-weight:700;color:#000000;">稳定</span>：巡检作为保证数据库稳定的工具，它自身的稳定性也必须有所保证； <span style="box-sizing:border-box;font-weight:700;color:#000000;">高效</span>：以用户为中心，尽量化繁为简，降低用户的使用成本，让新同学也能迅速上手治理和管理隐患；提高新巡检部署效率，随着架构、版本、基础模块等运维环境不断变化，新的巡检需求层出不穷，更快的部署等于更早的保障； <span style="box-sizing:border-box;font-weight:700;color:#000000;">可运营</span>：用数据做基础，对巡检隐患进行运营，包括推进隐患治理，查看治理效率、趋势、薄弱点等。</p>
<h2 id="三-系统架构" style="box-sizing:border-box;font-family:&quot;pingfang sc&quot;, verdana, &quot;helvetica neue&quot;, &quot;microsoft yahei&quot;, &quot;hiragino sans gb&quot;, &quot;microsoft sans serif&quot;, &quot;wenquanyi micro hei&quot;, sans-serif;font-weight:500;line-height:1.1;color:#2a2935;margin:0.8em 0px 1rem;font-size:24px;padding:0px;text-shadow:0px 1px 0px;background-color:#fdfdfd;">三、系统架构</h2>
<p>美团MySQL数据库巡检系统架构图设计如下。接下来，我们按照架构图从下到上的顺序来对巡检系统主要模块进行简单的介绍：</p>
<p><img src="https://p0.meituan.net/travelcube/727c56e76d99e241de17569afc293e81174230.png" alt="图2 美团MySQL数据库巡检系统架构图" style="box-sizing:border-box;border:0px;vertical-align:middle;display:block;margin:2rem auto 0.2rem;max-width:75%;cursor:pointer;" /></p>
<div class="img-figure" style="box-sizing:border-box;margin:0.5rem 0px 1.5rem;text-align:center;"><span style="box-sizing:border-box;padding:0.4rem 1rem;color:#777777;font-size:1.2rem;font-family:serif;">图2 美团MySQL数据库巡检系统架构图</span></div>
<p></p>
<h3 id="1-执行层" style="box-sizing:border-box;font-family:&quot;pingfang sc&quot;, verdana, &quot;helvetica neue&quot;, &quot;microsoft yahei&quot;, &quot;hiragino sans gb&quot;, &quot;microsoft sans serif&quot;, &quot;wenquanyi micro hei&quot;, sans-serif;font-weight:500;line-height:1.1;color:#2a2935;margin:0.8em 0px 1rem;font-size:22px;padding:0px;text-shadow:0px 1px 0px;background-color:#fdfdfd;">1. 执行层</h3>
<p><span style="box-sizing:border-box;font-weight:700;color:#000000;">巡检执行环境</span>：由多台巡检执行机组成，巡检任务脚本会同时部署在所有执行机上。执行机会定时从巡检Git仓库拉取最新的脚本，脚本使用Python Virtualenv + Git进行管理，方便扩充新的执行机。</p>
<p><span style="box-sizing:border-box;font-weight:700;color:#000000;">任务调度</span>：巡检任务使用了美团基础架构部研发的分布式定时任务系统Crane进行调度，解决传统定时任务单点问题。Crane会随机指派某一台执行机执行任务，假如这台执行机出现故障，会指派其他执行机重新执行任务。一般一个巡检任务对应着一个巡检项，巡检任务会针对特定的巡检目标根据一定的规则来判断是否存在隐患。</p>
<p><span style="box-sizing:border-box;font-weight:700;color:#000000;">巡检目标</span>：除了对生产数据库进行巡检以外，还会对高可用组件、中间件等数据库周边产品进行巡检，尽可能覆盖所有会引发数据库故障的风险点。</p>
<h3 id="2-存储层" style="box-sizing:border-box;font-family:&quot;pingfang sc&quot;, verdana, &quot;helvetica neue&quot;, &quot;microsoft yahei&quot;, &quot;hiragino sans gb&quot;, &quot;microsoft sans serif&quot;, &quot;wenquanyi micro hei&quot;, sans-serif;font-weight:500;line-height:1.1;color:#2a2935;margin:0.8em 0px 1rem;font-size:22px;padding:0px;text-shadow:0px 1px 0px;background-color:#fdfdfd;">2. 存储层</h3>
<p><span style="box-sizing:border-box;font-weight:700;color:#000000;">巡检数据库</span>：主要用来保存巡检相关数据。为了规范和简化流程，我们将巡检发现的隐患保存到数据库中，提供了通用的入库函数，能够实现以下功能：</p>
<ul>
<li>
<p>自动补齐隐患负责人、隐患发现时间等信息；</p>
</li>
<li>
<p>入库操作幂等；</p>
</li>
<li>
<p>支持半结构化的巡检结果入库，不同巡检的隐患结果包括不同的属性，比如巡检A的隐患有“中间件类型”，巡检B有“主库CPU核数”，以上不同结构的数据均可解析入库；</p>
</li>
<li>
<p>针对表粒度的隐患项，如果分库分表的表出现隐患，会自动合并成一个逻辑表隐患入库。</p>
</li>
</ul>
<p><span style="box-sizing:border-box;font-weight:700;color:#000000;">巡检脚本Git仓库</span>：用来管理巡检脚本。为了方便DBA添加巡检，在系统建设过程中，我们增加了多个公共函数，用来降低开发新巡检的成本，也方便将老的巡检脚本迁移到新的体系中。</p>
<h3 id="3-应用层" style="box-sizing:border-box;font-family:&quot;pingfang sc&quot;, verdana, &quot;helvetica neue&quot;, &quot;microsoft yahei&quot;, &quot;hiragino sans gb&quot;, &quot;microsoft sans serif&quot;, &quot;wenquanyi micro hei&quot;, sans-serif;font-weight:500;line-height:1.1;color:#2a2935;margin:0.8em 0px 1rem;font-size:22px;padding:0px;text-shadow:0px 1px 0px;background-color:#fdfdfd;">3. 应用层</h3>
<p><span style="box-sizing:border-box;font-weight:700;color:#000000;">集成到数据库运维平台</span>：作为隐患明细展示、配置巡检展示、管理白名单等功能的入口。为了提高隐患治理效率。我们做了以下设计。</p>
<ul>
<li>
<p>隐患明细展示页面会标注每个隐患出现的天数，便于追踪隐患出现原因。</p>
</li>
<li>
<p>配置新的巡检展示时必须要同时制定隐患解决方案，确保隐患治理有章可循，避免错误的治理方式导致“错上加错”。</p>
</li>
</ul>
<p><span style="box-sizing:border-box;font-weight:700;color:#000000;">隐患运营后台</span>：这个模块主要目的是推进隐患的治理。</p>
<ul>
<li>
<p>运营报表，帮助管理者从全局角度掌握隐患治理进展，报表包括隐患趋势、存量分布、增量分布、平均治理周期等核心内容，进而由上到下推动隐患治理；报表数据同样是通过crane定时任务计算获得。</p>
</li>
<li>
<p>隐患治理催办功能，用来督促DBA处理隐患。催办内容中会带有隐患具体内容、出现时长、处理方案等。催办形式包括大象消息、告警，具体选用哪种形式可根据巡检关键程度做相应配置。</p>
</li>
</ul>
<p><span style="box-sizing:border-box;font-weight:700;color:#000000;">外部数据服务</span>：主要是将巡检隐患数据提供给美团内部其他平台或项目使用，让巡检数据发挥更大的价值。</p>
<ul>
<li>
<p>对接先知平台（美团SRE团队开发的主要面向RD用户的风险发现和运营平台），平台接收各服务方上报的隐患数据，以RD视角从组织架构维度展示各服务的风险点，并跟进RD处理进度。巡检系统会把需要RD参与治理的隐患，比如大表、无唯一键表等，借助先知平台统一推送给RD进行治理。</p>
</li>
<li>
<p>运维周报，主要面向业务线RD负责人和业务线DBA，以静态报告形式展示业务线数据库运行情况以及存在的问题，巡检隐患是报告内容之一。</p>
</li>
</ul>
<h2 id="四-巡检项目" style="box-sizing:border-box;font-family:&quot;pingfang sc&quot;, verdana, &quot;helvetica neue&quot;, &quot;microsoft yahei&quot;, &quot;hiragino sans gb&quot;, &quot;microsoft sans serif&quot;, &quot;wenquanyi micro hei&quot;, sans-serif;font-weight:500;line-height:1.1;color:#2a2935;margin:0.8em 0px 1rem;font-size:24px;padding:0px;text-shadow:0px 1px 0px;background-color:#fdfdfd;">四、巡检项目</h2>
<p>巡检项目根据负责方分为DBA和RD，DBA主要负责处理数据库基础功能组件以及影响服务稳定性的隐患。RD主要负责库表设计缺陷、数据库使用不规范等引起的业务故障或性能问题的隐患。也存在需要他们同时参与治理的巡检项，比如“磁盘可用空间预测”等。目前巡检项目共64个，类目分布情况如下图所示：</p>
<p><img src="https://p0.meituan.net/travelcube/5e212c895f1b1b22bb2a254008b2af4841025.png" alt="图3 巡检项类目分布" style="box-sizing:border-box;border:0px;vertical-align:middle;display:block;margin:2rem auto 0.2rem;max-width:75%;cursor:pointer;" /></p>
<div class="img-figure" style="box-sizing:border-box;margin:0.5rem 0px 1.5rem;text-align:center;"><span style="box-sizing:border-box;padding:0.4rem 1rem;color:#777777;font-size:1.2rem;font-family:serif;">图3 巡检项类目分布</span></div>
<p></p>
<p><span style="box-sizing:border-box;font-weight:700;color:#000000;">集群</span>：主要检查集群拓扑、核心参数等集群层面的隐患； <span style="box-sizing:border-box;font-weight:700;color:#000000;">机器</span>：主要检查服务器硬件层面的隐患； <span style="box-sizing:border-box;font-weight:700;color:#000000;">Schema/SQL</span>：检查表结构设计、数据库使用、SQL质量等方面的隐患； <span style="box-sizing:border-box;font-weight:700;color:#000000;">高可用/备份/中间件/报警</span>：主要检查相关核心功能组件是否存在隐患。</p>
<p>下面，我们通过列举几个巡检任务来对巡检项做简单的说明：</p>
<p><img src="https://p0.meituan.net/travelcube/6db1dac0bd0adc84fbe3a793e9251fe0441697.png" style="box-sizing:border-box;border:0px;vertical-align:middle;display:block;margin:2rem auto 0.2rem;max-width:75%;cursor:pointer;" /></p>
<h2 id="五-成果" style="box-sizing:border-box;font-family:&quot;pingfang sc&quot;, verdana, &quot;helvetica neue&quot;, &quot;microsoft yahei&quot;, &quot;hiragino sans gb&quot;, &quot;microsoft sans serif&quot;, &quot;wenquanyi micro hei&quot;, sans-serif;font-weight:500;line-height:1.1;color:#2a2935;margin:0.8em 0px 1rem;font-size:24px;padding:0px;text-shadow:0px 1px 0px;background-color:#fdfdfd;">五、成果</h2>
<p>美团MySQL巡检系统已稳定运行近一年时间，基于新巡检体系上线的巡检项49个。通过巡检体系持续运行，在团队的共同努力下，我们共治理了8000+核心隐患，近3个月隐患治理周期平均不超过4天，将隐患总数持续保持在极小的量级，有效地保障了数据库的稳定。</p>
<p><img src="https://p0.meituan.net/travelcube/44a3590e3be54787bca4a95354a819fd50823.png" alt="图4 隐患运营-团队内各虚拟小组隐患平均治理周期" style="box-sizing:border-box;border:0px;vertical-align:middle;display:block;margin:2rem auto 0.2rem;max-width:75%;cursor:pointer;" /></p>
<div class="img-figure" style="box-sizing:border-box;margin:0.5rem 0px 1.5rem;text-align:center;"><span style="box-sizing:border-box;padding:0.4rem 1rem;color:#777777;font-size:1.2rem;font-family:serif;">图4 隐患运营-团队内各虚拟小组隐患平均治理周期</span></div>
<p></p>
<p>下面的隐患趋势图，展示了近一年中隐患的个数，数量突然增长是由于新的巡检项上线。从整体趋势上看，隐患存量有非常明显的下降。</p>
<p><img src="https://p1.meituan.net/travelcube/993118c88889b7bf07b83fd37f17d417118281.png" alt="图5 隐患运营-隐患总量趋势情况" style="box-sizing:border-box;border:0px;vertical-align:middle;display:block;margin:2rem auto 0.2rem;max-width:75%;cursor:pointer;" /></p>
<div class="img-figure" style="box-sizing:border-box;margin:0.5rem 0px 1.5rem;text-align:center;"><span style="box-sizing:border-box;padding:0.4rem 1rem;color:#777777;font-size:1.2rem;font-family:serif;">图5 隐患运营-隐患总量趋势情况</span></div>
<p></p>
<p>除了推动内部隐患治理之外，我们还通过对接先知平台，积极推动RD治理隐患数量超过5000个。</p>
<p><img src="https://p0.meituan.net/travelcube/1d13dca3e0821da7c8baf544dd31b9c215515.png" alt="图6 对接先知-推动RD治理隐患" style="box-sizing:border-box;border:0px;vertical-align:middle;display:block;margin:2rem auto 0.2rem;max-width:75%;cursor:pointer;" /></p>
<div class="img-figure" style="box-sizing:border-box;margin:0.5rem 0px 1.5rem;text-align:center;"><span style="box-sizing:border-box;padding:0.4rem 1rem;color:#777777;font-size:1.2rem;font-family:serif;">图6 对接先知-推动RD治理隐患</span></div>
<p></p>
<p>为了提升用户体验，我们在提升准确率方面也做了重点的投入，让每一个巡检在上线前都会经过严格的测试和校验。</p>
<p>对比其他先知接入方，DBA上报隐患在总量、转化率、反馈率几个指标上都处于较高水平，可见我们上报的隐患风险也得到了RD的认可。</p>
<p><img src="https://p0.meituan.net/travelcube/3f1927df938374ff35d913a3988e9590206830.png" alt="图7 对接先知-各接入方上报隐患情况" style="box-sizing:border-box;border:0px;vertical-align:middle;display:block;margin:2rem auto 0.2rem;max-width:75%;cursor:pointer;" /></p>
<div class="img-figure" style="box-sizing:border-box;margin:0.5rem 0px 1.5rem;text-align:center;"><span style="box-sizing:border-box;padding:0.4rem 1rem;color:#777777;font-size:1.2rem;font-family:serif;">图7 对接先知-各接入方上报隐患情况</span></div>
<p></p>
<p><span style="box-sizing:border-box;font-weight:700;color:#000000;">指标说明：</span></p>
<ul>
<li>
<p>反馈率 = 截止到当前时刻反馈过的风险事件数量/截止到当前时刻产生的风险事件总量 * 100%；</p>
</li>
<li>
<p>反馈准确率 = 截止到当前时刻反馈准确的风险事件数量/截止到当前时刻反馈过的风险事件总量 * 100%；</p>
</li>
<li>
<p>转化率 = 截止到当前时刻用户反馈准确且需要处理的风险事件数量 / 截止到当前时刻产生的风险事件总量 * 100%。</p>
</li>
</ul>
<h2 id="六-未来规划" style="box-sizing:border-box;font-family:&quot;pingfang sc&quot;, verdana, &quot;helvetica neue&quot;, &quot;microsoft yahei&quot;, &quot;hiragino sans gb&quot;, &quot;microsoft sans serif&quot;, &quot;wenquanyi micro hei&quot;, sans-serif;font-weight:500;line-height:1.1;color:#2a2935;margin:0.8em 0px 1rem;font-size:24px;padding:0px;text-shadow:0px 1px 0px;background-color:#fdfdfd;">六、未来规划</h2>
<p>除了继续完善补充巡检项以外，未来巡检系统还会在以下几个方向继续探索迭代：</p>
<ul>
<li>
<p>提高自动化能力，完善CI和审计；</p>
</li>
<li>
<p>加强运营能力，进一步细化每个隐患的重要程度，辅助决策治理优先级；</p>
</li>
<li>
<p>隐患自动修复。</p>
</li>
</ul>
<h2 id="作者简介" style="box-sizing:border-box;font-family:&quot;pingfang sc&quot;, verdana, &quot;helvetica neue&quot;, &quot;microsoft yahei&quot;, &quot;hiragino sans gb&quot;, &quot;microsoft sans serif&quot;, &quot;wenquanyi micro hei&quot;, sans-serif;font-weight:500;line-height:1.1;color:#2a2935;margin:0.8em 0px 1rem;font-size:24px;padding:0px;text-shadow:0px 1px 0px;background-color:#fdfdfd;">作者简介</h2>
<p>王琦，基础架构部DBA组成员，2018年加入美团，负责MySQL数据库运维/数据库巡检系统/监控/自动化运维周报/运维数据集市建设等工作。</p>
<p></p>
<h2  class="related_post_title">猜想失败，您看看下面的文章有用吗？</h2><ul class="related_post"><li><a href="http://ourmysql.com/archives/1429" title="MySQL怎么计算打开文件数?">MySQL怎么计算打开文件数?</a></li><li><a href="http://ourmysql.com/archives/424" title="MySQL语句优化的原则">MySQL语句优化的原则</a></li><li><a href="http://ourmysql.com/archives/965" title="使用 Sphinx 更好地进行 MySQL 搜索">使用 Sphinx 更好地进行 MySQL 搜索</a></li><li><a href="http://ourmysql.com/archives/705" title="mysql数据库备份脚本">mysql数据库备份脚本</a></li><li><a href="http://ourmysql.com/archives/1236" title="案例：MySQL优化器如何选择索引和JOIN顺序">案例：MySQL优化器如何选择索引和JOIN顺序</a></li><li><a href="http://ourmysql.com/archives/1209" title="MySQL源码：Range优化相关的数据结构">MySQL源码：Range优化相关的数据结构</a></li><li><a href="http://ourmysql.com/archives/1298" title="RDS MySql支持online ddl">RDS MySql支持online ddl</a></li><li><a href="http://ourmysql.com/archives/1315" title="MYSQL表无法修复的解决办法">MYSQL表无法修复的解决办法</a></li><li><a href="http://ourmysql.com/archives/379" title="随机获取N条数据库记录的四个方法">随机获取N条数据库记录的四个方法</a></li><li><a href="http://ourmysql.com/archives/1102" title="Mysql源码学习——Thread Manager">Mysql源码学习——Thread Manager</a></li></ul>]]></content:encoded>
			<wfw:commentRss>http://ourmysql.com/archives/1472/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>按照重要程度划分数据库级别</title>
		<link>http://ourmysql.com/archives/1471</link>
		<comments>http://ourmysql.com/archives/1471#comments</comments>
		<pubDate>Wed, 26 May 2021 23:07:37 +0000</pubDate>
		<dc:creator>OurMySQL</dc:creator>
				<category><![CDATA[MySQL初级应用]]></category>
		<category><![CDATA[程度]]></category>
		<category><![CDATA[级别]]></category>

		<guid isPermaLink="false">http://ourmysql.com/?p=1471</guid>
		<description><![CDATA[按照重要程度划分数据库级别 级别 D C B A S 影响面 小于10人 10-1000人 1000-1000 […] <a href="http://ourmysql.com/archives/1471"><br /><br />继续阅读全文 <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<table style="width:712px;" border="1" width="1623">
<tbody>
<tr>
<td style="width:702px;" colspan="6">按照重要程度划分数据库级别</td>
</tr>
<tr>
<td style="width:83px;">级别</td>
<td style="width:128px;">D</td>
<td style="width:156px;">C</td>
<td style="width:93px;">B</td>
<td style="width:128px;">A</td>
<td style="width:84px;">S</td>
</tr>
<tr>
<td style="width:83px;">影响面</td>
<td style="width:128px;">小于10人</td>
<td style="width:156px;">10-1000人</td>
<td style="width:93px;">1000-100000人</td>
<td style="width:128px;">100000-1000000人</td>
<td style="width:84px;">1000000人以上</td>
</tr>
<tr>
<td style="width:83px;">业务类型举例</td>
<td style="width:128px;">测试/开发系统，小型OA 记账软件等</td>
<td style="width:156px;">中型OA ERP 财务软件等</td>
<td style="width:93px;">中大型ERP MES HRM ，大型医院HIS</td>
<td style="width:128px;">电信CRM 银行BANKING等</td>
<td style="width:84px;">大型公共应用 如12306等</td>
</tr>
<tr>
<td style="width:83px;">灾难救援价格</td>
<td style="width:128px;">500-5000</td>
<td style="width:156px;">5千到三万</td>
<td style="width:93px;">3万到10万</td>
<td style="width:128px;">10万到50万</td>
<td style="width:84px;">50万以上</td>
</tr>
<tr>
<td style="width:83px;">一般的配套设施</td>
<td style="width:128px;">几乎无任何有效备份</td>
<td style="width:156px;">少量磁盘上逻辑备份</td>
<td style="width:93px;">可能有物理备份+其他备份形式</td>
<td style="width:128px;">物理/逻辑备份+DataGuard,OGG等物理/逻辑灾备;存储级别冗余等+多数据中心冗余</td>
<td style="width:84px;">都有</td>
</tr>
</tbody>
</table>
<h2  class="related_post_title">猜想失败，您看看下面的文章有用吗？</h2><ul class="related_post"><li><a href="http://ourmysql.com/archives/1283" title="MySQL Innodb数据库性能实践——VARCHAR vs CHAR">MySQL Innodb数据库性能实践——VARCHAR vs CHAR</a></li><li><a href="http://ourmysql.com/archives/242" title="数据库的设计方法!">数据库的设计方法!</a></li><li><a href="http://ourmysql.com/archives/705" title="mysql数据库备份脚本">mysql数据库备份脚本</a></li><li><a href="http://ourmysql.com/archives/1226" title="MySQL数据库实时同步数据到Hadoop分布式文件系统的工具Applier">MySQL数据库实时同步数据到Hadoop分布式文件系统的工具Applier</a></li><li><a href="http://ourmysql.com/archives/547" title="MySQL时间字段究竟使用INT还是DateTime？">MySQL时间字段究竟使用INT还是DateTime？</a></li><li><a href="http://ourmysql.com/archives/428" title="再谈“MySQL 数据库的备份和恢复问题” ">再谈“MySQL 数据库的备份和恢复问题” </a></li><li><a href="http://ourmysql.com/archives/777" title="教你写MySQL UDF ">教你写MySQL UDF </a></li><li><a href="http://ourmysql.com/archives/788" title="mysql audit-访问日志记录 ">mysql audit-访问日志记录 </a></li><li><a href="http://ourmysql.com/archives/1429" title="MySQL怎么计算打开文件数?">MySQL怎么计算打开文件数?</a></li><li><a href="http://ourmysql.com/archives/1008" title="mysql执行show processlist出现”unauthenticated user”">mysql执行show processlist出现”unauthenticated user”</a></li></ul>]]></content:encoded>
			<wfw:commentRss>http://ourmysql.com/archives/1471/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>修复 MySQL 编码问题</title>
		<link>http://ourmysql.com/archives/1470</link>
		<comments>http://ourmysql.com/archives/1470#comments</comments>
		<pubDate>Mon, 17 May 2021 23:26:15 +0000</pubDate>
		<dc:creator>OurMySQL</dc:creator>
				<category><![CDATA[MySQL基础知识]]></category>
		<category><![CDATA[编码]]></category>

		<guid isPermaLink="false">http://ourmysql.com/?p=1470</guid>
		<description><![CDATA[有个疑似 OCD 患者最近抽风升级了一下 MySQL 数据库，然后发现 blog 里面全都变成了乱码。
那乱码的模式一看就是把 utf8 直接扔进了 latin1 的数据库，一看 SHOW CREATE TABLE mt_entry 发现果然如此。 <a href="http://ourmysql.com/archives/1470"><br /><br />继续阅读全文 <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p> &nbsp; &nbsp;有个疑似 OCD 患者最近抽风升级了一下 MySQL 数据库，然后发现 blog 里面全都变成了乱码。</p>
<p> &nbsp; &nbsp;那乱码的模式一看就是把 utf8 直接扔进了 latin1 的数据库，一看 SHOW CREATE TABLE mt_entry 发现果然如此。</p>
<p> &nbsp; &nbsp;略有些慌神，看了 MySQL 文档发现用 ALTER TABLE 的 CONVERT TO 硬来有点不太行好，遂想到可以试试看 mysqldump，于是做了：</p>
<p> &nbsp; &nbsp;当作 latin1(不然会再按 utf8 编码一次)：</p>
<p> &nbsp; &nbsp;mysqldump mt_delphij &#8211;default-character-set=latin1 -r utf8.dump</p>
<p> &nbsp; &nbsp;把里面的 CHARSET=latin1 替换为 CHARSET=utf8：</p>
<p> &nbsp; &nbsp;sed -e s,CHARSET=latin1,CHARSET=utf8,g &lt; utf8.dump &gt; utf8.dump.edited</p>
<p> &nbsp; &nbsp;删掉其中的 SET NAMES latin1。</p>
<p> &nbsp; &nbsp;然后重新导入：</p>
<div class="highlight">
<pre class="chroma">mysql -uroot -p --default-character-set=utf8 mt_delphij
mysql&gt; SET names utf8;
mysql&gt; SOURCE utf8.dump.edited;
</pre>
</div>
<p> &nbsp; &nbsp;还好没用到 zfs rollback。</p>
<h2  class="related_post_title">猜想失败，您看看下面的文章有用吗？</h2><ul class="related_post"><li><a href="http://ourmysql.com/archives/702" title="CHAR定长字段对MyISAM和InnoDB的意义">CHAR定长字段对MyISAM和InnoDB的意义</a></li><li><a href="http://ourmysql.com/archives/1234" title="MySQL5.6主键的在线DDL变更测试">MySQL5.6主键的在线DDL变更测试</a></li><li><a href="http://ourmysql.com/archives/829" title="DBA工作初体验之心惊胆战">DBA工作初体验之心惊胆战</a></li><li><a href="http://ourmysql.com/archives/876" title="mysql replication 报告">mysql replication 报告</a></li><li><a href="http://ourmysql.com/archives/574" title="在同一台主机配置MySQL Cluster">在同一台主机配置MySQL Cluster</a></li><li><a href="http://ourmysql.com/archives/1205" title="量化InnoDB group commit的效果">量化InnoDB group commit的效果</a></li><li><a href="http://ourmysql.com/archives/1405" title="EXPLAIN执行计划中要重点关注哪些要素">EXPLAIN执行计划中要重点关注哪些要素</a></li><li><a href="http://ourmysql.com/archives/435" title="count() in mysql">count() in mysql</a></li><li><a href="http://ourmysql.com/archives/320" title="MySQL 中 Join 的基本实现原理">MySQL 中 Join 的基本实现原理</a></li><li><a href="http://ourmysql.com/archives/448" title="Mysql + DRBD + Heartbeat(v1)基本配置笔记及切换测试">Mysql + DRBD + Heartbeat(v1)基本配置笔记及切换测试</a></li></ul>]]></content:encoded>
			<wfw:commentRss>http://ourmysql.com/archives/1470/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>如何获取 MySQL innodb 的 B+tree 的高度</title>
		<link>http://ourmysql.com/archives/1469</link>
		<comments>http://ourmysql.com/archives/1469#comments</comments>
		<pubDate>Wed, 05 Feb 2020 15:06:48 +0000</pubDate>
		<dc:creator>OurMySQL</dc:creator>
				<category><![CDATA[MySQL基础知识]]></category>
		<category><![CDATA[B+tree]]></category>
		<category><![CDATA[InnoDB]]></category>
		<category><![CDATA[mysql]]></category>
		<category><![CDATA[tree]]></category>

		<guid isPermaLink="false">http://ourmysql.com/?p=1469</guid>
		<description><![CDATA[MySQL 的 innodb 引擎之所以使用 B+tree 来存储索引，就是想尽量减少数据查询时磁盘 IO 次数。树的高度直接影响了查询的性能。一般树的高度在 3~4 层较为适宜。数据库分表的目的也是为了控制树的高度。那么如何获取树的高度呢？下面使用一个示例来说明如何获取树的高度。​ <a href="http://ourmysql.com/archives/1469"><br /><br />继续阅读全文 <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<h2 style="margin:24px 0px;padding:0px;border-width:0px 0px 1px;border-bottom-style:solid;border-bottom-color:#e6e6e6;font-size:18px;vertical-align:baseline;clear:both;line-height:1.846153846;caret-color:#444444;color:#444444;font-family:&quot;microsoft yahei&quot;, &quot;helvetica neue&quot;, helvetica, arial, sans-serif;letter-spacing:1px;">前言</h2>
<p style="padding:0px;border:0px;font-size:15px;vertical-align:baseline;word-break:break-all;caret-color:#444444;color:#444444;font-family:&quot;microsoft yahei&quot;, &quot;helvetica neue&quot;, helvetica, arial, sans-serif;letter-spacing:1px;margin-top:0px;margin-bottom:10px;">MySQL 的 innodb 引擎之所以使用 B+tree 来存储索引，就是想尽量减少数据查询时磁盘 IO 次数。树的高度直接影响了查询的性能。一般树的高度在 3~4 层较为适宜。数据库分表的目的也是为了控制树的高度。那么如何获取树的高度呢？下面使用一个示例来说明如何获取树的高度。</p>
<h2 style="margin:24px 0px;padding:0px;border-width:0px 0px 1px;border-bottom-style:solid;border-bottom-color:#e6e6e6;font-size:18px;vertical-align:baseline;clear:both;line-height:1.846153846;caret-color:#444444;color:#444444;font-family:&quot;microsoft yahei&quot;, &quot;helvetica neue&quot;, helvetica, arial, sans-serif;letter-spacing:1px;">示例数据准备</h2>
<p style="padding:0px;border:0px;font-size:15px;vertical-align:baseline;word-break:break-all;caret-color:#444444;color:#444444;font-family:&quot;microsoft yahei&quot;, &quot;helvetica neue&quot;, helvetica, arial, sans-serif;letter-spacing:1px;margin-top:0px;margin-bottom:10px;">建表语句如下：</p>
<div style="margin:0px;padding:0px;border:0px;font-size:14px;vertical-align:baseline;caret-color:#444444;color:#444444;font-family:&quot;microsoft yahei&quot;, &quot;helvetica neue&quot;, helvetica, arial, sans-serif;letter-spacing:1px;">
<pre class="null">CREATETABLE`user` (
  `id` int(11) NOTNULLAUTO_INCREMENT,
  `name` varchar(100) CHARACTERSETlatin1 DEFAULTNULL,
  `age` int(11) DEFAULTNULL,
  PRIMARYKEY(`id`),
  KEY`name` (`name`),
  KEY`age` (`age`)
) ENGINE=InnoDB DEFAULTCHARSET=utf8</pre>
</div>
<p style="padding:0px;border:0px;font-size:15px;vertical-align:baseline;word-break:break-all;caret-color:#444444;color:#444444;font-family:&quot;microsoft yahei&quot;, &quot;helvetica neue&quot;, helvetica, arial, sans-serif;letter-spacing:1px;margin-top:0px;margin-bottom:10px;">表中插入100万条数据。数据如下：</p>
<div style="margin:0px;padding:0px;border:0px;font-size:14px;vertical-align:baseline;caret-color:#444444;color:#444444;font-family:&quot;microsoft yahei&quot;, &quot;helvetica neue&quot;, helvetica, arial, sans-serif;letter-spacing:1px;">
<pre class="null">mysql&gt; select* fromuserlimit 2\G
*************************** 1. row ***************************
  id: 110000
name: ab
 age: 100
*************************** 2. row ***************************
  id: 110001
name: ab
 age: 100
2 rowsinset(0.00 sec)</pre>
</div>
<h2 style="margin:24px 0px;padding:0px;border-width:0px 0px 1px;border-bottom-style:solid;border-bottom-color:#e6e6e6;font-size:18px;vertical-align:baseline;clear:both;line-height:1.846153846;caret-color:#444444;color:#444444;font-family:&quot;microsoft yahei&quot;, &quot;helvetica neue&quot;, helvetica, arial, sans-serif;letter-spacing:1px;">通过查询相关数据表获取树的高度</h2>
<p style="padding:0px;border:0px;font-size:15px;vertical-align:baseline;word-break:break-all;caret-color:#444444;color:#444444;font-family:&quot;microsoft yahei&quot;, &quot;helvetica neue&quot;, helvetica, arial, sans-serif;letter-spacing:1px;margin-top:0px;margin-bottom:10px;">以 MySQL5.6 版本为例说明如何获取树的高度。</p>
<h3 style="margin:24px 0px;padding:0px;border:0px;font-size:18px;vertical-align:baseline;line-height:0.8;caret-color:#444444;color:#444444;font-family:&quot;microsoft yahei&quot;, &quot;helvetica neue&quot;, helvetica, arial, sans-serif;letter-spacing:1px;">首先获取 page_no</h3>
<div style="margin:0px;padding:0px;border:0px;font-size:14px;vertical-align:baseline;caret-color:#444444;color:#444444;font-family:&quot;microsoft yahei&quot;, &quot;helvetica neue&quot;, helvetica, arial, sans-serif;letter-spacing:1px;">
<pre class="null">mysql&gt; SELECTb.name, a.name, index_id, type, a.space, a.PAGE_NO FROMinformation_schema.INNODB_SYS_INDEXES a, information_schema.INNODB_SYS_TABLES b WHEREa.table_id = b.table_id ANDa.space&lt;&gt; 0 andb.name='test/user';
+-----------+---------+----------+------+-------+---------+
| name      | name    | index_id | type | space| PAGE_NO |
+-----------+---------+----------+------+-------+---------+
| test/user| PRIMARY|       22 |    3 |     6 |       3 |
| test/user| name    |       23 |    0 |     6 |       4 |
| test/user| age     |       24 |    0 |     6 |       5 |
+-----------+---------+----------+------+-------+---------+
3 rowsinset(0.00 sec)</pre>
</div>
<p style="padding:0px;border:0px;font-size:15px;vertical-align:baseline;word-break:break-all;caret-color:#444444;color:#444444;font-family:&quot;microsoft yahei&quot;, &quot;helvetica neue&quot;, helvetica, arial, sans-serif;letter-spacing:1px;margin-top:0px;margin-bottom:10px;">page_no 是索引树中Root页的序列号。其它各项的含义可以参照：<br />https://dev.mysql.com/doc/refman/5.6/en/innodb-sys-indexes-table.html</p>
<h3 style="margin:24px 0px;padding:0px;border:0px;font-size:18px;vertical-align:baseline;line-height:0.8;caret-color:#444444;color:#444444;font-family:&quot;microsoft yahei&quot;, &quot;helvetica neue&quot;, helvetica, arial, sans-serif;letter-spacing:1px;">再读取页的大小</h3>
<div style="margin:0px;padding:0px;border:0px;font-size:14px;vertical-align:baseline;caret-color:#444444;color:#444444;font-family:&quot;microsoft yahei&quot;, &quot;helvetica neue&quot;, helvetica, arial, sans-serif;letter-spacing:1px;">
<pre class="null">mysql&gt; show global variables like 'innodb_page_size';
+------------------+-------+
| Variable_name    | Value |
+------------------+-------+
| innodb_page_size | 16384 |
+------------------+-------+
1 row inset(0.00 sec) </pre>
</div>
<h3 style="margin:24px 0px;padding:0px;border:0px;font-size:18px;vertical-align:baseline;line-height:0.8;caret-color:#444444;color:#444444;font-family:&quot;microsoft yahei&quot;, &quot;helvetica neue&quot;, helvetica, arial, sans-serif;letter-spacing:1px;">最后读取索引树的高度</h3>
<div style="margin:0px;padding:0px;border:0px;font-size:14px;vertical-align:baseline;caret-color:#444444;color:#444444;font-family:&quot;microsoft yahei&quot;, &quot;helvetica neue&quot;, helvetica, arial, sans-serif;letter-spacing:1px;">
<pre class="null">$ hexdump -s 49216 -n 10 ./user.ibd
000c040 0200 0000 0000 0000 1600
000c04a</pre>
</div>
<p style="padding:0px;border:0px;font-size:15px;vertical-align:baseline;word-break:break-all;caret-color:#444444;color:#444444;font-family:&quot;microsoft yahei&quot;, &quot;helvetica neue&quot;, helvetica, arial, sans-serif;letter-spacing:1px;margin-top:0px;margin-bottom:10px;">可以发现 PAGE_LEVEL 为 0200，表示这棵二级索引树的高度为 3。后面的 1600 是索引的 index_id 值。十六进制的 16 转换为十进制数字是 22。这个 22 正好就是上面主键的 index_id。<br />上面 hexdump 命令中 49216 是怎么算出来的？公式是 page_no * innodb_page_size + 64。<br />3*16384+64=49216</p>
<p style="padding:0px;border:0px;font-size:15px;vertical-align:baseline;word-break:break-all;caret-color:#444444;color:#444444;font-family:&quot;microsoft yahei&quot;, &quot;helvetica neue&quot;, helvetica, arial, sans-serif;letter-spacing:1px;margin-top:0px;margin-bottom:10px;">我们在用这个方式查看下其他两个索引的高度。</p>
<div style="margin:0px;padding:0px;border:0px;font-size:14px;vertical-align:baseline;caret-color:#444444;color:#444444;font-family:&quot;microsoft yahei&quot;, &quot;helvetica neue&quot;, helvetica, arial, sans-serif;letter-spacing:1px;">
<pre class="null">$ hexdump -s 65600 -n 10 ./user.ibd
0010040 0100 0000 0000 0000 1700
001004a
$ hexdump -s 81984 -n 10 ./user.ibd
0014040 0200 0000 0000 0000 1800
001404a</pre>
</div>
<p style="padding:0px;border:0px;font-size:15px;vertical-align:baseline;word-break:break-all;caret-color:#444444;color:#444444;font-family:&quot;microsoft yahei&quot;, &quot;helvetica neue&quot;, helvetica, arial, sans-serif;letter-spacing:1px;margin-top:0px;margin-bottom:10px;">可见，name 索引的高度是 2，age 索引的高度是 3。</p>
<h2 style="margin:24px 0px;padding:0px;border-width:0px 0px 1px;border-bottom-style:solid;border-bottom-color:#e6e6e6;font-size:18px;vertical-align:baseline;clear:both;line-height:1.846153846;caret-color:#444444;color:#444444;font-family:&quot;microsoft yahei&quot;, &quot;helvetica neue&quot;, helvetica, arial, sans-serif;letter-spacing:1px;">根据索引的结构估算</h2>
<p style="padding:0px;border:0px;font-size:15px;vertical-align:baseline;word-break:break-all;caret-color:#444444;color:#444444;font-family:&quot;microsoft yahei&quot;, &quot;helvetica neue&quot;, helvetica, arial, sans-serif;letter-spacing:1px;margin-top:0px;margin-bottom:10px;">如果你没有数据库服务器的权限。自己也可以根据数据库索引结构进行估算树的高度。<br />根据 B+Tree 结构，非叶子节点存储的是索引数据，叶子节点存储的是每行的所有数据。<br />非叶子节点每个索引项的大小是，数据大小+指针大小。假设指针大小为 8 个字节。每页不会被占满，预留1/5的空隙。下面我们估算下 name 和 age 两个索引的高度。</p>
<h3 style="margin:24px 0px;padding:0px;border:0px;font-size:18px;vertical-align:baseline;line-height:0.8;caret-color:#444444;color:#444444;font-family:&quot;microsoft yahei&quot;, &quot;helvetica neue&quot;, helvetica, arial, sans-serif;letter-spacing:1px;">name 索引高度估算</h3>
<p style="padding:0px;border:0px;font-size:15px;vertical-align:baseline;word-break:break-all;caret-color:#444444;color:#444444;font-family:&quot;microsoft yahei&quot;, &quot;helvetica neue&quot;, helvetica, arial, sans-serif;letter-spacing:1px;margin-top:0px;margin-bottom:10px;">非叶子节点每页存放的索引项数量。每页大小是 16k。name 的值为 ab。占2个字节。每项数据大小是 2+8=10字节。每页能存放的索引项数量是 16384 * 0.8 / 10 = 1310 个。<br />叶子节点每页存放的索引数量。每页大小是 16k。每项数据大小是 4+2+8=14 个字节。没页能存放的索引数量是 16384 * 0.8 / 14 = 936 个。<br />两层能存放 1310*936=1226160 个数据记录。可见120万条记录以下，树的高度为2。</p>
<h3 style="margin:24px 0px;padding:0px;border:0px;font-size:18px;vertical-align:baseline;line-height:0.8;caret-color:#444444;color:#444444;font-family:&quot;microsoft yahei&quot;, &quot;helvetica neue&quot;, helvetica, arial, sans-serif;letter-spacing:1px;">age 索引高度估算</h3>
<p style="padding:0px;border:0px;font-size:15px;vertical-align:baseline;word-break:break-all;caret-color:#444444;color:#444444;font-family:&quot;microsoft yahei&quot;, &quot;helvetica neue&quot;, helvetica, arial, sans-serif;letter-spacing:1px;margin-top:0px;margin-bottom:10px;">非叶子节点每页存放的索引项数量。每页大小是 16k。age 的类型为 int。占4个字节。每项数据大小是 4+8=12字节。每页能存放的索引项数量是 16384 * 0.8 / 12 = 1092 个。<br />叶子节点每页存放的索引数量。每页大小是 16k。每项数据大小是 4+4+8=16 个字节。没页能存放的索引数量是 16384 * 0.8 / 16 = 819 个。<br />两层能存放 1092*819=894348 个数据记录。可见90万条记录以下，树的高度为2。100万条为 3 层。</p>
<h2 style="margin:24px 0px;padding:0px;border-width:0px 0px 1px;border-bottom-style:solid;border-bottom-color:#e6e6e6;font-size:18px;vertical-align:baseline;clear:both;line-height:1.846153846;caret-color:#444444;color:#444444;font-family:&quot;microsoft yahei&quot;, &quot;helvetica neue&quot;, helvetica, arial, sans-serif;letter-spacing:1px;">其它工具</h2>
<p style="padding:0px;border:0px;font-size:15px;vertical-align:baseline;word-break:break-all;caret-color:#444444;color:#444444;font-family:&quot;microsoft yahei&quot;, &quot;helvetica neue&quot;, helvetica, arial, sans-serif;letter-spacing:1px;margin-top:0px;margin-bottom:10px;">还有一个小工具可以查看。InnoDB 表空间可视化工具innodb_ruby<br />https://www.cnblogs.com/cnzeno/p/6322842.html</p>
<h2  class="related_post_title">猜您喜欢</h2><ul class="related_post"><li><a href="http://ourmysql.com/archives/902" title="InnoDB的Master Thread调度流程">InnoDB的Master Thread调度流程</a></li><li><a href="http://ourmysql.com/archives/1387" title="从MyISAM转到InnoDB需要注意什么">从MyISAM转到InnoDB需要注意什么</a></li><li><a href="http://ourmysql.com/archives/1316" title="InnoDB还是MyISAM 再谈MySQL存储引擎的选择">InnoDB还是MyISAM 再谈MySQL存储引擎的选择</a></li><li><a href="http://ourmysql.com/archives/1306" title="MySQL数据库InnoDB存储引擎在线加字段实现原理详解">MySQL数据库InnoDB存储引擎在线加字段实现原理详解</a></li><li><a href="http://ourmysql.com/archives/1289" title="阿里巴巴数据库历程:放弃 Oracle 选 MySQL 的来龙去脉">阿里巴巴数据库历程:放弃 Oracle 选 MySQL 的来龙去脉</a></li><li><a href="http://ourmysql.com/archives/1250" title="InnoDB Adaptive Hash Index浅析">InnoDB Adaptive Hash Index浅析</a></li><li><a href="http://ourmysql.com/archives/1203" title="InnoDB一定会在索引中加上主键吗">InnoDB一定会在索引中加上主键吗</a></li><li><a href="http://ourmysql.com/archives/1199" title="Innodb IO优化 — 数据库表设计">Innodb IO优化 — 数据库表设计</a></li><li><a href="http://ourmysql.com/archives/1174" title="Innodb IO优化－配置优化">Innodb IO优化－配置优化</a></li><li><a href="http://ourmysql.com/archives/1164" title="新手必看：一步到位之InnoDB">新手必看：一步到位之InnoDB</a></li></ul>]]></content:encoded>
			<wfw:commentRss>http://ourmysql.com/archives/1469/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>纳尼，mysqldump导出的数据居然少了40万？</title>
		<link>http://ourmysql.com/archives/1467</link>
		<comments>http://ourmysql.com/archives/1467#comments</comments>
		<pubDate>Sat, 11 Mar 2017 23:45:37 +0000</pubDate>
		<dc:creator>OurMySQL</dc:creator>
				<category><![CDATA[MySQL解错方案]]></category>
		<category><![CDATA[mysqldump]]></category>

		<guid isPermaLink="false">http://ourmysql.com/?p=1467</guid>
		<description><![CDATA[用mysqldump备份数据时，加上 -w 条件选项过滤部分数据，发现导出结果比实际少了40万，什么情况？

我的朋友小文前几天遇到一个怪事，他用mysqldump备份数据时，加上了 -w 选项过滤部分数据，发现导出的数据比实际上少了40万。 <a href="http://ourmysql.com/archives/1467"><br /><br />继续阅读全文 <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<h1>0、导读</h1>
<p> &nbsp; &nbsp;用mysqldump备份数据时，加上 -w 条件选项过滤部分数据，发现导出结果比实际少了40万，什么情况？</p>
<p> &nbsp; &nbsp;本文约1500字，阅读时间约5分钟。</p>
<h1>1、问题</h1>
<p> &nbsp; &nbsp;我的朋友小文前几天遇到一个怪事，他用mysqldump备份数据时，加上了 -w 选项过滤部分数据，发现导出的数据比实际上少了40万。</p>
<p> &nbsp; &nbsp;要进行备份表DDL见下：</p>
<p> &nbsp; &nbsp;CREATE TABLE `oldbiao` (</p>
<p> &nbsp; &nbsp;`aaaid` int(11) NOT NULL,</p>
<p> &nbsp; &nbsp;`bbbid` int(11) NOT NULL,</p>
<p> &nbsp; &nbsp;`cccid` int(11) NOT NULL,</p>
<p> &nbsp; &nbsp;`time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,</p>
<p> &nbsp; &nbsp;`dddid` int(11) DEFAULT NULL,</p>
<p> &nbsp; &nbsp;KEY `index01` (`ccccid`),</p>
<p> &nbsp; &nbsp;KEY `index02` (`dddid`,`time`)</p>
<p> &nbsp; &nbsp;) ENGINE=InnoDB DEFAULT CHARSET=utf8;</p>
<p> &nbsp; &nbsp;顺便吐槽下，这个表DDL设计的真是low啊。没主键，允许NULL。</p>
<p> &nbsp; &nbsp;mysqldump备份指令增加的 -w/-where 选项是：</p>
<p> &nbsp; &nbsp;-w “time&gt;‘2016-08-01 00:00:00′”</p>
<p> &nbsp; &nbsp;加上这个参数的作用是：只备份 2016-8-1 之后的所有数据，相当于执行了下面这样的SQL命令：</p>
<p> &nbsp; &nbsp;SELECT SQL_NO_CACHE * FROM t WHERE time&gt;‘2016-08-01 00:00:00′</p>
<p> &nbsp; &nbsp;然后把导出的SQL文件恢复后，再随机抽查下数据看看是否有遗漏的。不查不知道，一查吓一跳，发现 2016-12-12 下午的数据是缺失的。经过仔细核查，发现比原数据大概少了40万条记录。</p>
<p> &nbsp; &nbsp;百思不得其解的小文请我帮忙排查问题。</p>
<h1>2、排查</h1>
<p> &nbsp; &nbsp;既然是少了一部分数据，那就要先定位到底是丢失了的是哪部分数据。</p>
<p> &nbsp; &nbsp;那么，如何定位呢？</p>
<p> &nbsp; &nbsp;搞数据库的人，应该都知道<strong>折半查找法</strong>，这是计算机科学里比较基础的概念之一。我们就利用这种方法来快速定位。</p>
<p> &nbsp; &nbsp;经过排查，发现是缺少的数据有个特点，根据时间排序，发现最早的数据是 2016-8-1 8点的，而我们上面设定的条件则是 2016-8-1 0点开始的所有数据，整整差了8个小时。</p>
<p> &nbsp; &nbsp;看到8小时这个特点，我想你应该大概想到什么原因了吧。对，没错，就是因为时区的因素导致的。</p>
<p> &nbsp; &nbsp;经过排查，发现是因为原先写数据时，是以 <strong>0时区</strong> 时间写入的，但执行mysqldump备份时则使用的是本地 <strong>东8区</strong> 的时间，所以就有了8小时的差距。</p>
<h1>2、解决</h1>
<p> &nbsp; &nbsp;知道了问题所在，方法就简单了。有两个方法：</p>
<p> &nbsp; &nbsp;1、修改mysqldump中的where条件时间值，减去8个小时。建议采用该方法。</p>
<p> &nbsp; &nbsp;mysqldump … -w “time&gt;‘2016-07-31 16:00:00′”</p>
<p> &nbsp; &nbsp;2、修改MySQL全局时区，从 0时区 改成 东8区，并且mysqldump加上 -skip-tz-utc 选项。这种方法需要修改MySQL的全局时区，可能会导致更多的业务问题，因此<strong>强烈不建议使用</strong>。</p>
<p> &nbsp; &nbsp;mysqldump … -skip-tz-utc -w “time&gt;‘2016-08-01 08:00:00′”</p>
<p> &nbsp; &nbsp;问题暂且按下，我们先来看下时区因素怎么影响查询结果的。</p>
<p> &nbsp; &nbsp;先看下系统本地时间：</p>
<p> &nbsp; &nbsp;[yejr@imsyql]$ date -R</p>
<p> &nbsp; &nbsp;Wed, 21 Dec 2016 14:04:51 +0800</p>
<p> &nbsp; &nbsp;测试表DDL：</p>
<p> &nbsp; &nbsp;CREATE TABLE `t1` (</p>
<p> &nbsp; &nbsp;`id` int(10) unsigned NOT NULL AUTO_INCREMENT,</p>
<p> &nbsp; &nbsp;…</p>
<p> &nbsp; &nbsp;`c1` timestamp NULL DEFAULT NULL,</p>
<p> &nbsp; &nbsp;PRIMARY KEY (`id`)</p>
<p> &nbsp; &nbsp;) ENGINE=InnoDB;</p>
<p> &nbsp; &nbsp;查看MySQL的时区设置：</p>
<p> &nbsp; &nbsp;<strong> &nbsp; &nbsp;<a href="http://imysql.com/wp-content/uploads/2017/03/640-1.png"><img class="alignnone size-full wp-image-4263" src="http://imysql.com/wp-content/uploads/2017/03/640-1.png" width="553" height="136" srcset="http://imysql.com/wp-content/uploads/2017/03/640-1.png 553w, http://imysql.com/wp-content/uploads/2017/03/640-1-300x74.png 300w" sizes="(max-width:553px) 100vw, 553px" /></a></strong></p>
<p> &nbsp; &nbsp;<strong>图1</strong></p>
<p> &nbsp; &nbsp;然后写入一条数据：</p>
<p> &nbsp; &nbsp;<strong><a href="http://imysql.com/wp-content/uploads/2017/03/640-1.jpeg"><img class="alignnone size-full wp-image-4262" src="http://imysql.com/wp-content/uploads/2017/03/640-1.jpeg" width="471" height="325" srcset="http://imysql.com/wp-content/uploads/2017/03/640-1.jpeg 471w, http://imysql.com/wp-content/uploads/2017/03/640-1-300x207.jpeg 300w" sizes="(max-width:471px) 100vw, 471px" /></a></strong></p>
<p> &nbsp; &nbsp;<strong>图2</strong></p>
<p> &nbsp; &nbsp;第一次备份，用本地时间条件去过滤：</p>
<p> &nbsp; &nbsp;mysqldump -w “dt &gt;= ‘2016-12-21 14:00:00′”</p>
<p> &nbsp; &nbsp;这种情况下，显然是没有结果的。</p>
<p> &nbsp; &nbsp;<strong><a href="http://imysql.com/wp-content/uploads/2017/03/640-2.png"><img class="alignnone size-full wp-image-4260" src="http://imysql.com/wp-content/uploads/2017/03/640-2.png" width="442" height="196" srcset="http://imysql.com/wp-content/uploads/2017/03/640-2.png 442w, http://imysql.com/wp-content/uploads/2017/03/640-2-300x133.png 300w" sizes="(max-width:442px) 100vw, 442px" /></a></strong></p>
<p> &nbsp; &nbsp;<strong>图3</strong></p>
<p> &nbsp; &nbsp;第二次备份，用本地时间减去8小时再去过滤：</p>
<p> &nbsp; &nbsp;mysqldump -w “dt &gt;= ‘2016-12-21 06:00:00′”</p>
<p> &nbsp; &nbsp;这种就可以备份出数据了。</p>
<p> &nbsp; &nbsp;<strong><a href="http://imysql.com/wp-content/uploads/2017/03/640-2-1.jpeg"><img class="alignnone size-full wp-image-4259" src="http://imysql.com/wp-content/uploads/2017/03/640-2-1.jpeg" width="441" height="196" srcset="http://imysql.com/wp-content/uploads/2017/03/640-2-1.jpeg 441w, http://imysql.com/wp-content/uploads/2017/03/640-2-1-300x133.jpeg 300w" sizes="(max-width:441px) 100vw, 441px" /></a></strong></p>
<p> &nbsp; &nbsp;<strong>图4</strong></p>
<p> &nbsp; &nbsp;此外，我们注意到mysqldump的 -tz-utc 选项，它是和时区设定有关系的：</p>
<p> &nbsp; &nbsp;-tz-utc</p>
<p> &nbsp; &nbsp;SET TIME_ZONE=’+00:00′ at top of dump to allow dumping of TIMESTAMP data when a server has data in different time zones or data is being moved between servers with different time zones.</p>
<p> &nbsp; &nbsp;(Defaults to on; use -skip-tz-utc to disable.)</p>
<p> &nbsp; &nbsp;这个选项的作用，就是以 0时区 &nbsp;备份数据，把所有时间都转换成 0时区 的数据。比如本来是在 东8区(+08:00) 的时间 14:00:00，转换成 0时区 后，会变成 06:00:00，原来是 西8区(-08:00) 的时间14:00:00，则转换成 22:00:00。这个选项是默认启用的。</p>
<p> &nbsp; &nbsp;在上面第一次备份时没有数据，就是因为MySQL里本身存储的就是 0时区 的数据，mysqldump也设定了转换成 0时区，我们传递进去的参数却是 东8区 的时间，因此没有数据。</p>
<h1>3、总结</h1>
<p> &nbsp; &nbsp;本来只想简单写一下的，结果里嗦写了好多。</p>
<p> &nbsp; &nbsp;其实我们只需要注意一点，服务器在哪里，就是用哪里的时区，也就是 SYSTEM 时区，在做SQL查询以及mysqldump备份数据时，也使用服务器上的时间，而不使用我们本地时间。</p>
<p> &nbsp; &nbsp;<strong><a href="http://imysql.com/wp-content/uploads/2017/03/640-3.png"><img class="alignnone size-full wp-image-4261" src="http://imysql.com/wp-content/uploads/2017/03/640-3.png" width="549" height="132" srcset="http://imysql.com/wp-content/uploads/2017/03/640-3.png 549w, http://imysql.com/wp-content/uploads/2017/03/640-3-300x72.png 300w" sizes="(max-width:549px) 100vw, 549px" /></a></strong></p>
<p> &nbsp; &nbsp;<strong>图5</strong></p>
<div class="yarpp-related-rss yarpp-related-none"></div>
<h2  class="related_post_title">猜您喜欢</h2><ul class="related_post"><li><a href="http://ourmysql.com/archives/1386" title="使用mysqldump备份时为什么要加上 -q 参数">使用mysqldump备份时为什么要加上 -q 参数</a></li><li><a href="http://ourmysql.com/archives/1353" title="mysqldump加-w参数备份">mysqldump加-w参数备份</a></li><li><a href="http://ourmysql.com/archives/1339" title="一个mysqldump导出失败的案例分析">一个mysqldump导出失败的案例分析</a></li><li><a href="http://ourmysql.com/archives/1215" title="mysqldump的流程">mysqldump的流程</a></li><li><a href="http://ourmysql.com/archives/1213" title="MySQL数据库逻辑备份工具mysqldump的输出方式和进度报告功能增加与改进">MySQL数据库逻辑备份工具mysqldump的输出方式和进度报告功能增加与改进</a></li><li><a href="http://ourmysql.com/archives/1197" title="mysqldump选项之skip-opt">mysqldump选项之skip-opt</a></li><li><a href="http://ourmysql.com/archives/813" title="mysqldump意外终止的原因以及解决方法">mysqldump意外终止的原因以及解决方法</a></li><li><a href="http://ourmysql.com/archives/687" title="source sql文件报错">source sql文件报错</a></li><li><a href="http://ourmysql.com/archives/570" title="mysqldump 导出触发器遇到的问题">mysqldump 导出触发器遇到的问题</a></li><li><a href="http://ourmysql.com/archives/463" title="改良版本mysqldump来备份MYSQL数据库">改良版本mysqldump来备份MYSQL数据库</a></li></ul>]]></content:encoded>
			<wfw:commentRss>http://ourmysql.com/archives/1467/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>今天你检查备份了吗？</title>
		<link>http://ourmysql.com/archives/1466</link>
		<comments>http://ourmysql.com/archives/1466#comments</comments>
		<pubDate>Sat, 11 Mar 2017 23:44:28 +0000</pubDate>
		<dc:creator>OurMySQL</dc:creator>
				<category><![CDATA[MySQL解错方案]]></category>
		<category><![CDATA[备份]]></category>

		<guid isPermaLink="false">http://ourmysql.com/?p=1466</guid>
		<description><![CDATA[今天引爆各大技术群的事情就是网易游戏《炉​石传说》游戏数据库发生宕机并引发数据丢失事故，最终决定回档并后续补偿玩家损失。详情可见官网公告：http://hs.blizzard.cn/articles/16/8565

我以前也在搜狐畅游负责游戏数据库维护，也遇到过因为服务器故障最终导致回档的事故，不过都没像这次炉石搞这么大动作。在这里我并不想借机调侃消费他们或搞营销，只想和大家一起聊聊作为DBA，应该注意哪些事。 <a href="http://ourmysql.com/archives/1466"><br /><br />继续阅读全文 <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p> &nbsp; &nbsp;<a href="http://imysql.com/wp-content/uploads/2017/03/640.png"><img class="alignnone size-full wp-image-4250" src="http://imysql.com/wp-content/uploads/2017/03/640.png" width="640" height="382" srcset="http://imysql.com/wp-content/uploads/2017/03/640.png 640w, http://imysql.com/wp-content/uploads/2017/03/640-300x179.png 300w, http://imysql.com/wp-content/uploads/2017/03/640-624x372.png 624w" sizes="(max-width:640px) 100vw, 640px" /></a></p>
<p></p>
<p style="padding:0px;border:0px;font-size:14px;vertical-align:baseline;line-height:1.714285714;color:#444444;font-family:helvetica, arial, sans-serif;margin-top:0px;margin-bottom:1.714285714rem;">0、导读</p>
<blockquote style="margin:0px 0px 1.714285714rem;padding:1.714285714rem;border:0px;font-size:14px;vertical-align:baseline;quotes:none;font-style:italic;color:#444444;font-family:helvetica, arial, sans-serif;"><p style="padding:0px;border:0px;vertical-align:baseline;line-height:1.714285714;margin-top:0px;margin-bottom:1.714285714rem;">《炉石传说》游戏数据库回档事件反思</p>
</blockquote>
<p style="padding:0px;border:0px;font-size:14px;vertical-align:baseline;line-height:1.714285714;color:#444444;font-family:helvetica, arial, sans-serif;margin-top:0px;margin-bottom:1.714285714rem;">今天引爆各大技术群的事情就是网易游戏《炉石传说》游戏数据库发生宕机并引发数据丢失事故，最终决定回档并后续补偿玩家损失。详情可见官网公告：http://hs.blizzard.cn/articles/16/8565</p>
<p style="padding:0px;border:0px;font-size:14px;vertical-align:baseline;line-height:1.714285714;color:#444444;font-family:helvetica, arial, sans-serif;margin-top:0px;margin-bottom:1.714285714rem;">我以前也在搜狐畅游（http://www.changyou.com，NASDAQ:CYOU）负责游戏数据库维护，也遇到过因为服务器故障最终导致回档的事故，不过都没像这次炉石搞这么大动作。在这里我并不想借机调侃消费他们或搞营销，只想和大家一起聊聊作为DBA，应该注意哪些事。</p>
<p style="padding:0px;border:0px;font-size:14px;vertical-align:baseline;line-height:1.714285714;color:#444444;font-family:helvetica, arial, sans-serif;margin-top:0px;margin-bottom:1.714285714rem;">我们从公告的内容中，我们看到了几个问题：</p>
<ol class="list-paddingleft-2" style="margin:0px 0px 1.714285714rem;padding:0px;border:0px;font-size:14px;vertical-align:baseline;list-style-position:outside;list-style-image:initial;line-height:1.714285714;color:#444444;font-family:helvetica, arial, sans-serif;">
<li style="margin:0px 0px 0px 2.571428571rem;padding:0px;border:0px;vertical-align:baseline;">
<p>公告发布时间是2017.1.18 18点，决定回档到2017.1.14 15:20，中间这段时间难道一直都在尝试恢复数据库，就不能<strong style="margin:0px;padding:0px;border:0px;vertical-align:baseline;">快速做出决策尽快直接回档</strong>吗，这是在考验游戏玩家的耐心，很容易引发玩家的“群体事件”；</p>
</li>
<li style="margin:0px 0px 0px 2.571428571rem;padding:0px;border:0px;vertical-align:baseline;">
<p>因为供电意外导致故障，并造成数据库损坏，如果也用MySQL数据库的话，看起来应该是<strong style="margin:0px;padding:0px;border:0px;vertical-align:baseline;">没开启双1设置</strong>，并且有可能还在使用<strong style="margin:0px;padding:0px;border:0px;vertical-align:baseline;">老式的锂电池BBU</strong>。所以断电后很容易导致阵列卡cache中的数据丢失，数据库也跟着损坏，以前没少才踩这个坑；</p>
</li>
<li style="margin:0px 0px 0px 2.571428571rem;padding:0px;border:0px;vertical-align:baseline;">
<p>连备份数据库也发生故障，有点不可思议，这样就容易让人产生是人为事故的联想了。不过，我多年前也发生过类似的情况，不过那次是因为用<strong style="margin:0px;padding:0px;border:0px;vertical-align:baseline;">mysqldump备份时指定了错误的字符集</strong>，并且在<strong style="margin:0px;padding:0px;border:0px;vertical-align:baseline;">做备份恢复测试时没严格测试数据的有效性</strong>，致使发生故障时不能正常恢复，结果也悲剧了。作为不了解内情的局外人，只能以官方公告为准，无要无端臆测；</p>
</li>
</ol>
<p style="padding:0px;border:0px;font-size:14px;vertical-align:baseline;line-height:1.714285714;color:#444444;font-family:helvetica, arial, sans-serif;margin-top:0px;margin-bottom:1.714285714rem;">关于服务器可靠性以及数据库备份，有几点建议：</p>
<ol class="list-paddingleft-2" style="margin:0px 0px 1.714285714rem;padding:0px;border:0px;font-size:14px;vertical-align:baseline;list-style-position:outside;list-style-image:initial;line-height:1.714285714;color:#444444;font-family:helvetica, arial, sans-serif;">
<li style="margin:0px 0px 0px 2.571428571rem;padding:0px;border:0px;vertical-align:baseline;">
<p><strong style="margin:0px;padding:0px;border:0px;vertical-align:baseline;">必须定期全备</strong>，并且<strong style="margin:0px;padding:0px;border:0px;vertical-align:baseline;">优先推荐物理备份</strong>，逻辑备份通常相对更慢。一般至少每天一次全备；</p>
</li>
<li style="margin:0px 0px 0px 2.571428571rem;padding:0px;border:0px;vertical-align:baseline;">
<p>每小时一次<strong style="margin:0px;padding:0px;border:0px;vertical-align:baseline;">增备或差异备份</strong>，我以前的做法是开binlog，并且利用last_update_time列特征每小时做一次差异备份。这样我要恢复的话，一般最多只损失不到一个小时的数据；</p>
</li>
<li style="margin:0px 0px 0px 2.571428571rem;padding:0px;border:0px;vertical-align:baseline;">
<p>备份文件<strong style="margin:0px;padding:0px;border:0px;vertical-align:baseline;">务必进行恢复测试</strong>，如果有多个备份集，可以采用随机抽取的方式做恢复测试，但一定要保证所有实例的备份最终都会被验证一次；</p>
</li>
<li style="margin:0px 0px 0px 2.571428571rem;padding:0px;border:0px;vertical-align:baseline;">
<p>必须监控服务器硬件健康状况，包括CPU、内存、阵列卡、阵列卡电池等部件，以及服务器温度等。我们曾经有在哈尔滨及西安某机房的服务器，一到夏天就很容易因为温度过高而引发自动重启</p>
<h2  class="related_post_title">猜您喜欢</h2><ul class="related_post"><li><a href="http://ourmysql.com/archives/1353" title="mysqldump加-w参数备份">mysqldump加-w参数备份</a></li><li><a href="http://ourmysql.com/archives/1172" title="linux 定期自动备份mysql的shell">linux 定期自动备份mysql的shell</a></li></ul>]]></content:encoded>
			<wfw:commentRss>http://ourmysql.com/archives/1466/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>MySQL工具推荐 &#124; 基于MySQL binlog的flashback工具</title>
		<link>http://ourmysql.com/archives/1465</link>
		<comments>http://ourmysql.com/archives/1465#comments</comments>
		<pubDate>Sat, 11 Mar 2017 23:43:07 +0000</pubDate>
		<dc:creator>OurMySQL</dc:creator>
				<category><![CDATA[MySQL基础知识]]></category>

		<guid isPermaLink="false">http://ourmysql.com/?p=1465</guid>
		<description><![CDATA[相信您应该遇到过因为误操作破坏数据库的问题，比如忘了带WHERE条件的UPDATE、DELETE操作，然后就需要进行传统方式的全量 &#038; 增量恢复。现在，给您介绍一下MySQL中的flashback玩法，也可以做到像Oracle的flashback那样。

目前MySQL的 flashback(又称 闪回)一般是利用binlog完成的，能快速完成恢复且无需停机维护。

第一个实现该功能的是阿里云的 彭立勋，他在MySQL 5.5版本上就已实现，并将其开源及提交给MariaDB，为社区提供了非常优秀的参考模型。 <a href="http://ourmysql.com/archives/1465"><br /><br />继续阅读全文 <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<h1>1、前言</h1>
<p>相信您应该遇到过因为误操作破坏数据库的问题，比如忘了带WHERE条件的UPDATE、DELETE操作，然后就需要进行传统方式的全量 &amp; 增量恢复。现在，给您介绍一下MySQL中的flashback玩法，也可以做到像Oracle的flashback那样。</p>
<p>目前MySQL的 flashback(又称 <strong>闪回</strong>)一般是利用binlog完成的，能快速完成恢复且无需停机维护。</p>
<p>第一个实现该功能的是阿里云的<strong> 彭立勋</strong>，他在MySQL 5.5版本上就已实现，并将其开源及提交给MariaDB，为社区提供了非常优秀的参考模型。</p>
<h1>2、闪回原理</h1>
<p>本节我们先来介绍一下MySQL binlog flashback的基本工作原理。</p>
<p>MySQL的binlog以event的形式，记录了MySQL中所有的变更情况，利用binlog我们就能够重现所记录的所有操作。</p>
<p>MySQL引入binlog主要有两个用途/目的：一是为了主从复制；二是用于备份恢复后需要重新应用部分binlog，从而达到全备+增备的效果。</p>
<p><strong>MySQL的binlog共有三种可选格式(binlog_format)，其各有优缺点：</strong></p>
<ul>
<li>
<p><strong>statement，</strong>基于SQL语句的模式，一般来说生成的binlog尺寸较小，但是某些不确定性SQL语句或函数在复制过程可能导致数据不一致甚至出错；</p>
</li>
<li>
<p><strong>row，</strong>基于数据行的模式，记录的是数据行的完整变化。相对更安全，推荐使用(但通常生成的binlog会比其他两种模式大很多)；</p>
</li>
<li>
<p><strong>mixed，</strong>混合模式，可以根据情况自动选用statement抑或row模式；这个模式下也可能造成主从数据不一直。它属于MySQL 5.1版本时期的过渡方案。因此，如果你现在还使用mixed的话，那你的过渡时间也太久了……</p>
</li>
</ul>
<p><strong>备注：想要使用</strong><strong>binlog flashback工具，需要将binlog_format设置为row才行。</strong></p>
<h1>3、工具推荐</h1>
<p><strong>项目一：mysqlbinlog_flashback</strong></p>
<p>项目作者：赖亿@58到家</p>
<p>github项目地址：https://github.com/58daojia-dba/mysqlbinlog_flashback</p>
<p>也可在github.com上搜索“<strong>mysqlbinlog_flashback</strong>”</p>
<p><strong>项目介绍：</strong>产生在线mysqlbinlog的回滚的sql，现在已经在阿里的rds上，db为utf8字符集的生产环境下使用。其他环境没有在生产环境下使用，请小心。</p>
<p>项目使用反馈：laiyi@daojia.com</p>
<p><strong>项目二：binlog2sql</strong><strong> </strong></p>
<p>项目作者：曹单锋</p>
<p>github项目地址：https://github.com/danfengcao/binlog2sql</p>
<p>也可在github.com上搜索“<strong>binlog2sql</strong>”</p>
<p><strong>项目介绍：</strong>从MySQL binlog解析出你要的SQL。根据不同选项，你可以得到原始SQL、回滚SQL、去除主键的INSERT SQL等。</p>
<p>项目反馈：danfengcao.info@gmail.com</p>
<p><strong>应用场景</strong></p>
<ul>
<li>
<p>flashback，数据快速回滚；</p>
</li>
<li>
<p>主从切换后数据不一致的修复；</p>
</li>
<li>
<p>从binlog生成标准SQL，再自行二次开发；</p>
</li>
</ul>
<h1>5、使用方法</h1>
<p>两个软件的使用上都比简单，都是在 https://github.com/noplay/python-mysql-replication 项目基础上进行的二次开发。</p>
<p>两个项目中都有详细的使用说明，感谢两位作者细心的整理，我们这里不再进行赘述，请自行到作者的项目上查看，如果对你帮助，请记得给个 star 哟！</p>
<h1>6、flashback总结</h1>
<p>社区里做这块的工具比较多，不开源的这里不在讨论，开源产品随着时间的前进，作者有可能忙于其它事情，没来的及更新也会失效过期。所以使用中需要有一定自我修订能力，也希望各位使用者也能加入到开源的大家庭中，共同维护这些项目。</p>
<p>这两款工具开发时侧重点不同，所以使用中也需要注意一下：</p>
<ul>
<li>
<p>mysqlbinlog_flashback 更便重于阿里云 RDS环境的使用。</p>
</li>
<li>
<p>binlog2sql &nbsp;便重于通常MySQL的处理。从代码上来看，该项目更简洁一点。</p>
</li>
</ul>
<p>在具体使用中及项目定制中那个更合适，只有使用后，找到适合自已就可以。 这也是开源的魅力。 如果对这两个软件有兴趣深度交流的，也可以加到QQ群： <a href="http://shang.qq.com/wpa/qunwpa?idkey=2ed7db382e6f97fc47e0cc4849ce6fa493f94e3ded40bffbf59ccd4f1657c62b" target="_blank">529671799</a> &nbsp;(两位作者已在)来交流吧。</p>
<div class="yarpp-related-rss yarpp-related-none"></div>
<h2  class="related_post_title">猜想失败，您看看下面的文章有用吗？</h2><ul class="related_post"><li><a href="http://ourmysql.com/archives/700" title="MySQL 关于毫秒的处理">MySQL 关于毫秒的处理</a></li><li><a href="http://ourmysql.com/archives/124" title="MYSQL索引和优化详细说明教程">MYSQL索引和优化详细说明教程</a></li><li><a href="http://ourmysql.com/archives/827" title="MySQL server has gone away解决办法">MySQL server has gone away解决办法</a></li><li><a href="http://ourmysql.com/archives/740" title="mysql 中show 命令用法简介">mysql 中show 命令用法简介</a></li><li><a href="http://ourmysql.com/archives/1379" title="持续可用与CAP理论 – 一个系统开发者的观点">持续可用与CAP理论 – 一个系统开发者的观点</a></li><li><a href="http://ourmysql.com/archives/1429" title="MySQL怎么计算打开文件数?">MySQL怎么计算打开文件数?</a></li><li><a href="http://ourmysql.com/archives/475" title="MySQL命令行中无法输入中文的解决方法 ">MySQL命令行中无法输入中文的解决方法 </a></li><li><a href="http://ourmysql.com/archives/3" title="MySQL server has gone away问题及其解决">MySQL server has gone away问题及其解决</a></li><li><a href="http://ourmysql.com/archives/1199" title="Innodb IO优化 — 数据库表设计">Innodb IO优化 — 数据库表设计</a></li><li><a href="http://ourmysql.com/archives/122" title="MySQL优化之COUNT(*)效率">MySQL优化之COUNT(*)效率</a></li></ul>]]></content:encoded>
			<wfw:commentRss>http://ourmysql.com/archives/1465/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>关于MySQL线程池资料整理–Percona Server</title>
		<link>http://ourmysql.com/archives/1464</link>
		<comments>http://ourmysql.com/archives/1464#comments</comments>
		<pubDate>Mon, 20 Feb 2017 00:18:18 +0000</pubDate>
		<dc:creator>OurMySQL</dc:creator>
				<category><![CDATA[MySQL基础知识]]></category>
		<category><![CDATA[Percona]]></category>
		<category><![CDATA[线程池]]></category>

		<guid isPermaLink="false">http://ourmysql.com/?p=1464</guid>
		<description><![CDATA[​MySQL执行statement使用一个连接一个thread的方式,当连接数增加到某一个点,那么性能将会开始下降.

这个特性的作用就是无论有多少连接,thread pool都讲保证性能处于最好水平.

thread pool的原理主要是减少线程,减少上下文交换和锁资源争抢,针对OLTP环境特别有效.

为可以开启thread pool功能,请将thread_handling=pool-of-threads.

percona server实现的thread pool是在server级别,和oracle mysql的不一样(插件形式),另外一个不同点在于,percona的thread pool不尝试最小化并发事物数量. <a href="http://ourmysql.com/archives/1464"><br /><br />继续阅读全文 <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>MySQL执行statement使用一个连接一个thread的方式,当连接数增加到某一个点,那么性能将会开始下降.<br style="margin:0px;padding:0px;" />这个特性的作用就是无论有多少连接,thread pool都讲保证性能处于最好水平.<br style="margin:0px;padding:0px;" />thread pool的原理主要是减少线程,减少上下文交换和锁资源争抢,针对OLTP环境特别有效.</p>
<p>为可以开启thread pool功能,请将<strong style="margin:0px;padding:0px;border:0px;vertical-align:baseline;">thread_handling=pool-of-threads</strong>.</p>
<p>percona server实现的thread pool是在server级别,和oracle mysql的不一样(插件形式),另外一个不同点在于,percona的thread pool不尝试最小化并发事物数量.</p>
<p><strong style="margin:0px;padding:0px;border:0px;vertical-align:baseline;">优先连接调度:</strong><br style="margin:0px;padding:0px;" />在percona server 5.5.30,thread pool的优先连接调度已经实现,虽然线程池会限制并发执行的queries的数量,但是open的transactions依然可能很多.因为新开启的transaction<br style="margin:0px;padding:0px;" />会跟在queue后面,高并发的transaction意味着很多当前运行的查询.为了增强性能,引入了thread_pool_high_prio_tickets参数.</p>
<p>这个参数控制进入高优先级队列的策略,对每个新连接分配可以进入高优先级队列的ticket,如果当一个query因为没有可用的线程导致执行延时,如果这个连接满足下面的条件可以<br style="margin:0px;padding:0px;" />直接进入高优先级的队列.<br style="margin:0px;padding:0px;" />1、这个连接有已经在执行的transaction<br style="margin:0px;padding:0px;" />2、这个连接持有的ticket是非0的.<br style="margin:0px;padding:0px;" />如果满足这两个条件,这个连接将被放到高优先级队列,并且ticket会被缩减.<br style="margin:0px;padding:0px;" />也就是说,如果不满足上面的条件会被放入普通的queue.ticket的初始值就是thread_pool_high_prio_tickets参数指定的.<br style="margin:0px;padding:0px;" />每次线程池寻找一个新的连接进行处理,首先检查高优先级队列,如果高优先级队列为空,将会把连接从普通队列放到高优先级队列.</p>
<p>这样做的目标就是减少服务器上正在进行的事务量,好处在于减少事务的运行时间,减少系统资源的等待.</p>
<p>基于某些自动提交或者需要使用低优先级队列的情况,我们提供thread_pool_high_prio_mode参数.</p>
<p>variable thread_pool_idle_timeout<br style="margin:0px;padding:0px;" />Command Line:Yes<br style="margin:0px;padding:0px;" />Config File:Yes<br style="margin:0px;padding:0px;" />Scope:Global<br style="margin:0px;padding:0px;" />Dynamic:Yes<br style="margin:0px;padding:0px;" />Variable Type:Numeric<br style="margin:0px;padding:0px;" />Default Value:60 (seconds)<br style="margin:0px;padding:0px;" />这个值用来设定线程空闲多久会将退出.</p>
<p>variable thread_pool_high_prio_mode<br style="margin:0px;padding:0px;" />Command Line:Yes<br style="margin:0px;padding:0px;" />Config File:Yes<br style="margin:0px;padding:0px;" />Scope:Global, Session<br style="margin:0px;padding:0px;" />Dynamic:Yes<br style="margin:0px;padding:0px;" />Variable Type:String<br style="margin:0px;padding:0px;" />Default Value:transactions<br style="margin:0px;padding:0px;" />Allowed Values:transactions, statements, none<br style="margin:0px;padding:0px;" />控制高优先级队列的模式.<br style="margin:0px;padding:0px;" />transaction：只有已经开启事务的连接可以进入高优先级队列<br style="margin:0px;padding:0px;" />statements:所有的statement都可以单独进入高优先级队列,不判断是否开启事务或者ticket的值.<br style="margin:0px;padding:0px;" />none:禁止进入高优先级队列,主要针对监控之类的线程做设置.如果全局设置none的话,等同于statements.</p>
<p>variable thread_pool_high_prio_tickets<br style="margin:0px;padding:0px;" />Command Line:Yes<br style="margin:0px;padding:0px;" />Config File:Yes<br style="margin:0px;padding:0px;" />Scope:Global, Session<br style="margin:0px;padding:0px;" />Dynamic:Yes<br style="margin:0px;padding:0px;" />Variable Type:Numeric<br style="margin:0px;padding:0px;" />Default Value:4294967295<br style="margin:0px;padding:0px;" />对新建立的连接分配ticket值,如果当ticket值为0,那么将被禁止进入高优先级队列.</p>
<p>variable thread_pool_max_threads<br style="margin:0px;padding:0px;" />Command Line:Yes<br style="margin:0px;padding:0px;" />Config File:Yes<br style="margin:0px;padding:0px;" />Scope:Global<br style="margin:0px;padding:0px;" />Dynamic:Yes<br style="margin:0px;padding:0px;" />Variable Type:Numeric<br style="margin:0px;padding:0px;" />Default Value:100000<br style="margin:0px;padding:0px;" />限制pool里面最大的线程数量,如果达到这个限制,将不会创建新的线程.</p>
<p>variable thread_pool_oversubscribe<br style="margin:0px;padding:0px;" />Command Line:Yes<br style="margin:0px;padding:0px;" />Config File:Yes<br style="margin:0px;padding:0px;" />Scope:Global<br style="margin:0px;padding:0px;" />Dynamic:Yes<br style="margin:0px;padding:0px;" />Variable Type:Numeric<br style="margin:0px;padding:0px;" />Default Value:3<br style="margin:0px;padding:0px;" />该参数的值越高,可以同时运行多个线程,如果低于3的值可能会导致更多的睡觉和唤醒。</p>
<p>variable thread_pool_size<br style="margin:0px;padding:0px;" />Command Line:Yes<br style="margin:0px;padding:0px;" />Config File:Yes<br style="margin:0px;padding:0px;" />Scope:Global<br style="margin:0px;padding:0px;" />Dynamic:Yes<br style="margin:0px;padding:0px;" />Variable Type:Numeric<br style="margin:0px;padding:0px;" />Default Value:Number of processors<br style="margin:0px;padding:0px;" />设置线程池可以同时使用CPU的线程数.</p>
<p>thread_pool_stall_limit<br style="margin:0px;padding:0px;" />Command Line:Yes<br style="margin:0px;padding:0px;" />Config File:Yes<br style="margin:0px;padding:0px;" />Scope:Global<br style="margin:0px;padding:0px;" />Dynamic:No<br style="margin:0px;padding:0px;" />Variable Type:Numeric<br style="margin:0px;padding:0px;" />Default Value:500 (ms)<br style="margin:0px;padding:0px;" />执行单个sql的超时时间,如果sql执行时间超过这个值,那么线程池将唤醒或者创建另外的线程开始工作.主要为long-running query设计.</p>
<p>状态值:<br style="margin:0px;padding:0px;" />variable Threadpool_idle_threads<br style="margin:0px;padding:0px;" />Command Line:Yes<br style="margin:0px;padding:0px;" />Variable Type:Numeric<br style="margin:0px;padding:0px;" />查看线程池中空闲的线程</p>
<p>variable Threadpool_threads<br style="margin:0px;padding:0px;" />Command Line:Yes<br style="margin:0px;padding:0px;" />Variable Type:Numeric<br style="margin:0px;padding:0px;" />查看线程池中有多少线程</p>
<p><strong style="margin:0px;padding:0px;border:0px;vertical-align:baseline;">调优：</strong><br style="margin:0px;padding:0px;" />一般来说默认情况已经很好了.所以只需要对下面两个参数就可以了.<br style="margin:0px;padding:0px;" />thread_handling = pool-of-threads #开启线程池<br style="margin:0px;padding:0px;" />thread_pool_oversubscribe = 10 #这个值建议在3~20间</p>
<p>http://www.percona.com/doc/percona-server/5.5/performance/threadpool.html</p>
<p>http://www.percona.com/blog/2014/01/29/percona-server-thread-pool-improvements/</p>
<p>http://imysql.com/2014/07/02/percona-thread-pool-benchmark-testing.shtml</p>
<h2  class="related_post_title">猜您喜欢</h2><ul class="related_post"><li><a href="http://ourmysql.com/archives/1361" title="关于MySQL线程池资料整理–Percona Server">关于MySQL线程池资料整理–Percona Server</a></li><li><a href="http://ourmysql.com/archives/1303" title="MariaDB线程池源码分析">MariaDB线程池源码分析</a></li><li><a href="http://ourmysql.com/archives/1299" title="使用Percona Data Recovery Tool for InnoDB恢复数据">使用Percona Data Recovery Tool for InnoDB恢复数据</a></li></ul>]]></content:encoded>
			<wfw:commentRss>http://ourmysql.com/archives/1464/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>SQL里是否可以使用JOIN</title>
		<link>http://ourmysql.com/archives/1463</link>
		<comments>http://ourmysql.com/archives/1463#comments</comments>
		<pubDate>Thu, 22 Dec 2016 23:29:54 +0000</pubDate>
		<dc:creator>OurMySQL</dc:creator>
				<category><![CDATA[MySQL基础知识]]></category>
		<category><![CDATA[join]]></category>

		<guid isPermaLink="false">http://ourmysql.com/?p=1463</guid>
		<description><![CDATA[很多公司都禁止程序员在 SQL 中使用 JOIN，至于原因则出奇的一致：用 JOIN 慢。不过我从没见过谁来论证为什么用 JOIN 慢，结果这个人云亦云的结论越传越广，让我觉得是时候来讨论一下这个看似正确的结论了。
 <a href="http://ourmysql.com/archives/1463"><br /><br />继续阅读全文 <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p> &nbsp; &nbsp;很多公司都禁止程序员在 SQL 中使用 JOIN，至于原因则出奇的一致：用 JOIN 慢。不过我从没见过谁来论证为什么用 JOIN 慢，结果这个人云亦云的结论越传越广，让我觉得是时候来讨论一下这个看似正确的结论了。</p>
<p> &nbsp; &nbsp;举个例子：查询最新的十篇帖子和对应的用户信息，用 JOIN 是这样的：</p>
<pre>SELECT posts.id, posts.content, users.name, ...
FROM posts
JOIN users on posts.user_id = users.id
ORDER BY posts.created_at DESC
LIMIT 10</pre>
<p> &nbsp; &nbsp;如果不使用 JOIN 的话，那么大概会改写成如下两条 SQL：</p>
<pre>SELECT id, content, ...
FROM posts
ORDER BY created_at DESC
LIMIT 10

SELECT name, ...
FROM users
WHERE id in (...)</pre>
<p> &nbsp; &nbsp;第一次查询得到帖子数据，然后在程序代码里收集好想要的 user_id，第二次查询通过 user_id 得到用户数据，接着在程序代码里把两份数据组合起来。</p>
<p> &nbsp; &nbsp;哪个快？我就不用跑个 bench 了吧，正常人都能看出来是用 JOIN 的快！</p>
<div id="attachment_580" style="width:640px" class="wp-caption alignnone"><a href="http://huoding.com/wp-content/uploads/2016/12/join.png" target="_blank"><img class="wp-image-580 size-full" src="http://huoding.com/wp-content/uploads/2016/12/join.png" alt="JOIN" width="630" height="333" /></a>
<p class="wp-caption-text">JOIN</p>
</div>
<p> &nbsp; &nbsp;在我看来，JOIN 的问题不是性能，而是当你执行 posts JOIN users 的时候，实际上相当于做出了一个假设：posts 和 users 两个结婚的表将永远住在同一个 DB 实例上，以后无论贫穷还是富有，疾病还是健康，永不分离。不过实际上，随着项目的发展，很可能会出现 posts 和 users 两个表不得不离婚的情况，结果它们会被划分到不同 DB 实例，一旦出现此类情况，那么当初使用 JOIN 的地方将不得不大量改写。</p>
<p> &nbsp; &nbsp;至于 SQL 里是否可以使用 JOIN，如果相关的表以后有独立部署的可能性，那么就要考虑避免使用 JOIN，否则用 JOIN 也无妨。当然，有人会找出一些使用 JOIN 后效率奇差的例子，不过这样的问题一来可能是索引不佳，二来可能是特殊情况，用不用 JOIN 都会有类似的问题，只要使用的时候留意即可。下次如果大家再听到别人以性能为由反对 JOIN 的使用，那么不妨把本文的链接发给他，因为他多半没有搞清楚真正的原因是什么。</p>
<h2  class="related_post_title">猜您喜欢</h2><ul class="related_post"><li><a href="http://ourmysql.com/archives/1322" title="SQL常见的可优化点">SQL常见的可优化点</a></li><li><a href="http://ourmysql.com/archives/1236" title="案例：MySQL优化器如何选择索引和JOIN顺序">案例：MySQL优化器如何选择索引和JOIN顺序</a></li><li><a href="http://ourmysql.com/archives/1207" title="MySQL源码:JOIN顺序选择的复杂度">MySQL源码:JOIN顺序选择的复杂度</a></li><li><a href="http://ourmysql.com/archives/1188" title="MySQL源码:JOIN顺序选择的复杂度">MySQL源码:JOIN顺序选择的复杂度</a></li><li><a href="http://ourmysql.com/archives/775" title="MySQL中LEFT JOIN的主表">MySQL中LEFT JOIN的主表</a></li><li><a href="http://ourmysql.com/archives/524" title="MySql 随机读取数据">MySql 随机读取数据</a></li><li><a href="http://ourmysql.com/archives/320" title="MySQL 中 Join 的基本实现原理">MySQL 中 Join 的基本实现原理</a></li></ul>]]></content:encoded>
			<wfw:commentRss>http://ourmysql.com/archives/1463/feed</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>MYSQL基础笔记</title>
		<link>http://ourmysql.com/archives/1461</link>
		<comments>http://ourmysql.com/archives/1461#comments</comments>
		<pubDate>Sat, 11 Jun 2016 15:26:58 +0000</pubDate>
		<dc:creator>OurMySQL</dc:creator>
				<category><![CDATA[MySQL基础知识]]></category>

		<guid isPermaLink="false">http://ourmysql.com/?p=1461</guid>
		<description><![CDATA[一个很棒的MySQL基础SQL的介绍！ <a href="http://ourmysql.com/archives/1461"><br /><br />继续阅读全文 <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<section id="toc">
<div id="toc">
<ul>
<li><a title="Mysql基础笔记" href="http://ourmysql.com/archives/1461#">Mysql基础笔记</a>
<ul>
<li><a title="环境配置" href="http://ourmysql.com/archives/1461#_1">环境配置</a></li>
<li><a title="基本概念" href="http://ourmysql.com/archives/1461#_2">基本概念</a></li>
<li><a title="mysql命令行" href="http://ourmysql.com/archives/1461#mysql">mysql命令行</a>
<ul>
<li><a title="进入" href="http://ourmysql.com/archives/1461#_3">进入</a></li>
<li><a title="use" href="http://ourmysql.com/archives/1461#use">use</a></li>
<li><a title="show" href="http://ourmysql.com/archives/1461#show">show</a></li>
</ul>
</li>
<li><a title="查询" href="http://ourmysql.com/archives/1461#_5">查询</a>
<ul>
<li><a title="select" href="http://ourmysql.com/archives/1461#select">select</a></li>
<li><a title="order by" href="http://ourmysql.com/archives/1461#order-by">order by</a></li>
<li><a title="where" href="http://ourmysql.com/archives/1461#where">where</a></li>
<li><a title="like" href="http://ourmysql.com/archives/1461#like">like</a></li>
<li><a title="数据过滤regexp" href="http://ourmysql.com/archives/1461#regexp">数据过滤regexp</a></li>
<li><a title="concat" href="http://ourmysql.com/archives/1461#concat">concat</a></li>
<li><a title="文本函数" href="http://ourmysql.com/archives/1461#_6">文本函数</a></li>
<li><a title="日期函数" href="http://ourmysql.com/archives/1461#_7">日期函数</a></li>
<li><a title="数值函数" href="http://ourmysql.com/archives/1461#_8">数值函数</a></li>
<li><a title="聚集函数" href="http://ourmysql.com/archives/1461#_9">聚集函数</a></li>
<li><a title="group" href="http://ourmysql.com/archives/1461#group">group</a></li>
<li><a title="子查询" href="http://ourmysql.com/archives/1461#_10">子查询</a></li>
<li><a title="联结表" href="http://ourmysql.com/archives/1461#_11">联结表</a></li>
<li><a title="高级联结表" href="http://ourmysql.com/archives/1461#_12">高级联结表</a></li>
<li><a title="组合查询" href="http://ourmysql.com/archives/1461#_13">组合查询</a></li>
<li><a title="全文本搜索" href="http://ourmysql.com/archives/1461#_14">全文本搜索</a></li>
</ul>
</li>
<li><a title="插入数据" href="http://ourmysql.com/archives/1461#_16">插入数据</a></li>
<li><a title="更新" href="http://ourmysql.com/archives/1461#_17">更新</a></li>
<li><a title="删除" href="http://ourmysql.com/archives/1461#_18">删除</a></li>
<li><a title="表操作" href="http://ourmysql.com/archives/1461#_19">表操作</a></li>
<li><a title="视图操作" href="http://ourmysql.com/archives/1461#_20">视图操作</a></li>
<li><a title="存储过程" href="http://ourmysql.com/archives/1461#_21">存储过程</a></li>
<li><a title="游标" href="http://ourmysql.com/archives/1461#_22">游标</a></li>
<li><a title="触发器" href="http://ourmysql.com/archives/1461#_23">触发器</a></li>
<li><a title="事务" href="http://ourmysql.com/archives/1461#_24">事务</a></li>
<li><a title="导入导出" href="http://ourmysql.com/archives/1461#_25">导入导出</a></li>
<li><a title="性能研究" href="http://ourmysql.com/archives/1461#_26">性能研究</a></li>
<li><a title="实时监控" href="http://ourmysql.com/archives/1461#_27">实时监控</a></li>
</ul>
</li>
</ul>
</div>
</section>
<section id="content">update: 2013-08-11, 笔记录了一半不到，还没码完&#8230;.&gt;&lt; update: 2013-11-23, DONEmysql速查</p>
<p>参考： Mysql必知必会,网络blog, stackoverflow</p>
<p>注； 基础部分sql参考 《mysql必知必会》, 还不错的一本书，菜鸟入门级，需要的话可以入手</p>
<p>在浏览器中使用查找</p>
<p>寻找一个好的mysql开源gui工具</p>
<h2 id="_1">环境配置</h2>
<p>ubuntu安装mysql</p>
<div>
<pre>sudo apt-get install mysql-server mysql-client
netstat -nltp | grep mysql
配置文件 /etc/mysql/my.conf</pre>
</div>
<h2 id="_2">基本概念</h2>
<p>数据库基础：</p>
<div>
<pre>InnoDB是一个可靠地事务处理引擎，不支持全文本搜索
MyISAM是一个性能极高的引擎，支持全文本搜索，不支持事务处理</pre>
</div>
<p>数据库-database</p>
<div>
<pre>保存有组织的数据的容器（通常是一个文件或一组文件）</pre>
</div>
<p>表-table</p>
<div>
<pre>某种特定类型数据的结构化清单</pre>
</div>
<p>模式-schema</p>
<div>
<pre>关于数据库和表的布局及特性的信息</pre>
</div>
<p>列-column</p>
<div>
<pre>表中的一个字段，所有表都是由一个或多个列组成的</pre>
</div>
<p>数据类型-datatype</p>
<div>
<pre>所容许的数据的类型。每个表列都有相应的数据类型，它限制（或容许）该列中存储的数据</pre>
</div>
<p>行-row</p>
<div>
<pre>表中的一个记录</pre>
</div>
<p>主键-primary key</p>
<div>
<pre>一列或一组列，其值能够唯一区分表中的每个行</pre>
</div>
<h2 id="mysql">mysql命令行</h2>
<h3 id="_3">进入</h3>
<div>
<pre>输入： mysql
或者   mysql -u ken
       mysql -u ken -p -h myserver -P 9999 【给出用户名，主机名，端口】

获取帮助: mysql --help</pre>
</div>
<p>命令格式和说明：</p>
<div>
<pre>1.命令必须；或\g结束，仅Enter不执行明林
2.help 或\h获得帮助
3.quit或exit退出</pre>
</div>
<p>可以用GUI工具</p>
<div>
<pre>MySQL Administrator
MySQL Query Browser</pre>
</div>
<h3 id="use">use</h3>
<p>创建库:</p>
<div>
<pre>&gt;CREATE DATABASE MYSQLDATA</pre>
</div>
<p>使用某个库</p>
<div>
<pre>use db_name</pre>
</div>
<h3 id="show">show</h3>
<p>查看所有数据库</p>
<div>
<pre>show databases;</pre>
</div>
<p>列出库中所有表</p>
<div>
<pre>use db_name;
show tables;</pre>
</div>
<p>列出表的所有列信息</p>
<div>
<pre>show columns from table_name;
or
desc table_name;</pre>
</div>
<p>显示创建的sql语句</p>
<div>
<pre>show create database db_name;
show create table table_name;</pre>
</div>
<p>其他</p>
<div>
<pre>show status  服务器状态信息
show grants  显示授权用户
show errors/show warnings 显示服务器错误或警告信息</pre>
</div>
<h2 id="_5">查询</h2>
<p>SELECT子句顺序</p>
<div>
<pre>SELECT
FROM
WHERE
GROUP BY
HAVING
ORDER BY
LIMIT</pre>
</div>
<h3 id="select">select</h3>
<p>检索单个列</p>
<div>
<pre>&gt;SELECT col FROM tb_name;</pre>
</div>
<p>多个列</p>
<div>
<pre>&gt;SELECT col1, col2
 FROM tb_name</pre>
</div>
<p>检索所有列</p>
<div>
<pre>&gt;SELECT *
 FROM tb_name;
#除非确认要用到所有列</pre>
</div>
<p>检索去重</p>
<div>
<pre>&gt;SELECT DISTINCT col
 FROM tb_name</pre>
</div>
<p>限制结果数</p>
<div>
<pre>&gt;SELECT col1
 FROM tb_name
 LIMIT 5;
返回不多于五行

&gt;SELECT col1
 FROM tb_name
 LIMIT 5, 5
 第一个为开始位置，初始为0.第二个为显示个数
等价于LIMIT 5 OFFSET 5</pre>
</div>
<h3 id="order-by">order by</h3>
<p>按某个字段排序</p>
<div>
<pre>&gt;SELECT col1
 FROM tb_name
 ORDER BY col1</pre>
</div>
<p>按多列排序</p>
<div>
<pre>&gt;SELECT col1, col2, col3
 FROM tb_name
 ORDER BY col1, col2</pre>
</div>
<p>指定排序方向（升序降序）</p>
<div>
<pre>&gt;SELECT col1, col2
 FROM tb_name
 ORDER BY col1 DESC;【默认ASC】
注意：如果想在多个列上排序，必须对每个列使用DESC
注意：ORDER BY必须放在LIMIT之前</pre>
</div>
<h3 id="where">where</h3>
<p>过滤</p>
<div>
<pre>&gt;SELECT col1, col2
 FROM tb_name
 WHERE col1 = 2.5;</pre>
</div>
<p>过滤不匹配</p>
<div>
<pre>&gt;SELECT col1, col2
 FROM tb_name
 WHERE col1 &lt;&gt; 1000</pre>
</div>
<p>范围检查</p>
<div>
<pre>&gt;SELECT col1, col2
 FROM tb_name
 WHERE col1 BETWEEN 5 AND 10</pre>
</div>
<p>空值检查</p>
<div>
<pre>&gt;SELECT col1
 FROM tb_name
 WHERE col2 IS NULL
NULL, 无值，它与字段包含0，空字符串或仅仅包含空格不同</pre>
</div>
<p>多条件，组合and</p>
<div>
<pre>&gt;SELECT col1
 FROM tb_name
 WHERE col1=100 AND col2 &lt;= 10</pre>
</div>
<p>多条件, 组合or</p>
<div>
<pre>&gt;SELECT col1
 FROM tb_name
 WHERE col1=100 OR col2 &lt;= 10</pre>
</div>
<p>优先级 and 大于 or, 先处理的and,所以应该适当使用括号</p>
<div>
<pre>select prod_id from products where (prod_price &lt; 2.5 or vend_id = 1000) and prod_price &gt; 1;</pre>
</div>
<p>指定查询范围, in操作符</p>
<div>
<pre>&gt;SELECT col1
 FROM tb_name
 WHERE col1 IN (1001,1002)</pre>
</div>
<p>取反，not操作符</p>
<div>
<pre>&gt;SELECT col1
 FROM tb_name
 WHERE col1 NOT IN (1001,1002)</pre>
</div>
<p>操作符</p>
<div>
<pre>=
&lt;&gt;
!=
&lt;
&lt;=
&gt;
&gt;=
between A and B</pre>
</div>
<h3 id="like">like</h3>
<p>通配</p>
<div>
<pre>&gt;SELECT col1
 FROM tb_name
 WHERE col1 LIKE ‘jet%’

%匹配0个或多个字符</pre>
</div>
<p>单个字符</p>
<div>
<pre>&gt;SELECT col1
 FROM tb_name
 WHERE col1 LIKE ‘_ ton anvil’</pre>
</div>
<h3 id="regexp">数据过滤regexp</h3>
<p>正则搜索</p>
<div>
<pre>&gt;SELECT col1
FROM tb_name
WHERE col1 REGEXP ‘1000’

REGEXP ‘.000’
REGEXP对列值匹配</pre>
</div>
<p>进行or匹配</p>
<div>
<pre>&gt;SELECT col1
 FROM tb_name
 WHERE col1 REGEXP ‘1000|2000’</pre>
</div>
<p>几个之一</p>
<div>
<pre>select prod_id from products where prod_name regexp '[1|2]000';</pre>
</div>
<p>匹配范围</p>
<div>
<pre>select prod_id from products where prod_name regexp '[1-5]000';</pre>
</div>
<p>匹配特殊字符，\ 进行转义</p>
<div>
<pre>必须使用\\为前导。 \\-
&gt;SELECT col1
 FROM tb_name
 WHERE col1 REGEXP ‘\\.’</pre>
</div>
<p>like和 regexp</p>
<div>
<pre>like整列匹配
regexp 列值内匹配</pre>
</div>
<h3 id="concat">concat</h3>
<p>拼接字符</p>
<div>
<pre>&gt;SELECT Concat(name, ‘ ----‘, age)
 FROM tb_name</pre>
</div>
<p>去除空白</p>
<div>
<pre>&gt;SELECT Rtrim(name)
 FROM tb_name

Ltrim() Trim()</pre>
</div>
<p>使用列名</p>
<div>
<pre>&gt;SELECT Concat(name, ‘---‘, age) AS info
 FROM tb_name</pre>
</div>
<p>算术计算</p>
<div>
<pre>&gt;SELECT quantity * item_price AS total_price
 FROM tb_name

支持+ - * /</pre>
</div>
<h3 id="_6">文本函数</h3>
<p>文本处理函数</p>
<div>
<pre>left()  串左边字符
length() 串长度
locate() 找出串的一个子串
lower() 转为小写
ltrim() 去掉左边空格
right() 返回串右边字符
rtrim() 去掉串右边空格
soundex() 返回字符串soundex值
upper() 大写</pre>
</div>
<p>eg</p>
<div>
<pre>&gt;SELECT Upper(name)
FROM tb_name</pre>
</div>
<h3 id="_7">日期函数</h3>
<p>日期和时间处理函数</p>
<div>
<pre>adddate() 增加一个日期-天或周
addtime() 增加一个时间
curdate() 返回当前日期
curtime() 返回当前时间
date() 返回日期时间的日期部分
datediff() 计算两个日期差
date_add() 高度灵活的日期运算函数
date_format() 返回一个格式化的日期或时间串
day() 返回一个日期的天数部分
dayofweek() 对于一个日期，返回对应的星期几
hour()
minute()
month()
now() 当前日期和时间
second()
time() 当前日期时间的时间部分
year()</pre>
</div>
<p>eg</p>
<div>
<pre>&gt;SELECT col1
 FROM tb_name
 WHERE Date(order_date) = ‘2005-09-01’</pre>
</div>
<p>常用日期和时间函数</p>
<div>
<pre>Date()返回日期时间的日期部分
Day()返回日期的天数部分</pre>
</div>
<h3 id="_8">数值函数</h3>
<p>数值处理函数</p>
<div>
<pre>abs()
cos()
exp() 指数
mod()
pi() 返回圆周率
rand() 随机数
sin()
sqrt()
tan()</pre>
</div>
<h3 id="_9">聚集函数</h3>
<p>avg 平均</p>
<div>
<pre>&gt;SELECT AVG(price) AS avg_price
 FROM tb_name</pre>
</div>
<p>count 计数</p>
<div>
<pre>select count(*) from products; #无论Null还是非空，均纳入计数
select count(prod_id) from products; #计数有值记录，忽略NULL值</pre>
</div>
<p>max 最大</p>
<div>
<pre>&gt;SELECT MAX(price) AS max_price
 FROM tb_name</pre>
</div>
<p>min 最小</p>
<div>
<pre>&gt;SELECT MIN(price) AS min_price
 FROM tb_name</pre>
</div>
<p>sum 求和</p>
<div>
<pre>&gt;SELECT SUM(quantity) AS total
 FROM tb_name
#sum函数忽略值为NULL的行</pre>
</div>
<h3 id="group">group</h3>
<p>group</p>
<div>
<pre>&gt;SELECT id, COUNT(*) AS num_prods
 FROM tb_name
 GROUP BY id</pre>
</div>
<p>注意：</p>
<div>
<pre>1.group by 可以包含任意数目的列
2.group by 中每个列都必须是检索列或有效的表达式（但不能使聚集函数）
3.除聚集函数外，select语句中的每个列都必须在group by子句中出现
4.如果分组列有Null值，Null将作为一个分组返回
5.group by 子句必须出现在where子句之后, order by 之前</pre>
</div>
<p>过滤分组</p>
<div>
<pre>&gt;SELECT cust_id, COUNT(*) AS orders
 FROM orders
 GROUP BY cust_id
 HAVING COUNT(*) &gt; 2</pre>
</div>
<p>where和having区别</p>
<div>
<pre>where在分组前过滤，having在分组后过滤</pre>
</div>
<h3 id="_10">子查询</h3>
<p>1.用于过滤</p>
<div>
<pre>&gt;SELECT cust_id
 FROM orders
 WHERE order_num IN (SELECT order_num
                    FROM orderitems)</pre>
</div>
<p>2.作为字段</p>
<div>
<pre>&gt;SELECT cust_name,
       cust_state,
       (SELECT COUNT(*)
        FROM orders
        WHERE orders.cust_id = customers.cust_id) AS orders
 FROM customers
 ORDER BY cust_name</pre>
</div>
<h3 id="_11">联结表</h3>
<p>1.创建联结</p>
<div>
<pre>&gt;SELECT vend_name, prod_name, prod_price
 FROM vendors, products
 WHERE vendors.vend_id = products.vend_id
 ORDER BY vend_name, prod_name;</pre>
</div>
<p>可进行联结多个表</p>
<p>2.内部联结</p>
<div>
<pre>&gt;SELECT vend_name,prod_name,prod_price
 FROM vendors INNER JOIN products ON vendors.vend_id = products.vend_id</pre>
</div>
<h3 id="_12">高级联结表</h3>
<p>1.自联结</p>
<div>
<pre>&gt;SELECT prod_id, prod_name
 FROM products
 WHERE vend_id = (SELECT vend_id FROM products
                WHERE prod_id = ‘DTNTR’)</pre>
</div>
<p>等价于</p>
<div>
<pre>&gt;SELECT p1.prod_id, p1.prod_name
 FROM products AS p1, products AS p2
 WHERE p1.vend_id = p2.vend_id
        AND p2.prod_id = ‘DTNTR’</pre>
</div>
<p>2.外部联结</p>
<div>
<pre>&gt;SELECT customers.cust_id, orders.order_num
 FROM customers LEFT OUTER JOIN orders
      ON customers.cust_id = orders.cust_id</pre>
</div>
<h3 id="_13">组合查询</h3>
<p>1.UNION</p>
<div>
<pre>&gt;SELECT vend_id, prod_id, prod_price
 FROM products
 WHERE prod_price &lt;=5
 UNION
 SELECT vend_id, prod_id, prod_price
 FROM products
 WHERE vend_id IN (1001,1002)

UNION自动去除重复行
UNION ALL 保留</pre>
</div>
<p>2.放在UNION后的排序语句</p>
<div>
<pre>对所有SELECT生效</pre>
</div>
<h3 id="_14">全文本搜索</h3>
<p>MyISAM 支持全文本搜索</p>
<p>InnoDB不支持全文本搜索</p>
<p>1.启用</p>
<div>
<pre>&gt;CREATE TABLE productnotes(
 note_id int NOT NULL AUT_INCREMENT,
 note_text text NULL,
 FULLTEXT(note_text)</pre>
</div>
<p>2.进行全文本搜索</p>
<div>
<pre>&gt;SELECT note_text
 FROM tb_name
 WHERE Match(note_text) Against(‘rabbit’)</pre>
</div>
<p>3.布尔文本搜索</p>
<div>
<pre>&gt;SELECT note_text
 FROM productontes
 WHERE Match(note_text) Against(‘heavy’ IN BOOLEAN MODE)</pre>
</div>
<h2 id="_16">插入数据</h2>
<p>1.基本插入</p>
<div>
<pre>&gt;INSERT INTO customers(cust_name,
                     cust_address)
 VALUES(‘Pep’, ‘100 main street’)</pre>
</div>
<p>2.插入多行</p>
<div>
<pre>&gt;INSERT INTO customers(cust_name,
                     cust_address)
 VALUES(‘Pep’, ‘100 main street’),
       (‘Tim’, ‘200 main Street’);</pre>
</div>
<p>3.插入检索出来的数据</p>
<div>
<pre>&gt;INSERT INTO customers(cust_name,
                     cust_address)
 SELECT cust_name, custaddress
 FROM custnew;</pre>
</div>
<h2 id="_17">更新</h2>
<p>1.更新行</p>
<div>
<pre>&gt;UPDATE customers
 SET cust_email = ‘a@fudd.com’
 WHERE cust_id = 10005</pre>
</div>
<p>2.即使发生错误也继续进行而不是退出</p>
<div>
<pre>&gt;UPDATE IGNORE customers</pre>
</div>
<h2 id="_18">删除</h2>
<p>1.删除数据</p>
<div>
<pre>&gt;DELETE FROM customers
 WHERE cust_id = 10006</pre>
</div>
<h2 id="_19">表操作</h2>
<p>1.创建表</p>
<div>
<pre>&gt;CREATE TABLE customers(
   cust_id int NOT NULL AUTO_INCREMENT,
   cust_name char(50) NOT NULL,
   vend_city char(50) NULL,
   quantity int NOT NULL DEFAULT 1,
   PRIMARY KEY(cust_id)
)ENGINE=InnoDB</pre>
</div>
<p>2.更新表</p>
<p>加字段</p>
<div>
<pre>&gt;ALTER TABLE vendors
 ADD vend_phone CHAR(20)</pre>
</div>
<p>删除某个字段</p>
<div>
<pre>&gt;ALTER TABLE tb1 DROP COLUMN names;</pre>
</div>
<p>改变列类型</p>
<div>
<pre>&gt;ALTER TABLE infos CHANGE list list tinyint NOT NULL DEFAULT '0'</pre>
</div>
<p>加主键</p>
<div>
<pre>&gt;ALTER TABLE tb1 ADD primary key(id)</pre>
</div>
<p>删除一个字段</p>
<div>
<pre>&gt;ALTER TABLE tb1 DROP field_name</pre>
</div>
<p>增加自增长主键</p>
<div>
<pre>alter table customers change id id not null auto_increment primary key;</pre>
</div>
<p>增加新字段并设置为主键</p>
<div>
<pre>Alter TABLE tablename ADD new_field_id int(5) default 0 not null auto_increment ADD primary key(new_field_id)

ALTER TABLE example ADD ID INT NOT NULL;
ALTER TABLE example ADD UNIQUE(url)

&gt;ALTER TABLE vendors
 DROP COLUMN vend_phone</pre>
</div>
<p>alter table syntax: http://dev.mysql.com/doc/refman/5.1/en/alter-table.html</p>
<p>3.删除表</p>
<div>
<pre>&gt;DROP TABLE customers2;</pre>
</div>
<p>4.清空表数据</p>
<div>
<pre>&gt;DELETE FROM mytable;</pre>
</div>
<p>5.重命名表</p>
<div>
<pre>&gt;RENAME TABLE customers2 TO customers;
 ALTER TABLE 'oldname' RENAME TO 'newname'</pre>
</div>
<h2 id="_20">视图操作</h2>
<p>1.创建视图</p>
<div>
<pre>&gt;CREATE VIEW productcustomers AS
 SELECT cust_name, cust_contact
 FROM customers, orders, orderitems
 WHERE customers.cust_id = orders.cust_id</pre>
</div>
<p>2.使用视图</p>
<div>
<pre>&gt;SELECT cust_name, cust_contact
 FROM productcustomers
 WHERE prod_id = ‘TNT2’</pre>
</div>
<h2 id="_21">存储过程</h2>
<p>1.创建简单存储过程</p>
<div>
<pre>&gt;CREATE PROCEDURE productpricing()
 BEGIN
SELECT Avg(price) AS priceavg
FROM products;
 END;</pre>
</div>
<p>调用:CALL productpricing()</p>
<p>2.删除存储过程</p>
<div>
<pre>&gt;DROP PROCEDURE productpricing</pre>
</div>
<p>3.使用参数</p>
<div>
<pre>&gt;CREATE PROCEDURE ordertotal(
IN onumber INT,
OUT ototal DECIMAL(8,2)
)
BEGIN
SELECT Sum(item_price*quality)
FROM orderitems
WHERE order_num = onumber
INTO ototal;
END;</pre>
</div>
<p>调用:</p>
<div>
<pre>&gt;CALL ordertotal(200005, @total;
&gt;SELECT @total;</pre>
</div>
<p>3.检查存储过程</p>
<div>
<pre>&gt;SHOW CREATE PROCEDURE ordertotal;</pre>
</div>
<h2 id="_22">游标</h2>
<p>1.创建游标</p>
<div>
<pre>&gt;CREATE PROCEDURE processorders()
 BEGIN
DECLARE ordernumbers CURSOR
FOR
SELECT order_number FROM orders;

BEGIN ordernumbers;

FETCH ordernumbers INTO o;

CLOSE ordernumbers;
 END;

DECLARE CONTINUE HANDLER FOR SQLSTATE ‘02000’ SET done=1;
REPEAT
    FETCH ordernumbers INTO o;
END;</pre>
</div>
<h2 id="_23">触发器</h2>
<p>1.创建触发器</p>
<div>
<pre>&gt;CREATE TRIGGER newproduct AFTER INSERT ON products
 FOR EACH ROW SELECT ‘Product added’</pre>
</div>
<p>2.删除触发器</p>
<div>
<pre>&gt;DROP TRIGGER newproduct;</pre>
</div>
<p>3.INSERT触发器</p>
<div>
<pre>&gt;CREATE TRIGGER neworder AFTER INSERT ON orders
 FOR EACH ROW SELECT NEW.order_num</pre>
</div>
<p>4.DELETE触发器</p>
<div>
<pre>&gt;CREATE TRIGGER deleteorder BEFORE DELETE ON orders
 FOR EACH ROW
 BEGIN
INSERT INTO archive_orders(order_num, order_date, cust_id)
VALUES(OLD.order_num, OLD.order_date, OLD.cust_id);
 END;</pre>
</div>
<p>5.UPDATE触发器</p>
<div>
<pre>&gt;CREATE TRIGGER updatevendor BEFORE UPDATE ON vendors
 FOR EACH ROW SET NEW.vend_state = Upper(NEW.vend_state);</pre>
</div>
<h2 id="_24">事务</h2>
<p>基本概念</p>
<div>
<pre>ACID
A,原子性，食物是一个原子操作单元，其对数据的修改，要么全执行，要么全不执行
C.一致性，事务开始和完成的时候，数据必须都保持一致状态（所有相关数据规则和内部数据结构）
I.隔离性，保证事务不受外部并发操作影响，即事务处理中间过程状态对外不可见
D.持久性，事务完成后，对数据修改时永久性的，及时出现系统故障也能够保持</pre>
</div>
<p>1.事务</p>
<div>
<pre>&gt;START TRANSACTION
 DELETE FROM ordertotals;
 SELECT * FROM ordertotals;

&gt;ROLLBACK
回退

&gt;COMMIT
提交</pre>
</div>
<p>2.设立保留点</p>
<div>
<pre>&gt;SAVEPOINT delete1;

&gt;ROLLBACK TO delete1;</pre>
</div>
<h2 id="_25">导入导出</h2>
<p>1.导入</p>
<p>用文本形式插入数据</p>
<div>
<pre>&gt;LOAD DATA LOCAL INFILE 'd:/mysql.txt' INTO TABLE mytable;</pre>
</div>
<p>导入.sql</p>
<div>
<pre>&gt;use database;
&gt;source d:/mysql.sql</pre>
</div>
<p>从另外一张表往这张表插入</p>
<div>
<pre>INSERT INTO tab1(f1,f2)
SELECT a.f1, a.f2
FROM a WHERE a.f1='a'</pre>
</div>
<p>2.备份</p>
<p>导出要用到MySQL的mysqldump工具，基本用法是：</p>
<div>
<pre>mysqldump [OPTIONS] database [tables]</pre>
</div>
<p>备份MySQL数据库的命令</p>
<div>
<pre>mysqldump -hhostname -uusername -ppassword databasename &gt; backupfile.sql</pre>
</div>
<p>备份MySQL数据库为带删除表的格式，能够让该备份覆盖已有数据库而不需要手动删除原有数据库。</p>
<div>
<pre>mysqldump -–add-drop-table -uusername -ppassword databasename &gt; backupfile.sql</pre>
</div>
<p>直接将MySQL数据库压缩备份</p>
<div>
<pre>mysqldump -hhostname -uusername -ppassword databasename | gzip &gt; backupfile.sql.gz</pre>
</div>
<p>备份MySQL数据库某个(些)表</p>
<div>
<pre>mysqldump -hhostname -uusername -ppassword databasename specific_table1 specific_table2 &gt; backupfile.sql</pre>
</div>
<p>同时备份多个MySQL数据库</p>
<div>
<pre>mysqldump -hhostname -uusername -ppassword –databases databasename1 databasename2 databasename3 &gt; multibackupfile.sql</pre>
</div>
<p>仅仅备份数据库结构</p>
<div>
<pre>mysqldump –no-data –databases databasename1 databasename2 databasename3 &gt; structurebackupfile.sql</pre>
</div>
<p>备份服务器上所有数据库</p>
<div>
<pre>mysqldump –all-databases &gt; allbackupfile.sql</pre>
</div>
<p>还原</p>
<p>还原MySQL数据库的命令</p>
<div>
<pre>mysql -hhostname -uusername -ppassword databasename &lt; backupfile.sql
mysql -hhostname -ppassword databasename tablename &lt; backuptablefile.sql</pre>
</div>
<p>还原压缩的MySQL数据库</p>
<div>
<pre>gunzip &lt; backupfile.sql.gz | mysql -uusername -ppassword databasename</pre>
</div>
<p>将数据库转移到新服务器</p>
<div>
<pre>mysqldump -uusername -ppassword databasename | mysql –host=*.*.*.* -C databasename</pre>
</div>
<p>将查询结果导入外部文件</p>
<div>
<pre>SELECT a,b,a+b 
FROM test_table
INTO OUTFILE '/tmp/result.txt'
FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '"'
LINES TERMINATED BY '\n'

或者

mysql -u you -p -e "SELECT ..." &gt;  file_name</pre>
</div>
<h2 id="_26">性能研究</h2>
<div>
<pre>1.什么情况下无法使用索引？</pre>
</div>
<h2 id="_27">实时监控</h2>
<p>查看mysql数据库的当前连接数</p>
<div>
<pre>命令： show processlist;
或者 # mysqladmin -uroot -p密码 processlist</pre>
</div>
<p>当前状态</p>
<div>
<pre>命令： show status;
或者 # mysqladmin -uroot -p密码 status</pre>
</div>
</section>
<h2  class="related_post_title">猜想失败，您看看下面的文章有用吗？</h2><ul class="related_post"><li><a href="http://ourmysql.com/archives/1385" title="MySQL怎么禁用autocommit">MySQL怎么禁用autocommit</a></li><li><a href="http://ourmysql.com/archives/1257" title="MySQL优化的奇技淫巧之STRAIGHT_JOIN">MySQL优化的奇技淫巧之STRAIGHT_JOIN</a></li><li><a href="http://ourmysql.com/archives/232" title="MySQL排序原理分析">MySQL排序原理分析</a></li><li><a href="http://ourmysql.com/archives/1313" title="使用Autoconf检测MySQL相关的软件包">使用Autoconf检测MySQL相关的软件包</a></li><li><a href="http://ourmysql.com/archives/822" title="MySQL半同步存在的问题">MySQL半同步存在的问题</a></li><li><a href="http://ourmysql.com/archives/1466" title="今天你检查备份了吗？">今天你检查备份了吗？</a></li><li><a href="http://ourmysql.com/archives/1300" title="Unique索引优化实践">Unique索引优化实践</a></li><li><a href="http://ourmysql.com/archives/1453" title="MySQL relay_log_purge=0 时的风险">MySQL relay_log_purge=0 时的风险</a></li><li><a href="http://ourmysql.com/archives/373" title="关于设计表时应该注意的问题">关于设计表时应该注意的问题</a></li><li><a href="http://ourmysql.com/archives/1430" title="更好的 SQL 模式的 10 条规则">更好的 SQL 模式的 10 条规则</a></li></ul>]]></content:encoded>
			<wfw:commentRss>http://ourmysql.com/archives/1461/feed</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>数据导入主键冲突问题</title>
		<link>http://ourmysql.com/archives/1459</link>
		<comments>http://ourmysql.com/archives/1459#comments</comments>
		<pubDate>Mon, 06 Jun 2016 23:41:13 +0000</pubDate>
		<dc:creator>OurMySQL</dc:creator>
				<category><![CDATA[MySQL解错方案]]></category>
		<category><![CDATA[主键]]></category>

		<guid isPermaLink="false">http://ourmysql.com/?p=1459</guid>
		<description><![CDATA[我在很多场合强调过，InnoDB引擎已可适用95%以上的业务场景，完全没必要再使用其他引擎了，这次的奇葩案例也是一开始没注意到用ARCHIVE引擎而走了些弯路。 <a href="http://ourmysql.com/archives/1459"><br /><br />继续阅读全文 <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<h1 style="margin:1.714285714rem 0px;padding:0px;border:0px;font-size:1.5rem;vertical-align:baseline;clear:both;line-height:1.5;color:#444444;font-family:helvetica, arial, sans-serif;">0、导读</h1>
<blockquote style="margin:0px 0px 1.714285714rem;padding:1.714285714rem;border:0px;font-size:14px;vertical-align:baseline;quotes:none;font-style:italic;color:#444444;font-family:helvetica, arial, sans-serif;"><p style="padding:0px;border:0px;vertical-align:baseline;line-height:1.714285714;margin-top:0px;margin-bottom:0px;">用LOAD DATA导入数据却一直提示主键冲突问题解决案例。</p>
</blockquote>
<h1 style="margin:1.714285714rem 0px;padding:0px;border:0px;font-size:1.5rem;vertical-align:baseline;clear:both;line-height:1.5;color:#444444;font-family:helvetica, arial, sans-serif;">1、问题描述</h1>
<p style="padding:0px;border:0px;font-size:14px;vertical-align:baseline;line-height:1.714285714;color:#444444;font-family:helvetica, arial, sans-serif;margin-top:0px;margin-bottom:1.714285714rem;">有位学生遇到数据导入时一直提示1022主键冲突问题，而导入的数据明明完全没有任何冲突，百思不得其解，请我帮忙协查。</p>
<p style="padding:0px;border:0px;font-size:14px;vertical-align:baseline;line-height:1.714285714;color:#444444;font-family:helvetica, arial, sans-serif;margin-top:0px;margin-bottom:1.714285714rem;">下面是关于该问题现象描述：</p>
<p style="padding:0px;border:0px;font-size:14px;vertical-align:baseline;line-height:1.714285714;color:#444444;font-family:helvetica, arial, sans-serif;margin-top:0px;margin-bottom:1.714285714rem;">1、表结构DDL</p>
<p style="padding:0px;border:0px;font-size:14px;vertical-align:baseline;line-height:1.714285714;color:#444444;font-family:helvetica, arial, sans-serif;margin-top:0px;margin-bottom:1.714285714rem;">CREATE TABLE `wcp` (</p>
<p style="padding:0px;border:0px;font-size:14px;vertical-align:baseline;line-height:1.714285714;color:#444444;font-family:helvetica, arial, sans-serif;margin-top:0px;margin-bottom:1.714285714rem;">`id` int(10) unsigned NOT NULL AUTO_INCREMENT,</p>
<p style="padding:0px;border:0px;font-size:14px;vertical-align:baseline;line-height:1.714285714;color:#444444;font-family:helvetica, arial, sans-serif;margin-top:0px;margin-bottom:1.714285714rem;">`txcode` char(4) NOT NULL,</p>
<p style="padding:0px;border:0px;font-size:14px;vertical-align:baseline;line-height:1.714285714;color:#444444;font-family:helvetica, arial, sans-serif;margin-top:0px;margin-bottom:1.714285714rem;">`notice_from` enum(‘page’,’server’) ,</p>
<p style="padding:0px;border:0px;font-size:14px;vertical-align:baseline;line-height:1.714285714;color:#444444;font-family:helvetica, arial, sans-serif;margin-top:0px;margin-bottom:1.714285714rem;">`message` varchar(600) NOT NULL ,</p>
<p style="padding:0px;border:0px;font-size:14px;vertical-align:baseline;line-height:1.714285714;color:#444444;font-family:helvetica, arial, sans-serif;margin-top:0px;margin-bottom:1.714285714rem;">`signature` varchar(260) NOT NULL ,</p>
<p style="padding:0px;border:0px;font-size:14px;vertical-align:baseline;line-height:1.714285714;color:#444444;font-family:helvetica, arial, sans-serif;margin-top:0px;margin-bottom:1.714285714rem;">`payment_no` char(30) NOT NULL ,</p>
<p style="padding:0px;border:0px;font-size:14px;vertical-align:baseline;line-height:1.714285714;color:#444444;font-family:helvetica, arial, sans-serif;margin-top:0px;margin-bottom:1.714285714rem;">`notice_time` int(10) unsigned NOT NULL COMMENT ,</p>
<p style="padding:0px;border:0px;font-size:14px;vertical-align:baseline;line-height:1.714285714;color:#444444;font-family:helvetica, arial, sans-serif;margin-top:0px;margin-bottom:1.714285714rem;">`dealt_ok` tinyint(1) NOT NULL DEFAULT ‘0’ COMMENT,</p>
<p style="padding:0px;border:0px;font-size:14px;vertical-align:baseline;line-height:1.714285714;color:#444444;font-family:helvetica, arial, sans-serif;margin-top:0px;margin-bottom:1.714285714rem;"><strong style="margin:0px;padding:0px;border:0px;vertical-align:baseline;"> &nbsp;PRIMARY KEY (`id`)</strong></p>
<p style="padding:0px;border:0px;font-size:14px;vertical-align:baseline;line-height:1.714285714;color:#444444;font-family:helvetica, arial, sans-serif;margin-top:0px;margin-bottom:1.714285714rem;">) ENGINE=ARCHIVE AUTO_INCREMENT=117 DEFAULT CHARSET=utf8;</p>
<p style="padding:0px;border:0px;font-size:14px;vertical-align:baseline;line-height:1.714285714;color:#444444;font-family:helvetica, arial, sans-serif;margin-top:0px;margin-bottom:1.714285714rem;">欲导入的数据有116条，可以非常肯定的是，主键值都是顺序增长的，完全没有冲突，所以感觉非常奇怪。</p>
<h1 style="margin:1.714285714rem 0px;padding:0px;border:0px;font-size:1.5rem;vertical-align:baseline;clear:both;line-height:1.5;color:#444444;font-family:helvetica, arial, sans-serif;">2、原因分析</h1>
<p style="padding:0px;border:0px;font-size:14px;vertical-align:baseline;line-height:1.714285714;color:#444444;font-family:helvetica, arial, sans-serif;margin-top:0px;margin-bottom:1.714285714rem;">细心的同学，从上面我贴的表DDL或许能感觉出什么不对劲的味道（嗯，有点像狗狗嗅觉灵敏的意思，哈哈）</p>
<p style="padding:0px;border:0px;font-size:14px;vertical-align:baseline;line-height:1.714285714;color:#444444;font-family:helvetica, arial, sans-serif;margin-top:0px;margin-bottom:1.714285714rem;">经我这么一提醒，再认真看一下，是不是真的发现了什么？嗯，很棒，答对了（从我女儿爱看的米奇妙妙屋里学到的语气词，嘿），该表的引擎是<strong style="margin:0px;padding:0px;border:0px;vertical-align:baseline;">ARCHIVE</strong>，而不是我们常用的InnoDB或MyISAM，会不会和这个有关系呢？</p>
<p style="padding:0px;border:0px;font-size:14px;vertical-align:baseline;line-height:1.714285714;color:#444444;font-family:helvetica, arial, sans-serif;margin-top:0px;margin-bottom:1.714285714rem;"><strong style="margin:0px;padding:0px;border:0px;vertical-align:baseline;">ARCHIVE</strong>几乎没怎么被用过，非常冷门，它有什么特点呢。翻翻手册便知：</p>
<blockquote style="margin:0px 0px 1.714285714rem;padding:1.714285714rem;border:0px;font-size:14px;vertical-align:baseline;quotes:none;font-style:italic;color:#444444;font-family:helvetica, arial, sans-serif;"><p style="padding:0px;border:0px;vertical-align:baseline;line-height:1.714285714;margin-top:0px;margin-bottom:1.714285714rem;">The ARCHIVE storage engine is used for storing large amounts of data <strong style="margin:0px;padding:0px;border:0px;vertical-align:baseline;">without indexes</strong> in a very small footprint.</p>
<p style="padding:0px;border:0px;vertical-align:baseline;line-height:1.714285714;margin-top:0px;margin-bottom:1.714285714rem;">The ARCHIVE engine supports INSERT and SELECT, <strong style="margin:0px;padding:0px;border:0px;vertical-align:baseline;">but not DELETE, REPLACE, or UPDATE</strong>. It does support ORDER BY operations, BLOB columns, and basically all but spatial data types (see Section 11.17.4.1, “MySQL Spatial Data Types”). The ARCHIVE engine uses row-level locking.</p>
<p style="padding:0px;border:0px;vertical-align:baseline;line-height:1.714285714;margin-top:0px;margin-bottom:0px;">The ARCHIVE engine supports the AUTO_INCREMENT column attribute. The AUTO_INCREMENT column can have either a unique or nonunique index.<strong style="margin:0px;padding:0px;border:0px;vertical-align:baseline;"> Attempting to create an index on any other column results in an error</strong>. The ARCHIVE engine also supports the AUTO_INCREMENT table option in CREATE TABLE and ALTER TABLE statements to specify the initial sequence value for a new table or reset the sequence value for an existing table, respectively.</p>
</blockquote>
<p style="padding:0px;border:0px;font-size:14px;vertical-align:baseline;line-height:1.714285714;color:#444444;font-family:helvetica, arial, sans-serif;margin-top:0px;margin-bottom:1.714285714rem;">可以看到，ARCHIVE引擎和我们平时用的InnoDB、MyISAM区别还是很大的。它不支持DELETE、REPLACE、UPDATE等操作命令，只支持INSERT、SELECT、LOAD DATA等。ARCHIVE也支持自增列属性，但也必须是普通索引、唯一索引或主键索引（这个和其他引擎基本一致）。</p>
<p style="padding:0px;border:0px;font-size:14px;vertical-align:baseline;line-height:1.714285714;color:#444444;font-family:helvetica, arial, sans-serif;margin-top:0px;margin-bottom:1.714285714rem;">接下来我们尝试解决数据导入主键冲突的问题。</p>
<h1 style="margin:1.714285714rem 0px;padding:0px;border:0px;font-size:1.5rem;vertical-align:baseline;clear:both;line-height:1.5;color:#444444;font-family:helvetica, arial, sans-serif;">3、问题解决</h1>
<p style="padding:0px;border:0px;font-size:14px;vertical-align:baseline;line-height:1.714285714;color:#444444;font-family:helvetica, arial, sans-serif;margin-top:0px;margin-bottom:1.714285714rem;">在这个例子中，想要最终能导入数据的话，有几个方法：</p>
<blockquote style="margin:0px 0px 1.714285714rem;padding:1.714285714rem;border:0px;font-size:14px;vertical-align:baseline;quotes:none;font-style:italic;color:#444444;font-family:helvetica, arial, sans-serif;"><ol class="list-paddingleft-2" style="margin:0px 0px 1.714285714rem;padding:0px;border:0px;vertical-align:baseline;list-style-position:outside;list-style-image:initial;line-height:1.714285714;">
<li style="margin:0px 0px 0px 2.571428571rem;padding:0px;border:0px;vertical-align:baseline;">
<p>删除主键定义，或者删除主键的自增属性；</p>
</li>
<li style="margin:0px 0px 0px 2.571428571rem;padding:0px;border:0px;vertical-align:baseline;">
<p>修改id列的主键索引为唯一索引或者普通索引；</p>
</li>
<li style="margin:0px 0px 0px 2.571428571rem;padding:0px;border:0px;vertical-align:baseline;">
<p>调整表DDL定义时指定的AUTO_INCREMENT值为0或1；</p>
</li>
<li style="margin:0px 0px 0px 2.571428571rem;padding:0px;border:0px;vertical-align:baseline;">
<p>修改表引擎为InnoDB或MyISAM；</p>
</li>
</ol>
</blockquote>
<p style="padding:0px;border:0px;font-size:14px;vertical-align:baseline;line-height:1.714285714;color:#444444;font-family:helvetica, arial, sans-serif;margin-top:0px;margin-bottom:1.714285714rem;">第3个解决方案也是我自己几次反复测试才发现的，手册中也未提及，比较奇葩，这也是这次的案例令人最为不解的地方。</p>
<h1 style="margin:1.714285714rem 0px;padding:0px;border:0px;font-size:1.5rem;vertical-align:baseline;clear:both;line-height:1.5;color:#444444;font-family:helvetica, arial, sans-serif;">4、其他建议</h1>
<p style="padding:0px;border:0px;font-size:14px;vertical-align:baseline;line-height:1.714285714;color:#444444;font-family:helvetica, arial, sans-serif;margin-top:0px;margin-bottom:1.714285714rem;">我在很多场合强调过，InnoDB引擎已可适用95%以上的业务场景，完全没必要再使用其他引擎了，这次的奇葩案例也是一开始没注意到用ARCHIVE引擎而走了些弯路。</p>
<p style="padding:0px;border:0px;font-size:14px;vertical-align:baseline;line-height:1.714285714;color:#444444;font-family:helvetica, arial, sans-serif;margin-top:0px;margin-bottom:1.714285714rem;">不听老叶言，吃亏在眼前，这话我看在理，嘿嘿~</p>
<h2  class="related_post_title">猜您喜欢</h2><ul class="related_post"><li><a href="http://ourmysql.com/archives/1421" title="MySQL索引之主键索引">MySQL索引之主键索引</a></li><li><a href="http://ourmysql.com/archives/1399" title="[MySQL异常恢复]无主键情况下innodb数据恢复">[MySQL异常恢复]无主键情况下innodb数据恢复</a></li><li><a href="http://ourmysql.com/archives/1294" title="mysql主键的缺少导致备库hang">mysql主键的缺少导致备库hang</a></li><li><a href="http://ourmysql.com/archives/1203" title="InnoDB一定会在索引中加上主键吗">InnoDB一定会在索引中加上主键吗</a></li></ul>]]></content:encoded>
			<wfw:commentRss>http://ourmysql.com/archives/1459/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>MySQL复制线程长时间Opening tables</title>
		<link>http://ourmysql.com/archives/1457</link>
		<comments>http://ourmysql.com/archives/1457#comments</comments>
		<pubDate>Thu, 05 May 2016 13:07:12 +0000</pubDate>
		<dc:creator>OurMySQL</dc:creator>
				<category><![CDATA[MySQL解错方案]]></category>
		<category><![CDATA[Opening tables]]></category>
		<category><![CDATA[线程]]></category>

		<guid isPermaLink="false">http://ourmysql.com/?p=1457</guid>
		<description><![CDATA[从master上用xtrabackup物理备份到slave，启动实例后，应该再执行 mysql_upgrade 升级相关表结构，确保P_S（performanc_schema）、I_S（information_schema）以及 mysql 等几个系统库表结构都升级到最新版本。​ <a href="http://ourmysql.com/archives/1457"><br /><br />继续阅读全文 <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<h1>0、导读</h1>
<blockquote><p> &nbsp; &nbsp;在slave上，发现SQL thread长时间处于Opening tables状态</p>
</blockquote>
<h1>1、问题描述</h1>
<p> &nbsp; &nbsp;朋友的数据库，做了主从replication复制。在slave实例上，SQL thread的长时间处于Opening tables状态，复制进程异常。</p>
<blockquote><p> &nbsp; &nbsp;<span style="color:#3366ff;">mysql&gt; show processlist;</span></p>
<p> &nbsp; &nbsp;<span style="color:#3366ff;">+—-+————-+———-+——+———+——-+—————————————-+——————+</span></p>
<p> &nbsp; &nbsp;<span style="color:#3366ff;">| Id | User &nbsp; &nbsp; &nbsp; &nbsp;| Host &nbsp; &nbsp; &nbsp;| db &nbsp; | Command | Time &nbsp;| State &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;| Info &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; |</span></p>
<p> &nbsp; &nbsp;<span style="color:#3366ff;">+—-+————-+———-+——+———+——-+—————————————-+——————+</span></p>
<p> &nbsp; &nbsp;<span style="color:#3366ff;">| &nbsp;1 | system user | &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | NULL | Connect | &nbsp; 554 | Queueing master event to the relay log | NULL &nbsp; &nbsp; &nbsp; |</span></p>
<p> &nbsp; &nbsp;<span style="color:#3366ff;">| &nbsp;2 | system user | &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | NULL | Connect | 59212 | <strong>Opening tables</strong> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | NULL &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; |</span></p>
</blockquote>
<p> &nbsp; &nbsp;整个实例大概20个database，总共300G左右。</p>
<p> &nbsp; &nbsp;master是5.5版本，slave是5.6版本，master上执行xtrabackup全库备份后搭建的slave。</p>
<h1>2、原因分析</h1>
<p> &nbsp; &nbsp;我的第一反应是table cache是不是太小了，导致open table比较慢，所以才长时间处于这个状态。无论如何，先一层层排查吧。</p>
<p> &nbsp; &nbsp;先看下slave status（部分无用信息我隐掉了）：</p>
<blockquote><p> &nbsp; &nbsp;<span style="color:#3366ff;">mysql&gt; show slave status\G</span></p>
<p> &nbsp; &nbsp;<span style="color:#3366ff;">*************************** 1. row ***************************</span></p>
<p> &nbsp; &nbsp;<span style="color:#3366ff;">Slave_IO_State: Queueing master event to the relay log</span></p>
<p> &nbsp; &nbsp;<span style="color:#3366ff;">Master_Log_File: master-bin.000618</span></p>
<p> &nbsp; &nbsp;<span style="color:#3366ff;">Read_Master_Log_Pos: 614915856</span></p>
<p> &nbsp; &nbsp;<span style="color:#3366ff;">Relay_Log_File: replicate.000008</span></p>
<p> &nbsp; &nbsp;<span style="color:#3366ff;">Relay_Log_Pos: 2384117</span></p>
<p> &nbsp; &nbsp;<span style="color:#3366ff;">Relay_Master_Log_File: master-bin.000617</span></p>
<p> &nbsp; &nbsp;<span style="color:#3366ff;">Slave_IO_Running: Yes</span></p>
<p> &nbsp; &nbsp;<span style="color:#3366ff;">Slave_SQL_Running: Yes</span></p>
<p> &nbsp; &nbsp;<span style="color:#3366ff;">Replicate_Do_DB:</span></p>
<p> &nbsp; &nbsp;<span style="color:#3366ff;">Replicate_Ignore_DB:</span></p>
<p> &nbsp; &nbsp;<span style="color:#3366ff;">Replicate_Do_Table:</span></p>
<p> &nbsp; &nbsp;<span style="color:#3366ff;">Replicate_Ignore_Table:</span></p>
<p> &nbsp; &nbsp;<span style="color:#3366ff;">Replicate_Wild_Do_Table:</span></p>
<p> &nbsp; &nbsp;<span style="color:#3366ff;">Replicate_Wild_Ignore_Table:</span></p>
<p> &nbsp; &nbsp;<span style="color:#3366ff;">Last_Errno: 0</span></p>
<p> &nbsp; &nbsp;<span style="color:#3366ff;">Last_Error:</span></p>
<p> &nbsp; &nbsp;<span style="color:#3366ff;">Skip_Counter: 0</span></p>
<p> &nbsp; &nbsp;<span style="color:#3366ff;">Exec_Master_Log_Pos: 252048331</span></p>
<p> &nbsp; &nbsp;<span style="color:#3366ff;">Relay_Log_Space: 1438994074</span></p>
<p> &nbsp; &nbsp;<span style="color:#3366ff;">Until_Condition: None</span></p>
<p> &nbsp; &nbsp;<span style="color:#3366ff;">Until_Log_File:</span></p>
<p> &nbsp; &nbsp;<span style="color:#3366ff;">Until_Log_Pos: 0</span></p>
<p> &nbsp; &nbsp;<span style="color:#3366ff;">Seconds_Behind_Master: 59240</span></p>
<p> &nbsp; &nbsp;<span style="color:#3366ff;">Master_SSL_Verify_Server_Cert: No</span></p>
<p> &nbsp; &nbsp;<span style="color:#3366ff;">Last_IO_Errno: 0</span></p>
<p> &nbsp; &nbsp;<span style="color:#3366ff;">Last_IO_Error:</span></p>
<p> &nbsp; &nbsp;<span style="color:#3366ff;">Last_SQL_Errno: 0</span></p>
<p> &nbsp; &nbsp;<span style="color:#3366ff;">Last_SQL_Error:</span></p>
<p> &nbsp; &nbsp;<span style="color:#3366ff;">Replicate_Ignore_Server_Ids:</span></p>
<p> &nbsp; &nbsp;<span style="color:#3366ff;">Master_Server_Id: 1</span></p>
<p> &nbsp; &nbsp;<span style="color:#3366ff;">Master_UUID:</span></p>
<p> &nbsp; &nbsp;<span style="color:#3366ff;">Master_Info_File: /home/mysql/master.info</span></p>
<p> &nbsp; &nbsp;<span style="color:#3366ff;">SQL_Delay: 0</span></p>
<p> &nbsp; &nbsp;<span style="color:#3366ff;">SQL_Remaining_Delay: NULL</span></p>
<p> &nbsp; &nbsp;<span style="color:#3366ff;">Slave_SQL_Running_State: <strong>Opening tables</strong></span></p>
</blockquote>
<blockquote><p> &nbsp; &nbsp;<span style="color:#3366ff;"> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Master_Retry_Count: 86400</span></p>
<p> &nbsp; &nbsp;<span style="color:#3366ff;">Last_IO_Error_Timestamp:</span></p>
<p> &nbsp; &nbsp;<span style="color:#3366ff;">Last_SQL_Error_Timestamp:</span></p>
<p> &nbsp; &nbsp;<span style="color:#3366ff;">Master_SSL_Crlpath:</span></p>
<p> &nbsp; &nbsp;<span style="color:#3366ff;">Retrieved_Gtid_Set:</span></p>
<p> &nbsp; &nbsp;<span style="color:#3366ff;">Executed_Gtid_Set:</span></p>
<p> &nbsp; &nbsp;<span style="color:#3366ff;">Auto_Position: 0</span></p>
</blockquote>
<p> &nbsp; &nbsp;看不出来有什么异常的。</p>
<p> &nbsp; &nbsp;再看下系统负载情况：</p>
<blockquote><p lang="zh-CN"><span style="color:#3366ff;">[root@localhost mysql]# vmstat -S m 1</span></p>
<p lang="zh-CN"><span style="color:#3366ff;">procs ———-memory———- —swap- —-io—- -system- —-cpu—-</span></p>
<p lang="zh-CN"><span style="color:#3366ff;"> r &nbsp;b &nbsp; swpd &nbsp; free &nbsp; buff &nbsp;cache &nbsp; si &nbsp; so &nbsp; &nbsp;bi &nbsp; &nbsp;bo &nbsp; in &nbsp; cs us sy id wa st</span></p>
<p lang="zh-CN"><span style="color:#3366ff;"> 0 &nbsp;2 &nbsp; &nbsp; &nbsp;1 &nbsp;19591 &nbsp; &nbsp;458 230576 &nbsp; &nbsp;0 &nbsp; &nbsp;0 &nbsp; &nbsp;11 &nbsp; &nbsp;20 &nbsp; &nbsp;0 &nbsp; &nbsp;0 &nbsp;0 &nbsp;0 100 &nbsp;0 &nbsp;0</span></p>
<p lang="zh-CN"><span style="color:#3366ff;"> 1 &nbsp;1 &nbsp; &nbsp; &nbsp;1 &nbsp;19587 &nbsp; &nbsp;458 230579 &nbsp; &nbsp;0 &nbsp; &nbsp;0 &nbsp;2032 &nbsp;2528 1645 &nbsp;584 &nbsp;1 &nbsp;1 93 &nbsp;4 &nbsp;0</span></p>
<p lang="zh-CN"><span style="color:#3366ff;"> 1 &nbsp;1 &nbsp; &nbsp; &nbsp;1 &nbsp;19583 &nbsp; &nbsp;458 230582 &nbsp; &nbsp;0 &nbsp; &nbsp;0 &nbsp;1664 &nbsp;2712 1773 &nbsp;461 &nbsp;1 &nbsp;1 93 &nbsp;4 &nbsp;0</span></p>
<p lang="zh-CN"><span style="color:#3366ff;"> 0 &nbsp;2 &nbsp; &nbsp; &nbsp;1 &nbsp;19578 &nbsp; &nbsp;458 230585 &nbsp; &nbsp;0 &nbsp; &nbsp;0 &nbsp;2080 &nbsp;3376 1810 &nbsp;660 &nbsp;1 &nbsp;1 93 &nbsp;4 &nbsp;0</span></p>
<p lang="zh-CN"><span style="color:#3366ff;"> 2 &nbsp;0 &nbsp; &nbsp; &nbsp;1 &nbsp;19576 &nbsp; &nbsp;458 230587 &nbsp; &nbsp;0 &nbsp; &nbsp;0 &nbsp;2224 &nbsp;1804 1634 &nbsp;594 &nbsp;1 &nbsp;1 94 &nbsp;4 &nbsp;0</span></p>
<p lang="zh-CN"><span style="color:#3366ff;"> 3 &nbsp;1 &nbsp; &nbsp; &nbsp;1 &nbsp;19569 &nbsp; &nbsp;458 230590 &nbsp; &nbsp;0 &nbsp; &nbsp;0 &nbsp;1968 &nbsp;3488 1693 &nbsp;566 &nbsp;1 &nbsp;1 93 &nbsp;4 &nbsp;0</span></p>
<p lang="zh-CN"><span style="color:#3366ff;"> 1 &nbsp;1 &nbsp; &nbsp; &nbsp;1 &nbsp;19567 &nbsp; &nbsp;458 230593 &nbsp; &nbsp;0 &nbsp; &nbsp;0 &nbsp;2016 &nbsp;2632 1775 &nbsp;515 &nbsp;1 &nbsp;1 93 &nbsp;4 &nbsp;0</span></p>
<p lang="zh-CN"><span style="color:#3366ff;">[root@localhost mysql]# sar -d 1</span></p>
<p lang="zh-CN"><span style="color:#3366ff;">Linux 2.6.32-431.el6.x86_64 (localhost.localdomain) &nbsp; &nbsp; 03/21/2015 &nbsp; &nbsp; &nbsp;_x86_64_ &nbsp; &nbsp; &nbsp; &nbsp;(24 CPU)</span></p>
<p lang="zh-CN"><span style="color:#3366ff;">03:21:57 PM &nbsp; &nbsp; &nbsp; DEV &nbsp; &nbsp; &nbsp; tps &nbsp;rd_sec/s &nbsp;wr_sec/s &nbsp;avgrq-sz &nbsp;avgqu-sz &nbsp; &nbsp; await &nbsp; &nbsp; svctm &nbsp; &nbsp; %util</span></p>
<p lang="zh-CN"><span style="color:#3366ff;">03:21:58 PM &nbsp; &nbsp;dev8-0 &nbsp; &nbsp;185.86 &nbsp; 5753.54 &nbsp; &nbsp; 64.65 &nbsp; &nbsp; 31.30 &nbsp; &nbsp; &nbsp;1.20 &nbsp; &nbsp; &nbsp;6.48 &nbsp; &nbsp; &nbsp;5.08 &nbsp; &nbsp; 94.44</span></p>
<p lang="zh-CN"><span style="color:#3366ff;">03:21:58 PM &nbsp; &nbsp; &nbsp; DEV &nbsp; &nbsp; &nbsp; tps &nbsp;rd_sec/s &nbsp;wr_sec/s &nbsp;avgrq-sz &nbsp;avgqu-sz &nbsp; &nbsp; await &nbsp; &nbsp; svctm &nbsp; &nbsp; %util</span></p>
<p lang="zh-CN"><span style="color:#3366ff;">03:21:59 PM &nbsp; &nbsp;dev8-0 &nbsp; &nbsp;197.03 &nbsp; 6114.85 &nbsp; &nbsp; 95.05 &nbsp; &nbsp; 31.52 &nbsp; &nbsp; &nbsp;1.16 &nbsp; &nbsp; &nbsp;5.88 &nbsp; &nbsp; &nbsp;4.48 &nbsp; &nbsp; 88.32</span></p>
<p lang="zh-CN"><span style="color:#3366ff;">03:21:59 PM &nbsp; &nbsp; &nbsp; DEV &nbsp; &nbsp; &nbsp; tps &nbsp;rd_sec/s &nbsp;wr_sec/s &nbsp;avgrq-sz &nbsp;avgqu-sz &nbsp; &nbsp; await &nbsp; &nbsp; svctm &nbsp; &nbsp; %util</span></p>
<p lang="zh-CN"><span style="color:#3366ff;">03:22:00 PM &nbsp; &nbsp;dev8-0 &nbsp; &nbsp;188.89 &nbsp; 5882.83 &nbsp; &nbsp; 88.89 &nbsp; &nbsp; 31.61 &nbsp; &nbsp; &nbsp;1.14 &nbsp; &nbsp; &nbsp;6.03 &nbsp; &nbsp; &nbsp;5.09 &nbsp; &nbsp; 96.16</span></p>
<p lang="zh-CN"><span style="color:#3366ff;">03:22:00 PM &nbsp; &nbsp; &nbsp; DEV &nbsp; &nbsp; &nbsp; tps &nbsp;rd_sec/s &nbsp;wr_sec/s &nbsp;avgrq-sz &nbsp;avgqu-sz &nbsp; &nbsp; await &nbsp; &nbsp; svctm &nbsp; &nbsp; %util</span></p>
<p lang="zh-CN"><span style="color:#3366ff;">03:22:01 PM &nbsp; &nbsp;dev8-0 &nbsp; &nbsp;166.00 &nbsp; 5152.00 &nbsp; &nbsp; 80.00 &nbsp; &nbsp; 31.52 &nbsp; &nbsp; &nbsp;1.42 &nbsp; &nbsp; &nbsp;8.56 &nbsp; &nbsp; &nbsp;5.58 &nbsp; &nbsp; 92.70</span></p>
</blockquote>
<p> &nbsp; &nbsp;也看不出来异常，继续看看mysql的日志吧：</p>
<blockquote><p> &nbsp; &nbsp;<span style="color:#3366ff;">2015-04-21 14:51:04 18667 [ERROR] Native table ‘performance_schema’.’objects_summary_global_by_type’ has the wrong structure</span></p>
<p> &nbsp; &nbsp;<span style="color:#3366ff;">2015-04-21 14:51:04 18667 [ERROR] Incorrect definition of table performance_schema.rwlock_instances: expected column ‘WRITE_LOCKED_BY_THREAD_ID’ at position 2 to have type bigint(20), found type int(11).</span></p>
<p> &nbsp; &nbsp;<span style="color:#3366ff;">2015-04-21 14:51:04 18667 [ERROR] Native table ‘performance_schema’.’setup_actors’ has the wrong structure</span></p>
<p> &nbsp; &nbsp;<span style="color:#3366ff;">2015-04-21 14:51:04 18667 [ERROR] Native table ‘performance_schema’.’setup_objects’ has the wrong structure</span></p>
<p> &nbsp; &nbsp;<span style="color:#3366ff;">2015-04-21 14:51:04 18667 [ERROR] Native table ‘performance_schema’.’table_io_waits_summary_by_index_usage’ has the wrong structure</span></p>
<p> &nbsp; &nbsp;<span style="color:#3366ff;">2015-04-21 14:51:04 18667 [ERROR] Native table ‘performance_schema’.’table_io_waits_summary_by_table’ has the wrong structure</span></p>
<p> &nbsp; &nbsp;<span style="color:#3366ff;">2015-04-21 14:51:04 18667 [ERROR] Native table ‘performance_schema’.’table_lock_waits_summary_by_table’ has the wrong structure</span></p>
<p> &nbsp; &nbsp;<span style="color:#3366ff;">2015-04-21 14:51:04 18667 [ERROR] Column count of mysql.threads is wrong. Expected 14, found 3. Created with MySQL 50524, now running 50623. Please use mysql_upgrade to fix this error.</span></p>
<p> &nbsp; &nbsp;<span style="color:#3366ff;">2015-04-21 14:51:04 18667 [ERROR] Native table ‘performance_schema’.’events_stages_current’ has the wrong structure</span></p>
<p> &nbsp; &nbsp;<span style="color:#3366ff;">2015-04-21 14:51:04 18667 [ERROR] Native table ‘performance_schema’.’events_stages_history’ has the wrong structure</span></p>
<p> &nbsp; &nbsp;<span style="color:#3366ff;">2015-04-21 14:51:04 18667 [ERROR] Native table ‘performance_schema’.’events_stages_history_long’ has the wrong structure</span></p>
<p> &nbsp; &nbsp;<span style="color:#3366ff;">…</span></p>
<p> &nbsp; &nbsp;<span style="color:#3366ff;">…</span></p>
<p> &nbsp; &nbsp;<span style="color:#3366ff;">2015-04-21 15:05:17 7f5997fff700 InnoDB: Error: Table “mysql”.”innodb_table_stats” not found.</span></p>
<p> &nbsp; &nbsp;<span style="color:#3366ff;">2015-04-21 15:05:17 7f5997fff700 InnoDB: Error: Fetch of persistent statistics requested for table “db_anonymous_info_10”.”t_friend_info_3″ but the required system tables mysql.innodb_table_stats and mysql.innodb_index_stats are not present or have unexpected structure. Using transient stats instead.</span></p>
<p> &nbsp; &nbsp;<span style="color:#3366ff;">2015-04-21 15:05:17 7f7beb0cd700 InnoDB: Error: Table “mysql”.”innodb_table_stats” not found.</span></p>
<p> &nbsp; &nbsp;<span style="color:#3366ff;">2015-04-21 15:05:17 7f7beb0cd700 InnoDB: Error: Fetch of persistent statistics requested for table “db_user_trade_1”.”t_trade_15″ but the required system tables mysql.innodb_table_stats and mysql.innodb_index_stats are not present or have unexpected structure. Using transient stats instead.</span></p>
</blockquote>
<p> &nbsp; &nbsp;可以看到，这个实例中，P_S（performanc_schema）库的几个表结构都异常了。另外，mysql.innodb_table_stats表也异常了，导致InnoDB表数据收集异常，然后SQL thread也跟着异常了。</p>
<h1>3、问题解决建议</h1>
<p> &nbsp; &nbsp;造成上面问题主要原因是，没有用正确的方式来部署slave实例。从master上用xtrabackup物理备份到slave，启动实例后，应该再执行 mysql_upgrade 升级相关表结构，确保P_S（performanc_schema）、I_S（information_schema）以及 mysql 等几个系统库表结构都升级到最新版本。</p>
<div class="yarpp-related-rss yarpp-related-none"></div>
<h2  class="related_post_title">猜想失败，您看看下面的文章有用吗？</h2><ul class="related_post"><li><a href="http://ourmysql.com/archives/373" title="关于设计表时应该注意的问题">关于设计表时应该注意的问题</a></li><li><a href="http://ourmysql.com/archives/1379" title="持续可用与CAP理论 – 一个系统开发者的观点">持续可用与CAP理论 – 一个系统开发者的观点</a></li><li><a href="http://ourmysql.com/archives/501" title="MySQL 5.1 中 Innodb 的事务完整性Bug">MySQL 5.1 中 Innodb 的事务完整性Bug</a></li><li><a href="http://ourmysql.com/archives/1359" title="安装MySQL慢查询日志工具Anemometer">安装MySQL慢查询日志工具Anemometer</a></li><li><a href="http://ourmysql.com/archives/668" title="MySQL的日志文件">MySQL的日志文件</a></li><li><a href="http://ourmysql.com/archives/1180" title="php与mysql通讯那点事">php与mysql通讯那点事</a></li><li><a href="http://ourmysql.com/archives/1369" title="备份与还原MySQL从服务器">备份与还原MySQL从服务器</a></li><li><a href="http://ourmysql.com/archives/1299" title="使用Percona Data Recovery Tool for InnoDB恢复数据">使用Percona Data Recovery Tool for InnoDB恢复数据</a></li><li><a href="http://ourmysql.com/archives/1466" title="今天你检查备份了吗？">今天你检查备份了吗？</a></li><li><a href="http://ourmysql.com/archives/1471" title="按照重要程度划分数据库级别">按照重要程度划分数据库级别</a></li></ul>]]></content:encoded>
			<wfw:commentRss>http://ourmysql.com/archives/1457/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>MySQL 管理工具集 percona-toolkit</title>
		<link>http://ourmysql.com/archives/1456</link>
		<comments>http://ourmysql.com/archives/1456#comments</comments>
		<pubDate>Sun, 17 Apr 2016 17:46:38 +0000</pubDate>
		<dc:creator>OurMySQL</dc:creator>
				<category><![CDATA[MySQL初级应用]]></category>
		<category><![CDATA[percona-toolkit]]></category>
		<category><![CDATA[工具]]></category>

		<guid isPermaLink="false">http://ourmysql.com/?p=1456</guid>
		<description><![CDATA[MySQL 管理工具集 persona-toolkit。 <a href="http://ourmysql.com/archives/1456"><br /><br />继续阅读全文 <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>apt-get install -y percona-toolkit</p>
<p># 检查重复索引<br style="box-sizing:border-box;" />pt-duplicate-key-checker -host=’sohu.dev.chenpeng.info’ -port=’43307′ -databases=’grape’</p>
<p># 运行状态监控<br style="box-sizing:border-box;" />pt-mysql-summary -host=’sohu.dev.chenpeng.info’ -port=’43307′ -databases=’grape’</p>
<p># 在线修改表结构<br style="box-sizing:border-box;" />pt-online-schema-change -host=’sohu.dev.chenpeng.info’ -port=’3306′ -alter “ADD COLUMN c1 INT” D=chenpeng_litchi,t=lc_operate_log -execute -print<br style="box-sizing:border-box;" />pt-online-schema-change -host=’sohu.dev.chenpeng.info’ -port=’3306′ -alter “ENGINE=InnoDB” D=chenpeng_litchi,t=lc_operate_log -execute -print</p>
<p># 格式化explain结果<br style="box-sizing:border-box;" />mysql -hsohu.dev.chenpeng.info -P43307 grape -e”explain SELECT a.line_id,b.dnf_source FROM gp_report_advertiser_day a INNER JOIN gp_line b ON a.line_id=b.id WHERE a.data_date=’2016-04-10′ LIMIT 100″ | pt-visual-explain</p>
<p>重复索引结果示例：</p>
<p># ########################################################################<br style="box-sizing:border-box;" /># grape.gp_mars_report_advertiser_hour &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<br style="box-sizing:border-box;" /># ########################################################################</p>
<p># line_id is a left-prefix of line_id_data_time<br style="box-sizing:border-box;" /># Key definitions:<br style="box-sizing:border-box;" /># &nbsp; KEY `line_id` (`line_id`) USING BTREE,<br style="box-sizing:border-box;" /># &nbsp; KEY `line_id_data_time` (`line_id`,`data_time`) USING BTREE<br style="box-sizing:border-box;" /># Column types:<br style="box-sizing:border-box;" /># &nbsp; &nbsp; &nbsp;`line_id` bigint(20) unsigned not null comment ‘??id’<br style="box-sizing:border-box;" /># &nbsp; &nbsp; &nbsp;`data_time` datetime not null comment ‘??’<br style="box-sizing:border-box;" /># To remove this duplicate index, execute:<br style="box-sizing:border-box;" />ALTER TABLE `grape`.`gp_mars_report_advertiser_hour` DROP INDEX `line_id`;</p>
<p># ########################################################################<br style="box-sizing:border-box;" /># grape.gp_operate_log &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<br style="box-sizing:border-box;" /># ########################################################################</p>
<p># related_id is a left-prefix of search3<br style="box-sizing:border-box;" /># Key definitions:<br style="box-sizing:border-box;" /># &nbsp; KEY `related_id` (`related_id`),<br style="box-sizing:border-box;" /># &nbsp; KEY `search3` (`related_id`,`opt_datetime`),<br style="box-sizing:border-box;" /># Column types:<br style="box-sizing:border-box;" /># &nbsp; &nbsp; &nbsp;`related_id` int(10) unsigned not null comment ‘?????id’<br style="box-sizing:border-box;" /># &nbsp; &nbsp; &nbsp;`opt_datetime` datetime not null comment ‘??????’<br style="box-sizing:border-box;" /># To remove this duplicate index, execute:<br style="box-sizing:border-box;" />ALTER TABLE `grape`.`gp_operate_log` DROP INDEX `related_id`;</p>
<p># ########################################################################<br style="box-sizing:border-box;" /># grape.gp_report_advertiser_hour &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <br style="box-sizing:border-box;" /># ########################################################################</p>
<p># idx_line_id is a left-prefix of line_id_data_time<br style="box-sizing:border-box;" /># Key definitions:<br style="box-sizing:border-box;" /># &nbsp; KEY `idx_line_id` (`line_id`),<br style="box-sizing:border-box;" /># &nbsp; KEY `line_id_data_time` (`line_id`,`data_time`),<br style="box-sizing:border-box;" /># Column types:<br style="box-sizing:border-box;" /># &nbsp; &nbsp; &nbsp;`line_id` bigint(20) not null<br style="box-sizing:border-box;" /># &nbsp; &nbsp; &nbsp;`data_time` datetime not null<br style="box-sizing:border-box;" /># To remove this duplicate index, execute:<br style="box-sizing:border-box;" />ALTER TABLE `grape`.`gp_report_advertiser_hour` DROP INDEX `idx_line_id`;</p>
<p># ########################################################################<br style="box-sizing:border-box;" /># Summary of indexes &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<br style="box-sizing:border-box;" /># ########################################################################</p>
<p># Size Duplicate Indexes &nbsp; 48<br style="box-sizing:border-box;" /># Total Duplicate Indexes &nbsp;3<br style="box-sizing:border-box;" /># Total Indexes &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;268</p>
<p></p>
<p>工具检测到gp_operate_log有重复的索引，提供以下SQL语句删除重复的索引：</p>
<p>ALTER TABLE `grape`.`gp_operate_log` DROP INDEX `related_id`;</p>
<p></p>
<p>explain简化显示示例：</p>
<p>root@ubuntu:/tmp/d3OnxmMr# mysql -hsohu.dev.chenpeng.info -P43307 -ugrapeuser -pfaf74223tr grape -e”explain SELECT a.line_id,b.dnf_source FROM gp_report_advertiser_day a INNER JOIN gp_line b ON a.line_id=b.id WHERE a.data_date=’2016-04-10′ LIMIT 100″ | pt-visual-explain<br style="box-sizing:border-box;" />JOIN<br style="box-sizing:border-box;" />+- Filter with WHERE<br style="box-sizing:border-box;" />| &nbsp;+- Bookmark lookup<br style="box-sizing:border-box;" />| &nbsp; &nbsp; +- Table<br style="box-sizing:border-box;" />| &nbsp; &nbsp; | &nbsp;table &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;b<br style="box-sizing:border-box;" />| &nbsp; &nbsp; | &nbsp;possible_keys &nbsp;PRIMARY<br style="box-sizing:border-box;" />| &nbsp; &nbsp; +- Unique index lookup<br style="box-sizing:border-box;" />| &nbsp; &nbsp; &nbsp; &nbsp;key &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;b-&gt;PRIMARY<br style="box-sizing:border-box;" />| &nbsp; &nbsp; &nbsp; &nbsp;possible_keys &nbsp;PRIMARY<br style="box-sizing:border-box;" />| &nbsp; &nbsp; &nbsp; &nbsp;key_len &nbsp; &nbsp; &nbsp; &nbsp;4<br style="box-sizing:border-box;" />| &nbsp; &nbsp; &nbsp; &nbsp;ref &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;grape.a.line_id<br style="box-sizing:border-box;" />| &nbsp; &nbsp; &nbsp; &nbsp;rows &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1<br style="box-sizing:border-box;" />+- Index lookup<br style="box-sizing:border-box;" /> &nbsp; key &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;a-&gt;data_date<br style="box-sizing:border-box;" /> &nbsp; possible_keys &nbsp;line_id,data_date<br style="box-sizing:border-box;" /> &nbsp; key_len &nbsp; &nbsp; &nbsp; &nbsp;3<br style="box-sizing:border-box;" /> &nbsp; ref &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;const<br style="box-sizing:border-box;" /> &nbsp; rows &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 10722</p>
<p></p>
<h2  class="related_post_title">猜想失败，您看看下面的文章有用吗？</h2><ul class="related_post"><li><a href="http://ourmysql.com/archives/1164" title="新手必看：一步到位之InnoDB">新手必看：一步到位之InnoDB</a></li><li><a href="http://ourmysql.com/archives/1107" title="Mysql源码学习——没那么简单的Hash">Mysql源码学习——没那么简单的Hash</a></li><li><a href="http://ourmysql.com/archives/338" title="Mysql执行计划中的Using filesort">Mysql执行计划中的Using filesort</a></li><li><a href="http://ourmysql.com/archives/108" title="Mysql数据库索引查询优化的分享">Mysql数据库索引查询优化的分享</a></li><li><a href="http://ourmysql.com/archives/314" title="深入Mysql字符集设置">深入Mysql字符集设置</a></li><li><a href="http://ourmysql.com/archives/379" title="随机获取N条数据库记录的四个方法">随机获取N条数据库记录的四个方法</a></li><li><a href="http://ourmysql.com/archives/1207" title="MySQL源码:JOIN顺序选择的复杂度">MySQL源码:JOIN顺序选择的复杂度</a></li><li><a href="http://ourmysql.com/archives/746" title="用MySQL 产生随机密码 ">用MySQL 产生随机密码 </a></li><li><a href="http://ourmysql.com/archives/1186" title="mysql监测工具">mysql监测工具</a></li><li><a href="http://ourmysql.com/archives/344" title="调用存储过程时报错:There is no &#8216;username&#8217;@'host&#8217; registered ">调用存储过程时报错:There is no &#8216;username&#8217;@'host&#8217; registered </a></li></ul>]]></content:encoded>
			<wfw:commentRss>http://ourmysql.com/archives/1456/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>MySQL锁问题最佳实践</title>
		<link>http://ourmysql.com/archives/1455</link>
		<comments>http://ourmysql.com/archives/1455#comments</comments>
		<pubDate>Tue, 05 Apr 2016 10:30:05 +0000</pubDate>
		<dc:creator>OurMySQL</dc:creator>
				<category><![CDATA[MySQL源码分析]]></category>
		<category><![CDATA[锁]]></category>

		<guid isPermaLink="false">http://ourmysql.com/?p=1455</guid>
		<description><![CDATA[最近一段时间处理了较多锁的问题，包括锁等待导致业务连接堆积或超时，死锁导致业务失败等，这类问题对业务可能会造成严重的影响，没有处理经验的用户往往无从下手。下面将从整个数据库设计，开发，运维阶段介绍如何避免锁问题的发生，提供一些最佳实践供RDS的用户参考。 <a href="http://ourmysql.com/archives/1455"><br /><br />继续阅读全文 <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p> &nbsp; &nbsp;最近一段时间处理了较多锁的问题，包括锁等待导致业务连接堆积或超时，死锁导致业务失败等，这类问题对业务可能会造成严重的影响，没有处理经验的用户往往无从下手。下面将从整个数据库设计，开发，运维阶段介绍如何避免锁问题的发生，提供一些最佳实践供RDS的用户参考。</p>
<p> &nbsp; &nbsp;<strong>一．设计阶段：</strong>在数据库设计阶段，引擎选择和索引设计不当可能导致后期业务上线后出现较为严重的锁或者死锁问题。</p>
<p> &nbsp; &nbsp;(1).表引擎选择使用myisam，引发table level lock wait。</p>
<p> &nbsp; &nbsp;从5.5版本开始，MySQL官方就把默认引擎由myisam转为innodb，这两种引擎的主要区别：</p>
<p> &nbsp; &nbsp;<a href="http://hidba.org/wp-content/uploads/2016/03/engine.png"><img class="aligncenter size-full wp-image-1081" src="http://hidba.org/wp-content/uploads/2016/03/engine.png" alt="engine" width="439" height="130" /></a></p>
<p> &nbsp; &nbsp;由于myisam引擎只支持table lock，在使用myisam引擎表过程中，当数据库中出现执行时间较长的查询后就会堵塞该表上的更新动作，所以经常会碰到线程会话处于表级锁等待（Waiting for table level lock）的情况，严重的情况下会出现由于实例连接数被占满而应用无法正常连接的情况</p>
<p> &nbsp; &nbsp;CREATE TABLE `t_myisam` (</p>
<p> &nbsp; &nbsp;`id` int(11) DEFAULT NULL</p>
<p> &nbsp; &nbsp;) ENGINE=MyISAM DEFAULT CHARSET=utf8；</p>
<p> &nbsp; &nbsp;Query |111 | User sleep &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;| select id,sleep(100) from t_myisam &nbsp; |</p>
<p> &nbsp; &nbsp;Query |108 | Waiting for table level lock | update t_myisam set id=2 where id=1|</p>
<p> &nbsp; &nbsp;Query | &nbsp;3 | Waiting for table level lock | update t_myisam set id=2 where id=1|</p>
<p> &nbsp; &nbsp;从上述的案例中可以看到，t_myisam表为myisam存储引擎，当该表上有执行时间较长的查询语句在执行的时候，该表上其他的更新全被堵塞住了，这个时候应用或者数据库的连接很快耗完，导致应用请求失败。这个时候快速的恢复方法为将线程id：111 kill掉即可（可以执行show processlist查看到当前数据库所有连接状态）。另外myisam存储引擎的表索引在实例异常关闭的情况下会导致索引损坏，这个时候必须要对表进行repair操作，该操作同样会阻塞该表上的所有请求。</p>
<p> &nbsp; &nbsp;(2).表索引设计不当，导致数据库出现死锁。</p>
<p> &nbsp; &nbsp;索引设计是数据库设计非常重要的一环，不仅仅关系到后续业务的性能，如果设计不当还可导致业务上的死锁。下面的一则案例就出现在线上系统，数据库在并发更新的时候出现了死锁，通过排查定位于update更新使用了两个索引导致，死锁信息如下：</p>
<p> &nbsp; &nbsp;*** (1) TRANSACTION:</p>
<p> &nbsp; &nbsp;TRANSACTION 29285454235, ACTIVE 0.001 sec fetching rows</p>
<p> &nbsp; &nbsp;mysql tables in use 3, locked 3</p>
<p> &nbsp; &nbsp;LOCK WAIT 6 lock struct(s), heap size 1184, 4 row lock(s)</p>
<p> &nbsp; &nbsp;MySQL thread id 6641616, OS thread handle 0x2b165c4b1700, query id 28190427937 10.103.180.86 test_ebs Searching rows for update</p>
<p> &nbsp; &nbsp;UPDATE test SET is_deleted = 1 WHERE group_id = 1332577 and test_id = 4580605</p>
<p> &nbsp; &nbsp;*** (1) WAITING FOR THIS LOCK TO BE GRANTED:</p>
<p> &nbsp; &nbsp;RECORD LOCKS space id 132 page no 37122 n bits 352 index `PRIMARY` of table `testdriver`.`test` trx id 29285454235 lock_mode X locks rec but not gap waiting</p>
<p> &nbsp; &nbsp;Record lock, heap no 179 PHYSICAL RECORD: n_fields 8; compact format; info bits 0</p>
<p> &nbsp; &nbsp;*** (2) TRANSACTION:</p>
<p> &nbsp; &nbsp;TRANSACTION 29285454237, ACTIVE 0.001 sec fetching rows, thread declared inside InnoDB 4980</p>
<p> &nbsp; &nbsp;mysql tables in use 3, locked 3 5 lock struct(s), heap size 1184, 3 row lock(s)</p>
<p> &nbsp; &nbsp;MySQL thread id 6639213, OS thread handle 0x2b1694cc2700, query id 28190427939 10.103.180.113 test_ebs Searching rows for update</p>
<p> &nbsp; &nbsp;UPDATE test SET is_deleted = 1 WHERE group_id = 1332577 and test_id = 4212859</p>
<p> &nbsp; &nbsp;*** (2) HOLDS THE LOCK(S):</p>
<p> &nbsp; &nbsp;RECORD LOCKS space id 132 page no 37122 n bits 352 index `PRIMARY` of table `testdriver`.`test` trx id 29285454237 lock_mode X locks rec but not gap</p>
<p> &nbsp; &nbsp;Record lock, heap no 179 PHYSICAL RECORD: n_fields 8; compact format;</p>
<p> &nbsp; &nbsp;表结构：</p>
<p> &nbsp; &nbsp;CREATE TABLE `test` (</p>
<p> &nbsp; &nbsp;`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT ‘主键’,</p>
<p> &nbsp; &nbsp;`test_id` bigint(20) DEFAULT NULL,</p>
<p> &nbsp; &nbsp;`group_id` bigint(20) DEFAULT NULL COMMENT ‘Id，对应test_group.id’,</p>
<p> &nbsp; &nbsp;`gmt_created` datetime DEFAULT NULL COMMENT ‘创建时间’,</p>
<p> &nbsp; &nbsp;`gmt_modified` datetime DEFAULT NULL COMMENT ‘修改时间’,</p>
<p> &nbsp; &nbsp;`is_deleted` tinyint(4) DEFAULT ‘0’ COMMENT ‘删除。’,</p>
<p> &nbsp; &nbsp;PRIMARY KEY (`id`),</p>
<p> &nbsp; &nbsp;KEY `idx_testid` (`test_id`),</p>
<p> &nbsp; &nbsp;KEY `idx_groupid` (`group_id`)</p>
<p> &nbsp; &nbsp;) ENGINE=InnoDB AUTO_INCREMENT=7429111 ;</p>
<p> &nbsp; &nbsp;SQL执行计划：</p>
<p> &nbsp; &nbsp;mysql&gt;explain UPDATE test SET is_deleted = 1 WHERE group_id = 1332577 and test_id = 4212859</p>
<p> &nbsp; &nbsp;| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |</p>
<p> &nbsp; &nbsp;| 1 | SIMPLE | test | index_merge | idx_testid,idx_groupid | idx_testid,idx_groupid | 9,9 | | 1 | Using intersect(idx_testid,idx_groupid); Using where; Using temporary |</p>
<p> &nbsp; &nbsp;所以第一个事务先根据group_id索引，已经锁住primary id，然后再根据test_id索引，锁定primary id；第二个事务先根据test_id索引，已经锁住primary id，然后再根据group_id索引，去锁primary id；所以这样并发更新就可能出现死索引。</p>
<p> &nbsp; &nbsp;MySQL官方也已经确认了此bug：https://bugs.mysql.com/bug.php?id=77209</p>
<p> &nbsp; &nbsp;解决方法有两种：</p>
<p> &nbsp; &nbsp;第一、添加test_id+group_id的组合索引，这样就可以避免掉index merge；</p>
<p> &nbsp; &nbsp;第二、将优化器的index merge优化关闭；</p>
<p> &nbsp; &nbsp;<strong>二．开发阶段：</strong>事务处理时间过长，导致并发出现锁等待。</p>
<p> &nbsp; &nbsp;并发事务处理在数据库中经常看到的应用场景，在这种场景下，需要避免大事务，长事务，复杂事务导致事务在数据库中的运行时间加长，事务时间变长则导致事务中锁的持有时间变长，影响整体的数据库吞吐量。下面的一则案例中，用户的业务数据库中出现大量的update等待，导致大量的业务超时报错：</p>
<p> &nbsp; &nbsp;<a href="http://hidba.org/wp-content/uploads/2016/03/lock.png"><img class="aligncenter size-full wp-image-1082" src="http://hidba.org/wp-content/uploads/2016/03/lock.png" alt="lock" width="533" height="92" /></a></p>
<p> &nbsp; &nbsp;问题排查：</p>
<p> &nbsp; &nbsp;1).通过show processlist 确定出现锁等待的线程以及SQL信息:</p>
<p> &nbsp; &nbsp;|Query|37|updating|UPDATE test_warning SET … WHERE test_id = ’46a9b’</p>
<p> &nbsp; &nbsp;2).通过innodb的information_schema数据库中的锁等待以及事务试图，查出相关的锁信息：</p>
<p> &nbsp; &nbsp;select r.trx_mysql_thread_id waiting_thread, r.trx_id waiting_trx_id,r.trx_query waiting_query, b.trx_id blocking_trx_id, b.trx_query blocking_query,b.trx_mysql_thread_id blocking_thread,b.trx_ started,b.trx_wait_started from information_schema.innodb_lock_waits w inner join information_schema.innodb_trx b on b.trx_id =w.blocking_trx_id inner join</p>
<p> &nbsp; &nbsp;information_schema.innodb_trx r on r.trx_id=w.requesting_trx_id \G</p>
<p> &nbsp; &nbsp;waiting_thread: 318984063</p>
<p> &nbsp; &nbsp;waiting_trx_id: 26432631</p>
<p> &nbsp; &nbsp;waiting_query: UPDATE test_warning SET …….. WHERE test_id = ’46a9b’</p>
<p> &nbsp; &nbsp;blocking_trx_id: 26432630</p>
<p> &nbsp; &nbsp;blocking_query: NULL</p>
<p> &nbsp; &nbsp;blocking_thread: 235202017</p>
<p> &nbsp; &nbsp;trx_started: 2016-03-01 13:54:39</p>
<p> &nbsp; &nbsp;从述的锁等待信息中发现，事务26432631被26432630阻塞了，那么我们就可以从general log中去排查一下事务26432630做了哪些操作。</p>
<p> &nbsp; &nbsp;3).从提前打开数据库的general log中查找到上述被blcok 的update语句在日志中的位置，发现了update被blcok的根本原因： 日志中有两条不同的SQL同时并发更新同一条记录，所以后更新的SQL会等待前更新的SQL，如果SQL1所在的事务1直没有提交，那么事务2将会一直等待，这样就出现上述updating的状态</p>
<p> &nbsp; &nbsp;235202017 Query UPDATE test_warning ….. WHERE test_id = ’46a9b’</p>
<p> &nbsp; &nbsp;318984063 Query UPDATE test_warning ….. task_order_id = ” WHERE test_id = ’46a9b’</p>
<p> &nbsp; &nbsp;所以我们就可以在看一下这个事务的上下文：</p>
<p> &nbsp; &nbsp;thread id=235202017 的SQL上下文：</p>
<p> &nbsp; &nbsp;235202017 Query SET autocommit=0</p>
<p> &nbsp; &nbsp;235202017 (13:54:39) Query UPDATE test_warning SET …. WHERE test_id = ’46a9b’</p>
<p> &nbsp; &nbsp;235202017 Query commit</p>
<p> &nbsp; &nbsp; </p>
<p> &nbsp; &nbsp;thread id=318984063 的SQL上下文：</p>
<p> &nbsp; &nbsp;318984063 Query SET autocommit=1</p>
<p> &nbsp; &nbsp;318984063 (13:54:39)Query SELECT …. FROM test_waybill WHERE (test_id IN (’46a9b’))</p>
<p> &nbsp; &nbsp;318984063 Query SELECT……FROM test_waybill WHERE test_id = ’46a9b’</p>
<p> &nbsp; &nbsp;318984063 Query UPDATE test_warning SET ….. WHERE test_id = ’46a9b’</p>
<p> &nbsp; &nbsp;318984063 (13:55:31)Query UPDATE test_waybill_current t ….. WHERE t.test_id IN (’46a9b’)</p>
<p> &nbsp; &nbsp;318984063 Query SET autocommit=0</p>
<p> &nbsp; &nbsp;可以看到事务1 从13:54:39开始，直到13:55:30结束，事务2 中有更新事务1中的同一条记录，所以直到事务1 提交后，事务2才得以执行完毕，有了这样的日志，将此信息发给用户很快就找到了问题，在事务1中由于还存在其他的业务逻辑，导致事务1的提交迟迟没有完成，进而导致了其他业务锁的发生。</p>
<p> &nbsp; &nbsp;<strong>三．维护阶段：</strong>DDL操作被大查询block。</p>
<p> &nbsp; &nbsp;当应用上线进入维护阶段，则开始会有较多的数据库变更操作，比如：添加字段，添加索引等操作，这一类操作导致的锁故障也是非常频繁的，下面将会介绍一则案例，一个DDL操作被查询block，导致数据库连接堆积：</p>
<p> &nbsp; &nbsp;Query |6 | User sleep &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | select id ,sleep(50) from t</p>
<p> &nbsp; &nbsp;Query |4 | Waiting for table metadata lock &nbsp;| alter table t add column gmt_create datetime</p>
<p> &nbsp; &nbsp;Query |2 | Waiting for table metadata lock &nbsp;| select * from t where id=1</p>
<p> &nbsp; &nbsp;Query |1 | Waiting for table metadata lock &nbsp;| select * from t where id=2</p>
<p> &nbsp; &nbsp;Query |1 | Waiting for table metadata lock &nbsp;| update t set id =2 where id=1</p>
<p> &nbsp; &nbsp;Metadata lock wait 的含义：为了在并发环境下维护表元数据的数据一致性，在表上有活动事务（显式或隐式）的时候，不可以对元数据进行写入操作。因此 MySQL 引入了 metadata lock ，来保护表的元数据信息。因此在对表进行上述操作时，如果表上有活动事务（未提交或回滚），请求写入的会话会等待在 Metadata lock wait。</p>
<p> &nbsp; &nbsp;导致 Metadata lock wait 等待的常见因素包括：活动事务，当前有对表的长时间查询，显示或者隐式开启事务后未提交或回滚，比如查询完成后未提交或者回滚，表上有失败的查询事务等。</p>
<p> &nbsp; &nbsp;上述案例中，查询，更新和DDL操作的线程状态都为Waiting for table metadata lock，对表t的操作全部被阻塞，前端源源不断的请求到达数据库，这个时候数据库的连接很容易被打满，那我们来分析一下为什么有这这些锁等待：</p>
<ul>
<li>
<p>alter 操作的锁等待：由于在表t上做了一个添加字段的操作，该操作会在结束前对表获取一个metadata lock，但是该表上已经有一个查询一直未结束，导致metadata lock一直获取不到，所以添加字段操作只能等待查询结束，这就解释了alter操作为什么状态为Waiting for table metadata lock。</p>
</li>
<li>
<p>查询和更新的锁等待：由于前面进行的alter操作已经在T表上试图获取metadata lock，所以后续对表T的的查询和更新操作在获取metadata lock的时候会被alter操作所阻塞，进而导致这些线程状态为Waiting for table metadata lock。</p>
</li>
</ul>
<p> &nbsp; &nbsp;解决办法则是将线程6 kill 掉即可。</p>
<p> &nbsp; &nbsp;锁问题是非常常见的问题，需要我们在数据库开发，设计，管理的各个阶段都需要注意，防范未然，做到心中有数。</p>
<p> &nbsp; &nbsp;设计开发阶段</p>
<ul>
<li>
<p>表设计要避免使用myisam存储引擎，改用innodb引擎；</p>
</li>
<li>
<p>为SQL创建合适的索引，避免多个单列索引执行出错；</p>
</li>
<li>
<p>避免大事务，长事务，复杂事务导致事务在数据库中的运行时间加长；</p>
</li>
</ul>
<p> &nbsp; &nbsp;管理运维阶段：</p>
<ul>
<li>
<p> 在业务低峰期执行上述操作，比如创建删除索引；</p>
</li>
<li>
<p>在结构变更前，观察数据库中是否存在长时间运行的SQL，未提交的事务；</p>
</li>
<li>
<p>结构变更期间，监控数据库的线程状态是否存在lock wait。</p>
</li>
</ul>
<p> &nbsp; &nbsp; </p>
<p></p>
<p></p>
<h2  class="related_post_title">猜您喜欢</h2><ul class="related_post"><li><a href="http://ourmysql.com/archives/1354" title="MySQL 加锁处理分析">MySQL 加锁处理分析</a></li></ul>]]></content:encoded>
			<wfw:commentRss>http://ourmysql.com/archives/1455/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>MySQL防范SQL注入风险</title>
		<link>http://ourmysql.com/archives/1454</link>
		<comments>http://ourmysql.com/archives/1454#comments</comments>
		<pubDate>Tue, 05 Apr 2016 10:17:08 +0000</pubDate>
		<dc:creator>OurMySQL</dc:creator>
				<category><![CDATA[MySQL源码分析]]></category>
		<category><![CDATA[注入]]></category>

		<guid isPermaLink="false">http://ourmysql.com/?p=1454</guid>
		<description><![CDATA[    互联网很危险，信息及数据安全很重要，SQL注入是最常见的入侵手段之一，其技术门槛低、成本低、收益大，颇受各层次的黑客们所青睐。

    一般来说，SQL注入的手法是利用各种机会将恶意SQL代码添加到程序参数中，并最终被服务器端执行，造成不良后果。 <a href="http://ourmysql.com/archives/1454"><br /><br />继续阅读全文 <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<h1>0、导读</h1>
<blockquote><p> &nbsp; &nbsp;在MySQL里，如何识别并且避免发生SQL注入风险</p>
</blockquote>
<h1>1、关于SQL注入</h1>
<p> &nbsp; &nbsp;互联网很危险，信息及数据安全很重要，SQL注入是最常见的入侵手段之一，其技术门槛低、成本低、收益大，颇受各层次的黑客们所青睐。</p>
<p> &nbsp; &nbsp;一般来说，SQL注入的手法是利用各种机会将恶意SQL代码添加到程序参数中，并最终被服务器端执行，造成不良后果。</p>
<p> &nbsp; &nbsp;例如，我们访问接口 http://imysql.com/user.php?userid=123 来根据userid获取用户信息，假设程序中是这么处理的：</p>
<blockquote><p> &nbsp; &nbsp;$sql = “SELECT * FROM user WHERE userid = <span style="color:#0000ff;"><strong>$_GET[userid]</strong></span>“;</p>
</blockquote>
<p> &nbsp; &nbsp;上面这段代码看起来既low有很xx对吧，尤其是在双引号里面还可以直接引用数据类型变量，所以说php是世界上最好的语言一点不为过，哈哈（其实我早期也写过几年php的）。</p>
<p> &nbsp; &nbsp;这时候，如果我们传递进去的参数改成这样：http://imysql.com/user.php?<span style="color:#0000ff;"><strong>userid=123 or 1=1</strong></span>，这就会<strong>导致SQL条件永远成立</strong>，所有的数据都会被读取出来。又或者可以传递这样的参数：http://imysql.com/user.php?userid=<span style="color:#0000ff;"><strong>123 or if(now()=sysdate(),sleep(5),1)</strong></span>，这时候不但所有的数据都会被读取到，也会让这个SQL执行完毕后再等待5秒才能返回，黑客可据此来判断这个SQL注入探测是否成功。</p>
<p> &nbsp; &nbsp;在上面这个例子中，其实我们只需要对用户输入的参数进行简单的类型判断和控制，即可快速避免被注入的风险，例如改成下面这样就可以了：</p>
<blockquote><p> &nbsp; &nbsp;$userid = <span style="color:#0000ff;"><strong>intval(strim($_GET[‘userid’]));</strong></span></p>
<p> &nbsp; &nbsp;$sql = “SELECT * FROM user WHERE userid = “ . <span style="color:#0000ff;"><strong>mysql_real_escape_string</strong></span>($userid);</p>
</blockquote>
<p> &nbsp; &nbsp;可见，至少基础的SQL注入并不难防范，只要在各个层面都做足工作就可以。而简单的SQL盲注（就是乱拳打死老师傅的玩法）已经可以采用<strong>sqlmap</strong>之类的辅助工具来做了，完全不需要人工执行。</p>
<h1>2、如何防范</h1>
<p> &nbsp; &nbsp;上面提到过sqlmap，它既可以作为SQL盲注的工具，也可以在新项目上线前内部扫一次，提前发现潜在漏洞，及时修补，反过来为我们所用。其他可以检测sql注入漏洞的知名扫描工具有：<strong>SQLIer、SQLID、SQL Power Injector、SQLNinja</strong>。</p>
<p> &nbsp; &nbsp;我们也可以自己通过频繁扫描当前执行的SQL列表，根据一些关键字来判断是否发生了SQL注入或潜在风险，常见的关键字有：</p>
<blockquote><ul class=" list-paddingleft-2">
<li>
<p><span style="color:#0000ff;"><strong>SLEEP()</strong> </span>— 一般的SQL盲注都会伴随SLEEP()函数出现，而且一般至少SLEEP 5秒以上</p>
</li>
<li>
<p>MID()</p>
</li>
<li>
<p>CHAR()</p>
</li>
<li>
<p>ORD()</p>
</li>
<li>
<p>SYSDATE()</p>
</li>
<li>
<p>SUBSTRING()</p>
</li>
<li>
<p>DATABASES()</p>
</li>
<li>
<p>SCHEMA()</p>
</li>
<li>
<p>USER()</p>
</li>
<li>
<p>VERSION()</p>
</li>
<li>
<p>CURRENT_USER()</p>
</li>
<li>
<p>LOAD_FILE()</p>
</li>
<li>
<p>OUTFILE/DUMPFILE</p>
</li>
<li>
<p>INFORMATION_SCHEMA</p>
</li>
<li>
<p>TABLE_NAME</p>
</li>
<li>
<p>fwrite()/fopen()/file_get_contents() — 这几个是PHP文件操作函数</p>
</li>
</ul>
</blockquote>
<p> &nbsp; &nbsp;我们可以以较高频率检查当前的活跃SQL命令，一旦发现上述关键字，可以立即记录下来并触发告警，通知管理员及时人工确认处理，甚至也可以先直接自动杀掉这些SQL查询（可以用 <strong>pt-kill</strong> 工具来做到这点，也可以自行开发），以防万一，少给黑客留机会。</p>
<p> &nbsp; &nbsp;还有，我们<span style="color:#0000ff;"><strong>建议把选项 safe-update/sql_safe_updates 设置为 1，防止没有任何 WHERE 条件的误操作更新，将全表数据都写错</strong></span>。</p>
<h1>3、其他建议</h1>
<p> &nbsp; &nbsp;防范SQL注入只是数据安全保护工作很小的一部分，只要做好基本功就可以防住至少80%以上的SQL注入探测。</p>
<p> &nbsp; &nbsp;在app server层，以PHP开发语言为例，除了上面提到的规范用户输入类型外，还可以<span style="color:#0000ff;"><strong>改成用 sprintf() 函数来格式化构造 SQL 语句</strong></span>，也可以一定程度防范SQL注入。还可以<span style="color:#0000ff;"><strong>修改 php cgi 程序的运行属主为普通用户</strong></span>，最起码不能使用 root 用户，避免因为代码层不严谨导致被黑客上传可执行 php 程序代码文件。还可以<span style="color:#0000ff;"><strong>把php中的远程文件调用权限关闭，把选项 allow_url_fopen、allow_url_include 均设置为 off，并限定php可以打开的文件目录</strong></span>，不允许跨区域访问敏感文件。</p>
<p> &nbsp; &nbsp;除了在代码层面做好数据类型判断、用户输入判断外，还可以在web server层加上过滤策略，比如在nginx上启用WAF插件。或者，也可以购买IDC运营商、云主机提供商提供的商业解决方案。对于重视数据安全的企业来说，花点钱保平安更为重要。</p>
<h1>4、附录</h1>
<p> &nbsp; &nbsp;下面是一些常见SQL注入参考案例：</p>
<p> &nbsp; &nbsp;<strong>案例1：</strong>SELECT * FROM t WHERE a LIKE ‘%xxx%’ <strong>OR (IF(NOW=SYSDATE(), SLEEP(5), 1))</strong><strong> OR b LIKE ‘1=1</strong>‘;</p>
<p> &nbsp; &nbsp;<strong>案例2：</strong>SELECT * FROM t WHERE a &gt; 0 AND b IN(497 <strong>AND (SELECT * FROM (SELECT(SLEEP(20)))a)</strong>);</p>
<p> &nbsp; &nbsp;<strong>案例3：</strong>SELECT * FROM t WHERE a=1 and b in (1234<strong>,(SELECT (CASE WHEN (5=5) THEN SLEEP(5) ELSE 5*(SELECT 5 FROM INFORMATION_SCHEMA.CHARACTER_SETS) END))</strong>)；</p>
<h2  class="related_post_title">猜您喜欢</h2><ul class="related_post"><li><a href="http://ourmysql.com/archives/1437" title="解决 SQL 注入的另类方法">解决 SQL 注入的另类方法</a></li></ul>]]></content:encoded>
			<wfw:commentRss>http://ourmysql.com/archives/1454/feed</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>MySQL relay_log_purge=0 时的风险</title>
		<link>http://ourmysql.com/archives/1453</link>
		<comments>http://ourmysql.com/archives/1453#comments</comments>
		<pubDate>Sat, 02 Apr 2016 13:49:07 +0000</pubDate>
		<dc:creator>OurMySQL</dc:creator>
				<category><![CDATA[MySQL优化设计]]></category>
		<category><![CDATA[relay_log_purge]]></category>
		<category><![CDATA[日志]]></category>

		<guid isPermaLink="false">http://ourmysql.com/?p=1453</guid>
		<description><![CDATA[有时候，我们希望将 MySQL 的 relay log 多保留一段时间，比如用于高可用切换后的数据补齐，于是就会设置 relay_log_purge=0，禁止 SQL 线程在执行完一个 relay log 后自动将其删除。但是在官方文档关于这个设置有这么一句话： Disabling purging of relay logs when using the --relay-log-recovery option risks data consistency and is therefore not crash-safe. 究竟是什么样的风险呢？ <a href="http://ourmysql.com/archives/1453"><br /><br />继续阅读全文 <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p> &nbsp; &nbsp;有时候，我们希望将 MySQL 的 relay log 多保留一段时间，比如用于高可用切换后的数据补齐，于是就会设置 relay_log_purge=0，禁止 SQL 线程在执行完一个 relay log 后自动将其删除。但是在官方文档关于这个设置有这么一句话：</p>
<pre>Disabling purging of relay logs when using the --relay-log-recovery option risks data consistency and is therefore not crash-safe.
</pre>
<p> &nbsp; &nbsp;究竟是什么样的风险呢？查找了一番后，基本上明白了原因。</p>
<p> &nbsp; &nbsp;首先，为了让从库是 crash safe 的，必须设置 relay_log_recovery=1，这个选项的作用是，在 MySQL 崩溃或人工重启后，由于 IO 线程无法保证记录的从主库读取的 binlog 位置的正确性，因此，就不管 master_info 中记录的位置，而是根据 &nbsp;relay_log_info 中记录的已执行的 binlog 位置从主库下载，并让 SQL 线程也从这个位置开始执行。MySQL 启动时，相当于执行了 flush logs ，会新开一个 relay log 文件，新的 relay log 会记录在新的文件中。如果默认情况 relay_log_purge=1 时，SQL 线程就会自动将之前的 relay log 全部删除。而当 relay_log_purge=0 时，旧的 relay log 则会被保留。虽然这并不会影响从库复制本身，但还是会有地雷：</p>
<ol>
<li>
<p>由于崩溃或停止 MySQL 时，SQL 线程可能没有执行完全部的 relay log，最后一个 relay log 中的一部分数据会被重新下载到新的文件中。也就是说，这部分数据重复了两次。</p>
</li>
<li>
<p>如果 SQL 跟得很紧，则可能在 IO 线程写入 relay log ，但还没有将同步到磁盘时，就已经读取执行了。这时，就会造成新的文件和旧的文件中少了一段数据。</p>
</li>
</ol>
<p> &nbsp; &nbsp;如果我们读取 relay log 来获取数据，必须注意这一点，否则就会造成数据不一致。而保留 relay log 的目的也在于此。因此，在处理 relay log 时必须格外小心，通过其中 binlog 头信息来确保正确性。</p>
<p> &nbsp; &nbsp;关于如何配置 crash safe 的复制本身的配置，可以参照：<br /><a href="http://blog.itpub.net/22664653/viewspace-1752588/" target="_blank">http://blog.itpub.net/22664653/viewspace-1752588/</a><br /><a href="http://www.innomysql.net/article/34.html" target="_blank">http://www.innomysql.net/article/34.html</a></p>
<p> &nbsp; &nbsp;参考资料：<br /><a href="http://blog.booking.com/better_crash_safe_replication_for_mysql.html" target="_blank">http://blog.booking.com/better_crash_safe_replication_for_mysql.html</a><br /><a href="https://bugs.mysql.com/bug.php?id=73038" target="_blank">https://bugs.mysql.com/bug.php?id=73038</a><br /><a href="http://bugs.mysql.com/bug.php?id=74324" target="_blank">http://bugs.mysql.com/bug.php?id=74324</a></p>
<h2  class="related_post_title">猜您喜欢</h2><ul class="related_post"><li><a href="http://ourmysql.com/archives/1360" title="MySQL 二进制日志格式基础(一)">MySQL 二进制日志格式基础(一)</a></li></ul>]]></content:encoded>
			<wfw:commentRss>http://ourmysql.com/archives/1453/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>MySQL安全策略</title>
		<link>http://ourmysql.com/archives/1452</link>
		<comments>http://ourmysql.com/archives/1452#comments</comments>
		<pubDate>Tue, 22 Mar 2016 23:03:21 +0000</pubDate>
		<dc:creator>OurMySQL</dc:creator>
				<category><![CDATA[MySQL优化设计]]></category>
		<category><![CDATA[安全]]></category>

		<guid isPermaLink="false">http://ourmysql.com/?p=1452</guid>
		<description><![CDATA[MySQL被运用于越来越多的业务中，在关键业务中对数据安全性的要求也更高，如何保证MySQL的数据安全？ <a href="http://ourmysql.com/archives/1452"><br /><br />继续阅读全文 <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<h1>0、导读</h1>
<blockquote><p> &nbsp; &nbsp;MySQL被运用于越来越多的业务中，在关键业务中对数据安全性的要求也更高，如何保证MySQL的数据安全？</p>
</blockquote>
<p> &nbsp; &nbsp;MySQL被运用于越来越多的业务中，在关键业务中对数据安全性的要求也更高，如何保证MySQL的数据安全。</p>
<p> &nbsp; &nbsp;数据安全如果只靠MySQL应用层面显然是不够的，是需要在多个层面来保护的，包括网络、系统、逻辑应用层、数据库层等。</p>
<p> &nbsp; &nbsp;下面是我们可借鉴的一些安全策略。</p>
<h1>1、网络、系统层面</h1>
<p> &nbsp; &nbsp;在这个层面可以做很多的事情，我们可以把这些安全要求作为新系统安装时的标准要求，放到自动化装机方案中。</p>
<ul class=" list-paddingleft-2">
<li>
<p>把运行MySQL的服务器放在内网中，不要启用公网；</p>
</li>
<li>
<p>迫不得已启用公网的话，修改sshd端口到10000以上；</p>
</li>
<li>
<p>设置防火墙策略，只允许信任的服务器连接sshd和MySQL端口；</p>
</li>
<li>
<p>修改idrac/imm密码，设置GRUB密码；</p>
</li>
<li>
<p>设置密码安全策略，比如要求 PASS_MIN_LEN 不低于8位，其实最好是直接用一个复杂密码做MD5之后再作为正式密码，32位长度的安全程度够高吧；</p>
</li>
<li>
<p>将操作日志记入syslog并且发送到远程log server上，坚决不能只存储在本地；</p>
</li>
<li>
<p>除了必须的账号，其他的都设为无登入权限；</p>
</li>
<li>
<p>尽量把运行MySQL的服务器独立出来，不要和web server、app server放一起。必须放一起的话，也要设置好权限分离，不允许web server、app server进程的属主有直接访问MySQL datadir的权限；</p>
</li>
<li>
<p>禁用web server层的autoindex配置；</p>
</li>
<li>
<p>可能的话，采用https代替http；</p>
</li>
<li>
<p>关键应用保持更新，避免老版本的漏洞风险；</p>
</li>
<li>
<p>设置nginx、php等应用服务的安全策略，禁用危险函数等；</p>
</li>
<li>
<p>可以考虑购买运营商提供的一些安全防护、扫描器等产品；</p>
</li>
<li>
<p>坚决杜绝二逼行为，把关键配置文件上传到公共网络上（如把公司项目代码放在github上作为个人项目，内含内网账号密码信息）。</p>
</li>
</ul>
<h1>2、逻辑应用层</h1>
<p> &nbsp; &nbsp;在这个层面，等多的是依赖运营及开发人员的安全意识，很多本可以避免的低级安全漏洞完全可以在这个层面处理掉，比如下面提到的XSS、CSRF、SQL注入等漏洞。</p>
<ul class=" list-paddingleft-2">
<li>
<p>尽量不要在公网上使用开源的cms、blog、论坛等系统，除非做过代码安全审计，或者事先做好安全策略。这类系统一般都是黑客重点研究对象，很容易被搞；</p>
</li>
<li>
<p>在web server层，可以用一些安全模块，比如nginx的WAF模块；</p>
</li>
<li>
<p>在app server层，可以做好代码安全审计、安全扫描，防止XSS攻击、CSRF攻击、SQL注入、文件上传攻击、绕过cookie检测等安全漏洞；</p>
</li>
<li>
<p>应用程序中涉及账号密码的地方例如JDBC连接串配置，尽量把明文密码采用加密方式存储，再利用内部私有的解密工具进行反解密后再使用。或者可以让应用程序先用中间账号连接proxy层，再由proxy连接MySQL，避免应用层直连MySQL；</p>
</li>
<li>
<p>应用层启用关键日志记录，例如交易日志，方便后续对账什么的。</p>
</li>
</ul>
<h1>3、MySQL数据库层</h1>
<p> &nbsp; &nbsp;前面几层如果都做的不够安全的话，在这层也几乎是岌岌可危了。但我们依然可以做些事情的。</p>
<ul class=" list-paddingleft-2">
<li>
<p>启用 safe-update 选项，避免没有 WHERE 条件的全表数据被修改；</p>
</li>
<li>
<p>将 binlog 的保存周期加长，便于后续的审计、审查；</p>
</li>
<li>
<p>应用账号只赋予SELECT、UPDATE、INSERT权限，取消DELETE权限。把需要DELETE权限的逻辑改成用UPDATE实现，避免被物理删除；</p>
</li>
<li>
<p>需要真正删除时，交由DBA先备份后再物理删除；</p>
</li>
<li>
<p>可以采用Percona的SQL审计插件，据说还有macfee的插件；</p>
</li>
<li>
<p>还可以采用触发器来做一些辅助功能，比如防止黑客恶意篡改数据。</p>
</li>
</ul>
<h1>4、后记</h1>
<p> &nbsp; &nbsp;数据安全可以做的事情很多，本文也只是罗列了一些比较简单可快速实施的方案。每个企业应有自己的安全策略规范，每一位参与者都应该心怀敬畏，努力遵守这些必要的规范，不使信息安全成为空谈。</p>
<p> &nbsp; &nbsp;真正的数据安全，是靠所有人的意识安全作为支撑的，没有这个意识靠机制、制度、工具都是不靠谱。</p>
<h2  class="related_post_title">猜您喜欢</h2><ul class="related_post"><li><a href="http://ourmysql.com/archives/1235" title="MySQL 5.6 新增的两个密码安全策略体验">MySQL 5.6 新增的两个密码安全策略体验</a></li></ul>]]></content:encoded>
			<wfw:commentRss>http://ourmysql.com/archives/1452/feed</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>MYSQL分页limit速度太慢优化方法</title>
		<link>http://ourmysql.com/archives/1451</link>
		<comments>http://ourmysql.com/archives/1451#comments</comments>
		<pubDate>Mon, 21 Mar 2016 23:24:00 +0000</pubDate>
		<dc:creator>OurMySQL</dc:creator>
				<category><![CDATA[MySQL优化设计]]></category>
		<category><![CDATA[limit]]></category>
		<category><![CDATA[分页]]></category>

		<guid isPermaLink="false">http://ourmysql.com/?p=1451</guid>
		<description><![CDATA[在mysql中limit可以实现快速分页，但是如果数据到了几百万时我们的limit必须优化才能有效的合理的实现分页了，否则可能卡死你的服务器哦。 <a href="http://ourmysql.com/archives/1451"><br /><br />继续阅读全文 <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p> &nbsp; &nbsp;在mysql中limit可以实现快速分页，但是如果数据到了几百万时我们的limit必须优化才能有效的合理的实现分页了，否则可能卡死你的服务器哦。</p>
<p> &nbsp; &nbsp;当一个表数据有几百万的数据的时候成了问题！</p>
<p> &nbsp; &nbsp;如 * from table limit 0,10 这个没有问题 当 limit 200000,10 的时候数据读取就很慢，可以按照一下方法解决</p>
<p> &nbsp; &nbsp; 第一页会很快</p>
<p> &nbsp; &nbsp;PERCONA PERFORMANCE CONFERENCE 2009上，来自雅虎的几位工程师带来了一篇”EfficientPagination Using MySQL”的报告</p>
<p> &nbsp; &nbsp;limit10000,20的意思扫描满足条件的10020行，扔掉前面的10000行，返回最后的20行，问题就在这里。</p>
<p> &nbsp; &nbsp;LIMIT 451350 , 30 扫描了45万多行，怪不得慢的都堵死了。</p>
<p> &nbsp; &nbsp;但是</p>
<p> &nbsp; &nbsp;limit 30 这样的语句仅仅扫描30行。</p>
<p> &nbsp; &nbsp;那么如果我们之前记录了最大ID，就可以在这里做文章</p>
<p> &nbsp; &nbsp;举个例子</p>
<p> &nbsp; &nbsp;日常分页SQL语句</p>
<p> &nbsp; &nbsp;select id,name,content from users order by id asc limit 100000,20</p>
<p> &nbsp; &nbsp;扫描100020行</p>
<p> &nbsp; &nbsp;如果记录了上次的最大ID</p>
<p> &nbsp; &nbsp;select id,name,content from users where id&gt;100073 order by id asc limit 20</p>
<p> &nbsp; &nbsp;扫描20行。</p>
<p> &nbsp; &nbsp;总数据有500万左右</p>
<p> &nbsp; &nbsp;以下例子 当时候 select * from wl_tagindex where byname=’f’ order by id limit 300000,10 执行时间是 3.21s</p>
<p> &nbsp; &nbsp;优化后：</p>
<p> &nbsp; &nbsp;select * from (</p>
<p> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;select id from wl_tagindex</p>
<p> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;where byname=’f’ order by id limit 300000,10</p>
<p> &nbsp; &nbsp;) a</p>
<p> &nbsp; &nbsp;left join wl_tagindex b on a.id=b.id</p>
<p> &nbsp; &nbsp;执行时间为 0.11s 速度明显提升</p>
<p> &nbsp; &nbsp;这里需要说明的是 我这里用到的字段是 byname ,id 需要把这两个字段做复合索引，否则的话效果提升不明显</p>
<p> &nbsp; &nbsp;总结</p>
<p> &nbsp; &nbsp;当一个数据库表过于庞大，LIMIT offset, length中的offset值过大，则SQL查询语句会非常缓慢，你需增加order by，并且order by字段需要建立索引。</p>
<p> &nbsp; &nbsp;如果使用子查询去优化LIMIT的话，则子查询必须是连续的，某种意义来讲，子查询不应该有where条件，where会过滤数据，使数据失去连续性。</p>
<p> &nbsp; &nbsp;如果你查询的记录比较大，并且数据传输量比较大，比如包含了text类型的field，则可以通过建立子查询。</p>
<p> &nbsp; &nbsp;SELECT id,title,content FROM items WHERE id IN (SELECT id FROM items ORDER BY id limit 900000, 10);</p>
<p> &nbsp; &nbsp;如果limit语句的offset较大，你可以通过传递pk键值来减小offset = 0，这个主键最好是int类型并且auto_increment</p>
<p> &nbsp; &nbsp;SELECT * FROM users WHERE uid &gt; 456891 ORDER BY uid LIMIT 0, 10;</p>
<p> &nbsp; &nbsp;这条语句，大意如下:</p>
<p> &nbsp; &nbsp;SELECT * FROM users WHERE uid &gt;= &nbsp;(SELECT uid FROM users ORDER BY uid limit 895682, 1) limit 0, 10;</p>
<p> &nbsp; &nbsp;如果limit的offset值过大，用户也会翻页疲劳，你可以设置一个offset最大的，超过了可以另行处理，一般连续翻页过大，用户体验很差，则应该提供更优的用户体验给用户。</p>
<p> &nbsp; &nbsp;limit 分页优化方法</p>
<p> &nbsp; &nbsp;1.子查询优化法</p>
<p> &nbsp; &nbsp;先找出第一条数据，然后大于等于这条数据的id就是要获取的数据</p>
<p> &nbsp; &nbsp;缺点：数据必须是连续的，可以说不能有where条件，where条件会筛选数据，导致数据失去连续性</p>
<p> &nbsp; &nbsp;实验下</p>
<p> &nbsp; &nbsp; mysql&gt; set profi=1;</p>
<p> &nbsp; &nbsp;Query OK, 0 rows affected (0.00 sec)</p>
<p> &nbsp; &nbsp;mysql&gt; select count(*) from Member;</p>
<p> &nbsp; &nbsp;+———-+</p>
<p> &nbsp; &nbsp;| count(*) |</p>
<p> &nbsp; &nbsp;+———-+</p>
<p> &nbsp; &nbsp;| &nbsp; 169566 |</p>
<p> &nbsp; &nbsp;+———-+</p>
<p> &nbsp; &nbsp;1 row in set (0.00 sec)</p>
<p> &nbsp; &nbsp;mysql&gt; pager grep !~-</p>
<p> &nbsp; &nbsp;PAGER set to ‘grep !~-‘</p>
<p> &nbsp; &nbsp;mysql&gt; select * from Member limit 10, 100;</p>
<p> &nbsp; &nbsp;100 rows in set (0.00 sec)</p>
<p> &nbsp; &nbsp;mysql&gt; select * from Member where MemberID &gt;= (select MemberID from Member limit 10,1) limit 100;</p>
<p> &nbsp; &nbsp;100 rows in set (0.00 sec)</p>
<p> &nbsp; &nbsp;mysql&gt; select * from Member limit 1000, 100;</p>
<p> &nbsp; &nbsp;100 rows in set (0.01 sec)</p>
<p> &nbsp; &nbsp;mysql&gt; select * from Member where MemberID &gt;= (select MemberID from Member limit 1000,1) limit 100;</p>
<p> &nbsp; &nbsp;100 rows in set (0.00 sec)</p>
<p> &nbsp; &nbsp;mysql&gt; select * from Member limit 100000, 100;</p>
<p> &nbsp; &nbsp;100 rows in set (0.10 sec)</p>
<p> &nbsp; &nbsp;mysql&gt; select * from Member where MemberID &gt;= (select MemberID from Member limit 100000,1) limit 100;</p>
<p> &nbsp; &nbsp;100 rows in set (0.02 sec)</p>
<p> &nbsp; &nbsp;mysql&gt; nopager</p>
<p> &nbsp; &nbsp;PAGER set to stdout</p>
<p> &nbsp; &nbsp;mysql&gt; show profilesG</p>
<p> &nbsp; &nbsp;*************************** 1. row ***************************</p>
<p> &nbsp; &nbsp;Query_ID: 1</p>
<p> &nbsp; &nbsp;Duration: 0.00003300</p>
<p> &nbsp; &nbsp; &nbsp; Query: select count(*) from Member</p>
<p> &nbsp; &nbsp;*************************** 2. row ***************************</p>
<p> &nbsp; &nbsp;Query_ID: 2</p>
<p> &nbsp; &nbsp;Duration: 0.00167000</p>
<p> &nbsp; &nbsp; &nbsp; Query: select * from Member limit 10, 100</p>
<p> &nbsp; &nbsp;*************************** 3. row ***************************</p>
<p> &nbsp; &nbsp;Query_ID: 3</p>
<p> &nbsp; &nbsp;Duration: 0.00112400</p>
<p> &nbsp; &nbsp; &nbsp; Query: select * from Member where MemberID &gt;= (select MemberID from Member limit 10,1) limit 100</p>
<p> &nbsp; &nbsp;*************************** 4. row ***************************</p>
<p> &nbsp; &nbsp;Query_ID: 4</p>
<p> &nbsp; &nbsp;Duration: 0.00263200</p>
<p> &nbsp; &nbsp; &nbsp; Query: select * from Member limit 1000, 100</p>
<p> &nbsp; &nbsp;*************************** 5. row ***************************</p>
<p> &nbsp; &nbsp;Query_ID: 5</p>
<p> &nbsp; &nbsp;Duration: 0.00134000</p>
<p> &nbsp; &nbsp; &nbsp; Query: select * from Member where MemberID &gt;= (select MemberID from Member limit 1000,1) limit 100</p>
<p> &nbsp; &nbsp;*************************** 6. row ***************************</p>
<p> &nbsp; &nbsp;Query_ID: 6</p>
<p> &nbsp; &nbsp;Duration: 0.09956700</p>
<p> &nbsp; &nbsp; &nbsp; Query: select * from Member limit 100000, 100</p>
<p> &nbsp; &nbsp;*************************** 7. row ***************************</p>
<p> &nbsp; &nbsp;Query_ID: 7</p>
<p> &nbsp; &nbsp;Duration: 0.02447700</p>
<p> &nbsp; &nbsp; &nbsp; Query: select * from Member where MemberID &gt;= (select MemberID from Member limit 100000,1) limit 100</p>
<p> &nbsp; &nbsp; 从结果中可以得知，当偏移1000以上使用子查询法可以有效的提高性能。</p>
<p> &nbsp; &nbsp;2.倒排表优化法</p>
<p> &nbsp; &nbsp;倒排表法类似建立索引，用一张表来维护页数，然后通过高效的连接得到数据</p>
<p> &nbsp; &nbsp;缺点：只适合数据数固定的情况，数据不能删除，维护页表困难</p>
<p> &nbsp; &nbsp;3.反向查找优化法</p>
<p> &nbsp; &nbsp;当偏移超过一半记录数的时候，先用排序，这样偏移就反转了</p>
<p> &nbsp; &nbsp;缺点：order by优化比较麻烦，要增加索引，索引影响数据的修改效率，并且要知道总记录数</p>
<p> &nbsp; &nbsp;，偏移大于数据的一半</p>
<p> &nbsp; &nbsp;引用</p>
<p> &nbsp; &nbsp;limit偏移算法：</p>
<p> &nbsp; &nbsp;正向查找： (当前页 &#8211; 1) * 页长度</p>
<p> &nbsp; &nbsp;反向查找： 总记录 &#8211; 当前页 * 页长度</p>
<p> &nbsp; &nbsp;做下实验，看看性能如何</p>
<p> &nbsp; &nbsp;总记录数：1,628,775</p>
<p> &nbsp; &nbsp;每页记录数： 40</p>
<p> &nbsp; &nbsp;总页数：1,628,775 / 40 = 40720</p>
<p> &nbsp; &nbsp;中间页数：40720 / 2 = 20360</p>
<p> &nbsp; &nbsp;第21000页</p>
<p> &nbsp; &nbsp;正向查找SQL:</p>
<p> &nbsp; &nbsp;Sql代码</p>
<p> &nbsp; &nbsp;SELECT * FROM `abc` WHERE `BatchID` = 123 LIMIT 839960, 40</p>
<p> &nbsp; &nbsp;时间：1.8696 秒</p>
<p> &nbsp; &nbsp;反向查找sql:</p>
<p> &nbsp; &nbsp;Sql代码</p>
<p> &nbsp; &nbsp;SELECT * FROM `abc` WHERE `BatchID` = 123 ORDER BY InputDate DESC LIMIT 788775, 40</p>
<p> &nbsp; &nbsp;时间：1.8336 秒</p>
<p> &nbsp; &nbsp;第30000页</p>
<p> &nbsp; &nbsp;正向查找SQL:</p>
<p> &nbsp; &nbsp;Sql代码</p>
<p> &nbsp; &nbsp;1.SELECT * FROM `abc` WHERE `BatchID` = 123 LIMIT 1199960, 40</p>
<p> &nbsp; &nbsp;SELECT * FROM `abc` WHERE `BatchID` = 123 LIMIT 1199960, 40</p>
<p> &nbsp; &nbsp;时间：2.6493 秒</p>
<p> &nbsp; &nbsp;反向查找sql:</p>
<p> &nbsp; &nbsp;Sql代码</p>
<p> &nbsp; &nbsp;1.SELECT * FROM `abc` WHERE `BatchID` = 123 ORDER BY InputDate DESC LIMIT 428775, 40</p>
<p> &nbsp; &nbsp;SELECT * FROM `abc` WHERE `BatchID` = 123 ORDER BY InputDate DESC LIMIT 428775, 40</p>
<p> &nbsp; &nbsp; 时间：1.0035 秒</p>
<p> &nbsp; &nbsp;注意，反向查找的结果是是降序desc的，并且InputDate是记录的插入时间，也可以用主键联合索引，但是不方便。</p>
<p> &nbsp; &nbsp;4.limit限制优化法</p>
<p> &nbsp; &nbsp;把limit偏移量限制低于某个数。。超过这个数等于没数据，我记得alibaba的dba说过他们是这样做的</p>
<p> &nbsp; &nbsp;5.只查索引法</p>
<h2  class="related_post_title">猜您喜欢</h2><ul class="related_post"><li><a href="http://ourmysql.com/archives/1340" title="MySQL一个异常查询问题追查">MySQL一个异常查询问题追查</a></li><li><a href="http://ourmysql.com/archives/1331" title="[MySQL优化案例]系列 — 分页优化">[MySQL优化案例]系列 — 分页优化</a></li><li><a href="http://ourmysql.com/archives/1322" title="SQL常见的可优化点">SQL常见的可优化点</a></li><li><a href="http://ourmysql.com/archives/404" title="mysql limit查询优化">mysql limit查询优化</a></li></ul>]]></content:encoded>
			<wfw:commentRss>http://ourmysql.com/archives/1451/feed</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>获取 MySQL 崩溃时的 core file</title>
		<link>http://ourmysql.com/archives/1450</link>
		<comments>http://ourmysql.com/archives/1450#comments</comments>
		<pubDate>Mon, 21 Mar 2016 13:56:23 +0000</pubDate>
		<dc:creator>OurMySQL</dc:creator>
				<category><![CDATA[MySQL解错方案]]></category>
		<category><![CDATA[core]]></category>
		<category><![CDATA[崩溃]]></category>

		<guid isPermaLink="false">http://ourmysql.com/?p=1450</guid>
		<description><![CDATA[    对于一般进程，要让进程崩溃时能生成 core file 用于调试，只需要设置 rlimit 的 core file size > 0 即可。比如，用在 ulimit -c unlimited 时启动程序。
    对 MySQL 来说，由于 core file 中会包含表空间的数据，所以默认情况下为了安全，mysqld 捕获了 SEGV 等信号，崩溃时并不会生成 core file，需要在 my.cnf 或启动参数中加上 core-file。
    但是即使做到了以上两点，在 mysqld crash 时还是可能无法 core dump。还有一些系统参数会影响 core dump。 <a href="http://ourmysql.com/archives/1450"><br /><br />继续阅读全文 <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p> &nbsp; &nbsp;对于一般进程，要让进程崩溃时能生成 core file 用于调试，只需要设置 rlimit 的 core file size &gt; 0 即可。比如，用在 ulimit -c unlimited 时启动程序。</p>
<p> &nbsp; &nbsp;对 MySQL 来说，由于 core file 中会包含表空间的数据，所以默认情况下为了安全，mysqld 捕获了 SEGV 等信号，崩溃时并不会生成 core file，需要在 my.cnf 或启动参数中加上 core-file。</p>
<p> &nbsp; &nbsp;但是即使做到了以上两点，在 mysqld crash 时还是可能无法 core dump。还有一些系统参数会影响 core dump。以下脚本可供参考：</p>
<pre>echo 2 &gt;/proc/sys/fs/suid_dumpable
chmod 0777 /var/crash
echo /var/crash/core&gt; /proc/sys/kernel/core_pattern
echo 1 &gt;/proc/sys/kernel/core_uses_pid
</pre>
<p> &nbsp; &nbsp;由于 mysql 通常会以 suid 方式启动，所以需要打开 suid_dumpable 。对于 core_pattern，最好指定一个保证可写的绝对路径。</p>
<p> &nbsp; &nbsp;之后，就可以用 kill -SEGV 让 mysqld 崩溃，测试一下能不能正常产生 core file 了。</p>
<h2  class="related_post_title">猜想失败，您看看下面的文章有用吗？</h2><ul class="related_post"><li><a href="http://ourmysql.com/archives/591" title="升级MySQL过程中出现Unknown command错误">升级MySQL过程中出现Unknown command错误</a></li><li><a href="http://ourmysql.com/archives/353" title="用MySQL-zrm来备份和恢复MySQL数据库">用MySQL-zrm来备份和恢复MySQL数据库</a></li><li><a href="http://ourmysql.com/archives/1396" title="老叶观点：MySQL开发规范之我见">老叶观点：MySQL开发规范之我见</a></li><li><a href="http://ourmysql.com/archives/777" title="教你写MySQL UDF ">教你写MySQL UDF </a></li><li><a href="http://ourmysql.com/archives/310" title="innodb_max_dirty_pages_pct与检查点的关系">innodb_max_dirty_pages_pct与检查点的关系</a></li><li><a href="http://ourmysql.com/archives/151" title="SQL中drop,delete和truncate的异同">SQL中drop,delete和truncate的异同</a></li><li><a href="http://ourmysql.com/archives/396" title="MySQL之Explain扫盲班实战">MySQL之Explain扫盲班实战</a></li><li><a href="http://ourmysql.com/archives/1300" title="Unique索引优化实践">Unique索引优化实践</a></li><li><a href="http://ourmysql.com/archives/711" title="随机主键对InnoDB插入性能的影响">随机主键对InnoDB插入性能的影响</a></li><li><a href="http://ourmysql.com/archives/1360" title="MySQL 二进制日志格式基础(一)">MySQL 二进制日志格式基础(一)</a></li></ul>]]></content:encoded>
			<wfw:commentRss>http://ourmysql.com/archives/1450/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>MySQL如何将两个表名对调</title>
		<link>http://ourmysql.com/archives/1449</link>
		<comments>http://ourmysql.com/archives/1449#comments</comments>
		<pubDate>Sun, 20 Mar 2016 22:16:02 +0000</pubDate>
		<dc:creator>OurMySQL</dc:creator>
				<category><![CDATA[MySQL基础知识]]></category>
		<category><![CDATA[表名]]></category>

		<guid isPermaLink="false">http://ourmysql.com/?p=1449</guid>
		<description><![CDATA[问题：有位同学问我，在类似pt-osc场景下，需要将两个表名对调，怎么才能确保万无一失呢？  <a href="http://ourmysql.com/archives/1449"><br /><br />继续阅读全文 <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<div class="rich_media">
<div class="rich_media_inner">
<div id="page-content">
<div id="img-content">
<div id="js_content" class="rich_media_content">
<p><strong>问题: </strong></p>
<p>有位同学问我，在类似pt-osc场景下，需要将两个表名对调，怎么才能确保万无一失呢？ </p>
<p><strong>分析: </strong></p>
<p>估计其他同学就笑了，表名对掉还不简单吗，相互RENAME一下嘛。</p>
<p><br class="tn-Powered-by-XIUMI" />但是，我们想要的是同时完成表名对调，如果是先后的对掉，可能会导致有些数据写入失败，那怎么办？</p>
<p>其实也不难，从MySQL手册里就能找到方法，那就是：同时锁定2个表，不允许写入，然后对调表名。<br class="tn-Powered-by-XIUMI" /><br class="tn-Powered-by-XIUMI" />我们通常只锁一个表，那么同时锁两个表应该怎么做呢，可以用下面的方法：</p>
<pre>LOCK TABLES t1 WRITE, t2 WRITE;
ALTER TABLE t1 RENAME TO t3;
ALTER TABLE t2 RENAME TO t1;
ALTER TABLE t3 RENAME TO t2;
UNLOCK TABLES;</pre>
<p>看到了吧，其实很简单，两个表同时加表级写锁，然后用ALTER语法改名就可以了。<br class="tn-Powered-by-XIUMI" /><br class="tn-Powered-by-XIUMI" />废话挺多的，谢谢各位客官耐心看完 ：)</p>
</div>
</div>
</div>
</div>
</div>
<h2  class="related_post_title">猜想失败，您看看下面的文章有用吗？</h2><ul class="related_post"><li><a href="http://ourmysql.com/archives/702" title="CHAR定长字段对MyISAM和InnoDB的意义">CHAR定长字段对MyISAM和InnoDB的意义</a></li><li><a href="http://ourmysql.com/archives/595" title="Xtrabackup：MySQL DBA的必备工具">Xtrabackup：MySQL DBA的必备工具</a></li><li><a href="http://ourmysql.com/archives/645" title="InnoDB insert性能拐点测试">InnoDB insert性能拐点测试</a></li><li><a href="http://ourmysql.com/archives/1014" title="mysql 的权限体系介绍">mysql 的权限体系介绍</a></li><li><a href="http://ourmysql.com/archives/537" title="MySQL内存使用-线程独享">MySQL内存使用-线程独享</a></li><li><a href="http://ourmysql.com/archives/1354" title="MySQL 加锁处理分析">MySQL 加锁处理分析</a></li><li><a href="http://ourmysql.com/archives/1417" title=" B+树索引和哈希索引的区别"> B+树索引和哈希索引的区别</a></li><li><a href="http://ourmysql.com/archives/813" title="mysqldump意外终止的原因以及解决方法">mysqldump意外终止的原因以及解决方法</a></li><li><a href="http://ourmysql.com/archives/1172" title="linux 定期自动备份mysql的shell">linux 定期自动备份mysql的shell</a></li><li><a href="http://ourmysql.com/archives/1385" title="MySQL怎么禁用autocommit">MySQL怎么禁用autocommit</a></li></ul>]]></content:encoded>
			<wfw:commentRss>http://ourmysql.com/archives/1449/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
	</channel>
</rss>
