<?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>MySQL | 酷 壳 - CoolShell</title>
	<atom:link href="https://coolshell.cn/tag/mysql/feed" rel="self" type="application/rss+xml" />
	<link>https://coolshell.cn</link>
	<description>享受编程和技术所带来的快乐 - Coding Your Ambition</description>
	<lastBuildDate>Wed, 20 Jun 2012 09:41:16 +0000</lastBuildDate>
	<language>zh-CN</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.2</generator>
	<item>
		<title>性能调优攻略</title>
		<link>https://coolshell.cn/articles/7490.html</link>
					<comments>https://coolshell.cn/articles/7490.html#comments</comments>
		
		<dc:creator><![CDATA[陈皓]]></dc:creator>
		<pubDate>Wed, 20 Jun 2012 01:24:53 +0000</pubDate>
				<category><![CDATA[Unix/Linux]]></category>
		<category><![CDATA[Windows]]></category>
		<category><![CDATA[操作系统]]></category>
		<category><![CDATA[数据库]]></category>
		<category><![CDATA[程序设计]]></category>
		<category><![CDATA[系统架构]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[Performance]]></category>
		<category><![CDATA[SQL]]></category>
		<category><![CDATA[TCP]]></category>
		<category><![CDATA[UDP]]></category>
		<guid isPermaLink="false">http://coolshell.cn/?p=7490</guid>

					<description><![CDATA[<p>关于性能优化这是一个比较大的话题，在《由12306.cn谈谈网站性能技术》中我从业务和设计上说过一些可用的技术以及那些技术的优缺点，今天，想从一些技术细节上谈谈...</p>
<p class="read-more"><a class="btn btn-default" href="https://coolshell.cn/articles/7490.html"> Read More<span class="screen-reader-text">  Read More</span></a></p>
The post <a href="https://coolshell.cn/articles/7490.html">性能调优攻略</a> first appeared on <a href="https://coolshell.cn">酷 壳 - CoolShell</a>.]]></description>
										<content:encoded><![CDATA[<p><script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-3415450859608158"
     crossorigin="anonymous"></script><img decoding="async" loading="lazy" class="alignright size-medium wp-image-7641" title="Performance Tuning" src="https://coolshell.cn/wp-content/uploads/2012/06/f1-300x216.jpg" alt="" width="300" height="216" srcset="https://coolshell.cn/wp-content/uploads/2012/06/f1-300x216.jpg 300w, https://coolshell.cn/wp-content/uploads/2012/06/f1.jpg 350w" sizes="(max-width: 300px) 100vw, 300px" />关于性能优化这是一个比较大的话题，在《<a title="由12306.cn谈谈网站性能技术" href="https://coolshell.cn/articles/6470.html" target="_blank">由12306.cn谈谈网站性能技术</a>》中我从业务和设计上说过一些可用的技术以及那些技术的优缺点，今天，想从一些技术细节上谈谈性能优化，主要是一些代码级别的技术和方法。<strong>本文的东西是我的一些经验和知识，并不一定全对，希望大家指正和补充</strong>。</p>
<p>在开始这篇文章之前，大家可以移步去看一下酷壳以前发表的《<a title="代码优化概要" href="https://coolshell.cn/articles/2967.html" target="_blank">代码优化概要</a>》，这篇文章基本上告诉你——<strong>要进行优化，先得找到性能瓶颈</strong>！ 但是在讲如何定位系统性能瓶劲之前，请让我讲一下系统性能的定义和测试，因为没有这两件事，后面的定位和优化无从谈起。</p>
<h4>一、系统性能定义</h4>
<p>让我们先来说说如何什么是系统性能。这个定义非常关键，如果我们不清楚什么是系统性能，那么我们将无法定位之。我见过很多朋友会觉得这很容易，但是仔细一问，其实他们并没有一个比较系统的方法，所以，在这里我想告诉大家如何系统地来定位性能。 总体来说，系统性能就是两个事：</p>
<ol>
<li><strong>Throughput</strong> ，吞吐量。也就是每秒钟可以处理的请求数，任务数。</li>
<li><strong>Latency</strong>， 系统延迟。也就是系统在处理一个请求或一个任务时的延迟。</li>
</ol>
<p>一般来说，一个系统的性能受到这两个条件的约束，缺一不可。比如，我的系统可以顶得住一百万的并发，但是系统的延迟是2分钟以上，那么，这个一百万的负载毫无意义。系统延迟很短，但是吞吐量很低，同样没有意义。所以，一个好的系统的性能测试必然受到这两个条件的同时作用。 有经验的朋友一定知道，这两个东西的一些关系：</p>
<ul>
<li><strong>Throughput越大，Latency会越差。</strong>因为请求量过大，系统太繁忙，所以响应速度自然会低。</li>
<li><strong>Latency越好，能支持的Throughput就会越高。</strong>因为Latency短说明处理速度快，于是就可以处理更多的请求。</li>
</ul>
<h4>二、系统性能测试</h4>
<p>经过上述的说明，我们知道要测试系统的性能，需要我们收集系统的Throughput和Latency这两个值。</p>
<p><span id="more-7490"></span></p>
<ul>
<li>首先，<strong>需要定义Latency这个值</strong>，比如说，对于网站系统响应时间必需是5秒以内（对于某些实时系统可能需要定义的更短，比如5ms以内，这个更根据不同的业务来定义）</li>
</ul>
<ul>
<li>其次，<strong>开发性能测试工具</strong>，一个工具用来制造高强度的Throughput，另一个工具用来测量Latency。对于第一个工具，你可以参考一下“<a title="十个免费的Web压力测试工具" href="https://coolshell.cn/articles/2589.html" target="_blank">十个免费的Web压力测试工具</a>”，关于如何测量Latency，你可以在代码中测量，但是这样会影响程序的执行，而且只能测试到程序内部的Latency，真正的Latency是整个系统都算上，包括操作系统和网络的延时，你可以使用Wireshark来抓网络包来测量。这两个工具具体怎么做，这个还请大家自己思考去了。</li>
</ul>
<ul>
<li>最后，<strong>开始性能测试</strong>。你需要不断地提升测试的Throughput，然后观察系统的负载情况，如果系统顶得住，那就观察Latency的值。这样，你就可以找到系统的最大负载，并且你可以知道系统的响应延时是多少。</li>
</ul>
<p>再多说一些，</p>
<ul>
<li>关于Latency，如果吞吐量很少，这个值估计会非常稳定，当吞吐量越来越大时，系统的Latency会出现非常剧烈的抖动，所以，我们在测量Latency的时候，我们需要注意到Latency的分布，也就是说，有百分之几的在我们允许的范围，有百分之几的超出了，有百分之几的完全不可接受。也许，平均下来的Latency达标了，但是其中仅有50%的达到了我们可接受的范围。那也没有意义。</li>
</ul>
<ul>
<li>关于性能测试，我们还需要定义一个时间段。比如：在某个吞吐量上持续15分钟。因为当负载到达的时候，系统会变得不稳定，当过了一两分钟后，系统才会稳定。另外，也有可能是，你的系统在这个负载下前几分钟还表现正常，然后就不稳定了，甚至垮了。所以，需要这么一段时间。这个值，我们叫做峰值极限。</li>
</ul>
<ul>
<li>性能测试还需要做Soak Test，也就是在某个吞吐量下，系统可以持续跑一周甚至更长。这个值，我们叫做系统的正常运行的负载极限。</li>
</ul>
<p>性能测试有很多很复要的东西，比如：burst test等。 这里不能一一详述，这里只说了一些和性能调优相关的东西。总之，性能测试是一细活和累活。</p>
<h4>三、定位性能瓶颈</h4>
<p><img decoding="async" loading="lazy" class="alignright size-full wp-image-7640" title="bottleneck" src="https://coolshell.cn/wp-content/uploads/2012/06/bottleneck.jpg" alt="" width="200" height="200" srcset="https://coolshell.cn/wp-content/uploads/2012/06/bottleneck.jpg 200w, https://coolshell.cn/wp-content/uploads/2012/06/bottleneck-150x150.jpg 150w" sizes="(max-width: 200px) 100vw, 200px" />有了上面的铺垫，我们就可以测试到到系统的性能了，再调优之前，我们先来说说如何找到性能的瓶颈。我见过很多朋友会觉得这很容易，但是仔细一问，其实他们并没有一个比较系统的方法。</p>
<h5>3.1）查看操作系统负载</h5>
<p>首先，当我们系统有问题的时候，我们不要急于去调查我们代码，这个毫无意义。我们首要需要看的是操作系统的报告。看看操作系统的CPU利用率，看看内存使用率，看看操作系统的IO，还有网络的IO，网络链接数，等等。Windows下的perfmon是一个很不错的工具，Linux下也有很多相关的命令和工具，比如：<a href="http://sourceware.org/systemtap/" target="_blank">SystemTap</a>，<a href="https://latencytop.org/" target="_blank">LatencyTOP</a>，vmstat, sar, iostat, top, tcpdump等等 。通过观察这些数据，我们就可以知道我们的软件的性能基本上出在哪里。比如：</p>
<p>1）先看CPU利用率，如果CPU利用率不高，但是系统的Throughput和Latency上不去了，这说明我们的程序并没有忙于计算，而是忙于别的一些事，比如IO。（另外，CPU的利用率还要看内核态的和用户态的，内核态的一上去了，整个系统的性能就下来了。而对于多核CPU来说，CPU 0 是相当关键的，如果CPU 0的负载高，那么会影响其它核的性能，因为CPU各核间是需要有调度的，这靠CPU0完成）</p>
<p>2）然后，我们可以看一下IO大不大，IO和CPU一般是反着来的，CPU利用率高则IO不大，IO大则CPU就小。关于IO，我们要看三个事，一个是磁盘文件IO，一个是驱动程序的IO（如：网卡），一个是内存换页率。这三个事都会影响系统性能。</p>
<p>3）然后，查看一下网络带宽使用情况，在Linux下，你可以使用iftop, iptraf, ntop, tcpdump这些命令来查看。或是用Wireshark来查看。</p>
<p>4）如果CPU不高，IO不高，内存使用不高，网络带宽使用不高。但是系统的性能上不去。这说明你的程序有问题，比如，你的程序被阻塞了。可能是因为等那个锁，可能是因为等某个资源，或者是在切换上下文。</p>
<p><strong>通过了解操作系统的性能，我们才知道性能的问题，比如：带宽不够，内存不够，TCP缓冲区不够，等等，很多时候，不需要调整程序的，只需要调整一下硬件或操作系统的配置就可以了</strong>。</p>
<h5>3.2）使用Profiler测试</h5>
<p>接下来，我们需要使用性能检测工具，也就是使用某个Profiler来差看一下我们程序的运行性能。如：Java的JProfiler/TPTP/CodePro Profiler，GNU的gprof，IBM的PurifyPlus，Intel的VTune，AMD的CodeAnalyst，还有Linux下的OProfile/perf，后面两个可以让你对你的代码优化到CPU的微指令级别，如果你关心CPU的L1/L2的缓存调优，那么你需要考虑一下使用VTune。 使用这些Profiler工具，可以让你程序中各个模块函数甚至指令的很多东西，如：<strong>运行的时间</strong> ，<strong>调用的次数</strong>，<strong>CPU的利用率</strong>，等等。这些东西对我们来说非常有用。</p>
<p>我们重点观察运行时间最多，调用次数最多的那些函数和指令。这里注意一下，对于调用次数多但是时间很短的函数，你可能只需要轻微优化一下，你的性能就上去了（比如：某函数一秒种被调用100万次，你想想如果你让这个函数提高0.01毫秒的时间 ，这会给你带来多大的性能）</p>
<p>使用Profiler有个问题我们需要注意一下，因为Profiler会让你的程序运行的性能变低，像PurifyPlus这样的工具会在你的代码中插入很多代码，会导致你的程序运行效率变低，从而没发测试出在高吞吐量下的系统的性能，对此，一般有两个方法来定位系统瓶颈：</p>
<p>1）在你的代码中自己做统计，使用微秒级的计时器和函数调用计算器，每隔10秒把统计log到文件中。</p>
<p>2）分段注释你的代码块，让一些函数空转，做Hard Code的Mock，然后再测试一下系统的Throughput和Latency是否有质的变化，如果有，那么被注释的函数就是性能瓶颈，再在这个函数体内注释代码，直到找到最耗性能的语句。</p>
<p>最后再说一点，<strong>对于性能测试，不同的Throughput会出现不同的测试结果，不同的测试数据也会有不同的测试结果。所以，用于性能测试的数据非常重要，性能测试中，我们需要观测试不同Throughput的结果</strong>。</p>
<h4>四、常见的系统瓶颈</h4>
<p>下面这些东西是我所经历过的一些问题，也许并不全，也许并不对，大家可以补充指正，我<strong>纯属抛砖引玉</strong>。关于系统架构方面的性能调优，大家可移步看一下《<a title="由12306.cn谈谈网站性能技术" href="https://coolshell.cn/articles/6470.html" target="_blank">由12306.cn谈谈网站性能技术</a>》，关于Web方面的一些性能调优的东西，大家可以看看《<a title="Web开发中需要了解的东西" href="https://coolshell.cn/articles/6043.html" target="_blank">Web开发中需要了解的东西</a>》一文中的性能一章。我在这里就不再说设计和架构上的东西了。</p>
<p><strong></strong>一般来说，性能优化也就是下面的几个策略：</p>
<ul>
<li><strong>用空间换时间</strong>。各种cache如CPU L1/L2/RAM到硬盘，都是用空间来换时间的策略。这样策略基本上是把计算的过程一步一步的保存或缓存下来，这样就不用每次用的时候都要再计算一遍，比如数据缓冲，CDN，等。这样的策略还表现为冗余数据，比如数据镜象，负载均衡什么的。</li>
</ul>
<ul>
<li><strong>用时间换空间</strong>。有时候，少量的空间可能性能会更好，比如网络传输，如果有一些压缩数据的算法（如前些天说的“<a title="Huffman 编码压缩算法" href="https://coolshell.cn/articles/7459.html">Huffman 编码压缩算法</a>” 和 “<a title="rsync 的核心算法" href="https://coolshell.cn/articles/7425.html">rsync 的核心算法</a>”），这样的算法其实很耗时，但是因为瓶颈在网络传输，所以用时间来换空间反而能省时间。</li>
</ul>
<ul>
<li><strong>简化代码</strong>。最高效的程序就是不执行任何代码的程序，所以，代码越少性能就越高。关于代码级优化的技术大学里的教科书有很多示例了。如：减少循环的层数，减少递归，在循环中少声明变量，少做分配和释放内存的操作，尽量把循环体内的表达式抽到循环外，条件表达的中的多个条件判断的次序，尽量在程序启动时把一些东西准备好，注意函数调用的开销（栈上开销），注意面向对象语言中临时对象的开销，小心使用异常（不要用异常来检查一些可接受可忽略并经常发生的错误），…… 等等，等等，这连东西需要我们非常了解编程语言和常用的库。</li>
</ul>
<ul>
<li><strong>并行处理</strong>。如果CPU只有一个核，你要玩多进程，多线程，对于计算密集型的软件会反而更慢（因为操作系统调度和切换开销很大），CPU的核多了才能真正体现出多进程多线程的优势。并行处理需要我们的程序有Scalability，不能水平或垂直扩展的程序无法进行并行处理。从架构上来说，这表再为——是否可以做到不改代码只是加加机器就可以完成性能提升？</li>
</ul>
<p>总之，<strong>根据2：8原则来说，20%的代码耗了你80%的性能，找到那20%的代码，你就可以优化那80%的性能</strong>。 下面的一些东西都是我的一些经验，我只例举了一些最有价值的性能调优的的方法，供你参考，也欢迎补充。</p>
<p><strong>4.1）算法调优</strong>。算法非常重要，好的算法会有更好的性能。举几个我经历过的项目的例子，大家可以感觉一下。</p>
<ul>
<li>一个是<strong>过滤算法</strong>，系统需要对收到的请求做过滤，我们把可以被filter in/out的东西配置在了一个文件中，原有的过滤算法是遍历过滤配置，后来，我们找到了一种方法可以对这个过滤配置进行排序，这样就可以用二分折半的方法来过滤，系统性能增加了50%。</li>
</ul>
<ul>
<li>一个是<strong>哈希算法</strong>。计算哈希算法的函数并不高效，一方面是计算太费时，另一方面是碰撞太高，碰撞高了就跟单向链表一个性能（可参看<a title="Hash Collision DoS 问题" href="https://coolshell.cn/articles/6424.html">Hash Collision DoS 问题</a>）。我们知道，算法都是和需要处理的数据很有关系的，就算是被大家所嘲笑的“冒泡排序”在某些情况下（大多数数据是排好序的）其效率会高于所有的排序算法。哈希算法也一样，广为人知的哈希算法都是用英文字典做测试，但是我们的业务在数据有其特殊性，所以，对于还需要根据自己的数据来挑选适合的哈希算法。对于我以前的一个项目，公司内某牛人给我发来了一个哈希算法，结果让我们的系统性能上升了150%。（关于各种哈希算法，你一定要看看<a href="http://programmers.stackexchange.com/questions/49550/which-hashing-algorithm-is-best-for-uniqueness-and-speed/145633#145633" target="_blank">StackExchange上的这篇关于各种hash算法的文章</a> ）</li>
</ul>
<ul>
<li><strong>分而治之和预处理</strong>。以前有一个程序为了生成月报表，每次都需要计算很长的时间，有时候需要花将近一整天的时间。于是我们把我们找到了一种方法可以把这个算法发成增量式的，也就是说我每天都把当天的数据计算好了后和前一天的报表合并，这样可以大大的节省计算时间，每天的数据计算量只需要20分钟，但是如果我要算整个月的，系统则需要10个小时以上（SQL语句在大数据量面前性能成级数性下降）。这种分而治之的思路在大数据面前对性能有很帮助，就像merge排序一样。SQL语句和数据库的性能优化也是这一策略，如：使用嵌套式的Select而不是笛卡尔积的Select，使用视图，等等。</li>
</ul>
<p><strong>4.2）代码调优</strong>。从我的经验上来说，代码上的调优有下面这几点：</p>
<ul>
<li><strong>字符串操作</strong>。这是最费系统性能的事了，无论是strcpy, strcat还是strlen，最需要注意的是字符串子串匹配。所以，能用整型最好用整型。举几个例子，第一个例子是N年前做银行的时候，我的同事喜欢把日期存成字符串（如：2012-05-29 08:30:02），我勒个去，一个select  where between语句相当耗时。另一个例子是，我以前有个同事把一些状态码用字符串来处理，他的理由是，这样可以在界面上直接显示，后来性能调优的时候，我把这些状态码全改成整型，然后用位操作查状态，因为有一个每秒钟被调用了150K次的函数里面有三处需要检查状态，经过改善以后，整个系统的性能上升了30%左右。还有一个例子是，我以前从事的某个产品编程规范中有一条是要在每个函数中把函数名定义出来，如：const char fname[]=&#8221;functionName()&#8221;, 这是为了好打日志，但是为什么不声明成 static类型的呢？</li>
</ul>
<ul>
<li><strong>多线程调优</strong>。有人说，thread is evil，这个对于系统性能在某些时候是个问题。因为多线程瓶颈就在于互斥和同步的锁上，以及线程上下文切换的成本，怎么样的少用锁或不用锁是根本（比如：<a title="多版本并发控制(MVCC)在分布式系统中的应用" href="https://coolshell.cn/articles/6790.html">多版本并发控制(MVCC)在分布式系统中的应用</a> 中说的乐观锁可以解决性能问题），此外，还有读写锁也可以解决大多数是读操作的并发的性能问题。这里多说一点在C++中，我们可能会使用线程安全的智能指针AutoPtr或是别的一些容器，只要是线程安全的，其不管三七二十一都要上锁，上锁是个成本很高的操作，使用AutoPtr会让我们的系统性能下降得很快，如果你可以保证不会有线程并发问题，那么你应该不要用AutoPtr。我记得我上次我们同事去掉智能指针的引用计数，让系统性能提升了50%以上。对于Java对象的引用计数，如果我猜的没错的话，到处都是锁，所以，Java的性能问题一直是个问题。另外，线程不是越多越好，线程间的调度和上下文切换也是很夸张的事，尽可能的在一个线程里干，尽可能的不要同步线程。这会让你有很多的性能。</li>
</ul>
<ul>
<li><strong>内存分配</strong>。不要小看程序的内存分配。malloc/realloc/calloc这样的系统调非常耗时，尤其是当内存出现碎片的时候。我以前的公司出过这样一个问题——在用户的站点上，我们的程序有一天不响应了，用GDB跟进去一看，系统hang在了malloc操作上，20秒都没有返回，重启一些系统就好了。这就是内存碎片的问题。这就是为什么很多人抱怨STL有严重的内存碎片的问题，因为太多的小内存的分配释放了。有很多人会以为用内存池可以解决这个问题，但是实际上他们只是重新发明了Runtime-C或操作系统的内存管理机制，完全于事无补。当然解决内存碎片的问题还是通过内存池，具体来说是一系列不同尺寸的内存池（这个留给大家自己去思考）。当然，少进行动态内存分配是最好的。说到内存池就需要说一下池化技术。比如线程池，连接池等。池化技术对于一些短作业来说（如http服务） 相当相当的有效。这项技术可以减少链接建立，线程创建的开销，从而提高性能。</li>
</ul>
<ul>
<li><strong>异步操作</strong>。我们知道Unix下的文件操作是有block和non-block的方式的，像有些系统调用也是block式的，如：Socket下的select，Windows下的WaitforObject之类的，如果我们的程序是同步操作，那么会非常影响性能，我们可以改成异步的，但是改成异步的方式会让你的程序变复杂。异步方式一般要通过队列，要注间队列的性能问题，另外，异步下的状态通知通常是个问题，比如消息事件通知方式，有callback方式，等，这些方式同样可能会影响你的性能。但是通常来说，异步操作会让性能的吞吐率有很大提升（Throughput），但是会牺牲系统的响应时间（latency）。这需要业务上支持。</li>
</ul>
<ul>
<li><strong>语言和代码库</strong>。我们要熟悉语言以及所使用的函数库或类库的性能。比如：STL中的很多容器分配了内存后，那怕你删除元素，内存也不会回收，其会造成内存泄露的假像，并可能造成内存碎片问题。再如，STL某些容器的size()==0  和 empty()是不一样的，因为，size()是O(n)复杂度，empty()是O(1)的复杂度，这个要小心。Java中的JVM调优需要使用的这些参数：-Xms -Xmx -Xmn -XX:SurvivorRatio -XX:MaxTenuringThreshold，还需要注意JVM的GC，GC的霸气大家都知道，尤其是full GC（还整理内存碎片），他就像“恐龙特级克赛号”一样，他运行的时候，整个世界的时间都停止了。</li>
</ul>
<p><strong>4.3）网络调优</strong></p>
<p>关于网络调优，尤其是TCP Tuning（你可以以这两个关键词在网上找到很多文章），这里面有很多很多东西可以说。看看Linux下TCP/IP的那么多参数就知道了（顺便说一下，你也许不喜欢Linux，但是你不能否认Linux给我们了很多可以进行内核调优的权力）。强烈建议大家看看《<a href="http://book.douban.com/subject/1088054/" target="_blank">TCP/IP 详解 卷1:协议</a>》这本书。我在这里只讲一些概念上的东西。</p>
<p><strong>A） TCP调优</strong></p>
<p>我们知道TCP链接是有很多开销的，一个是会占用文件描述符，另一个是会开缓存，一般来说一个系统可以支持的TCP链接数是有限的，我们需要清楚地认识到TCP链接对系统的开销是很大的。正是因为TCP是耗资源的，所以，很多攻击都是让你系统上出现大量的TCP链接，把你的系统资源耗尽。比如著名的SYNC Flood攻击。</p>
<p>所以，我们要注意配置KeepAlive参数，这个参数的意思是定义一个时间，如果链接上没有数据传输，系统会在这个时间发一个包，如果没有收到回应，那么TCP就认为链接断了，然后就会把链接关闭，这样可以回收系统资源开销。（注：HTTP层上也有KeepAlive参数）对于像HTTP这样的短链接，设置一个1-2分钟的keepalive非常重要。这可以在一定程度上防止DoS攻击。有下面几个参数（下面这些参数的值仅供参考）：</p>
<pre data-enlighter-language="shell" class="EnlighterJSRAW">net.ipv4.tcp_keepalive_probes = 5
net.ipv4.tcp_keepalive_intvl = 20
net.ipv4.tcp_fin_timeout = 30</pre>
<p>对于TCP的TIME_WAIT这个状态，主动关闭的一方进入TIME_WAIT状态，TIME_WAIT状态将持续2个MSL(Max Segment Lifetime)，默认为4分钟，TIME_WAIT状态下的资源不能回收。有大量的TIME_WAIT链接的情况一般是在HTTP服务器上。对此，有两个参数需要注意，</p>
<pre data-enlighter-language="shell" class="EnlighterJSRAW">net.ipv4.tcp_tw_reuse=1
net.ipv4.tcp_tw_recycle=1</pre>
<p>前者表示重用TIME_WAIT，后者表示回收TIME_WAIT的资源。</p>
<p>TCP还有一个重要的概念叫RWIN（TCP Receive Window Size），这个东西的意思是，我一个TCP链接在没有向Sender发出ack时可以接收到的最大的数据包。为什么这个很重要？因为如果Sender没有收到Receiver发过来ack，Sender就会停止发送数据并会等一段时间，如果超时，那么就会重传。这就是为什么TCP链接是可靠链接的原因。重传还不是最严重的，如果有丢包发生的话，TCP的带宽使用率会马上受到影响（会盲目减半），再丢包，再减半，然后如果不丢包了，就逐步恢复。相关参数如下：</p>
<pre data-enlighter-language="shell" class="EnlighterJSRAW">net.core.wmem_default = 8388608
net.core.rmem_default = 8388608
net.core.rmem_max = 16777216
net.core.wmem_max = 16777216</pre>
<p>一般来说，理论上的RWIN应该设置成：吞吐量  * 回路时间。Sender端的buffer应该和RWIN有一样的大小，因为Sender端发送完数据后要等Receiver端确认，如果网络延时很大，buffer过小了，确认的次数就会多，于是性能就不高，对网络的利用率也就不高了。也就是说，对于延迟大的网络，我们需要大的buffer，这样可以少一点ack，多一些数据，对于响应快一点的网络，可以少一些buffer。因为，如果有丢包（没有收到ack），buffer过大可能会有问题，因为这会让TCP重传所有的数据，反而影响网络性能。（当然，网络差的情况下，就别玩什么高性能了） 所以，高性能的网络重要的是要让网络丢包率非常非常地小（基本上是用在LAN里），如果网络基本是可信的，这样用大一点的buffer会有更好的网络传输性能（来来回回太多太影响性能了）。</p>
<p>另外，我们想一想，如果网络质量非常好，基本不丢包，而业务上我们不怕偶尔丢几个包，如果是这样的话，那么，我们为什么不用速度更快的UDP呢？你想过这个问题了吗？</p>
<p><strong>B）UDP调优</strong></p>
<p>说到UDP的调优，有一些事我想重点说一样，那就是MTU——最大传输单元（其实这对TCP也一样，因为这是链路层上的东西）。所谓最大传输单元，你可以想像成是公路上的公交车，假设一个公交车可以最多坐70人，带宽就像是公路的车道数一样，如果一条路上最多可以容下100辆公交车，那意味着我最多可以运送7000人，但是如果公交车坐不满，比如平均每辆车只有20人，那么我只运送了2000人，于是我公路资源（带宽资源）就被浪费了。 所以，我们对于一个UDP的包，我们要尽量地让他大到MTU的最大尺寸再往网络上传，这样可以最大化带宽利用率。对于这个MTU，以太网是1500字节，光纤是4352字节，802.11无线网是7981。但是，当我们用TCP/UDP发包的时候，我们的有效负载Payload要低于这个值，因为IP协议会加上20个字节，UDP会加上8个字节（TCP加的更多），所以，一般来说，你的一个UDP包的最大应该是1500-8-20=1472，这是你的数据的大小。当然，如果你用光纤的话， 这个值就可以更大一些。（顺便说一下，对于某些NB的千光以态网网卡来说，在网卡上，网卡硬件如果发现你的包的大小超过了MTU，其会帮你做fragment，到了目标端又会帮你做重组，这就不需要你在程序中处理了）</p>
<p>再多说一下，使用Socket编程的时候，你可以使用setsockopt() 设置 SO_SNDBUF/SO_RCVBUF 的大小，TTL和KeepAlive这些关键的设置，当然，还有很多，具体你可以查看一下Socket的手册。</p>
<p>最后说一点，UDP还有一个最大的好处是multi-cast多播，这个技术对于你需要在内网里通知多台结点时非常方便和高效。而且，多播这种技术对于机会的水平扩展（需要增加机器来侦听多播信息）也很有利。</p>
<p><strong>C）网卡调优</strong></p>
<p><strong></strong>对于网卡，我们也是可以调优的，这对于千兆以及网网卡非常必要，在Linux下，我们可以用ifconfig查看网上的统计信息，如果我们看到overrun上有数据，我们就可能需要调整一下txqueuelen的尺寸（一般默认为1000），我们可以调大一些，如：ifconfig eth0 txqueuelen 5000。Linux下还有一个命令叫：ethtool可以用于设置网卡的缓冲区大小。在Windows下，我们可以在网卡适配器中的高级选项卡中调整相关的参数（如：Receive Buffers, Transmit Buffer等，不同的网卡有不同的参数）。把Buffer调大对于需要大数据量的网络传输非常有效。</p>
<p><strong>D）其它网络性能</strong></p>
<p>关于多路复用技术，也就是用一个线程来管理所有的TCP链接，有三个系统调用要重点注意：一个是select，这个系统调用只支持上限1024个链接，第二个是poll，其可以突破1024的限制，但是select和poll本质上是使用的轮询机制，轮询机制在链接多的时候性能很差，因主是O(n)的算法，所以，epoll出现了，epoll是操作系统内核支持的，仅当在链接活跃时，操作系统才会callback，这是由操作系统通知触发的，但其只有Linux Kernel 2.6以后才支持（准确说是2.5.44中引入的），当然，如果所有的链接都是活跃的，过多的使用epoll_ctl可能会比轮询的方式还影响性能，不过影响的不大。</p>
<p>另外，关于一些和DNS Lookup的系统调用要小心，比如：gethostbyaddr/gethostbyname，这个函数可能会相当的费时，因为其要到网络上去找域名，因为DNS的递归查询，会导致严重超时，而又不能通过设置什么参数来设置time out，对此你可以通过配置hosts文件来加快速度，或是自己在内存中管理对应表，在程序启动时查好，而不要在运行时每次都查。另外，在多线程下面，gethostbyname会一个更严重的问题，就是如果有一个线程的gethostbyname发生阻塞，其它线程都会在gethostbyname处发生阻塞，这个比较变态，要小心。（你可以试试GNU的gethostbyname_r()，这个的性能要好一些） 这种到网上找信息的东西很多，比如，如果你的Linux使用了NIS，或是NFS，某些用户或文件相关的系统调用就很慢，所以要小心。</p>
<p><strong>4.4）系统调优</strong></p>
<p><strong>A）I/O模型</strong></p>
<p>前面说到过select/poll/epoll这三个系统调用，我们都知道，Unix/Linux下把所有的设备都当成文件来进行I/O，所以，那三个操作更应该算是I/O相关的系统调用。说到  I/O模型，这对于我们的I/O性能相当重要，我们知道，Unix/Linux经典的I/O方式是（关于Linux下的I/O模型，大家可以读一下这篇文章《<a href="http://www.ibm.com/developerworks/cn/linux/l-async/" target="_blank">使用异步I/O大大提高性能</a>》）：</p>
<p>第一种，同步阻塞式I/O，这个不说了。</p>
<p>第二种，同步无阻塞方式。其通过fctnl设置 O_NONBLOCK 来完成。</p>
<p>第三种，对于select/poll/epoll这三个是I/O不阻塞，但是在事件上阻塞，算是：I/O异步，事件同步的调用。</p>
<p>第四种，AIO方式。这种I/O 模型是一种处理与 I/O 并行的模型。I/O请求会立即返回，说明请求已经成功发起了。在后台完成I/O操作时，向应用程序发起通知，通知有两种方式：一种是产生一个信号，另一种是执行一个基于线程的回调函数来完成这次 I/O 处理过程。</p>
<p>第四种因为没有任何的阻塞，无论是I/O上，还是事件通知上，所以，其可以让你充分地利用CPU，比起第二种同步无阻塞好处就是，第二种要你一遍一遍地去轮询。Nginx之所所以高效，是其使用了epoll和AIO的方式来进行I/O的。</p>
<p>再说一下Windows下的I/O模型，</p>
<p>a）一个是WriteFile系统调用，这个系统调用可以是同步阻塞的，也可以是同步无阻塞的，关于看文件是不是以Overlapped打开的。关于同步无阻塞，需要设置其最后一个参数Overlapped，微软叫Overlapped I/O，你需要WaitForSingleObject才能知道有没有写完成。这个系统调用的性能可想而知。</p>
<p>b）另一个叫WriteFileEx的系统调用，其可以实现异步I/O，并可以让你传入一个callback函数，等I/O结束后回调之， 但是这个回调的过程Windows是把callback函数放到了APC（<a href="http://msdn.microsoft.com/en-us/library/windows/desktop/ms681951(v=vs.85).aspx" target="_blank">Asynchronous Procedure Calls</a>）的队列中，然后，只用当应用程序当前线程成为可被通知状态（Alterable）时，才会被回调。只有当你的线程使用了这几个函数时<a href="http://msdn.microsoft.com/en-us/library/windows/desktop/ms687036(v=vs.85).aspx">WaitForSingleObjectEx</a>, <a href="http://msdn.microsoft.com/en-us/library/windows/desktop/ms687028(v=vs.85).aspx">WaitForMultipleObjectsEx</a>, <a href="http://msdn.microsoft.com/en-us/library/windows/desktop/ms684245(v=vs.85).aspx">MsgWaitForMultipleObjectsEx</a>, <a href="http://msdn.microsoft.com/en-us/library/windows/desktop/ms686293(v=vs.85).aspx">SignalObjectAndWait</a> 和 <a href="http://msdn.microsoft.com/en-us/library/windows/desktop/ms686307(v=vs.85).aspx">SleepEx</a>，线程才会成为Alterable状态。可见，这个模型，还是有wait，所以性能也不高。</p>
<p>c）然后是IOCP &#8211; IO Completion Port，IOCP会把I/O的结果放在一个队列中，但是，侦听这个队列的不是主线程，而是专门来干这个事的一个或多个线程去干（老的平台要你自己创建线程，新的平台是你可以创建一个线程池）。IOCP是一个线程池模型。这个和Linux下的AIO模型比较相似，但是实现方式和使用方式完全不一样。</p>
<p>当然，真正提高I/O性能方式是把和外设的I/O的次数降到最低，最好没有，所以，对于读来说，内存cache通常可以从质上提升性能，因为内存比外设快太多了。对于写来说，cache住要写的数据，少写几次，但是cache带来的问题就是实时性的问题，也就是latency会变大，我们需要在写的次数上和相应上做权衡。</p>
<p><strong>B）多核<strong>CPU</strong>调优</strong></p>
<p>关于CPU的多核技术，我们知道，CPU0是很关键的，如果0号CPU被用得过狠的话，别的CPU性能也会下降，因为CPU0是有调整功能的，所以，我们不能任由操作系统负载均衡，因为我们自己更了解自己的程序，所以，我们可以手动地为其分配CPU核，而不会过多地占用CPU0，或是让我们关键进程和一堆别的进程挤在一起。</p>
<ul>
<li>对于Windows来说，我们可以通过“任务管理器”中的“进程”而中右键菜单中的“设置相关性……”（Set Affinity&#8230;）来设置并限制这个进程能被运行在哪些核上。</li>
</ul>
<ul>
<li>对于Linux来说，可以使用taskset命令来设置（你可以通过安装schedutils来安装这个命令：apt-get install schedutils）</li>
</ul>
<p>多核CPU还有一个技术叫<a href="http://en.wikipedia.org/wiki/Non-Uniform_Memory_Access" target="_blank">NUMA</a>技术（Non-Uniform Memory Access）。传统的多核运算是使用SMP(Symmetric Multi-Processor )模式，多个处理器共享一个集中的存储器和I/O总线。于是就会出现一致存储器访问的问题，一致性通常意味着性能问题。NUMA模式下，处理器被划分成多个node， 每个node有自己的本地存储器空间。关于NUMA的一些技术细节，你可以查看一下这篇文章《<a href="http://www.ibm.com/developerworks/cn/linux/l-numa/index.html" target="_blank">Linux 的 NUMA 技术</a>》，在Linux下，对NUMA调优的命令是：<strong>numactl </strong>。如下面的命令：（指定命令“myprogram arg1 arg2”运行在node 0 上，其内存分配在node 0 和 1上）</p>
<p><code data-enlighter-language="shell" class="EnlighterJSRAW">numactl --cpubind=0 --membind=0,1 myprogram arg1 arg2</code></p>
<p>当然，上面这个命令并不好，因为内存跨越了两个node，这非常不好。最好的方式是只让程序访问和自己运行一样的node，如：</p>
<p><code data-enlighter-language="shell" class="EnlighterJSRAW">$ numactl --membind 1 --cpunodebind 1 --localalloc myapplication</code></p>
<p><strong>C）文件系统调优</strong></p>
<p>关于文件系统，因为文件系统也是有cache的，所以，为了让文件系统有最大的性能。首要的事情就是分配足够大的内存，这个非常关键，在Linux下可以使用free命令来查看 free/used/buffers/cached，理想来说，buffers和cached应该有40%左右。然后是一个快速的硬盘控制器，SCSI会好很多。最快的是Intel SSD 固态硬盘，速度超快，但是写次数有限。</p>
<p>接下来，我们就可以调优文件系统配置了，对于Linux的Ext3/4来说，几乎在所有情况下都有所帮助的一个参数是关闭文件系统访问时间，在/etc/fstab下看看你的文件系统 有没有noatime参数（一般来说应该有），还有一个是dealloc，它可以让系统在最后时刻决定写入文件发生时使用哪个块，可优化这个写入程序。还要注间一下三种日志模式：data=journal、data=ordered和data=writeback。默认设置data=ordered提供性能和防护之间的最佳平衡。</p>
<p>当然，对于这些来说，ext4的默认设置基本上是最佳优化了。</p>
<p>这里介绍一个Linux下的查看I/O的命令—— iotop，可以让你看到各进程的磁盘读写的负载情况。</p>
<p>其它还有一些关于NFS、XFS的调优，大家可以上google搜索一些相关优化的文章看看。关于各文件系统，大家可以看一下这篇文章——《<a href="http://www.ibm.com/developerworks/cn/linux/l-jfs/" target="_blank">Linux日志文件系统及性能分析</a>》</p>
<p><strong>4.5）数据库调优</strong></p>
<p>数据库调优并不是我的强项，我就仅用我非常有限的知识说上一些吧。注意，下面的这些东西并不一定正确，因为在不同的业务场景，不同的数据库设计下可能会得到完全相反的结论，所以，我仅在这里做一些一般性的说明，具体问题还要具体分析。</p>
<p><strong>A）数据库引擎调优</strong></p>
<p>我对数据库引擎不是熟，但是有几个事情我觉得是一定要去了解的。</p>
<ul>
<li><strong>数据库的锁的方式</strong>。这个非常非常地重要。并发情况下，锁是非常非常影响性能的。各种隔离级别，行锁，表锁，页锁，读写锁，事务锁，以及各种写优先还是读优先机制。性能最高的是不要锁，所以，分库分表，冗余数据，减少一致性事务处理，可以有效地提高性能。NoSQL就是牺牲了一致性和事务处理，并冗余数据，从而达到了分布式和高性能。</li>
<li><strong>数据库的存储机制</strong>。不但要搞清楚各种类型字段是怎么存储的，更重要的是数据库的数据存储方式，是怎么分区的，是怎么管理的，比如Oracle的数据文件，表空间，段，等等。了解清楚这个机制可以减轻很多的I/O负载。比如：MySQL下使用<span style="font-size: xx-small;">show engines;</span>可以看到各种存储引擎的支持。不同的存储引擎有不同的侧重点，针对不同的业务或数据库设计会让你有不同的性能。</li>
<li><strong>数据库的分布式策略</strong>。最简单的就是复制或镜像，需要了解分布式的一致性算法，或是主主同步，主从同步。通过了解这种技术的机理可以做到数据库级别的水平扩展。</li>
</ul>
<p><strong>B）SQL语句优化</strong></p>
<p>关于SQL语句的优化，首先也是要使用工具，比如：<a href="http://www.mysql.com/products/enterprise/query.html" target="_blank">MySQL SQL Query Analyzer</a>，<a href="http://www.oracle-base.com/articles/11g/sql-performance-analyzer-11gr1.php" target="_blank">Oracle SQL Performance Analyzer</a>，或是微软<a href="http://msdn.microsoft.com/en-us/library/aa216945(v=sql.80).aspx" target="_blank">SQL Query Analyzer</a>，基本上来说，所有的RMDB都会有这样的工具，来让你查看你的应用中的SQL的性能问题。 还可以使用explain来看看SQL语句最终Execution Plan会是什么样的。</p>
<p>还有一点很重要，数据库的各种操作需要大量的内存，所以服务器的内存要够，优其应对那些多表查询的SQL语句，那是相当的耗内存。</p>
<p>下面我根据我有限的数据库SQL的知识说几个会有性能问题的SQL：</p>
<ul>
<li><strong>全表检索</strong>。比如：select * from user where lastname = &#8220;xxxx&#8221;，这样的SQL语句基本上是全表查找，线性复杂度O(n)，记录数越多，性能也越差（如：100条记录的查找要50ms，一百万条记录需要5分钟）。对于这种情况，我们可以有两种方法提高性能：一种方法是分表，把记录数降下来，另一种方法是建索引（为lastname建索引）。索引就像是key-value的数据结构一样，key就是where后面的字段，value就是物理行号，对索引的搜索复杂度是基本上是O(log(n)) ——用B-Tree实现索引（如：100条记录的查找要50ms，一百万条记录需要100ms）。</li>
</ul>
<ul>
<li><strong>索引</strong>。对于索引字段，最好不要在字段上做计算、类型转换、函数、空值判断、字段连接操作，这些操作都会破坏索引原本的性能。当然，索引一般都出现在Where或是Order by字句中，所以对Where和Order by子句中的子段最好不要进行计算操作，或是加上什么NOT之类的，或是使用什么函数。</li>
</ul>
<ul>
<li><strong>多表查询</strong>。关系型数据库最多的操作就是多表查询，多表查询主要有三个关键字，EXISTS，IN和JOIN（关于各种join，可以参看<a title="图解SQL的Join" href="https://coolshell.cn/articles/3463.html" target="_blank">图解SQL的Join</a>一文）。基本来说，现代的数据引擎对SQL语句优化得都挺好的，JOIN和IN/EXISTS在结果上有些不同，但性能基本上都差不多。有人说，EXISTS的性能要好于IN，IN的性能要好于JOIN，我各人觉得，这个还要看你的数据、schema和SQL语句的复杂度，对于一般的简单的情况来说，都差不多，所以千万不要使用过多的嵌套，千万不要让你的SQL太复杂，宁可使用几个简单的SQL也不要使用一个巨大无比的嵌套N级的SQL。还有人说，如果两个表的数据量差不多，Exists的性能可能会高于In，In可能会高于Join，如果这两个表一大一小，那么子查询中，Exists用大表，In则用小表。这个，我没有验证过，放在这里让大家讨论吧。另，有一篇关于SQL Server的文章大家可以看看《<a href="http://explainextended.com/2009/06/16/in-vs-join-vs-exists/" target="_blank">IN vs JOIN vs EXISTS</a>》</li>
</ul>
<ul>
<li><strong>JOIN操作</strong>。有人说，Join表的顺序会影响性能，只要Join的结果集是一样，性能和join的次序无关。因为后台的数据库引擎会帮我们优化的。Join有三种实现算法，嵌套循环，排序归并，和Hash式的Join。（MySQL只支持第一种）</li>
</ul>
<ul style="padding-left: 60px;">
<ul>
<li>嵌套循环，就好像是我们常见的多重嵌套循环。注意，前面的索引说过，数据库的索引查找算法用的是B-Tree，这是O(log(n))的算法，所以，整个算法复法度应该是O(log(n)) * O(log(m)) 这样的。</li>
<li>Hash式的Join，主要解决嵌套循环的O(log(n))的复杂，使用一个临时的hash表来标记。</li>
<li>排序归并，意思是两个表按照查询字段排好序，然后再合并。当然，索引字段一般是排好序的。</li>
</ul>
</ul>
<p style="padding-left: 60px;">还是那句话，具体要看什么样的数据，什么样的SQL语句，你才知道用哪种方法是最好的。</p>
<ul>
<li><strong>部分结果集。</strong>我们知道MySQL里的Limit关键字，Oracle里的rownum，SQL Server里的Top都是在限制前几条的返回结果。这给了我们数据库引擎很多可以调优的空间。一般来说，返回top n的记录数据需要我们使用order by，注意在这里我们需要为order by的字段建立索引。有了被建索引的order by后，会让我们的select语句的性能不会被记录数的所影响。使用这个技术，一般来说我们前台会以分页方式来显现数据，Mysql用的是OFFSET，SQL Server用的是FETCH NEXT，这种Fetch的方式其实并不好是线性复杂度，所以，如果我们能够知道order by字段的第二页的起始值，我们就可以在where语句里直接使用&gt;=的表达式来select，这种技术叫seek，而不是fetch，seek的性能比fetch要高很多。</li>
</ul>
<ul>
<li><strong>字符串</strong>。正如我前面所说的，字符串操作对性能上有非常大的恶梦，所以，能用数据的情况就用数字，比如：时间，工号，等。</li>
</ul>
<ul>
<li><strong>全文检索</strong>。千万不要用Like之类的东西来做全文检索，如果要玩全文检索，可以尝试使用<a href="http://sphinxsearch.com/" target="_blank">Sphinx</a>。</li>
</ul>
<ul>
<li><strong>其它</strong>。
<ul>
<li>不要select *，而是明确指出各个字段，如果有多个表，一定要在字段名前加上表名，不要让引擎去算。</li>
<li>不要用Having，因为其要遍历所有的记录。性能差得不能再差。</li>
<li>尽可能地使用UNION ALL  取代  UNION。</li>
<li>索引过多，insert和delete就会越慢。而update如果update多数索引，也会慢，但是如果只update一个，则只会影响一个索引表。</li>
<li>等等。</li>
</ul>
</li>
</ul>
<p>关于SQL语句的优化，网上有很多文章， 不同的数据库引擎有不同的优化技巧，正如本站以前转发的《<a href="https://coolshell.cn/articles/1846.html" rel="bookmark">MySQL性能优化的最佳20+条经验</a>》</p>
<p>先写这么多吧，欢迎大家指正补充。</p>
<blockquote><p><strong>注：</strong>这篇文章的确是个大杂烩。其实其中的说到的很多技术在网上都有很多很多的技术文章，google一下就能找到一堆有很多细节的文章，所以我也就不写了。这篇性能调优的文章写作的动机是之前看到 <a href="http://weibo.com/n/%E6%B7%98%E5%AE%9D%E8%A4%9A%E9%9C%B8">@淘宝褚霸</a> 强推的<a href="http://highscalability.com/">highscalability.com</a>上的这篇文章：<a href="http://highscalability.com/blog/2012/5/16/big-list-of-20-common-bottlenecks.html" target="_blank">Big List Of 20 Common Bottlenecks</a>，觉得这篇文章泛泛而谈，觉得自己能写得比它好，所以就产生了动机。</p></blockquote>
<p>（<span style="color: #cc0000;"><strong>转载时请注明作者和出处，请勿用于商业用途</strong></span>）<!--



<p align="center"><a href= target=_blank><img decoding="async" src=""></a></p>





<p align="center"><img decoding="async" src="https://coolshell.cn/wp-content/uploads/2020/03/coolshell.weixin.jpg"> <img decoding="async" loading="lazy" src="https://coolshell.cn/wp-content/uploads/2020/03/coolshell.mini_.jpg" width="300" height="300"> <br />关注CoolShell微信公众账号和微信小程序</p>

 

--></p>
<div style="margin-top: 15px; font-size: 16px;color: #cc0000;">
<p align="center"><strong>（转载本站文章请注明作者和出处 <a href="https://coolshell.cn/">酷 壳 &#8211; CoolShell</a> ，请勿用于任何商业用途）</strong></p>
</div>

<div class="wp_rp_wrap  wp_rp_vertical_m" id="wp_rp_first"><div class="wp_rp_content"><h3 class="related_post_title">相关文章</h3><ul class="related_post wp_rp"><li ><a href="https://coolshell.cn/articles/19840.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/uploads/2019/10/HTTP-770x513-300x200-1-150x150.jpg" alt="HTTP的前世今生" width="150" height="150" /></a><a href="https://coolshell.cn/articles/19840.html" class="wp_rp_title">HTTP的前世今生</a></li><li ><a href="https://coolshell.cn/articles/9859.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/uploads/2013/06/Alan-Cox-150x150.jpg" alt="Alan Cox：单向链表中prev指针的妙用" width="150" height="150" /></a><a href="https://coolshell.cn/articles/9859.html" class="wp_rp_title">Alan Cox：单向链表中prev指针的妙用</a></li><li ><a href="https://coolshell.cn/articles/8883.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/uploads/2013/01/linux-bash-300x225-150x150.jpg" alt="应该知道的Linux技巧" width="150" height="150" /></a><a href="https://coolshell.cn/articles/8883.html" class="wp_rp_title">应该知道的Linux技巧</a></li><li ><a href="https://coolshell.cn/articles/7829.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/uploads/2012/07/dstat_screenshot-150x150.png" alt="28个Unix/Linux的命令行神器" width="150" height="150" /></a><a href="https://coolshell.cn/articles/7829.html" class="wp_rp_title">28个Unix/Linux的命令行神器</a></li><li ><a href="https://coolshell.cn/articles/5107.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/plugins/wordpress-23-related-posts-plugin/static/thumbs/5.jpg" alt="10大经典错误" width="150" height="150" /></a><a href="https://coolshell.cn/articles/5107.html" class="wp_rp_title">10大经典错误</a></li><li ><a href="https://coolshell.cn/articles/4102.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/plugins/wordpress-23-related-posts-plugin/static/thumbs/25.jpg" alt="如何学好C语言" width="150" height="150" /></a><a href="https://coolshell.cn/articles/4102.html" class="wp_rp_title">如何学好C语言</a></li></ul></div></div>The post <a href="https://coolshell.cn/articles/7490.html">性能调优攻略</a> first appeared on <a href="https://coolshell.cn">酷 壳 - CoolShell</a>.]]></content:encoded>
					
					<wfw:commentRss>https://coolshell.cn/articles/7490.html/feed</wfw:commentRss>
			<slash:comments>171</slash:comments>
		
		
			</item>
		<item>
		<title>Quora使用到的技术</title>
		<link>https://coolshell.cn/articles/4939.html</link>
					<comments>https://coolshell.cn/articles/4939.html#comments</comments>
		
		<dc:creator><![CDATA[陈皓]]></dc:creator>
		<pubDate>Mon, 04 Jul 2011 00:35:37 +0000</pubDate>
				<category><![CDATA[技术新闻]]></category>
		<category><![CDATA[杂项资源]]></category>
		<category><![CDATA[Facebook]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[Nginx]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[Quora]]></category>
		<category><![CDATA[StackExchange]]></category>
		<guid isPermaLink="false">http://coolshell.cn/?p=4939</guid>

					<description><![CDATA[<p>以前向大家介绍过Stack Exchange的系统架构和Facebook的系统架构，今天和大家说说Quora的。本文主要参考了Phil Whelan的这篇文章《...</p>
<p class="read-more"><a class="btn btn-default" href="https://coolshell.cn/articles/4939.html"> Read More<span class="screen-reader-text">  Read More</span></a></p>
The post <a href="https://coolshell.cn/articles/4939.html">Quora使用到的技术</a> first appeared on <a href="https://coolshell.cn">酷 壳 - CoolShell</a>.]]></description>
										<content:encoded><![CDATA[<p><script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-3415450859608158"
     crossorigin="anonymous"></script>以前向大家介绍过<a title="Stack Exchange 的架构" href="https://coolshell.cn/articles/3721.html" target="_blank">Stack Exchange的系统架构</a>和<a title="Facebook 的系统架构" href="https://coolshell.cn/articles/4549.html" target="_blank">Facebook的系统架构</a>，今天和大家说说Quora的。本文主要参考了<a title="Phil Whelan" href="http://www.philwhln.com/author/admin/">Phil Whelan</a>的这篇文章《<a href="http://www.philwhln.com/quoras-technology-examined" target="_blank">Quora&#8217;s Technology Examined</a>》。关于Quora是个什么网站我就不多说了，国内对他的C2C网站叫“知乎”。呵呵。我们还是来看看Quora的技术吧。</p>
<h4>Search-Box</h4>
<p>Quora只能搜索问题，主题标签，用户名，和主题标题。没有全文搜索，所以，你无法搜索问题和答案的内容。而搜索中使用前缀搜索方式，比如你输入mi，则Microsoft会马上出来。其搜索还会有一些非常简单的模糊匹配的算法。另外，如果有重复的问题，其中一个问题会自动跳转到另一个问题，但是在搜索中还是会出现。搜索中没有拼写检查。</p>
<p>一开始，他们使用的是一个开源的搜索服务器，叫<a href="http://sphinxsearch.com/">Sphinx</a>。其支持上述的那些功能。现在他们不用这个技术了，因为<a href="http://www.quora.com/What-is-the-best-open-source-solution-for-implementing-fast-auto-complete" target="_blank">受到了一些限制</a>。他们做了一个比较新的解决方案，这个算法由Python实现。</p>
<p><strong>参看</strong>：<a href="http://www.quora.com/What-libraries-does-Quora-use-for-search"><img decoding="async" loading="lazy" src="http://www.quora.com/favicon.ico" alt="" width="16" height="16" />What libraries does Quora use for search?</a></p>
<h4>实时查询</h4>
<p>Quora的查询是非常高速的，其查询请求是通过AJAX的GET请求发送的，结果返回用的是JSON数据格式，但他们解析JSON是在服务器端，而不是通过浏览器的javascript。这么做的原因可能是他们想高亮搜索关键词，似乎使用Client端的Javascript非常不好做。</p>
<p>Quora的即时搜索好像比较暴力，如果你输入Microsoft（一共9个字符），你会看到其会像后端发送9次查询——每按一个键一次，无论你敲这个单词的速底有多快，每输入一个字符都会发一个请求给后台。对于这样的看上去没有效率的对后台的请求，后台的服务器端会来控制相关的前台请求，所以，就算是前台这样做，也不会增加服务器端的负载，因为后台会做相关的处理。</p>
<p>Quora的搜索使用HTTP长连接，当你开始敲查询的时候，连接就建立了，这个连接会持续在那里，你下次搜索的时候会继续使用这个连接，除非你60秒没有动作了。</p>
<p><strong>参看</strong>：<a href="http://www.quora.com/Quora-product/Is-Quora-going-to-implement-full-text-search"><img decoding="async" loading="lazy" src="http://www.quora.com/favicon.ico" alt="" width="16" height="16" />Is Quora going to implement full-text search?</a></p>
<p><span id="more-4939"></span></p>
<h4 id="webnode2-and-livenode">Webnode2 和 LiveNode</h4>
<p>Webnode2 和 LiveNode 是 Quora 内部的系统，其用来管理内容。Webnode2  生成 HTML, CSS 和 JavaScript 并且和 LiveNode 紧紧地耦合在一起，Webnode2主要是用来管理内容在网页上显示的，LiveNode主要是用来做动态网页内容更新的。Charlie Cheever 说，如果他可以从新开始，他 <a href="http://www.quora.com/What-limitations-has-Quora-encountered-due-to-LiveNode-WebNode#answers" target="_blank">第一件事要做的就是重写整个LiveNode</a>.</p>
<p>Quora的工程师看上去对他们搞的这些东西非常的满意，并且 <a href="http://www.quora.com/What-limitations-has-Quora-encountered-due-to-LiveNode-WebNode#answers">他们也在努力地找到这些东西的弱点</a>。有一个有意思的关于LiveNode的问题是，如果A和B同时正在看相当的一个问题，那么用户A的一些交互动作会影响B的页面。例如，如果A顶了一下某个答案，那么这个答案可能会往上移动。这样的一个显示变化会通过AJAX更新B的浏览器。如果B此时展开了评论，可能会受到影响。</p>
<p><a href="http://www.quora.com/What-is-LiveNode-written-in">LiveNode 由这些东西写成：</a>Python, C++, and JavaScript. <a href="http://jquery.com/">jQuery</a> ，<a href="http://cython.org/">Cython</a>也用到了。</p>
<p>因为Quora <a href="http://www.quora.com/Is-Quora-planning-on-open-sourcing-LiveNode">想要对他们的LiveNode开源</a> 并准备把他们的代码分开，做这个事可能需要太多的工作和时间。</p>
<p>Charlie Cheever 指出 WebNode2 和 <a href="http://www.quora.com/Quora-Infrastructure/What-is-webnode2">有一个叫做 “free and easy website builder” 的 Webnode 的 webnode.com</a> 没有任何的关系。</p>
<p><strong>参考</strong>：<a href="http://www.quora.com/Quora-product/Is-Quora-going-to-implement-full-text-search"><img decoding="async" loading="lazy" src="http://www.quora.com/favicon.ico" alt="" width="16" height="16" /></a> <a href="http://www.quora.com/Shreyes-Seshasai/Tech-Talk-Webnode2-and-LiveNode" target="_blank">Tech Talk &#8211; Webnode2 and LiveNode</a></p>
<h4>Amazon Web Service</h4>
<p>Quora全部host在AWS的EC2和S3上，这对于这些刚刚起步的快速发展的公司非常关键，因为你可以省去了很多硬件和维护的成本。（建一个数据中心并不是所有公司都能干的事）。Quora的操作系统使用Ubuntu Linux，这是非常容易部署和管理。</p>
<p>其静态页使用了Amazon的CDN的 <a href="http://aws.amazon.com/cloudfront/" target="_blank">Cloudfront</a>服务分发，CloudFront用于所有的静态图片, CSS 和JavaScript。<a href="http://www.quora.com/How-is-Quora-doing-image-uploads-to-Amazon-S3" target="_blank">图片先传到 EC2 服务器</a>，使用 <a href="http://aws.amazon.com/code/134" target="_blank">Pyhon S3 <acronym title="Application Programming Interface ">API</acronym></a> 处理后后传到 S3。</p>
<h4 id="haproxy-load-balancing">HAProxy Load-Balancing</h4>
<p><a href="http://haproxy.1wt.eu/" target="_blank">HAProxy </a>作为前端负载均衡服务器，反向代理服务器是 Nginx，Nginx 后面则是 Pylons (<a href="http://spacepants.org/blog/pylons-paste-stack">Pylons + Paste</a>) , 承担动态 Web 请求。</p>
<p><a href="http://pylonshq.com/">Pylons</a>，是一个轻量级的Web框架，通常都是在Nginx后面使用。选用Pylons就像你在春节先饺子当主食一样。他们把Pylons中的template和ORM取走而使用自己的技术（由Python写成），这个地方就是 <a href="http://www.quora.com/What-languages-and-frameworks-were-used-to-code-Quora">LiveNode 和 WebNode2的地方</a>。</p>
<h4>Python</h4>
<p>从facebook出来的Charlie 和 Adam选用了Python而不是PHP。正如Adam指出的——“<a href="http://www.quora.com/Why-did-Quora-choose-Python-for-its-development">Facebook is stuck on that for legacy reasons, not because it is the best choice right now</a>”（Facebook使用PHP并不是因为其好，而是因为历史原因的问题），当然他们也不会使用C#，因为那样一来就会引入一堆微软的东西。当然，也不会是Java，因为Python要比Java更容易写出代码，Scala太年轻了，还需要考验。Ruby看上来很像Python，但是他们对Ruby没有过多的经验。最终还是Python胜出。当然，他们知道Python的弱点是性能和速度，所以，他们在需要速度和性能的地方使用了C/C++。 他们使用Python的版本是2.6。</p>
<p>使用Python的另一个原因是Python的数据结构和JSON可以很好的映射起来。代码易读性很高。而且有很多的库，调试器和重载器。Quora的B/S结构几乎完全通过JSON进行数据交互。</p>
<p>他们<a href="http://www.quora.com/Adam-DAngelo/What-version-of-Python-are-you-programming-in-and-what-IDE-do-you-use" target="_blank">没有使用IDE</a>，他们使用得最多的是Emacs，一看就知道这是一个个人的选择，随着他们开发团队的扩大，这个事会得到改变的。</p>
<p>另外，他们提到了<a href="http://codespeak.net/pypy/dist/pypy/doc/">PyPy</a>，一个让 Python更快更灵活的项目。</p>
<h4 id="thrift">Thrift</h4>
<p><a href="http://incubator.apache.org/thrift/">Thrift</a> 用于后端服务器间的通讯。Thrift  服务由 C++开发。<a href="https://coolshell.cn/articles/4549.html" target="_blank">Facebook同样使用了这个技术</a>。</p>
<p><strong>参考</strong>：<a href="http://www.quora.com/Why-would-you-write-a-Thrift-service-in-C"><img decoding="async" loading="lazy" src="http://www.quora.com/favicon.ico" alt="" width="16" height="16" />Why would you write a Thrift service in C++?</a></p>
<h4 id="tornado">Tornado</h4>
<p><a href="http://www.tornadoweb.org/">Tornado</a> web 框架用于实时更新，其运行在Comet 服务器上，其用来处理大量的需要长时间poll和push更新的网络连接。</p>
<h4 id="long-polling-comet">Long Polling (Comet)</h4>
<p>Quora的网页并不是简单的显示，每一个页面都需要更新，或是创建问题，答案和评论。所以，他们使用了Long Polling而不是传统的Polling，传统的Polling需要浏览器一端不停地重复地向服务器询问——“有更新吗？”，服务器说没有，于是过一会浏览大再问，现在呢？服务器说，还是没有，浏览器过一会又问，现在呢？服务器说，还没好。这样一来，就好像让我们的客户端放到了驾驶室里，这显然是有问题的，因为只有服务器知道什么时候会有更新。而且浏览器这么干，很快会让服务器的负载加上去。</p>
<p>Long polling 也就是我们熟知的 <a href="http://en.wikipedia.org/wiki/Comet_(programming)">Comet</a>，其让服务器来控制这些事，让客服端等在那里听服务器的响应。在client和 server的会话对于两者是是相同的，而不是client需要等着然后向服务器查询。服务器端可以把一个连接打开很长时间（比如：60秒），在这段时间里，服务器会查看是否有相应的东西需要更新，如果有的话，就发给浏览器。如果没有的话，就等下一次的client询问。可见，这种服务器等一会再响应的方法可以让浏览器少发几次查询。</p>
<p>对于long-polling 的最好的地方是，可以降低浏览器和客户端间来来回回的次数。让服务器端来控制时间，所以，内容更新可能会只是几个毫秒，或是几十秒。 服务器端也可以积攒一堆更新后，一次发给浏览器。这样做会更有效率。</p>
<p>但是，这个方法的黑暗面是——这会让服务器端出现大量的TCP链接，想一想，Quora也是百万级用户的应用了，只需要10%的在线用户，你就需要一个可以处理10万并发量的架构。注意，如果一个用户在其浏览器里打开了多个Quora网页的话，那么，这个链接器会是非常致命的。</p>
<p>当然，好的消息是已经有一些技术专门为Long Polling设计，这些技术可以让你在那些等待的连接中只会消耗非常非常少的内存（因为那些等待连接并不需要所有的资源）。例如：Nginx 是一个单线程的事件驱动的小型服务器，每一个链接只花非常小的内存。每一个Nginx的进程只会在一个时候处理一个连接。这意味着其很容易扩展成一个可以处理成千上的并发量的服务架构。</p>
<p><strong>参考</strong>：<a href="http://www.quora.com/How-do-you-push-messages-back-to-a-web-browser-client-through-AJAX-Is-there-any-way-to-do-this-without-having-the-client-constantly-polling-the-server-for-updates"><img decoding="async" loading="lazy" src="http://www.quora.com/favicon.ico" alt="" width="16" height="16" />How do you push messages back to a web-browser client through AJAX? Is there any way to do this without having the client constantly polling the server for updates?</a></p>
<h4 id="mysql">MySQL</h4>
<p>就像Adam D’Angelo 的老东家facebook一样，，Quora重度使用MySQL。对于，把数据库里的数据分区是最需要做的事。他们的行事原则是，尽可能的把数据放在一台机器上，使用hash主键把大规模的数据存放到多个数据库中。坚决不用表连接。Adam参考了FriendFeed的一篇文章<a href="http://bret.appspot.com/entry/how-friendfeed-uses-mysql">How FriendFeed uses MySQL to store schema-less data</a>，<a href="http://www.quora.com/NoSQL/In-what-parts-of-a-social-site-with-concert-listings-should-one-use-a-NoSQL-DB-versus-a-SQL-DB">并说</a>你不应该在你的社区还没有100万用户的时候使用NoSQL 数据库。</p>
<p>并不只是Quora和FriendFeed使用MySQL，Google，Twitter，Facebook都在使用MySQL.</p>
<p>参考：<a href="http://www.quora.com/How-does-one-evaluate-if-a-database-is-efficient-enough-to-not-crash-as-its-put-under-increasing-load"><img decoding="async" loading="lazy" src="http://www.quora.com/favicon.ico" alt="" width="16" height="16" />How does one evaluate if a database is efficient enough to not crash as it’s put under increasing load?</a></p>
<h4 id="memcached">Memcached</h4>
<p><a href="http://memcached.org/">Memcached</a> 用于 MySQL的前端缓存。</p>
<h4 id="git">Git</h4>
<p><a href="http://git-scm.com/">Git</a> <a href="http://www.quora.com/What-languages-and-frameworks-were-used-to-code-Quora">是他们的源码版本控制工具</a>.</p>
<h4 id="javascript-placement">JavaScript Placement</h4>
<p>如果你看一下Quora的网页源码，你会看到其JavaScript总是在页面的最后。 Charlie Cheever<a href="http://www.quora.com/Why-is-the-Quora-website-so-fast">建议</a> 这会让你的页面显得载入得很快，因为其先显示内容，然后在载入Javascript。</p>
<h4 id="charlie-cheever-follows-14-rules-for-faster-loading-web-sites">Charlie Cheever 遵从 “14 Rules for Faster-Loading Web Sites”</h4>
<p>Steve Souders,  High Performance Web Sites 和 Even Faster Web Sites的作者，其列了一些 <a href="http://stevesouders.com/hpws/rules.php">rules让你网页更快的原则</a>。 Charlie Cheever 的 Quora 创始人提到这些过，这应该也是Quora的速度的原因。</p>
<blockquote><p>“One resource we used as a guide is Steve Souders’ list of rules for high performance websites:<a href="http://stevesouders.com/hpws/rules.php">http://stevesouders.com/hpws/rules.php</a>”<br />
<small><a href="http://www.quora.com/Why-is-the-Quora-website-so-fast">– Charlie Cheever, Quora</a></small></p></blockquote>
<div>
<div>Steve Souders的14条规则是——<a href="http://www.amazon.com/gp/product/0596529309?ie=UTF8&amp;tag=getafil-20&amp;linkCode=as2&amp;camp=1789&amp;creative=9325&amp;creativeASIN=0596529309"><img decoding="async" class="alignright" src="https://images-na.ssl-images-amazon.com/images/I/41COtT-V1UL._SL160_.jpg" border="0" alt="" /></a><a href="http://www.amazon.com/gp/product/0596522304?ie=UTF8&amp;tag=getafil-20&amp;linkCode=as2&amp;camp=1789&amp;creative=9325&amp;creativeASIN=0596522304"><br />
</a>&nbsp;</p>
<ul>
<li>Make Fewer HTTP Requests</li>
<li>Use a Content Delivery Network</li>
<li>Add an Expires Header</li>
<li>Gzip Components</li>
<li>Put Stylesheets at the Top</li>
<li>Put Scripts at the Bottom</li>
<li><a href="http://www.amazon.com/gp/product/0596522304?ie=UTF8&amp;tag=getafil-20&amp;linkCode=as2&amp;camp=1789&amp;creative=9325&amp;creativeASIN=0596522304"><img decoding="async" class="alignright" src="https://images-na.ssl-images-amazon.com/images/I/41vfOvQugoL._SL160_.jpg" border="0" alt="" /></a>Avoid CSS Expressions</li>
<li>Make JavaScript and CSS External</li>
<li>Reduce DNS Lookups</li>
<li>Minify JavaScript</li>
<li>Avoid Redirects</li>
<li>Remove Duplicate Scripts</li>
<li>Configure ETags</li>
<li>Make AJAX Cacheable</li>
</ul>
</div>
</div>
<p>（全文完）<!--



<p align="center"><a href= target=_blank><img decoding="async" src=""></a></p>





<p align="center"><img decoding="async" src="https://coolshell.cn/wp-content/uploads/2020/03/coolshell.weixin.jpg"> <img decoding="async" loading="lazy" src="https://coolshell.cn/wp-content/uploads/2020/03/coolshell.mini_.jpg" width="300" height="300"> <br />关注CoolShell微信公众账号和微信小程序</p>

 

--></p>
<div style="margin-top: 15px; font-size: 16px;color: #cc0000;">
<p align="center"><strong>（转载本站文章请注明作者和出处 <a href="https://coolshell.cn/">酷 壳 &#8211; CoolShell</a> ，请勿用于任何商业用途）</strong></p>
</div>

<div class="wp_rp_wrap  wp_rp_vertical_m" ><div class="wp_rp_content"><h3 class="related_post_title">相关文章</h3><ul class="related_post wp_rp"><li ><a href="https://coolshell.cn/articles/4549.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/plugins/wordpress-23-related-posts-plugin/static/thumbs/7.jpg" alt="Facebook 的系统架构" width="150" height="150" /></a><a href="https://coolshell.cn/articles/4549.html" class="wp_rp_title">Facebook 的系统架构</a></li><li ><a href="https://coolshell.cn/articles/18360.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/uploads/2018/05/300x262-150x150.jpg" alt="程序员练级攻略（2018)  与我的专栏" width="150" height="150" /></a><a href="https://coolshell.cn/articles/18360.html" class="wp_rp_title">程序员练级攻略（2018)  与我的专栏</a></li><li ><a href="https://coolshell.cn/articles/18140.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/uploads/2017/09/react_patent-360x200-1-150x150.jpg" alt="关于Facebook 的 React 专利许可证" width="150" height="150" /></a><a href="https://coolshell.cn/articles/18140.html" class="wp_rp_title">关于Facebook 的 React 专利许可证</a></li><li ><a href="https://coolshell.cn/articles/11265.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/uploads/2014/03/snake-hat-new-year-schedule-800x960-150x150.jpg" alt="Python修饰器的函数式编程" width="150" height="150" /></a><a href="https://coolshell.cn/articles/11265.html" class="wp_rp_title">Python修饰器的函数式编程</a></li><li ><a href="https://coolshell.cn/articles/10822.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/uploads/2013/12/yoda-lambda-150x150.png" alt="函数式编程" width="150" height="150" /></a><a href="https://coolshell.cn/articles/10822.html" class="wp_rp_title">函数式编程</a></li><li ><a href="https://coolshell.cn/articles/10169.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/plugins/wordpress-23-related-posts-plugin/static/thumbs/5.jpg" alt="类型的本质和函数式实现" width="150" height="150" /></a><a href="https://coolshell.cn/articles/10169.html" class="wp_rp_title">类型的本质和函数式实现</a></li></ul></div></div>The post <a href="https://coolshell.cn/articles/4939.html">Quora使用到的技术</a> first appeared on <a href="https://coolshell.cn">酷 壳 - CoolShell</a>.]]></content:encoded>
					
					<wfw:commentRss>https://coolshell.cn/articles/4939.html/feed</wfw:commentRss>
			<slash:comments>48</slash:comments>
		
		
			</item>
		<item>
		<title>Web开发人员速查卡</title>
		<link>https://coolshell.cn/articles/3684.html</link>
					<comments>https://coolshell.cn/articles/3684.html#comments</comments>
		
		<dc:creator><![CDATA[陈皓]]></dc:creator>
		<pubDate>Wed, 16 Feb 2011 10:59:06 +0000</pubDate>
				<category><![CDATA[Web开发]]></category>
		<category><![CDATA[杂项资源]]></category>
		<category><![CDATA[Apache]]></category>
		<category><![CDATA[ASP]]></category>
		<category><![CDATA[Cheat Sheet]]></category>
		<category><![CDATA[CSS]]></category>
		<category><![CDATA[Flash]]></category>
		<category><![CDATA[HTML]]></category>
		<category><![CDATA[Javascript]]></category>
		<category><![CDATA[jQuery]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Unicode]]></category>
		<category><![CDATA[Web]]></category>
		<category><![CDATA[XML]]></category>
		<guid isPermaLink="false">http://coolshell.cn/?p=3684</guid>

					<description><![CDATA[<p>无论你是多牛的程序员，你都无法记住所有的东西。而很多时候，查找某些知识又比较费事。所以，网上有很多Cheat Sheets，翻译成小抄也好 ，速查卡也好，总之就...</p>
<p class="read-more"><a class="btn btn-default" href="https://coolshell.cn/articles/3684.html"> Read More<span class="screen-reader-text">  Read More</span></a></p>
The post <a href="https://coolshell.cn/articles/3684.html">Web开发人员速查卡</a> first appeared on <a href="https://coolshell.cn">酷 壳 - CoolShell</a>.]]></description>
										<content:encoded><![CDATA[<p><script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-3415450859608158"
     crossorigin="anonymous"></script>无论你是多牛的程序员，你都无法记住所有的东西。而很多时候，查找某些知识又比较费事。所以，网上有很多Cheat Sheets，翻译成小抄也好 ，速查卡也好，总之就是帮你节省 时间的。之前给大家介绍过<a rel="bookmark" href="https://coolshell.cn/articles/870.html" target="_blank">Web设计的速查卡</a>、<a rel="bookmark" href="https://coolshell.cn/articles/2964.html" target="_blank">25个jQuery的编程小抄</a>，还有<a rel="bookmark" href="https://coolshell.cn/articles/1566.html" target="_blank">程序员小抄大全</a>，今天转一篇开发人员的速查卡，<a href="http://www.topdesignmag.com/all-the-cheat-sheets-that-a-web-developer-needs/" target="_blank">源文在这里</a>。下面的文章我就不翻译了。</p>
<h2>HTML Cheat Sheet</h2>
<p><img decoding="async" loading="lazy" title="1" src="http://www.topdesignmag.com/wp-content/uploads/2011/01/1128.jpg" alt="" width="450" height="127" /></p>
<ul>
<li><a href="http://www.html.su/" target="_blank">HTML/XTML in one page</a></li>
<li><a href="http://refcardz.dzone.com/refcardz/html5-new-standards-web-interactivity" target="_blank">HTML5: The Evolution of Web Standards by James Sugrue</a></li>
<li><a href="http://www.elizabethcastro.com/html/extras/xhtml_ref.html" target="_blank">(X)HTML Elements and Attributes</a></li>
<li><a href="http://www.w3.org/QA/2002/04/valid-dtd-list.html" target="_blank">Doctype Declarations (DTDs)</a></li>
<li><a href="http://www.digitalmediaminute.com/reference/entity/index.php" target="_blank">XHTML Character Entity Reference</a></li>
<li><a href="http://downloads.gosquared.com/help_sheets/08/HTML-Help-Sheet-02.jpg" target="_blank">GoSquared HTML Help Sheet</a></li>
</ul>
<p><span id="more-3684"></span></p>
<p><strong> </strong></p>
<h2>CSS Cheat Sheets</h2>
<p><img decoding="async" loading="lazy" title="2" src="http://www.topdesignmag.com/wp-content/uploads/2011/01/2104.jpg" alt="" width="451" height="112" /></p>
<ul>
<li><a href="http://www.css.su/" target="_blank">CSS in one page</a></li>
<li><a href="http://www.elizabethcastro.com/html/extras/cssref.html" target="_blank">CSS Properties and Values</a></li>
<li><a href="http://www.blooberry.com/indexdot/css/propindex/all.htm" target="_blank">All CSS Properties Listed Alphabetically</a></li>
<li><a href="http://www.dustindiaz.com/css-shorthand/" target="_blank">CSS Shorthand Guide</a></li>
<li><a href="http://www.gosquared.com/liquidicity/archives/1010" target="_blank">GoSquared CSS Help Sheet</a></li>
</ul>
<h2>Adobe Flash Cheat Sheets</h2>
<p><img decoding="async" loading="lazy" title="3" src="http://www.topdesignmag.com/wp-content/uploads/2011/01/312.png" alt="" width="449" height="87" /></p>
<ul>
<li><a href="http://michaeldoyle.eu/blog/wp-content/uploads/2009/10/flash-cheat-sheet.pdf" target="_blank">Flash Cheat Sheet</a></li>
<li><a href="http://edutechwiki.unige.ch/en/Flash_CS3_keyboard_shortcuts" target="_blank">Flash CS3 Keyboard Shortcuts</a></li>
</ul>
<p><strong> </strong></p>
<h2><strong>ASP Cheat Sheets</strong></h2>
<h2><strong><img decoding="async" loading="lazy" title="4" src="http://www.topdesignmag.com/wp-content/uploads/2011/01/430.jpg" alt="" width="451" height="106" /><br />
</strong></h2>
<ul>
<li><a href="http://refcardz.dzone.com/refcardz/core-aspnet" target="_blank">Core ASP.NET</a></li>
<li><a href="http://www.newdrp.com/Posters/Development/tabid/67/id/284/Default.aspx" target="_blank">ASP.NET MVC Framework Cheat Sheet</a></li>
<li><a href="http://www.newdrp.com/Posters/Development/tabid/67/id/286/Default.aspx" target="_blank">ASP.NET MVC View Cheat Sheet</a></li>
</ul>
<h2>PHP Cheat Sheets</h2>
<p><img decoding="async" loading="lazy" title="5" src="http://www.topdesignmag.com/wp-content/uploads/2011/01/55.png" alt="" width="450" height="112" /></p>
<ul>
<li><a href="http://www.dreamincode.net/forums/topic/35660-php-quick-reference-cheat-sheet/" target="_blank">PHP Basics Quick Reference Sheet</a></li>
<li><a href="http://www.digilife.be/quickreferences/QRC/PHP%20Cheat%20Sheet.pdf" target="_blank">PHP Cheat Sheet</a></li>
<li><a href="http://www.sk89q.com/content/2010/04/phpsec_cheatsheet.pdf" target="_blank">PHP Security Cheat Sheet</a></li>
<li><a title="PHP Variable and Array Tests (php version 5.1.6) by Barry Hunter" href="http://www.deformedweb.co.uk/php_variable_tests.php" target="_blank">PHP Variable and Array Tests</a></li>
<li><a href="http://downloads.gosquared.com/help_sheets/08/PHP-Help-Sheet-01.jpg" target="_blank">GoSquared PHP Help Sheet</a></li>
</ul>
<h2>MySQL Cheat Sheets</h2>
<p><img decoding="async" loading="lazy" title="6" src="http://www.topdesignmag.com/wp-content/uploads/2011/01/65.png" alt="" width="450" height="89" /></p>
<ul>
<li><a href="http://www.addedbytes.com/cheat-sheets/mysql-cheat-sheet/" target="_blank">MySQL Cheat Sheet by Dave Child</a></li>
<li><a href="http://www.cheat-sheets.org/saved-copy/MySQL_QuickRef.pdf" target="_blank">MySQL Database Quick Reference</a></li>
<li><a href="http://www.sqltutorial.org/sql-cheat-sheet.aspx" target="_blank">SQL Statements Cheat Sheet</a></li>
</ul>
<h2>JavaScript Cheat Sheets</h2>
<p><img decoding="async" loading="lazy" title="7" src="http://www.topdesignmag.com/wp-content/uploads/2011/01/75.png" alt="" width="451" height="118" /></p>
<ul>
<li><a href="http://www.javascript.su/" target="_blank">JavaScript in one page</a></li>
<li><a href="http://www.addedbytes.com/cheat-sheets/javascript-cheat-sheet/" target="_blank">JavaScript Cheat Sheet</a></li>
<li><a href="http://wps.aw.com/wps/media/objects/2234/2287950/javascript_refererence.pdf" target="_blank">Addison-Wesley’s JavaScript Reference Card</a></li>
</ul>
<h2>jQuery Cheat Sheets</h2>
<p><img decoding="async" loading="lazy" title="8" src="http://www.topdesignmag.com/wp-content/uploads/2011/01/85.png" alt="" width="450" height="109" /></p>
<ul>
<li><a href="http://colorcharge.com/jquery/" target="_blank">jQuery Cheatsheet</a></li>
<li><a href="http://woork.blogspot.com/2009/09/jquery-visual-cheat-sheet.html" target="_blank">jQuery 1.3 Visual Cheat Sheet by Antonio Lupetti</a></li>
<li><a href="http://refcardz.dzone.com/refcardz/jquery-selectors" target="_blank">jQuery Selectors by Bear Bibeault &amp; Yehuda Katz</a></li>
</ul>
<h2>Unicode Cheat Sheets</h2>
<p><img decoding="async" loading="lazy" title="9" src="http://www.topdesignmag.com/wp-content/uploads/2011/01/97.png" alt="" width="450" height="112" /></p>
<ul>
<li><a href="http://www.utf.ru/" target="_blank">The Unicode Character Code</a></li>
<li><a href="http://www.visibone.com/htmlref/char/cer.htm" target="_blank">HTML Characters, Numeric Codes, 0-65535 by Bob Stein</a></li>
</ul>
<h2>XML Cheat Sheets</h2>
<p><img decoding="async" loading="lazy" title="10" src="http://www.topdesignmag.com/wp-content/uploads/2011/01/106.png" alt="" width="450" height="111" /></p>
<ul>
<li><a href="http://www.xml.su/" target="_blank">XML in one page</a></li>
<li><a href="http://www.mulberrytech.com/quickref/XMLquickref.pdf" target="_blank">XML 1.0 Syntax Quick Reference by Mulberry Technologies</a></li>
</ul>
<h2>mod_rewrite and .htaccess Cheat Sheets</h2>
<p><img decoding="async" loading="lazy" title="11" src="http://www.topdesignmag.com/wp-content/uploads/2011/01/1111.png" alt="" width="455" height="95" /></p>
<ul>
<li><a href="http://www.addedbytes.com/cheat-sheets/mod_rewrite-cheat-sheet/" target="_blank">mod_rewrite Cheat Sheet by Dave Child</a></li>
<li><a href="http://www.thejackol.com/htaccess-cheatsheet/" target="_blank">htaccess Cheatsheet</a></li>
</ul>
<p>（全文完）<!--



<p align="center"><a href= target=_blank><img decoding="async" src=""></a></p>





<p align="center"><img decoding="async" src="https://coolshell.cn/wp-content/uploads/2020/03/coolshell.weixin.jpg"> <img decoding="async" loading="lazy" src="https://coolshell.cn/wp-content/uploads/2020/03/coolshell.mini_.jpg" width="300" height="300"> <br />关注CoolShell微信公众账号和微信小程序</p>

 

--></p>
<div style="margin-top: 15px; font-size: 16px;color: #cc0000;">
<p align="center"><strong>（转载本站文章请注明作者和出处 <a href="https://coolshell.cn/">酷 壳 &#8211; CoolShell</a> ，请勿用于任何商业用途）</strong></p>
</div>

<div class="wp_rp_wrap  wp_rp_vertical_m" ><div class="wp_rp_content"><h3 class="related_post_title">相关文章</h3><ul class="related_post wp_rp"><li ><a href="https://coolshell.cn/articles/4795.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/plugins/wordpress-23-related-posts-plugin/static/thumbs/7.jpg" alt="开源中最好的Web开发的资源" width="150" height="150" /></a><a href="https://coolshell.cn/articles/4795.html" class="wp_rp_title">开源中最好的Web开发的资源</a></li><li ><a href="https://coolshell.cn/articles/9666.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/uploads/2013/05/Render-Process-150x150.jpg" alt="浏览器的渲染原理简介" width="150" height="150" /></a><a href="https://coolshell.cn/articles/9666.html" class="wp_rp_title">浏览器的渲染原理简介</a></li><li ><a href="https://coolshell.cn/articles/3013.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/uploads/2010/09/biolab-150x150.jpg" alt="一些非常有意思的杂项资源" width="150" height="150" /></a><a href="https://coolshell.cn/articles/3013.html" class="wp_rp_title">一些非常有意思的杂项资源</a></li><li ><a href="https://coolshell.cn/articles/1949.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/plugins/wordpress-23-related-posts-plugin/static/thumbs/16.jpg" alt="Web中的省略号" width="150" height="150" /></a><a href="https://coolshell.cn/articles/1949.html" class="wp_rp_title">Web中的省略号</a></li><li ><a href="https://coolshell.cn/articles/17634.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/uploads/2017/01/pretty-code-150x150.gif" alt="Chrome开发者工具的小技巧" width="150" height="150" /></a><a href="https://coolshell.cn/articles/17634.html" class="wp_rp_title">Chrome开发者工具的小技巧</a></li><li ><a href="https://coolshell.cn/articles/6840.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/uploads/2012/03/css-layouts-150x150.gif" alt="CSS 布局:40个教程、技巧、例子和最佳实践" width="150" height="150" /></a><a href="https://coolshell.cn/articles/6840.html" class="wp_rp_title">CSS 布局:40个教程、技巧、例子和最佳实践</a></li></ul></div></div>The post <a href="https://coolshell.cn/articles/3684.html">Web开发人员速查卡</a> first appeared on <a href="https://coolshell.cn">酷 壳 - CoolShell</a>.]]></content:encoded>
					
					<wfw:commentRss>https://coolshell.cn/articles/3684.html/feed</wfw:commentRss>
			<slash:comments>22</slash:comments>
		
		
			</item>
		<item>
		<title>6个有用的MySQL语句</title>
		<link>https://coolshell.cn/articles/3433.html</link>
					<comments>https://coolshell.cn/articles/3433.html#comments</comments>
		
		<dc:creator><![CDATA[陈皓]]></dc:creator>
		<pubDate>Fri, 31 Dec 2010 00:29:35 +0000</pubDate>
				<category><![CDATA[数据库]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[SQL]]></category>
		<guid isPermaLink="false">http://coolshell.cn/?p=3433</guid>

					<description><![CDATA[<p>以前本站给大家介绍过《MySQL性能优化的最佳20+条经验》，今天给大家介绍六条比较有用的MySQL的SQL语句，可能很多人都通过PHP来实现这些功能。 1. ...</p>
<p class="read-more"><a class="btn btn-default" href="https://coolshell.cn/articles/3433.html"> Read More<span class="screen-reader-text">  Read More</span></a></p>
The post <a href="https://coolshell.cn/articles/3433.html">6个有用的MySQL语句</a> first appeared on <a href="https://coolshell.cn">酷 壳 - CoolShell</a>.]]></description>
										<content:encoded><![CDATA[<p><script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-3415450859608158"
     crossorigin="anonymous"></script>以前本站给大家介绍过《<a rel="bookmark" href="https://coolshell.cn/articles/1846.html" target="_blank">MySQL性能优化的最佳20+条经验</a>》，今天给大家介绍六条比较有用的MySQL的SQL语句，可能很多人都通过PHP来实现这些功能。</p>
<h4>1. 计算年数</h4>
<p>你想通过生日来计算这个人有几岁了。</p>
<pre data-enlighter-language="sql" class="EnlighterJSRAW">

SELECT DATE_FORMAT(FROM_DAYS(TO_DAYS(now()) - TO_DAYS(@dateofbirth)), &#039;%Y&#039;) + 0;
</pre>
<h4>2. 两个时间的差</h4>
<p>取得两个 datetime 值的差。假设 dt1 和 dt2 是 datetime 类型，其格式为 ‘yyyy-mm-dd hh:mm:ss’，那么它们之间所差的秒数为：</p>
<pre data-enlighter-language="sql" class="EnlighterJSRAW">

UNIX_TIMESTAMP( dt2 ) - UNIX_TIMESTAMP( dt1 )
</pre>
<p>除以60就是所差的分钟数，除以3600就是所差的小时数，再除以24就是所差的天数。</p>
<h4>3. 显示某一列出现过N次的值</h4>
<pre data-enlighter-language="sql" class="EnlighterJSRAW">

SELECT id
FROM tbl
GROUP BY id
HAVING COUNT(*) = N;
</pre>
<p><span id="more-3433"></span></p>
<h4>4. 计算两个日子间的工作日</h4>
<p>所谓工作日就是除出周六周日和节假日。</p>
<pre data-enlighter-language="sql" class="EnlighterJSRAW">

SELECT COUNT(*)
FROM calendar
WHERE d BETWEEN Start AND Stop
  AND DAYOFWEEK(d) NOT IN(1,7)
  AND holiday=0;
</pre>
<h4>5. 查找表中的主键</h4>
<pre data-enlighter-language="sql" class="EnlighterJSRAW">

SELECT k.column_name
FROM information_schema.table_constraints t
JOIN information_schema.key_column_usage k
USING (constraint_name,table_schema,table_name)
WHERE t.constraint_type=&#039;PRIMARY KEY&#039;
  AND t.table_schema=&#039;db&#039;
  AND t.table_name=tbl&#039;
</pre>
<h4>6. 查看你的数库有多大</h4>
<pre data-enlighter-language="sql" class="EnlighterJSRAW">

SELECT
  table_schema AS &#039;Db Name&#039;,
  Round( Sum( data_length + index_length ) / 1024 / 1024, 3 ) AS &#039;Db Size (MB)&#039;,
  Round( Sum( data_free ) / 1024 / 1024, 3 ) AS &#039;Free Space (MB)&#039;
FROM information_schema.tables
GROUP BY table_schema ;
</pre>
<p>希望对你有帮助。</p>
<p>文章：<a href="http://www.codeforest.net/6-useful-mysql-queries" target="_blank">来源</a><!--



<p align="center"><a href= target=_blank><img decoding="async" src=""></a></p>





<p align="center"><img decoding="async" src="https://coolshell.cn/wp-content/uploads/2020/03/coolshell.weixin.jpg"> <img decoding="async" loading="lazy" src="https://coolshell.cn/wp-content/uploads/2020/03/coolshell.mini_.jpg" width="300" height="300"> <br />关注CoolShell微信公众账号和微信小程序</p>

 

--></p>
<div style="margin-top: 15px; font-size: 16px;color: #cc0000;">
<p align="center"><strong>（转载本站文章请注明作者和出处 <a href="https://coolshell.cn/">酷 壳 &#8211; CoolShell</a> ，请勿用于任何商业用途）</strong></p>
</div>

<div class="wp_rp_wrap  wp_rp_vertical_m" ><div class="wp_rp_content"><h3 class="related_post_title">相关文章</h3><ul class="related_post wp_rp"><li ><a href="https://coolshell.cn/articles/7490.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/uploads/2012/06/f1-150x150.jpg" alt="性能调优攻略" width="150" height="150" /></a><a href="https://coolshell.cn/articles/7490.html" class="wp_rp_title">性能调优攻略</a></li><li ><a href="https://coolshell.cn/articles/925.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/plugins/wordpress-23-related-posts-plugin/static/thumbs/12.jpg" alt="如何比较两个数据表" width="150" height="150" /></a><a href="https://coolshell.cn/articles/925.html" class="wp_rp_title">如何比较两个数据表</a></li><li ><a href="https://coolshell.cn/articles/8711.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/uploads/2012/12/200906020837401710-150x150.jpg" alt="程序员疫苗：代码注入" width="150" height="150" /></a><a href="https://coolshell.cn/articles/8711.html" class="wp_rp_title">程序员疫苗：代码注入</a></li><li ><a href="https://coolshell.cn/articles/7270.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/uploads/2012/05/overview2-1-150x150.png" alt="NoSQL 数据建模技术" width="150" height="150" /></a><a href="https://coolshell.cn/articles/7270.html" class="wp_rp_title">NoSQL 数据建模技术</a></li><li ><a href="https://coolshell.cn/articles/6639.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/uploads/2012/02/programming-language-150x150.jpg" alt="千万别惹程序员 " width="150" height="150" /></a><a href="https://coolshell.cn/articles/6639.html" class="wp_rp_title">千万别惹程序员 </a></li><li ><a href="https://coolshell.cn/articles/4939.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/plugins/wordpress-23-related-posts-plugin/static/thumbs/29.jpg" alt="Quora使用到的技术" width="150" height="150" /></a><a href="https://coolshell.cn/articles/4939.html" class="wp_rp_title">Quora使用到的技术</a></li></ul></div></div>The post <a href="https://coolshell.cn/articles/3433.html">6个有用的MySQL语句</a> first appeared on <a href="https://coolshell.cn">酷 壳 - CoolShell</a>.]]></content:encoded>
					
					<wfw:commentRss>https://coolshell.cn/articles/3433.html/feed</wfw:commentRss>
			<slash:comments>9</slash:comments>
		
		
			</item>
		<item>
		<title>MySQL性能优化的最佳20+条经验</title>
		<link>https://coolshell.cn/articles/1846.html</link>
					<comments>https://coolshell.cn/articles/1846.html#comments</comments>
		
		<dc:creator><![CDATA[陈皓]]></dc:creator>
		<pubDate>Fri, 27 Nov 2009 10:57:33 +0000</pubDate>
				<category><![CDATA[PHP脚本]]></category>
		<category><![CDATA[数据库]]></category>
		<category><![CDATA[Database]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[PHP]]></category>
		<guid isPermaLink="false">http://coolshell.cn/?p=1846</guid>

					<description><![CDATA[<p>今天，数据库的操作越来越成为整个应用的性能瓶颈了，这点对于Web应用尤其明显。关于数据库的性能，这并不只是DBA才需要担心的事，而这更是我们程序员需要去关注的事...</p>
<p class="read-more"><a class="btn btn-default" href="https://coolshell.cn/articles/1846.html"> Read More<span class="screen-reader-text">  Read More</span></a></p>
The post <a href="https://coolshell.cn/articles/1846.html">MySQL性能优化的最佳20+条经验</a> first appeared on <a href="https://coolshell.cn">酷 壳 - CoolShell</a>.]]></description>
										<content:encoded><![CDATA[<p><script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-3415450859608158"
     crossorigin="anonymous"></script>今天，数据库的操作越来越成为整个应用的性能瓶颈了，这点对于Web应用尤其明显。关于数据库的性能，这并不只是DBA才需要担心的事，而这更是我们程序员需要去关注的事情。当我们去设计数据库表结构，对操作数据库时（尤其是查表时的SQL语句），我们都需要注意数据操作的性能。这里，我们不会讲过多的SQL语句的优化，而只是针对MySQL这一Web应用最多的数据库。希望下面的这些优化技巧对你有用。</p>
<h4>1. 为查询缓存优化你的查询</h4>
<p>大多数的MySQL服务器都开启了查询缓存。这是提高性最有效的方法之一，而且这是被MySQL的数据库引擎处理的。当有很多相同的查询被执行了多次的时候，这些查询结果会被放到一个缓存中，这样，后续的相同的查询就不用操作表而直接访问缓存结果了。</p>
<p>这里最主要的问题是，对于程序员来说，这个事情是很容易被忽略的。因为，我们某些查询语句会让MySQL不使用缓存。请看下面的示例：</p>
<pre data-enlighter-language="php" class="EnlighterJSRAW">
// 查询缓存不开启
$r = mysql_query(&quot;SELECT username FROM user WHERE signup_date &gt;= CURDATE()&quot;);

// 开启查询缓存
$today = date(&quot;Y-m-d&quot;);
$r = mysql_query(&quot;SELECT username FROM user WHERE signup_date &gt;= &#039;$today&#039;&quot;);
</pre>
<p>上面两条SQL语句的差别就是 CURDATE() ，MySQL的查询缓存对这个函数不起作用。所以，像 NOW() 和 RAND() 或是其它的诸如此类的SQL函数都不会开启查询缓存，因为这些函数的返回是会不定的易变的。所以，你所需要的就是用一个变量来代替MySQL的函数，从而开启缓存。</p>
<p><span id="more-1846"></span></p>
<h4>2. EXPLAIN 你的 SELECT 查询</h4>
<p>使用 <a href="http://dev.mysql.com/doc/refman/5.0/en/explain.html" target="_blank">EXPLAIN</a> 关键字可以让你知道MySQL是如何处理你的SQL语句的。这可以帮你分析你的查询语句或是表结构的性能瓶颈。</p>
<p>EXPLAIN 的查询结果还会告诉你你的索引主键被如何利用的，你的数据表是如何被搜索和排序的……等等，等等。</p>
<p>挑一个你的SELECT语句（推荐挑选那个最复杂的，有多表联接的），把关键字EXPLAIN加到前面。你可以使用phpmyadmin来做这个事。然后，你会看到一张表格。下面的这个示例中，我们忘记加上了group_id索引，并且有表联接：</p>
<div class="tutorial_image"><img decoding="async" src="http://nettuts.s3.amazonaws.com/500_mysql/unoptimized_explain.jpg" border="0" alt="" /></div>
<p>当我们为 group_id 字段加上索引后：</p>
<div class="tutorial_image"><img decoding="async" src="http://nettuts.s3.amazonaws.com/500_mysql/optimized_explain.jpg" border="0" alt="" /></div>
<p>我们可以看到，前一个结果显示搜索了 7883 行，而后一个只是搜索了两个表的 9 和 16 行。查看rows列可以让我们找到潜在的性能问题。</p>
<h4>3. 当只要一行数据时使用 LIMIT 1</h4>
<p>当你查询表的有些时候，你已经知道结果只会有一条结果，但因为你可能需要去fetch游标，或是你也许会去检查返回的记录数。</p>
<p>在这种情况下，加上 LIMIT 1 可以增加性能。这样一样，MySQL数据库引擎会在找到一条数据后停止搜索，而不是继续往后查少下一条符合记录的数据。</p>
<p>下面的示例，只是为了找一下是否有“中国”的用户，很明显，后面的会比前面的更有效率。（请注意，第一条中是Select *，第二条是Select 1）</p>
<pre data-enlighter-language="php" class="EnlighterJSRAW">

// 没有效率的：
$r = mysql_query(&quot;SELECT * FROM user WHERE country = &#039;China&#039;&quot;);
if (mysql_num_rows($r) &gt; 0) {
	// ...
}

// 有效率的：
$r = mysql_query(&quot;SELECT 1 FROM user WHERE country = &#039;China&#039; LIMIT 1&quot;);
if (mysql_num_rows($r) &gt; 0) {
	// ...
}
</pre>
<h4>4. 为搜索字段建索引</h4>
<p>索引并不一定就是给主键或是唯一的字段。如果在你的表中，有某个字段你总要会经常用来做搜索，那么，请为其建立索引吧。</p>
<div class="tutorial_image"><img decoding="async" src="http://nettuts.s3.amazonaws.com/500_mysql/search_index.jpg" border="0" alt="" /></div>
<p>从上图你可以看到那个搜索字串 &#8220;last_name LIKE &#8216;a%'&#8221;，一个是建了索引，一个是没有索引，性能差了4倍左右。</p>
<p>另外，你应该也需要知道什么样的搜索是不能使用正常的索引的。例如，当你需要在一篇大的文章中搜索一个词时，如： &#8220;WHERE post_content LIKE &#8216;%apple%'&#8221;，索引可能是没有意义的。你可能需要使用<a href="http://dev.mysql.com/doc/refman/5.1/en/fulltext-search.html" target="_blank">MySQL全文索引</a> 或是自己做一个索引（比如说：搜索关键词或是Tag什么的）</p>
<h4>5. 在Join表的时候使用相当类型的例，并将其索引</h4>
<p>如果你的应用程序有很多 JOIN 查询，你应该确认两个表中Join的字段是被建过索引的。这样，MySQL内部会启动为你优化Join的SQL语句的机制。</p>
<p>而且，这些被用来Join的字段，应该是相同的类型的。例如：如果你要把 DECIMAL 字段和一个 INT 字段Join在一起，MySQL就无法使用它们的索引。对于那些STRING类型，还需要有相同的字符集才行。（两个表的字符集有可能不一样）</p>
<pre data-enlighter-language="php" class="EnlighterJSRAW">
// 在state中查找company
$r = mysql_query(&quot;SELECT company_name FROM users
	LEFT JOIN companies ON (users.state = companies.state)
	WHERE users.id = $user_id&quot;);

// 两个 state 字段应该是被建过索引的，而且应该是相当的类型，相同的字符集。
</pre>
<h4>6. 千万不要 ORDER BY RAND()</h4>
<p>想打乱返回的数据行？随机挑一个数据？真不知道谁发明了这种用法，但很多新手很喜欢这样用。但你确不了解这样做有多么可怕的性能问题。</p>
<p>如果你真的想把返回的数据行打乱了，你有N种方法可以达到这个目的。这样使用只让你的数据库的性能呈指数级的下降。这里的问题是：MySQL会不得不去执行RAND()函数（很耗CPU时间），而且这是为了每一行记录去记行，然后再对其排序。就算是你用了Limit 1也无济于事（因为要排序）</p>
<p>下面的示例是随机挑一条记录</p>
<pre data-enlighter-language="php" class="EnlighterJSRAW">
// 千万不要这样做：
$r = mysql_query(&quot;SELECT username FROM user ORDER BY RAND() LIMIT 1&quot;);

// 这要会更好：
$r = mysql_query(&quot;SELECT count(*) FROM user&quot;);
$d = mysql_fetch_row($r);
$rand = mt_rand(0,$d[0] - 1);

$r = mysql_query(&quot;SELECT username FROM user LIMIT $rand, 1&quot;);
</pre>
<h4>7. 避免 SELECT *</h4>
<p>从数据库里读出越多的数据，那么查询就会变得越慢。并且，如果你的数据库服务器和WEB服务器是两台独立的服务器的话，这还会增加网络传输的负载。</p>
<p>所以，你应该养成一个需要什么就取什么的好的习惯。</p>
<pre data-enlighter-language="php" class="EnlighterJSRAW">
// 不推荐
$r = mysql_query(&quot;SELECT * FROM user WHERE user_id = 1&quot;);
$d = mysql_fetch_assoc($r);
echo &quot;Welcome {$d[&#039;username&#039;]}&quot;;

// 推荐
$r = mysql_query(&quot;SELECT username FROM user WHERE user_id = 1&quot;);
$d = mysql_fetch_assoc($r);
echo &quot;Welcome {$d[&#039;username&#039;]}&quot;;
</pre>
<h4>8. 永远为每张表设置一个ID</h4>
<p>我们应该为数据库里的每张表都设置一个ID做为其主键，而且最好的是一个INT型的（推荐使用UNSIGNED），并设置上自动增加的AUTO_INCREMENT标志。</p>
<p>就算是你 users 表有一个主键叫 “email”的字段，你也别让它成为主键。使用 VARCHAR 类型来当主键会使用得性能下降。另外，在你的程序中，你应该使用表的ID来构造你的数据结构。</p>
<p>而且，在MySQL数据引擎下，还有一些操作需要使用主键，在这些情况下，主键的性能和设置变得非常重要，比如，集群，分区……</p>
<p>在这里，只有一个情况是例外，那就是“关联表”的“外键”，也就是说，这个表的主键，通过若干个别的表的主键构成。我们把这个情况叫做“外键”。比如：有一个“学生表”有学生的ID，有一个“课程表”有课程ID，那么，“成绩表”就是“关联表”了，其关联了学生表和课程表，在成绩表中，学生ID和课程ID叫“外键”其共同组成主键。</p>
<h4>9. 使用 ENUM 而不是 VARCHAR</h4>
<p><a href="http://dev.mysql.com/doc/refman/5.0/en/enum.html" target="_blank">ENUM</a> 类型是非常快和紧凑的。在实际上，其保存的是 TINYINT，但其外表上显示为字符串。这样一来，用这个字段来做一些选项列表变得相当的完美。</p>
<p>如果你有一个字段，比如“性别”，“国家”，“民族”，“状态”或“部门”，你知道这些字段的取值是有限而且固定的，那么，你应该使用 ENUM 而不是 VARCHAR。</p>
<p>MySQL也有一个“建议”（见第十条）告诉你怎么去重新组织你的表结构。当你有一个 VARCHAR 字段时，这个建议会告诉你把其改成 ENUM 类型。使用 PROCEDURE ANALYSE() 你可以得到相关的建议。</p>
<h4>10. 从 PROCEDURE ANALYSE() 取得建议</h4>
<p><a href="http://dev.mysql.com/doc/refman/5.0/en/procedure-analyse.html" target="_blank">PROCEDURE ANALYSE()</a> 会让 MySQL 帮你去分析你的字段和其实际的数据，并会给你一些有用的建议。只有表中有实际的数据，这些建议才会变得有用，因为要做一些大的决定是需要有数据作为基础的。</p>
<p>例如，如果你创建了一个 INT 字段作为你的主键，然而并没有太多的数据，那么，PROCEDURE ANALYSE()会建议你把这个字段的类型改成 MEDIUMINT 。或是你使用了一个 VARCHAR 字段，因为数据不多，你可能会得到一个让你把它改成 ENUM 的建议。这些建议，都是可能因为数据不够多，所以决策做得就不够准。</p>
<p>在phpmyadmin里，你可以在查看表时，点击 &#8220;Propose table structure&#8221; 来查看这些建议</p>
<div class="tutorial_image"><img decoding="async" src="http://nettuts.s3.amazonaws.com/500_mysql/suggestions.jpg" border="0" alt="" /></div>
<p>一定要注意，这些只是建议，只有当你的表里的数据越来越多时，这些建议才会变得准确。一定要记住，你才是最终做决定的人。</p>
<h4>11. 尽可能的使用 NOT NULL</h4>
<p>除非你有一个很特别的原因去使用 NULL 值，你应该总是让你的字段保持 NOT NULL。这看起来好像有点争议，请往下看。</p>
<p>首先，问问你自己“Empty”和“NULL”有多大的区别（如果是INT，那就是0和NULL）？如果你觉得它们之间没有什么区别，那么你就不要使用NULL。（你知道吗？在 Oracle 里，NULL 和 Empty 的字符串是一样的！)</p>
<p>不要以为 NULL 不需要空间，其需要额外的空间，并且，在你进行比较的时候，你的程序会更复杂。 当然，这里并不是说你就不能使用NULL了，现实情况是很复杂的，依然会有些情况下，你需要使用NULL值。</p>
<p>下面摘自MySQL自己的文档：</p>
<blockquote><p>&#8220;NULL columns require additional space in the row to record whether their values are NULL. For MyISAM tables, each NULL column takes one bit extra, rounded up to the nearest byte.&#8221;</p></blockquote>
<h4>12. Prepared Statements</h4>
<p>Prepared Statements很像存储过程，是一种运行在后台的SQL语句集合，我们可以从使用 prepared statements 获得很多好处，无论是性能问题还是安全问题。</p>
<p>Prepared Statements 可以检查一些你绑定好的变量，这样可以保护你的程序不会受到“SQL注入式”攻击。当然，你也可以手动地检查你的这些变量，然而，手动的检查容易出问题，而且很经常会被程序员忘了。当我们使用一些framework或是ORM的时候，这样的问题会好一些。</p>
<p>在性能方面，当一个相同的查询被使用多次的时候，这会为你带来可观的性能优势。你可以给这些Prepared Statements定义一些参数，而MySQL只会解析一次。</p>
<p>虽然最新版本的MySQL在传输Prepared Statements是使用二进制形势，所以这会使得网络传输非常有效率。</p>
<p>当然，也有一些情况下，我们需要避免使用Prepared Statements，因为其不支持查询缓存。但据说版本5.1后支持了。</p>
<p>在PHP中要使用prepared statements，你可以查看其使用手册：<a href="http://php.net/manual/en/book.mysqli.php" target="_blank">mysqli 扩展</a> 或是使用数据库抽象层，如： <a href="http://us.php.net/manual/en/book.pdo.php" target="_blank">PDO</a>.</p>
<pre data-enlighter-language="php" class="EnlighterJSRAW">
// 创建 prepared statement
if ($stmt = $mysqli-&gt;prepare(&quot;SELECT username FROM user WHERE state=?&quot;)) {

	// 绑定参数
    $stmt-&gt;bind_param(&quot;s&quot;, $state);

	// 执行
    $stmt-&gt;execute();

	// 绑定结果
    $stmt-&gt;bind_result($username);

	// 移动游标
    $stmt-&gt;fetch();

    printf(&quot;%s is from %s\n&quot;, $username, $state);

    $stmt-&gt;close();
}
</pre>
<h4>13. 无缓冲的查询</h4>
<p>正常的情况下，当你在当你在你的脚本中执行一个SQL语句的时候，你的程序会停在那里直到没这个SQL语句返回，然后你的程序再往下继续执行。你可以使用无缓冲查询来改变这个行为。</p>
<p>关于这个事情，在PHP的文档中有一个非常不错的说明： <a href="http://php.net/manual/en/function.mysql-unbuffered-query.php" target="_blank">mysql_unbuffered_query()</a> 函数：</p>
<blockquote><p>&#8220;mysql_unbuffered_query() sends the SQL query query to MySQL without automatically fetching and buffering the result rows as mysql_query() does. This saves a considerable amount of memory with SQL queries that produce large result sets, and you can start working on the result set immediately after the first row has been retrieved as you don&#8217;t have to wait until the complete SQL query has been performed.&#8221;</p></blockquote>
<p>上面那句话翻译过来是说，mysql_unbuffered_query() 发送一个SQL语句到MySQL而并不像mysql_query()一样去自动fethch和缓存结果。这会相当节约很多可观的内存，尤其是那些会产生大量结果的查询语句，并且，你不需要等到所有的结果都返回，只需要第一行数据返回的时候，你就可以开始马上开始工作于查询结果了。</p>
<p>然而，这会有一些限制。因为你要么把所有行都读走，或是你要在进行下一次的查询前调用 <a href="http://us2.php.net/manual/en/function.mysql-free-result.php" target="_blank">mysql_free_result()</a> 清除结果。而且， <a href="http://us2.php.net/manual/en/function.mysql-num-rows.php" target="_blank">mysql_num_rows()</a> 或 <a href="http://us2.php.net/manual/en/function.mysql-data-seek.php" target="_blank">mysql_data_seek()</a> 将无法使用。所以，是否使用无缓冲的查询你需要仔细考虑。</p>
<h4>14. 把IP地址存成 UNSIGNED INT</h4>
<p>很多程序员都会创建一个 VARCHAR(15) 字段来存放字符串形式的IP而不是整形的IP。如果你用整形来存放，只需要4个字节，并且你可以有定长的字段。而且，这会为你带来查询上的优势，尤其是当你需要使用这样的WHERE条件：IP between ip1 and ip2。</p>
<p>我们必需要使用UNSIGNED INT，因为 IP地址会使用整个32位的无符号整形。</p>
<p>而你的查询，你可以使用 <a href="http://dev.mysql.com/doc/refman/5.0/en/miscellaneous-functions.html#function_inet-aton" target="_blank">INET_ATON()</a> 来把一个字符串IP转成一个整形，并使用 <a href="http://dev.mysql.com/doc/refman/5.0/en/miscellaneous-functions.html#function_inet-ntoa" target="_blank">INET_NTOA()</a> 把一个整形转成一个字符串IP。在PHP中，也有这样的函数 <a href="http://php.net/manual/en/function.ip2long.php" target="_blank">ip2long()</a> 和 <a href="http://us.php.net/manual/en/function.long2ip.php" target="_blank">long2ip()</a>。</p>
<pre data-enlighter-language="php" class="EnlighterJSRAW">
$r = &quot;UPDATE users SET ip = INET_ATON(&#039;{$_SERVER[&#039;REMOTE_ADDR&#039;]}&#039;) WHERE user_id = $user_id&quot;;
</pre>
<h4>15. 固定长度的表会更快</h4>
<p>如果表中的所有字段都是“固定长度”的，整个表会被认为是 <a href="http://dev.mysql.com/doc/refman/5.1/en/static-format.html" target="_blank">&#8220;static&#8221; 或 &#8220;fixed-length&#8221;</a>。 例如，表中没有如下类型的字段： VARCHAR，TEXT，BLOB。只要你包括了其中一个这些字段，那么这个表就不是“固定长度静态表”了，这样，MySQL 引擎会用另一种方法来处理。</p>
<p>固定长度的表会提高性能，因为MySQL搜寻得会更快一些，因为这些固定的长度是很容易计算下一个数据的偏移量的，所以读取的自然也会很快。而如果字段不是定长的，那么，每一次要找下一条的话，需要程序找到主键。</p>
<p>并且，固定长度的表也更容易被缓存和重建。不过，唯一的副作用是，固定长度的字段会浪费一些空间，因为定长的字段无论你用不用，他都是要分配那么多的空间。</p>
<p>使用“垂直分割”技术（见下一条），你可以分割你的表成为两个一个是定长的，一个则是不定长的。</p>
<h4>16. 垂直分割</h4>
<p>“垂直分割”是一种把数据库中的表按列变成几张表的方法，这样可以降低表的复杂度和字段的数目，从而达到优化的目的。（以前，在银行做过项目，见过一张表有100多个字段，很恐怖）</p>
<p><strong>示例一</strong>：在Users表中有一个字段是家庭地址，这个字段是可选字段，相比起，而且你在数据库操作的时候除了个人信息外，你并不需要经常读取或是改写这个字段。那么，为什么不把他放到另外一张表中呢？ 这样会让你的表有更好的性能，大家想想是不是，大量的时候，我对于用户表来说，只有用户ID，用户名，口令，用户角色等会被经常使用。小一点的表总是会有好的性能。</p>
<p><strong>示例二</strong>： 你有一个叫 &#8220;last_login&#8221; 的字段，它会在每次用户登录时被更新。但是，每次更新时会导致该表的查询缓存被清空。所以，你可以把这个字段放到另一个表中，这样就不会影响你对用户ID，用户名，用户角色的不停地读取了，因为查询缓存会帮你增加很多性能。</p>
<p>另外，你需要注意的是，这些被分出去的字段所形成的表，你不会经常性地去Join他们，不然的话，这样的性能会比不分割时还要差，而且，会是极数级的下降。</p>
<h4>17. 拆分大的 DELETE 或 INSERT 语句</h4>
<p>如果你需要在一个在线的网站上去执行一个大的 DELETE 或 INSERT 查询，你需要非常小心，要避免你的操作让你的整个网站停止相应。因为这两个操作是会锁表的，表一锁住了，别的操作都进不来了。</p>
<p>Apache 会有很多的子进程或线程。所以，其工作起来相当有效率，而我们的服务器也不希望有太多的子进程，线程和数据库链接，这是极大的占服务器资源的事情，尤其是内存。</p>
<p>如果你把你的表锁上一段时间，比如30秒钟，那么对于一个有很高访问量的站点来说，这30秒所积累的访问进程/线程，数据库链接，打开的文件数，可能不仅仅会让你泊WEB服务Crash，还可能会让你的整台服务器马上掛了。</p>
<p>所以，如果你有一个大的处理，你定你一定把其拆分，使用 LIMIT 条件是一个好的方法。下面是一个示例：</p>
<pre data-enlighter-language="php" class="EnlighterJSRAW">
while (1) {
    //每次只做1000条
	mysql_query(&quot;DELETE FROM logs WHERE log_date &lt;= &#039;2009-11-01&#039; LIMIT 1000&quot;);
	if (mysql_affected_rows() == 0) {
		// 没得可删了，退出！
		break;
	}
	// 每次都要休息一会儿
	usleep(50000);
}
</pre>
<h4>18. 越小的列会越快</h4>
<p>对于大多数的数据库引擎来说，硬盘操作可能是最重大的瓶颈。所以，把你的数据变得紧凑会对这种情况非常有帮助，因为这减少了对硬盘的访问。</p>
<p>参看 MySQL 的文档 <a href="http://dev.mysql.com/doc/refman/5.0/en/storage-requirements.html" target="_blank">Storage Requirements</a> 查看所有的数据类型。</p>
<p>如果一个表只会有几列罢了（比如说字典表，配置表），那么，我们就没有理由使用 INT 来做主键，使用 MEDIUMINT, SMALLINT 或是更小的 TINYINT 会更经济一些。如果你不需要记录时间，使用 DATE 要比 DATETIME 好得多。</p>
<p>当然，你也需要留够足够的扩展空间，不然，你日后来干这个事，你会死的很难看，参看<a href="http://news.slashdot.org/article.pl?sid=06/11/09/1534204" target="_blank">Slashdot的例子</a>（2009年11月06日），一个简单的ALTER TABLE语句花了3个多小时，因为里面有一千六百万条数据。</p>
<h4>19. 选择正确的存储引擎</h4>
<p>在 MySQL 中有两个存储引擎 MyISAM 和 InnoDB，每个引擎都有利有弊。酷壳以前文章《<a href="https://coolshell.cn/articles/652.html" target="_blank">MySQL: InnoDB 还是 MyISAM?</a>》讨论和这个事情。</p>
<p>MyISAM 适合于一些需要大量查询的应用，但其对于有大量写操作并不是很好。甚至你只是需要update一个字段，整个表都会被锁起来，而别的进程，就算是读进程都无法操作直到读操作完成。另外，MyISAM 对于 SELECT COUNT(*) 这类的计算是超快无比的。</p>
<p>InnoDB 的趋势会是一个非常复杂的存储引擎，对于一些小的应用，它会比 MyISAM 还慢。他是它支持“行锁” ，于是在写操作比较多的时候，会更优秀。并且，他还支持更多的高级应用，比如：事务。</p>
<p>下面是MySQL的手册</p>
<ul>
<li><a href="http://dev.mysql.com/doc/refman/5.1/en/myisam-storage-engine.html">target=&#8221;_blank&#8221;MyISAM Storage Engine</a></li>
<li><a href="http://dev.mysql.com/doc/refman/5.1/en/innodb.html" target="_blank">InnoDB Storage Engine</a></li>
</ul>
<h4>20. 使用一个对象关系映射器（Object Relational Mapper）</h4>
<p>使用 ORM (Object Relational Mapper)，你能够获得可靠的性能增涨。一个ORM可以做的所有事情，也能被手动的编写出来。但是，这需要一个高级专家。</p>
<p>ORM 的最重要的是“Lazy Loading”，也就是说，只有在需要的去取值的时候才会去真正的去做。但你也需要小心这种机制的副作用，因为这很有可能会因为要去创建很多很多小的查询反而会降低性能。</p>
<p>ORM 还可以把你的SQL语句打包成一个事务，这会比单独执行他们快得多得多。</p>
<p>目前，个人最喜欢的PHP的ORM是：<a href="http://www.doctrine-project.org" target="_blank">Doctrine</a>。</p>
<h4>21. 小心“永久链接”</h4>
<p>“永久链接”的目的是用来减少重新创建MySQL链接的次数。当一个链接被创建了，它会永远处在连接的状态，就算是数据库操作已经结束了。而且，自从我们的Apache开始重用它的子进程后——也就是说，下一次的HTTP请求会重用Apache的子进程，并重用相同的 MySQL 链接。</p>
<ul>
<li><a href="http://php.net/manual/en/function.mysql-pconnect.php" target="_blank">PHP手册：mysql_pconnect() </a></li>
</ul>
<p>在理论上来说，这听起来非常的不错。但是从个人经验（也是大多数人的）上来说，这个功能制造出来的麻烦事更多。因为，你只有有限的链接数，内存问题，文件句柄数，等等。</p>
<p>而且，Apache 运行在极端并行的环境中，会创建很多很多的了进程。这就是为什么这种“永久链接”的机制工作地不好的原因。在你决定要使用“永久链接”之前，你需要好好地考虑一下你的整个系统的架构。</p>
<p>文章：<a href="http://net.tutsplus.com/tutorials/other/top-20-mysql-best-practices/" target="_blank">来源</a></p>
<p>（全文完）<!--



<p align="center"><a href= target=_blank><img decoding="async" src=""></a></p>





<p align="center"><img decoding="async" src="https://coolshell.cn/wp-content/uploads/2020/03/coolshell.weixin.jpg"> <img decoding="async" loading="lazy" src="https://coolshell.cn/wp-content/uploads/2020/03/coolshell.mini_.jpg" width="300" height="300"> <br />关注CoolShell微信公众账号和微信小程序</p>

 

--></p>
<div style="margin-top: 15px; font-size: 16px;color: #cc0000;">
<p align="center"><strong>（转载本站文章请注明作者和出处 <a href="https://coolshell.cn/">酷 壳 &#8211; CoolShell</a> ，请勿用于任何商业用途）</strong></p>
</div>

<div class="wp_rp_wrap  wp_rp_vertical_m" ><div class="wp_rp_content"><h3 class="related_post_title">相关文章</h3><ul class="related_post wp_rp"><li ><a href="https://coolshell.cn/articles/4795.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/plugins/wordpress-23-related-posts-plugin/static/thumbs/7.jpg" alt="开源中最好的Web开发的资源" width="150" height="150" /></a><a href="https://coolshell.cn/articles/4795.html" class="wp_rp_title">开源中最好的Web开发的资源</a></li><li ><a href="https://coolshell.cn/articles/3684.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/uploads/2011/02/1128-150x150.jpg" alt="Web开发人员速查卡" width="150" height="150" /></a><a href="https://coolshell.cn/articles/3684.html" class="wp_rp_title">Web开发人员速查卡</a></li><li ><a href="https://coolshell.cn/articles/1889.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/uploads/2009/12/sql.where_.clause-150x150.jpg" alt="SQL的Where语句" width="150" height="150" /></a><a href="https://coolshell.cn/articles/1889.html" class="wp_rp_title">SQL的Where语句</a></li><li ><a href="https://coolshell.cn/articles/652.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/plugins/wordpress-23-related-posts-plugin/static/thumbs/17.jpg" alt="MySQL: InnoDB 还是 MyISAM?" width="150" height="150" /></a><a href="https://coolshell.cn/articles/652.html" class="wp_rp_title">MySQL: InnoDB 还是 MyISAM?</a></li><li ><a href="https://coolshell.cn/articles/7886.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/uploads/2012/07/muxnt-150x150.jpg" alt="代码执行的效率" width="150" height="150" /></a><a href="https://coolshell.cn/articles/7886.html" class="wp_rp_title">代码执行的效率</a></li><li ><a href="https://coolshell.cn/articles/7490.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/uploads/2012/06/f1-150x150.jpg" alt="性能调优攻略" width="150" height="150" /></a><a href="https://coolshell.cn/articles/7490.html" class="wp_rp_title">性能调优攻略</a></li></ul></div></div>The post <a href="https://coolshell.cn/articles/1846.html">MySQL性能优化的最佳20+条经验</a> first appeared on <a href="https://coolshell.cn">酷 壳 - CoolShell</a>.]]></content:encoded>
					
					<wfw:commentRss>https://coolshell.cn/articles/1846.html/feed</wfw:commentRss>
			<slash:comments>169</slash:comments>
		
		
			</item>
		<item>
		<title>如何比较两个数据表</title>
		<link>https://coolshell.cn/articles/925.html</link>
					<comments>https://coolshell.cn/articles/925.html#comments</comments>
		
		<dc:creator><![CDATA[陈皓]]></dc:creator>
		<pubDate>Wed, 27 May 2009 15:02:14 +0000</pubDate>
				<category><![CDATA[数据库]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[PostgreSQL]]></category>
		<category><![CDATA[SQL]]></category>
		<guid isPermaLink="false">http://coolshell.cn/?p=925</guid>

					<description><![CDATA[<p>有些时候，我们可能想要比较一下两个数据表，以找到其中不同的数据。比如，在进行数据移植的时候，或是在合并数据的时候，或是在比对验证数据的时候。当然比较两个表，需要...</p>
<p class="read-more"><a class="btn btn-default" href="https://coolshell.cn/articles/925.html"> Read More<span class="screen-reader-text">  Read More</span></a></p>
The post <a href="https://coolshell.cn/articles/925.html">如何比较两个数据表</a> first appeared on <a href="https://coolshell.cn">酷 壳 - CoolShell</a>.]]></description>
										<content:encoded><![CDATA[<p><script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-3415450859608158"
     crossorigin="anonymous"></script>有些时候，我们可能想要比较一下两个数据表，以找到其中不同的数据。比如，在进行数据移植的时候，或是在合并数据的时候，或是在比对验证数据的时候。当然比较两个表，需要这两个表结构是一样的。</p>
<p>我们先假设一下有如下表结构：</p>
<pre data-enlighter-language="sql" class="EnlighterJSRAW">
CREATE TABLE jajal
(
    user_id integer NOT NULL,
    first_name character varying(255),
    last_name character varying(255),
    grade character(1),
    CONSTRAINT jajal_pkey PRIMARY KEY (user_id)
)
</pre>
<p><span id="more-925"></span><br />
然后，我们有两张表——jajal和jajal_copy，其内容如下：</p>
<h4> jajal</h4>
<table id="wptable-7" class="wptable rowstyle-alt" border="0" cellspacing="1">
<thead>
<tr>
<th class="sortable" style="width: 30px;" align="center">user_id</th>
<th class="sortable" style="width: 30px;" align="center">first_name</th>
<th class="sortable" style="width: 30px;" align="center">last_name</th>
<th class="sortable" style="width: 30px;" align="center">grade</th>
</tr>
</thead>
<tbody>
<tr>
<td style="width: 30px;" align="center">1</td>
<td style="width: 30px;" align="center">Some</td>
<td style="width: 30px;" align="center">Dude</td>
<td style="width: 30px;" align="center">A</td>
</tr>
<tr class="alt">
<td style="width: 30px;" align="center">2</td>
<td style="width: 30px;" align="center">Other</td>
<td style="width: 30px;" align="center">Guy</td>
<td style="width: 30px;" align="center">B</td>
</tr>
<tr>
<td style="width: 30px;" align="center">3</td>
<td style="width: 30px;" align="center">You are</td>
<td style="width: 30px;" align="center">Welcome</td>
<td style="width: 30px;" align="center">B</td>
</tr>
<tr class="alt">
<td style="width: 30px;" align="center">4</td>
<td style="width: 30px;" align="center">What</td>
<td style="width: 30px;" align="center">Other</td>
<td style="width: 30px;" align="center">A</td>
</tr>
<tr>
<td style="width: 30px;" align="center">5</td>
<td style="width: 30px;" align="center">INeed</td>
<td style="width: 30px;" align="center">You</td>
<td style="width: 30px;" align="center">C</td>
</tr>
<tr class="alt">
<td style="width: 30px;" align="center">6</td>
<td style="width: 30px;" align="center">Mixed</td>
<td style="width: 30px;" align="center">Nuts</td>
<td style="width: 30px;" align="center">Z</td>
</tr>
<tr>
<td style="width: 30px;" align="center">7</td>
<td style="width: 30px;" align="center">Kirk</td>
<td style="width: 30px;" align="center">Land</td>
<td style="width: 30px;" align="center">B</td>
</tr>
<tr class="alt">
<td style="width: 30px;" align="center">8</td>
<td style="width: 30px;" align="center">Bit</td>
<td style="width: 30px;" align="center">Shooter</td>
<td style="width: 30px;" align="center">A</td>
</tr>
<tr>
<td style="width: 30px;" align="center">9</td>
<td style="width: 30px;" align="center">Sun</td>
<td style="width: 30px;" align="center">Microsystem</td>
<td style="width: 30px;" align="center">C</td>
</tr>
<tr class="alt">
<td style="width: 30px;" align="center">10</td>
<td style="width: 30px;" align="center">Extra</td>
<td style="width: 30px;" align="center">Fancy</td>
<td style="width: 30px;" align="center">B</td>
</tr>
</tbody>
</table>
<h4>jajal_copy</h4>
<table id="wptable-8" class="wptable rowstyle-alt" border="0" cellspacing="1">
<thead>
<tr>
<th class="sortable" style="width: 30px;" align="center">user_id</th>
<th class="sortable" style="width: 30px;" align="center">first_name</th>
<th class="sortable" style="width: 30px;" align="center">last_name</th>
<th class="sortable" style="width: 30px;" align="center">grade</th>
</tr>
</thead>
<tbody>
<tr>
<td style="width: 30px;" align="center">1</td>
<td style="width: 30px;" align="center">Some</td>
<td style="width: 30px;" align="center">Dude</td>
<td style="width: 30px;" align="center">A</td>
</tr>
<tr class="alt">
<td style="width: 30px;" align="center">2</td>
<td style="width: 30px;" align="center">Other</td>
<td style="width: 30px;" align="center">Guy</td>
<td style="width: 30px;" align="center">B</td>
</tr>
<tr>
<td style="width: 30px;" align="center">3</td>
<td style="width: 30px;" align="center">You are</td>
<td style="width: 30px;" align="center">Welcome</td>
<td style="width: 30px;" align="center">B</td>
</tr>
<tr class="alt">
<td style="width: 30px;" align="center">4</td>
<td style="width: 30px;" align="center">What</td>
<td style="width: 30px;" align="center">Other</td>
<td style="width: 30px;" align="center">A</td>
</tr>
<tr>
<td style="width: 30px;" align="center">5</td>
<td style="width: 30px;" align="center">INeed</td>
<td style="width: 30px;" align="center">You</td>
<td style="width: 30px;" align="center">C</td>
</tr>
<tr class="alt">
<td style="width: 30px;" align="center">6</td>
<td style="width: 30px;" align="center">Mixed</td>
<td style="width: 30px;" align="center">Nuts</td>
<td style="width: 30px;" align="center">C</td>
</tr>
<tr>
<td style="width: 30px;" align="center">7</td>
<td style="width: 30px;" align="center">Kirk</td>
<td style="width: 30px;" align="center">Land</td>
<td style="width: 30px;" align="center">B</td>
</tr>
<tr class="alt">
<td style="width: 30px;" align="center">8</td>
<td style="width: 30px;" align="center">Bit</td>
<td style="width: 30px;" align="center">Shooter</td>
<td style="width: 30px;" align="center">A</td>
</tr>
<tr>
<td style="width: 30px;" align="center">9</td>
<td style="width: 30px;" align="center">Sun</td>
<td style="width: 30px;" align="center">Microsystem</td>
<td style="width: 30px;" align="center">C</td>
</tr>
<tr class="alt">
<td style="width: 30px;" align="center">10</td>
<td style="width: 30px;" align="center">Extra</td>
<td style="width: 30px;" align="center">Fancy</td>
<td style="width: 30px;" align="center">B</td>
</tr>
</tbody>
</table>
<p> </p>
<p>要比较这两张表的数据，找出不一样的数据行。我们可以使用<a href="http://en.wikipedia.org/wiki/Join_(SQL)#Outer_joins"><span style="color: #967001;">outer join</span></a> 技术。我给outer join做了一个链接，是Wikipedia的，如果你对这个技术不是很清楚，还请你行看看其技术细节。</p>
<p>下面是具体的SQL语句：</p>
<h4><span style="text-decoration: underline;">使用FULL OUTER JOIN</span></h4>
<pre data-enlighter-language="sql" class="EnlighterJSRAW">
SELECT
     *
FROM
     jajal j
     FULL OUTER JOIN jajal_copy jc ON jc.first_name = j.first_name
     AND jc.last_name = j.last_name
     AND jc.grade = j.grade
     AND jc.user_id = j.user_id
WHERE
     j.user_id IS NULL
     OR jc.user_id IS NULL
</pre>
<p>运行结果如下：</p>
<table id="wptable-9" class="wptable rowstyle-alt" border="0" cellspacing="1">
<thead>
<tr>
<th class="sortable" style="width: 30px;" align="center">user_id</th>
<th class="sortable" style="width: 30px;" align="center">first_name</th>
<th class="sortable" style="width: 30px;" align="center">last_name</th>
<th class="sortable" style="width: 30px;" align="center">grade</th>
<th class="sortable" style="width: 30px;" align="center">user_id</th>
<th class="sortable" style="width: 30px;" align="center">first_name</th>
<th class="sortable" style="width: 30px;" align="center">last_name</th>
<th class="sortable" style="width: 30px;" align="center">grade</th>
</tr>
</thead>
<tbody>
<tr>
<td style="width: 30px;" align="center">[NULL]</td>
<td style="width: 30px;" align="center">[NULL]</td>
<td style="width: 30px;" align="center">[NULL]</td>
<td style="width: 30px;" align="center">[NULL]</td>
<td style="width: 30px;" align="center">6</td>
<td style="width: 30px;" align="center">Mixed</td>
<td style="width: 30px;" align="center">Nuts</td>
<td style="width: 30px;" align="center">C</td>
</tr>
<tr class="alt">
<td style="width: 30px;" align="center">6</td>
<td style="width: 30px;" align="center">Mixed</td>
<td style="width: 30px;" align="center">Nuts</td>
<td style="width: 30px;" align="center">Z</td>
<td style="width: 30px;" align="center">[NULL]</td>
<td style="width: 30px;" align="center">[NULL]</td>
<td style="width: 30px;" align="center">[NULL]</td>
<td style="width: 30px;" align="center">[NULL]</td>
</tr>
</tbody>
</table>
<p> </p>
<h4><span style="text-decoration: underline;">使用NATURAL FULL OUTER JOIN</span></h4>
<p>关于<a href="http://en.wikipedia.org/wiki/Join_(SQL)#Natural_join"><span style="color: #967001;">natural join</span></a>，你可以看看Wikipedia是怎么说的。</p>
<pre data-enlighter-language="sql" class="EnlighterJSRAW">
SELECT
       *
FROM
       jajal j
       NATURAL FULL OUTER JOIN jajal_copy jc
WHERE
       j.user_id IS NULL
       OR jc.user_id IS NULL
</pre>
<p>运行结果如下：</p>
<table id="wptable-10" class="wptable rowstyle-alt" border="0" cellspacing="1">
<thead>
<tr>
<th class="sortable" style="width: 30px;" align="center">user_id</th>
<th class="sortable" style="width: 30px;" align="center">first_name</th>
<th class="sortable" style="width: 30px;" align="center">last_name</th>
<th class="sortable" style="width: 30px;" align="center">grade</th>
</tr>
</thead>
<tbody>
<tr>
<td style="width: 30px;" align="center">6</td>
<td style="width: 30px;" align="center">Mixed</td>
<td style="width: 30px;" align="center">Nuts</td>
<td style="width: 30px;" align="center">C</td>
</tr>
<tr class="alt">
<td style="width: 30px;" align="center">6</td>
<td style="width: 30px;" align="center">Mixed</td>
<td style="width: 30px;" align="center">Nuts</td>
<td style="width: 30px;" align="center">Z</td>
</tr>
</tbody>
</table>
<p> </p>
<h4><span style="text-decoration: underline;">MySQL SQL 代码</span></h4>
<pre>MySQL 并不支持 FULL OUTER JOIN，但是我们可以使用LEFT JOIN 和 RIGHT JOIN 来实现这一功能。如下所示。</pre>
<pre data-enlighter-language="sql" class="EnlighterJSRAW">
SELECT
*
FROM
jajal j
LEFT JOIN jajal_copy jc ON jc.first_name = j.first_name
AND jc.last_name = j.last_name
AND jc.grade = j.grade
AND jc.user_id = j.user_id
WHERE
jc.user_id IS NULL
UNION ALL
SELECT
*
FROM
jajal j
RIGHT JOIN jajal_copy jc ON jc.first_name = j.first_name
AND jc.last_name = j.last_name
AND jc.grade = j.grade
AND jc.user_id = j.user_id
WHERE
j.user_id IS NULL
</pre>
<p>或者你更喜欢NATURAL JOIN 版本</p>
<pre data-enlighter-language="sql" class="EnlighterJSRAW">
SELECT
*
FROM
jajal j
NATURAL LEFT JOIN jajal_copy jc
WHERE
jc.user_id IS NULL
UNION ALL
SELECT
*
FROM
jajal j
NATURAL RIGHT JOIN jajal_copy jc
WHERE
j.user_id IS NULL
</pre>
<p>当然，如果你需要一个MySQL的存储过程的话，下面是一个示例：</p>
<pre data-enlighter-language="sql" class="EnlighterJSRAW">
DELIMITER $$

CREATE PROCEDURE `db_schema`.`tablediff`
    (schema_name VARCHAR(64), table1 VARCHAR(64), table2 VARCHAR(64))
BEGIN
    DECLARE done INT DEFAULT 0;
    DECLARE sql_statement TEXT DEFAULT &#039;&#039;;
    DECLARE sql_statement_where TEXT DEFAULT &#039;&#039;;
    DECLARE sql_statement_pk TEXT DEFAULT &#039;&#039;;
    DECLARE col_name VARCHAR(64);
    DECLARE col_name_cur CURSOR FOR
        SELECT
            COLUMN_NAME
        FROM
            information_schema.COLUMNS
        WHERE
            TABLE_SCHEMA = schema_name
            AND TABLE_NAME = table1
    ;
    DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;

    OPEN col_name_cur;
    traverse_columns: LOOP
        FETCH col_name_cur INTO col_name;

        IF done THEN
            CLOSE col_name_cur;
            LEAVE traverse_columns;
        END IF;

        SET sql_statement_where = CONCAT(sql_statement_where,
            &#039; AND a.&#039;, col_name, &#039; = b.&#039;, col_name);
        SET sql_statement_pk = CONCAT(sql_statement_pk,
            &#039;AND b.&#039;, col_name, &#039; IS NULL&#039;);
    END LOOP;

    SELECT
        COLUMN_NAME INTO col_name
    FROM
        information_schema.KEY_COLUMN_USAGE
    WHERE
        CONSTRAINT_SCHEMA = schema_name
        AND CONSTRAINT_NAME = &#039;PRIMARY&#039;
        AND TABLE_NAME = table1
    LIMIT 1
    ;
    IF col_name IS NOT NULL THEN
        SET sql_statement_pk = CONCAT(&#039;AND b.&#039;, col_name, &#039; IS NULL&#039;);
    END IF;

    SET sql_statement = CONCAT(&#039;SELECT * FROM &#039;, schema_name, &#039;.&#039;, table1, &#039; a LEFT JOIN &#039;, schema_name, &#039;.&#039;, table2, &#039; b ON TRUE&#039;);
    SET sql_statement = CONCAT(sql_statement, sql_statement_where, &#039; WHERE TRUE &#039;, sql_statement_pk);
    SET sql_statement = CONCAT(sql_statement, &#039; UNION ALL SELECT * FROM &#039;, schema_name, &#039;.&#039;, table1, &#039; b RIGHT JOIN &#039;, schema_name, &#039;.&#039;, table2, &#039; a ON TRUE&#039;);
    SET sql_statement = CONCAT(sql_statement, sql_statement_where, &#039; WHERE TRUE &#039;, sql_statement_pk);

    SET @s = sql_statement;
    PREPARE stmt1 FROM @s;
    EXECUTE stmt1;
    DEALLOCATE PREPARE stmt1;

END$$
DELIMITER ;
</pre>
<p> </p>
<p> </p>
<h4><span style="text-decoration: underline;">PostgreSQL 下的SQL语句</span></h4>
<p>下面是PostgreSQL的一个存储过程：</p>
<pre data-enlighter-language="sql" class="EnlighterJSRAW">
CREATE OR REPLACE FUNCTION tablediff (
    IN schema_name VARCHAR(64),
    IN table1 VARCHAR(64),
    IN table2 VARCHAR(64)
) RETURNS BIGINT AS
$BODY$
DECLARE
    the_result BIGINT DEFAULT 0;
    sql_statement TEXT DEFAULT &#039;&#039;;
    sql_statement_where TEXT DEFAULT &#039;&#039;;
    sql_statement_pk TEXT DEFAULT &#039;&#039;;
    col_name VARCHAR(64);
    col_name_cur CURSOR FOR
        SELECT
            column_name
        FROM
            information_schema.columns
        WHERE
            table_catalog = schema_name
            AND table_schema = &#039;public&#039;
            AND table_name = table1
    ;
BEGIN
    OPEN col_name_cur;

    LOOP
        FETCH col_name_cur INTO col_name;
        IF NOT FOUND THEN
            EXIT;
        END IF;

        sql_statement_where := sql_statement_where || &#039; AND a.&#039; || col_name || &#039; = b.&#039; || col_name;
    END LOOP;

    SELECT
        column_name INTO col_name
    FROM
        information_schema.table_constraints tc
        JOIN information_schema.constraint_column_usage ccu ON
            ccu.constraint_name = tc.constraint_name
    WHERE
        tc.table_catalog = schema_name
        AND tc.table_schema = &#039;public&#039;
        AND tc.table_name = table1
    LIMIT 1
    ;

    IF col_name IS NOT NULL THEN
        sql_statement_pk := &#039; a.&#039; || col_name || &#039; IS NULL&#039;;
        sql_statement_pk := sql_statement_pk || &#039; OR b.&#039; || col_name || &#039; IS NULL&#039;;
    END IF;

    sql_statement := &#039;SELECT COUNT(*) FROM &#039; || schema_name || &#039;.public.&#039; || table1 || &#039; a FULL OUTER JOIN &#039; || schema_name || &#039;.public.&#039; || table2 || &#039; b ON TRUE&#039;;
    sql_statement := sql_statement || sql_statement_where || &#039; WHERE &#039; || sql_statement_pk;

    EXECUTE sql_statement INTO the_result;

    RETURN the_result;
END;$BODY$
LANGUAGE &#039;plpgsql&#039; STABLE;
</pre>
<p> </p>
<p>文章：<a href="http://www.microshell.com/database/sql/comparing-data-from-2-database-tables/" target="_blank">来源</a><!--



<p align="center"><a href= target=_blank><img decoding="async" src=""></a></p>





<p align="center"><img decoding="async" src="https://coolshell.cn/wp-content/uploads/2020/03/coolshell.weixin.jpg"> <img decoding="async" loading="lazy" src="https://coolshell.cn/wp-content/uploads/2020/03/coolshell.mini_.jpg" width="300" height="300"> <br />关注CoolShell微信公众账号和微信小程序</p>

 

--></p>
<div style="margin-top: 15px; font-size: 16px;color: #cc0000;">
<p align="center"><strong>（转载本站文章请注明作者和出处 <a href="https://coolshell.cn/">酷 壳 &#8211; CoolShell</a> ，请勿用于任何商业用途）</strong></p>
</div>

<div class="wp_rp_wrap  wp_rp_vertical_m" ><div class="wp_rp_content"><h3 class="related_post_title">相关文章</h3><ul class="related_post wp_rp"><li ><a href="https://coolshell.cn/articles/7490.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/uploads/2012/06/f1-150x150.jpg" alt="性能调优攻略" width="150" height="150" /></a><a href="https://coolshell.cn/articles/7490.html" class="wp_rp_title">性能调优攻略</a></li><li ><a href="https://coolshell.cn/articles/3433.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/plugins/wordpress-23-related-posts-plugin/static/thumbs/10.jpg" alt="6个有用的MySQL语句" width="150" height="150" /></a><a href="https://coolshell.cn/articles/3433.html" class="wp_rp_title">6个有用的MySQL语句</a></li><li ><a href="https://coolshell.cn/articles/8711.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/uploads/2012/12/200906020837401710-150x150.jpg" alt="程序员疫苗：代码注入" width="150" height="150" /></a><a href="https://coolshell.cn/articles/8711.html" class="wp_rp_title">程序员疫苗：代码注入</a></li><li ><a href="https://coolshell.cn/articles/7270.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/uploads/2012/05/overview2-1-150x150.png" alt="NoSQL 数据建模技术" width="150" height="150" /></a><a href="https://coolshell.cn/articles/7270.html" class="wp_rp_title">NoSQL 数据建模技术</a></li><li ><a href="https://coolshell.cn/articles/6639.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/uploads/2012/02/programming-language-150x150.jpg" alt="千万别惹程序员 " width="150" height="150" /></a><a href="https://coolshell.cn/articles/6639.html" class="wp_rp_title">千万别惹程序员 </a></li><li ><a href="https://coolshell.cn/articles/4939.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/plugins/wordpress-23-related-posts-plugin/static/thumbs/29.jpg" alt="Quora使用到的技术" width="150" height="150" /></a><a href="https://coolshell.cn/articles/4939.html" class="wp_rp_title">Quora使用到的技术</a></li></ul></div></div>The post <a href="https://coolshell.cn/articles/925.html">如何比较两个数据表</a> first appeared on <a href="https://coolshell.cn">酷 壳 - CoolShell</a>.]]></content:encoded>
					
					<wfw:commentRss>https://coolshell.cn/articles/925.html/feed</wfw:commentRss>
			<slash:comments>5</slash:comments>
		
		
			</item>
		<item>
		<title>MySQL: InnoDB 还是 MyISAM?</title>
		<link>https://coolshell.cn/articles/652.html</link>
					<comments>https://coolshell.cn/articles/652.html#comments</comments>
		
		<dc:creator><![CDATA[陈皓]]></dc:creator>
		<pubDate>Fri, 24 Apr 2009 06:33:09 +0000</pubDate>
				<category><![CDATA[技术读物]]></category>
		<category><![CDATA[数据库]]></category>
		<category><![CDATA[Database]]></category>
		<category><![CDATA[InnoDB]]></category>
		<category><![CDATA[MyISAM]]></category>
		<category><![CDATA[MySQL]]></category>
		<guid isPermaLink="false">http://coolshell.cn/?p=652</guid>

					<description><![CDATA[<p>MyISAM 是MySQL中默认的存储引擎，一般来说不是有太多人关心这个东西。决定使用什么样的存储引擎是一个很tricky的事情，但是还是值我们去研究一下，这里...</p>
<p class="read-more"><a class="btn btn-default" href="https://coolshell.cn/articles/652.html"> Read More<span class="screen-reader-text">  Read More</span></a></p>
The post <a href="https://coolshell.cn/articles/652.html">MySQL: InnoDB 还是 MyISAM?</a> first appeared on <a href="https://coolshell.cn">酷 壳 - CoolShell</a>.]]></description>
										<content:encoded><![CDATA[<p><script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-3415450859608158"
     crossorigin="anonymous"></script>MyISAM 是MySQL中默认的存储引擎，一般来说不是有太多人关心这个东西。决定使用什么样的存储引擎是一个很tricky的事情，但是还是值我们去研究一下，这里的文章只考虑 MyISAM 和InnoDB这两个，因为这两个是最常见的。</p>
<p>下面先让我们回答一些问题：</p>
<ul>
<li>你的数据库有外键吗？</li>
<li>你需要事务支持吗？</li>
<li>你需要全文索引吗？</li>
<li>你经常使用什么样的查询模式？</li>
<li>你的数据有多大？</li>
</ul>
<p><span id="more-652"></span></p>
<p>思考上面这些问题可以让你找到合适的方向，但那并不是绝对的。如果你需要事务处理或是外键，那么InnoDB 可能是比较好的方式。如果你需要全文索引，那么通常来说 MyISAM是好的选择，因为这是系统内建的，然而，我们其实并不会经常地去测试两百万行记录。所以，就算是慢一点，我们可以通过使用Sphinx从InnoDB中获得全文索引。</p>
<p>数据的大小，是一个影响你选择什么样存储引擎的重要因素，大尺寸的数据集趋向于选择InnoDB方式，因为其支持事务处理和故障恢复。数据库的在小决定了故障恢复的时间长短，InnoDB可以利用事务日志进行数据恢复，这会比较快。而MyISAM可能会需要几个小时甚至几天来干这些事，InnoDB只需要几分钟。</p>
<p>您操作数据库表的习惯可能也会是一个对性能影响很大的因素。比如： COUNT() 在 MyISAM 表中会非常快，而在InnoDB 表下可能会很痛苦。而主键查询则在InnoDB下会相当相当的快，但需要小心的是如果我们的主键太长了也会导致性能问题。大批的inserts 语句在MyISAM下会快一些，但是updates 在InnoDB 下会更快一些——尤其在并发量大的时候。</p>
<p>所以，到底你检使用哪一个呢？根据经验来看，如果是一些小型的应用或项目，那么MyISAM 也许会更适合。当然，在大型的环境下使用MyISAM 也会有很大成功的时候，但却不总是这样的。如果你正在计划使用一个超大数据量的项目，而且需要事务处理或外键支持，那么你真的应该直接使用InnoDB方式。但需要记住InnoDB 的表需要更多的内存和存储，转换100GB 的MyISAM 表到InnoDB 表可能会让你有非常坏的体验。</p>
<p style="display: none;"><img decoding="async" loading="lazy" style="display: none; width: 0px; height: 0px; border-style: none;" src="http://blog.inetu.net/wp-content/plugins/wp-spamfree/img/wpsf-img.php" alt="" width="0" height="0" /></p>
<p style="display: none;">文章：<a href="http://blog.inetu.net/2009/04/mysql-innodb-or-myisam/" target="_blank">来源</a></p>
<p><!--



<p align="center"><a href= target=_blank><img decoding="async" src=""></a></p>





<p align="center"><img decoding="async" src="https://coolshell.cn/wp-content/uploads/2020/03/coolshell.weixin.jpg"> <img decoding="async" loading="lazy" src="https://coolshell.cn/wp-content/uploads/2020/03/coolshell.mini_.jpg" width="300" height="300"> <br />关注CoolShell微信公众账号和微信小程序</p>

 

--></p>
<div style="margin-top: 15px; font-size: 16px;color: #cc0000;">
<p align="center"><strong>（转载本站文章请注明作者和出处 <a href="https://coolshell.cn/">酷 壳 &#8211; CoolShell</a> ，请勿用于任何商业用途）</strong></p>
</div>

<div class="wp_rp_wrap  wp_rp_vertical_m" ><div class="wp_rp_content"><h3 class="related_post_title">相关文章</h3><ul class="related_post wp_rp"><li ><a href="https://coolshell.cn/articles/1846.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/uploads/2009/11/unoptimized_explain-150x150.jpg" alt="MySQL性能优化的最佳20+条经验" width="150" height="150" /></a><a href="https://coolshell.cn/articles/1846.html" class="wp_rp_title">MySQL性能优化的最佳20+条经验</a></li><li ><a href="https://coolshell.cn/articles/7490.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/uploads/2012/06/f1-150x150.jpg" alt="性能调优攻略" width="150" height="150" /></a><a href="https://coolshell.cn/articles/7490.html" class="wp_rp_title">性能调优攻略</a></li><li ><a href="https://coolshell.cn/articles/7270.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/uploads/2012/05/overview2-1-150x150.png" alt="NoSQL 数据建模技术" width="150" height="150" /></a><a href="https://coolshell.cn/articles/7270.html" class="wp_rp_title">NoSQL 数据建模技术</a></li><li ><a href="https://coolshell.cn/articles/5826.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/plugins/wordpress-23-related-posts-plugin/static/thumbs/26.jpg" alt="千万别用MongoDB？真的吗？！" width="150" height="150" /></a><a href="https://coolshell.cn/articles/5826.html" class="wp_rp_title">千万别用MongoDB？真的吗？！</a></li><li ><a href="https://coolshell.cn/articles/4939.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/plugins/wordpress-23-related-posts-plugin/static/thumbs/29.jpg" alt="Quora使用到的技术" width="150" height="150" /></a><a href="https://coolshell.cn/articles/4939.html" class="wp_rp_title">Quora使用到的技术</a></li><li ><a href="https://coolshell.cn/articles/4795.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/plugins/wordpress-23-related-posts-plugin/static/thumbs/7.jpg" alt="开源中最好的Web开发的资源" width="150" height="150" /></a><a href="https://coolshell.cn/articles/4795.html" class="wp_rp_title">开源中最好的Web开发的资源</a></li></ul></div></div>The post <a href="https://coolshell.cn/articles/652.html">MySQL: InnoDB 还是 MyISAM?</a> first appeared on <a href="https://coolshell.cn">酷 壳 - CoolShell</a>.]]></content:encoded>
					
					<wfw:commentRss>https://coolshell.cn/articles/652.html/feed</wfw:commentRss>
			<slash:comments>95</slash:comments>
		
		
			</item>
	</channel>
</rss>
