<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>非鱼观点-互联网观察 &#187; 优化</title>
	<atom:link href="http://www.unfish.net/archives/tag/%e4%bc%98%e5%8c%96/feed" rel="self" type="application/rss+xml" />
	<link>http://www.unfish.net</link>
	<description>if(I&#039;m awake){I&#039;m writing code;}else{I&#039;m ready to write code;}</description>
	<lastBuildDate>Wed, 01 Sep 2010 08:57:17 +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>Mysql优化经验之一：奇怪的索引</title>
		<link>http://www.unfish.net/archives/409-20081219.html</link>
		<comments>http://www.unfish.net/archives/409-20081219.html#comments</comments>
		<pubDate>Fri, 19 Dec 2008 05:28:04 +0000</pubDate>
		<dc:creator>非鱼</dc:creator>
				<category><![CDATA[技术文章]]></category>
		<category><![CDATA[mysql]]></category>
		<category><![CDATA[优化]]></category>
		<category><![CDATA[索引]]></category>

		<guid isPermaLink="false">http://www.unfish.net/archives/409-20081219.html</guid>
		<description><![CDATA[自从学会了使用slow-query-log这一招以后，便经常关注一下这个日志里面的内容，执行的太慢的索引总要想办法清理掉不是？昨天晚上搞了三个多小时，才算是搞明白了一点东西。 以前总以为在where和order by所用到的字段上建个索引就OK了，有了索引Mysql就不会去物理数据里进行查询和计算，其实，远远不是这么回事。 在slow-query-log里面出现最多的一类语句是：select * from topics where category_id=1 and createdon&#62;&#8217;2008-12-10&#8242; order by createdon,id limit 6，很简单，不是吗？id是主键，索引当然不用我去关心，category_id和createdon分别建立了索引，可是这条语句执行的还是非常慢。（表里数据10万条，空间450M左右，文章content字段是text，比较大。） 执行explain以后，显示使用的索引是category_id，没有使用createdon，难道mysql执行的时候只能使用一个索引？于是想到建立联合索引，根据网上文章的说明，对于这条语句来说，给category_id和createdon建立联合索引是最有效的，查询和排序的时候都可以用到索引，而且对于where category_id=1 order by createdon这样的语句这个联合索引也是最有效的。于是删除了createdon的索引，给这两个字段建立联合索引，再执行，还是很慢，再explain，索引使用没有问题了，但是Extra里显示using filesort。为什么呢？一位朋友说可能是sort_buffer不够大，加大了这个配置以后无效，还是这样。后来在排序条件中把id删掉，只保留createdon，Extra里就没有using filesort了，测试查询运行时间从0.15秒降到了0.001秒。那好吧，放弃排序字段里的id字段，虽然可能会有搜索出来的内容有点影响，但是并不是什么至关重要的数据。 slow-query-log里出现最多的另一条语句是：select * from dts where (in_id=1 or out_id=1) and createdon&#62;&#8217;2008-12-10&#8242; order by createdon,id limit 1，三个字段分别建立了索引。使用explain查看结果，显示使用的索引是createdon，需要扫描的行数是9万多，（表内数据70万，空间150M左右），但是如果我删除createdon这个条件，只用前面两个or的话，explain显示最终使用的索引是in_id和out_id的union索引，也就是自动联合了两个索引，需要扫描的行数只要25行就能找到结果，执行速度当然不在同一个级别上了。见鬼了，为什么多了一个条件mysql反而会去使用更差的索引呢？ 后来在完整语句的基础上加上use index关键字，select * from dts use index(in_id,out_id) where (in_id=1 or out_id=1) and createdon&#62;&#8217;2008-12-10&#8242; order by createdon,id limit [...]]]></description>
			<content:encoded><![CDATA[<p>自从学会了使用slow-query-log这一招以后，便经常关注一下这个日志里面的内容，执行的太慢的索引总要想办法清理掉不是？昨天晚上搞了三个多小时，才算是搞明白了一点东西。</p>
<p>以前总以为在where和order by所用到的字段上建个索引就OK了，有了索引Mysql就不会去物理数据里进行查询和计算，其实，远远不是这么回事。</p>
<p>在slow-query-log里面出现最多的一类语句是：select * from topics where category_id=1 and createdon&gt;&#8217;2008-12-10&#8242; order by createdon,id limit 6，很简单，不是吗？id是主键，索引当然不用我去关心，category_id和createdon分别建立了索引，可是这条语句执行的还是非常慢。（表里数据10万条，空间450M左右，文章content字段是text，比较大。）</p>
<p>执行explain以后，显示使用的索引是category_id，没有使用createdon，难道mysql执行的时候只能使用一个索引？于是想到建立联合索引，根据网上文章的说明，对于这条语句来说，给category_id和createdon建立联合索引是最有效的，查询和排序的时候都可以用到索引，而且对于where category_id=1 order by createdon这样的语句这个联合索引也是最有效的。于是删除了createdon的索引，给这两个字段建立联合索引，再执行，还是很慢，再explain，索引使用没有问题了，但是Extra里显示using filesort。为什么呢？一位朋友说可能是sort_buffer不够大，加大了这个配置以后无效，还是这样。后来在排序条件中把id删掉，只保留createdon，Extra里就没有using filesort了，测试查询运行时间从0.15秒降到了0.001秒。那好吧，放弃排序字段里的id字段，虽然可能会有搜索出来的内容有点影响，但是并不是什么至关重要的数据。</p>
<p>slow-query-log里出现最多的另一条语句是：select * from dts where (in_id=1 or out_id=1) and createdon&gt;&#8217;2008-12-10&#8242; order by createdon,id limit 1，三个字段分别建立了索引。使用explain查看结果，显示使用的索引是createdon，需要扫描的行数是9万多，（表内数据70万，空间150M左右），但是如果我删除createdon这个条件，只用前面两个or的话，explain显示最终使用的索引是in_id和out_id的union索引，也就是自动联合了两个索引，需要扫描的行数只要25行就能找到结果，执行速度当然不在同一个级别上了。见鬼了，为什么多了一个条件mysql反而会去使用更差的索引呢？</p>
<p>后来在完整语句的基础上加上use index关键字，select * from dts use index(in_id,out_id) where (in_id=1 or out_id=1) and createdon&gt;&#8217;2008-12-10&#8242; order by createdon,id limit 1显示最终使用的索引就是两个id了。但是这条语句是django的ORM自动生成的，我也改不了。后来想到再加一个限定条件上去试试：select * from dts where user_id=1 and (in_id=1 or out_id=1) and createdon&gt;&#8217;2008-12-10&#8242; order by createdon,id limit 1，结果显示最终使用的索引就变成了user_id，虽然不如使用两个id的union index效果更好，但是已经远远好于createdon的索引了，需要扫描300多行取得结果。整条语句的实际执行时间从1.8秒缩短到0.0015秒。</p>
<p>问题虽然已经解决，原理却不甚清晰，是否有更好的解决方案也不知道，还得再研究研究，测试测试。</p>
<p><a class="a2a_dd addtoany_share_save" href="http://www.addtoany.com/share_save"><img src="http://www.unfish.net/wp-content/plugins/add-to-any/share_save_171_16.png" width="171" height="16" alt="Share/Bookmark"/></a> </p>]]></content:encoded>
			<wfw:commentRss>http://www.unfish.net/archives/409-20081219.html/feed</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
	</channel>
</rss>
