<?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>超群.com的博客 &#187; Tuning</title>
	<atom:link href="http://www.fuchaoqun.com/tag/tuning/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.fuchaoqun.com</link>
	<description></description>
	<lastBuildDate>Thu, 22 Jul 2010 23:31:23 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0.1</generator>
		<item>
		<title>根据status信息对MySQL服务器进行优化（二）</title>
		<link>http://www.fuchaoqun.com/2009/03/mysql-tuning-by-status-ii/?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=mysql-tuning-by-status-ii</link>
		<comments>http://www.fuchaoqun.com/2009/03/mysql-tuning-by-status-ii/#comments</comments>
		<pubDate>Wed, 25 Mar 2009 07:06:56 +0000</pubDate>
		<dc:creator>超群.com</dc:creator>
				<category><![CDATA[MySQL]]></category>
		<category><![CDATA[Tuning]]></category>

		<guid isPermaLink="false">http://chaoqun.17348.com/?p=204</guid>
		<description><![CDATA[续根据status信息对MySQL服务器进行优化（一），直入主题。 六、进程使用情况 mysql&#62; show global status like 'Thread%'; +-------------------+-------+ &#124; Variable_name     &#124; Value &#124; +-------------------+-------+ &#124; Threads_cached    &#124; 46    &#124; &#124; Threads_connected &#124; 2     &#124; &#124; Threads_created   &#124; 570   &#124; &#124; Threads_running   &#124; 1     &#124; +-------------------+-------+ 如果我们在MySQL服务器配置文件中设置了thread_cache_size，当客户端断开之后，服务器处理此客户的线程将会缓存起来以响应下一个客户而不是销毁（前提是缓存数未达上限）。Threads_created表示创建过的线程数，如果发现Threads_created值过大的话，表明MySQL服务器一直在创建线程，这也是比较耗资源，可以适当增加配置文件中thread_cache_size值，查询服务器thread_cache_size配置： mysql&#62; show variables like 'thread_cache_size'; +-------------------+-------+ &#124; Variable_name     &#124; Value &#124; +-------------------+-------+ &#124; thread_cache_size &#124; 64    &#124; [...]]]></description>
			<content:encoded><![CDATA[<p>续<a href="http://chaoqun.17348.com/2009/03/mysql-tuning-by-status/" target="_blank">根据status信息对MySQL服务器进行优化（一）</a>，直入主题。</p>
<p><strong>六、进程使用情况</strong></p>
<blockquote>
<pre>mysql&gt; show global status like 'Thread%';
+-------------------+-------+
| Variable_name     | Value |
+-------------------+-------+
| Threads_cached    | 46    |
| Threads_connected | 2     |
| Threads_created   | 570   |
| Threads_running   | 1     |
+-------------------+-------+</pre>
</blockquote>
<p>如果我们在MySQL服务器配置文件中设置了thread_cache_size，当客户端断开之后，服务器处理此客户的线程将会缓存起来以响应下一个客户而不是销毁（前提是缓存数未达上限）。Threads_created表示创建过的线程数，如果发现Threads_created值过大的话，表明MySQL服务器一直在创建线程，这也是比较耗资源，可以适当增加配置文件中thread_cache_size值，查询服务器thread_cache_size配置：</p>
<blockquote>
<pre>mysql&gt; show variables like 'thread_cache_size';
+-------------------+-------+
| Variable_name     | Value |
+-------------------+-------+
| thread_cache_size | 64    |
+-------------------+-------+</pre>
</blockquote>
<p>示例中的服务器还是挺健康的。</p>
<p><strong>七、查询缓存(query cache)</strong></p>
<blockquote>
<pre>mysql&gt; show global status like 'qcache%';
+-------------------------+-----------+
| Variable_name           | Value     |
+-------------------------+-----------+
| Qcache_free_blocks      | 22756     |
| Qcache_free_memory      | 76764704  |
| Qcache_hits             | 213028692 |
| Qcache_inserts          | 208894227 |
| Qcache_lowmem_prunes    | 4010916   |
| Qcache_not_cached       | 13385031  |
| Qcache_queries_in_cache | 43560     |
| Qcache_total_blocks     | 111212    |
+-------------------------+-----------+</pre>
</blockquote>
<p>MySQL查询缓存变量解释：</p>
<blockquote><p>Qcache_free_blocks：缓存中相邻内存块的个数。数目大说明可能有碎片。FLUSH QUERY CACHE会对缓存中的碎片进行整理，从而得到一个空闲块。<br />
Qcache_free_memory：缓存中的空闲内存。<br />
Qcache_hits：每次查询在缓存中命中时就增大<br />
Qcache_inserts：每次插入一个查询时就增大。命中次数除以插入次数就是不中比率。<br />
Qcache_lowmem_prunes：缓存出现内存不足并且必须要进行清理以便为更多查询提供空间的次数。这个数字最好长时间来看；如果这个数字在不断增长，就表示可能碎片非常严重，或者内存很少。（上面的 free_blocks和free_memory可以告诉您属于哪种情况）<br />
Qcache_not_cached：不适合进行缓存的查询的数量，通常是由于这些查询不是 <code>SELECT</code> 语句或者用了now()之类的函数。<br />
Qcache_queries_in_cache：当前缓存的查询（和响应）的数量。<br />
Qcache_total_blocks：缓存中块的数量。</p></blockquote>
<p>我们再查询一下服务器关于query_cache的配置：</p>
<blockquote>
<pre>mysql&gt; show variables like 'query_cache%';
+------------------------------+-----------+
| Variable_name                | Value     |
+------------------------------+-----------+
| query_cache_limit            | 2097152   |
| query_cache_min_res_unit     | 4096      |
| query_cache_size             | 203423744 |
| query_cache_type             | ON        |
| query_cache_wlock_invalidate | OFF       |
+------------------------------+-----------+</pre>
</blockquote>
<p>各字段的解释：</p>
<blockquote><p>query_cache_limit：超过此大小的查询将不缓存<br />
query_cache_min_res_unit：缓存块的最小大小<br />
query_cache_size：查询缓存大小<br />
query_cache_type：缓存类型，决定缓存什么样的查询，示例中表示不缓存 select sql_no_cache 查询<br />
query_cache_wlock_invalidate：当有其他客户端正在对MyISAM表进行写操作时，如果查询在query cache中，是否返回cache结果还是等写操作完成再读表获取结果。</p></blockquote>
<p>query_cache_min_res_unit的配置是一柄&#8221;双刃剑&#8221;，默认是4KB，设置值大对大数据查询有好处，但如果你的查询都是小数据查询，就容易造成内存碎片和浪费。</p>
<blockquote><p>查询缓存碎片率 = Qcache_free_blocks / Qcache_total_blocks * 100%</p></blockquote>
<p>如果查询缓存碎片率超过20%，可以用FLUSH QUERY CACHE整理缓存碎片，或者试试减小query_cache_min_res_unit，如果你的查询都是小数据量的话。</p>
<blockquote><p>查询缓存利用率 = (query_cache_size &#8211; Qcache_free_memory) / query_cache_size * 100%</p></blockquote>
<p>查询缓存利用率在25%以下的话说明query_cache_size设置的过大，可适当减小；查询缓存利用率在80％以上而且Qcache_lowmem_prunes &gt; 50的话说明query_cache_size可能有点小，要不就是碎片太多。</p>
<blockquote><p>查询缓存命中率 = (Qcache_hits &#8211; Qcache_inserts) / Qcache_hits * 100%</p></blockquote>
<p>示例服务器 查询缓存碎片率 ＝ 20.46％，查询缓存利用率 ＝ 62.26％，查询缓存命中率 ＝ 1.94％，命中率很差，可能写操作比较频繁吧，而且可能有些碎片。</p>
<p><strong>八、排序使用情况</strong></p>
<blockquote>
<pre>mysql&gt; show global status like 'sort%';
+-------------------+------------+
| Variable_name     | Value      |
+-------------------+------------+
| Sort_merge_passes | 29         |
| Sort_range        | 37432840   |
| Sort_rows         | 9178691532 |
| Sort_scan         | 1860569    |
+-------------------+------------+</pre>
</blockquote>
<p>Sort_merge_passes 包括两步。MySQL 首先会尝试在内存中做排序，使用的内存大小由系统变量 Sort_buffer_size 决定，如果它的大小不够把所有的记录都读到内存中，MySQL 就会把每次在内存中排序的结果存到临时文件中，等 MySQL 找到所有记录之后，再把临时文件中的记录做一次排序。这再次排序就会增加 Sort_merge_passes。实际上，MySQL 会用另一个临时文件来存再次排序的结果，所以通常会看到 Sort_merge_passes 增加的数值是建临时文件数的两倍。因为用到了临时文件，所以速度可能会比较慢，增加 Sort_buffer_size 会减少 Sort_merge_passes 和 创建临时文件的次数。但盲目的增加 Sort_buffer_size 并不一定能提高速度，见 <a href="http://www.mysqlperformanceblog.com/2007/08/18/how-fast-can-you-sort-data-with-mysql/" target="_blank">How fast can you sort data with MySQL?</a>（引自<a href="http://qroom.blogspot.com/2007/09/mysql-select-sort.html" target="_blank">http://qroom.blogspot.com/2007/09/mysql-select-sort.html</a>，貌似被墙）</p>
<p>另外，增加read_rnd_buffer_size(3.2.3是record_rnd_buffer_size)的值对排序的操作也有一点的好处，参见：<a href="http://www.mysqlperformanceblog.com/2007/07/24/what-exactly-is-read_rnd_buffer_size/" target="_blank">http://www.mysqlperformanceblog.com/2007/07/24/what-exactly-is-read_rnd_buffer_size/</a></p>
<p><strong>九、文件打开数(open_files)</strong></p>
<blockquote>
<pre>mysql&gt; show global status like 'open_files';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| Open_files    | 1410  |
+---------------+-------+

mysql&gt; show variables like 'open_files_limit';
+------------------+-------+
| Variable_name    | Value |
+------------------+-------+
| open_files_limit | 4590  |
+------------------+-------+</pre>
</blockquote>
<p>比较合适的设置：Open_files / open_files_limit * 100% &lt;= 75％</p>
<p><strong>十、表锁情况</strong></p>
<blockquote>
<pre>mysql&gt; show global status like 'table_locks%';
+-----------------------+-----------+
| Variable_name         | Value     |
+-----------------------+-----------+
| Table_locks_immediate | 490206328 |
| Table_locks_waited    | 2084912   |
+-----------------------+-----------+</pre>
</blockquote>
<p>Table_locks_immediate表示立即释放表锁数，Table_locks_waited表示需要等待的表锁数，如果Table_locks_immediate / Table_locks_waited &gt; 5000，最好采用InnoDB引擎，因为InnoDB是行锁而MyISAM是表锁，对于高并发写入的应用InnoDB效果会好些。示例中的服务器Table_locks_immediate / Table_locks_waited ＝ 235，MyISAM就足够了。</p>
<p><strong>十一、表扫描情况</strong></p>
<blockquote>
<pre>mysql&gt; show global status like 'handler_read%';
+-----------------------+-------------+
| Variable_name         | Value       |
+-----------------------+-------------+
| Handler_read_first    | 5803750     |
| Handler_read_key      | 6049319850  |
| Handler_read_next     | 94440908210 |
| Handler_read_prev     | 34822001724 |
| Handler_read_rnd      | 405482605   |
| Handler_read_rnd_next | 18912877839 |
+-----------------------+-------------+</pre>
</blockquote>
<p>各字段解释参见<a href="http://hi.baidu.com/thinkinginlamp/blog/item/31690cd7c4bc5cdaa144df9c.html" target="_blank">http://hi.baidu.com/thinkinginlamp/blog/item/31690cd7c4bc5cdaa144df9c.html</a>，调出服务器完成的查询请求次数：</p>
<blockquote>
<pre>mysql&gt; show global status like 'com_select';
+---------------+-----------+
| Variable_name | Value     |
+---------------+-----------+
| Com_select    | 222693559 |
+---------------+-----------+</pre>
</blockquote>
<p>计算表扫描率：</p>
<blockquote><p>表扫描率 ＝ Handler_read_rnd_next / Com_select</p></blockquote>
<p>如果表扫描率超过4000，说明进行了太多表扫描，很有可能索引没有建好，增加read_buffer_size值会有一些好处，但最好不要超过8MB。</p>
<p><strong>后记：</strong></p>
<p>文中提到一些数字都是参考值，了解基本原理就可以，除了MySQL提供的各种status值外，操作系统的一些性能指标也很重要，比如常用的top,iostat等，尤其是iostat，现在的系统瓶颈一般都在磁盘IO上，关于iostat的使用，可以参考：<a href="http://www.php-oa.com/2009/02/03/iostat.html" target="_blank">http://www.php-oa.com/2009/02/03/iostat.html</a></p>
<p>&#8220;根据status信息对MySQL服务器进行优化（一）、（二）&#8221;是最近学习MySQL status信息的读书笔记，谬讹之处，望请斧正。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.fuchaoqun.com/2009/03/mysql-tuning-by-status-ii/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>根据status信息对MySQL服务器进行优化（一）</title>
		<link>http://www.fuchaoqun.com/2009/03/mysql-tuning-by-status/?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=mysql-tuning-by-status</link>
		<comments>http://www.fuchaoqun.com/2009/03/mysql-tuning-by-status/#comments</comments>
		<pubDate>Tue, 24 Mar 2009 06:01:21 +0000</pubDate>
		<dc:creator>超群.com</dc:creator>
				<category><![CDATA[MySQL]]></category>
		<category><![CDATA[Tuning]]></category>

		<guid isPermaLink="false">http://chaoqun.17348.com/?p=201</guid>
		<description><![CDATA[网上有很多的文章教怎么配置MySQL服务器，但考虑到服务器硬件配置的不同，具体应用的差别，那些文章的做法只能作为初步设置参考，我们需要根据自己的情况进行配置优化，好的做法是MySQL服务器稳定运行了一段时间后运行，根据服务器的&#8221;状态&#8221;进行优化。 mysql&#62; show global status; 可以列出MySQL服务器运行各种状态值，另外，查询MySQL服务器配置信息语句： mysql&#62; show variables; 一、慢查询 mysql&#62; show variables like '%slow%'; +------------------+-------+ &#124; Variable_name    &#124; Value &#124; +------------------+-------+ &#124; log_slow_queries &#124; ON    &#124; &#124; slow_launch_time &#124; 2     &#124; +------------------+-------+ mysql&#62; show global status like '%slow%'; +---------------------+-------+ &#124; Variable_name       &#124; Value &#124; +---------------------+-------+ &#124; Slow_launch_threads &#124; 0     &#124; &#124; Slow_queries        &#124; 4148 [...]]]></description>
			<content:encoded><![CDATA[<p>网上有很多的文章教怎么配置MySQL服务器，但考虑到服务器硬件配置的不同，具体应用的差别，那些文章的做法只能作为初步设置参考，我们需要根据自己的情况进行配置优化，好的做法是MySQL服务器稳定运行了一段时间后运行，根据服务器的&#8221;状态&#8221;进行优化。</p>
<blockquote><p>mysql&gt; show global status;</p></blockquote>
<p>可以列出MySQL服务器运行各种状态值，另外，查询MySQL服务器配置信息语句：</p>
<blockquote><p>mysql&gt; show variables;</p></blockquote>
<p><strong>一、慢查询</strong></p>
<blockquote>
<pre>mysql&gt; show variables like '%slow%';
+------------------+-------+
| Variable_name    | Value |
+------------------+-------+
| log_slow_queries | ON    |
| slow_launch_time | 2     |
+------------------+-------+

mysql&gt; show global status like '%slow%';
+---------------------+-------+
| Variable_name       | Value |
+---------------------+-------+
| Slow_launch_threads | 0     |
| Slow_queries        | 4148 |
+---------------------+-------+</pre>
</blockquote>
<p>配置中打开了记录慢查询，执行时间超过2秒的即为慢查询，系统显示有4148个慢查询，你可以分析慢查询日志，找出有问题的SQL语句，慢查询时间不宜设置过长，否则意义不大，最好在5秒以内，如果你需要微秒级别的慢查询，可以考虑给MySQL打补丁：<a href="http://www.percona.com/docs/wiki/release:start" target="_blank">http://www.percona.com/docs/wiki/release:start</a>，记得找对应的版本。</p>
<p>打开慢查询日志可能会对系统性能有一点点影响，如果你的MySQL是主－从结构，可以考虑打开其中一台从服务器的慢查询日志，这样既可以监控慢查询，对系统性能影响又小。</p>
<p><strong>二、连接数</strong></p>
<p>经常会遇见&#8221;MySQL: ERROR 1040: Too many connections&#8221;的情况，一种是访问量确实很高，MySQL服务器抗不住，这个时候就要考虑增加从服务器分散读压力，另外一种情况是MySQL配置文件中max_connections值过小：</p>
<blockquote>
<pre>mysql&gt; show variables like 'max_connections';
+-----------------+-------+
| Variable_name   | Value |
+-----------------+-------+
| max_connections | 256   |
+-----------------+-------+</pre>
</blockquote>
<p>这台MySQL服务器最大连接数是256，然后查询一下服务器响应的最大连接数：</p>
<blockquote>
<pre>mysql&gt; show global status like 'Max_used_connections';
+----------------------+-------+
| Variable_name        | Value |
+----------------------+-------+
| Max_used_connections | 245   |
+----------------------+-------+</pre>
</blockquote>
<p>MySQL服务器过去的最大连接数是245，没有达到服务器连接数上限256，应该没有出现1040错误，比较理想的设置是：</p>
<blockquote><p>Max_used_connections / max_connections  * 100% ≈ 85%</p></blockquote>
<p>最大连接数占上限连接数的85％左右，如果发现比例在10%以下，MySQL服务器连接数上限设置的过高了。</p>
<p><strong>三、Key_buffer_size</strong></p>
<p>key_buffer_size是对MyISAM表性能影响最大的一个参数，下面一台以MyISAM为主要存储引擎服务器的配置：</p>
<blockquote>
<pre>mysql&gt; show variables like 'key_buffer_size';
+-----------------+------------+
| Variable_name   | Value      |
+-----------------+------------+
| key_buffer_size | 536870912 |
+-----------------+------------+</pre>
</blockquote>
<p>分配了512MB内存给key_buffer_size，我们再看一下key_buffer_size的使用情况：</p>
<blockquote>
<pre>mysql&gt; show global status like 'key_read%';
+------------------------+-------------+
| Variable_name          | Value       |
+------------------------+-------------+
| Key_read_requests      | 27813678764 |
| Key_reads              | 6798830     |
+------------------------+-------------+</pre>
</blockquote>
<p>一共有27813678764个索引读取请求，有6798830个请求在内存中没有找到直接从硬盘读取索引，计算索引未命中缓存的概率：</p>
<blockquote><p>key_cache_miss_rate ＝ Key_reads / Key_read_requests * 100%</p></blockquote>
<p>比如上面的数据，key_cache_miss_rate为0.0244%，4000个索引读取请求才有一个直接读硬盘，已经很BT了，key_cache_miss_rate在0.1%以下都很好（每1000个请求有一个直接读硬盘），如果key_cache_miss_rate在0.01%以下的话，key_buffer_size分配的过多，可以适当减少。</p>
<p>MySQL服务器还提供了key_blocks_*参数：</p>
<blockquote>
<pre>mysql&gt; show global status like 'key_blocks_u%';
+------------------------+-------------+
| Variable_name          | Value       |
+------------------------+-------------+
| Key_blocks_unused      | 0           |
| Key_blocks_used        | 413543      |
+------------------------+-------------+</pre>
</blockquote>
<p>Key_blocks_unused表示未使用的缓存簇(blocks)数，Key_blocks_used表示曾经用到的最大的blocks数，比如这台服务器，所有的缓存都用到了，要么增加key_buffer_size，要么就是过渡索引了，把缓存占满了。比较理想的设置：</p>
<blockquote><p>Key_blocks_used / (Key_blocks_unused + Key_blocks_used) * 100% ≈ 80%</p></blockquote>
<p><strong>四、临时表</strong></p>
<blockquote>
<pre>mysql&gt; show global status like 'created_tmp%';
+-------------------------+---------+
| Variable_name           | Value   |
+-------------------------+---------+
| Created_tmp_disk_tables | 21197   |
| Created_tmp_files       | 58      |
| Created_tmp_tables      | 1771587 |
+-------------------------+---------+</pre>
</blockquote>
<p>每次创建临时表，Created_tmp_tables增加，如果是在磁盘上创建临时表，Created_tmp_disk_tables也增加,Created_tmp_files表示MySQL服务创建的临时文件文件数，比较理想的配置是：</p>
<blockquote>
<pre>Created_tmp_disk_tables / Created_tmp_tables * 100% &lt;= 25%</pre>
</blockquote>
<p>比如上面的服务器Created_tmp_disk_tables / Created_tmp_tables * 100% ＝ 1.20%，应该相当好了。我们再看一下MySQL服务器对临时表的配置：</p>
<blockquote>
<pre>mysql&gt; show variables where Variable_name in ('tmp_table_size', 'max_heap_table_size');
+---------------------+-----------+
| Variable_name       | Value     |
+---------------------+-----------+
| max_heap_table_size | 268435456 |
| tmp_table_size      | 536870912 |
+---------------------+-----------+</pre>
</blockquote>
<p>只有256MB以下的临时表才能全部放内存，超过的就会用到硬盘临时表。</p>
<p><strong>五、Open Table情况</strong></p>
<blockquote>
<pre>mysql&gt; show global status like 'open%tables%';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| Open_tables   | 919   |
| Opened_tables | 1951  |
+---------------+-------+</pre>
</blockquote>
<p>Open_tables表示打开表的数量，Opened_tables表示打开过的表数量，如果Opened_tables数量过大，说明配置中table_cache(5.1.3之后这个值叫做table_open_cache)值可能太小，我们查询一下服务器table_cache值：</p>
<blockquote>
<pre>mysql&gt; show variables like 'table_cache';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| table_cache   | 2048  |
+---------------+-------+</pre>
</blockquote>
<p>比较合适的值为：</p>
<blockquote><p>Open_tables / Opened_tables  * 100% &gt;= 85%<br />
Open_tables / table_cache * 100% &lt;= 95%</p></blockquote>
<p>待续，本文参考以下网页：</p>
<p>1.<a href="http://dev.mysql.com/doc/refman/5.1/en/server-status-variables.htm" target="_blank">http://dev.mysql.com/doc/refman/5.1/en/server-status-variables.htm</a></p>
<p>2.<a href="http://dev.mysql.com/doc/refman/5.1/en/server-system-variables.html" target="_blank">http://dev.mysql.com/doc/refman/5.1/en/server-system-variables.html</a></p>
<p>3.<a href="http://www.ibm.com/developerworks/cn/linux/l-tune-lamp-3.html" target="_blank">http://www.ibm.com/developerworks/cn/linux/l-tune-lamp-3.html</a></p>
<p>4.<a href="http://www.day32.com/MySQL/tuning-primer.sh" target="_blank">http://www.day32.com/MySQL/tuning-primer.sh</a> 具体数值主要参考此工具</p>
]]></content:encoded>
			<wfw:commentRss>http://www.fuchaoqun.com/2009/03/mysql-tuning-by-status/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>你可能不知道的MySQL</title>
		<link>http://www.fuchaoqun.com/2009/03/something-you-may-do-not-know-about-mysql/?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=something-you-may-do-not-know-about-mysql</link>
		<comments>http://www.fuchaoqun.com/2009/03/something-you-may-do-not-know-about-mysql/#comments</comments>
		<pubDate>Wed, 11 Mar 2009 09:53:15 +0000</pubDate>
		<dc:creator>超群.com</dc:creator>
				<category><![CDATA[MySQL]]></category>
		<category><![CDATA[Performance]]></category>
		<category><![CDATA[Tuning]]></category>

		<guid isPermaLink="false">http://chaoqun.17348.com/?p=179</guid>
		<description><![CDATA[前言： 实验的数据表如下定义： mysql&#62; desc tbl_name; +-------+--------------+------+-----+---------+-------+ &#124; Field &#124; Type         &#124; Null &#124; Key &#124; Default &#124; Extra &#124; +-------+--------------+------+-----+---------+-------+ &#124; uid   &#124; int(11)      &#124; NO   &#124;     &#124; NULL    &#124;       &#124; &#124; sid   &#124; mediumint(9) &#124; NO   &#124;     &#124; NULL    &#124;       &#124; &#124; times &#124; mediumint(9) &#124; NO   &#124;     &#124; NULL    &#124;       &#124; +-------+--------------+------+-----+---------+-------+ 3 [...]]]></description>
			<content:encoded><![CDATA[<p><strong>前言：</strong></p>
<p>实验的数据表如下定义：</p>
<blockquote>
<pre>mysql&gt; desc tbl_name;
+-------+--------------+------+-----+---------+-------+
| Field | Type         | Null | Key | Default | Extra |
+-------+--------------+------+-----+---------+-------+
| uid   | int(11)      | NO   |     | NULL    |       |
| sid   | mediumint(9) | NO   |     | NULL    |       |
| times | mediumint(9) | NO   |     | NULL    |       |
+-------+--------------+------+-----+---------+-------+
3 rows in set (0.00 sec)</pre>
</blockquote>
<p>存储引擎是MyISAM，里面有10,000条数据。</p>
<p><strong>一、&#8221;\G&#8221;的作用</strong></p>
<blockquote>
<pre>mysql&gt; select * from tbl_name limit 1;
+--------+--------+-------+
| uid    | sid    | times |
+--------+--------+-------+
| 104460 | 291250 |    29 |
+--------+--------+-------+
1 row in set (0.00 sec)

mysql&gt; select * from tbl_name limit 1<span style="color: #ff0000;">\G</span>;
*************************** 1. row ***************************
  uid: 104460
  sid: 291250
times: 29
1 row in set (0.00 sec)</pre>
</blockquote>
<p>有时候，操作返回的列数非常多，屏幕不能一行显示完，显示折行，试试&#8221;\G&#8221;，把列数据逐行显示（&#8221;\G&#8221;挽救了我，以前看explain语句横向显示不全折行看起来巨费劲，还要把数据和列对应起来）。</p>
<p><strong>二、&#8221;Group by&#8221;的&#8221;隐形杀手&#8221;</strong></p>
<blockquote>
<pre>mysql&gt; explain select uid,sum(times) from tbl_name group by uid\G;
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: tbl_name
         type: ALL
possible_keys: NULL
          key: NULL
      key_len: NULL
          ref: NULL
         rows: 10000
        Extra: Using temporary; <span style="color: #ff0000;">Using filesort</span>
1 row in set (0.00 sec)

mysql&gt; explain select uid,sum(times) from tbl_name group by uid <span style="color: #ff0000;">order by null</span>\G;
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: tbl_name
         type: ALL
possible_keys: NULL
          key: NULL
      key_len: NULL
          ref: NULL
         rows: 10000
        Extra: Using temporary
1 row in set (0.00 sec)</pre>
</blockquote>
<p>默认情况下，Group by col会对col字段进行排序，这就是为什么第一语句里面有Using filesort的原因，如果你不需要对col字段进行排序，加上order by null吧，要快很多，因为filesort很慢的。</p>
<p><strong>三、大批量数据插入</strong></p>
<p>最高效的大批量插入数据的方法：</p>
<blockquote><p>load data infile &#8216;/path/to/file&#8217; into table tbl_name;</p></blockquote>
<p>如果没有办法先生成文本文件或者不想生成文本文件，可以一次插入多行：</p>
<blockquote><p>insert into tbl_name values (1,2,3),(4,5,6),(7,8,9)&#8230;</p></blockquote>
<p>注意一条sql语句的最大长度是有限制的。如果还不想这样，可以试试MySQL的<a href="http://dev.mysql.com/doc/refman/5.0/en/sql-syntax-prepared-statements.html" target="_blank">prepare</a>，应该都会比硬生生的逐条插入要快许多。</p>
<p>如果数据表有索引，建议先暂时禁用索引：</p>
<blockquote><p>alter table tbl_name disable keys;</p></blockquote>
<p>插入完毕之后再激活索引：</p>
<blockquote><p>alter table tbl_name enable keys;</p></blockquote>
<p>对MyISAM表尤其有用。避免每插入一条记录系统更新一下索引。</p>
<p><strong>四、最快复制表结构方法</strong></p>
<blockquote><p>mysql&gt; create table clone_tbl select * from tbl_name limit 0;<br />
Query OK, 0 rows affected (0.08 sec)</p></blockquote>
<p>只会复制表结构，索引不会复制，如果还要复制数据，把limit 0去掉即可。</p>
<p><strong>五、加引号和不加引号区别</strong></p>
<p>给数据表tbl_name添加索引：</p>
<blockquote><p>mysql&gt; create index uid on tbl_name(uid);</p></blockquote>
<p>测试如下查询：</p>
<blockquote>
<pre>mysql&gt; explain select * from tbl_name where uid = '1081283900'\G;
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: tbl_name
         type: ref
possible_keys: uid
          key: uid
      key_len: 4
          ref: const
         rows: 143
        Extra:
1 row in set (0.00 sec)</pre>
</blockquote>
<p>我们在整型字段的值上加索引，是可以用到索引的，网上不少人误传在整型字段上加引号无法使用索引。修改uid字段类型为varchar(12):</p>
<blockquote><p>mysql&gt; alter table tbl_name change uid uid varchar(12) not null;</p></blockquote>
<p>测试如下查询：</p>
<blockquote>
<pre>mysql&gt; explain select * from tbl_name where uid = 1081283900\G;
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: tbl_name
         type: ALL
possible_keys: uid
          key: NULL
      key_len: NULL
          ref: NULL
         rows: 10000
        Extra: Using where
1 row in set (0.00 sec)</pre>
</blockquote>
<p>我们在查询值上不加索引，结果索引无法使用，注意安全。</p>
<p><strong>六、前缀索引</strong></p>
<p>有时候我们的表中有varchar(255)这样的字段，而且我们还要对该字段建索引，一般没有必要对整个字段建索引，建立前8~12个字符的索引应该就够了，很少有连续8~12个字符都相等的字段。</p>
<p>为什么？更短的索引意味索引更小、占用CPU时间更少、占用内存更少、占用IO更少和很更好的性能。</p>
<p><strong>七、MySQL索引使用方式</strong></p>
<p>MySQL在一个查询中只能用到一个索引（5.0以后版本引入了index_merge合并索引，对某些特定的查询可以用到多个索引，具体查考[<a href="http://dev.mysql.com/doc/refman/5.1/zh/optimization.html#index-merge-optimization" target="_blank">中文</a>] [<a href="http://dev.mysql.com/doc/refman/5.0/en/index-merge-optimization.html" target="_blank">英文</a>]），所以要根据查询条件建立联合索引，联合索引只有第一位的字段在查询条件中能才能使用到。</p>
<p>如果MySQL认为不用索引比用索引更快的话，那么就不会用索引。</p>
<blockquote>
<pre>mysql&gt; create index times on tbl_name(times);
Query OK, 10000 rows affected (0.10 sec)
Records: 10000  Duplicates: 0  Warnings: 0

mysql&gt; explain select * from tbl_name where times &gt; 20\G;
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: tbl_name
         type: ALL
possible_keys: times
          key: NULL
      key_len: NULL
          ref: NULL
         rows: 10000
        Extra: Using where
1 row in set (0.00 sec)

mysql&gt; explain select * from tbl_name where times &gt; 200\G;
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: tbl_name
         type: range
possible_keys: times
          key: times
      key_len: 3
          ref: NULL
         rows: 1599
        Extra: Using where
1 row in set (0.00 sec)</pre>
</blockquote>
<p>数据表中times字段绝大多数都比20大，所以第一个查询没有用索引，第二个才用到索引。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.fuchaoqun.com/2009/03/something-you-may-do-not-know-about-mysql/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
	</channel>
</rss>
<!-- WP Super Cache is installed but broken. The path to wp-cache-phase1.php in wp-content/advanced-cache.php must be fixed! -->