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

<channel>
	<title>潘锦的空间 &#187; 工作事记</title>
	<atom:link href="https://www.phppan.com/tag/%e5%b7%a5%e4%bd%9c%e4%ba%8b%e8%ae%b0/feed/" rel="self" type="application/rss+xml" />
	<link>https://www.phppan.com</link>
	<description>SaaS SaaS架构 团队管理 技术管理 技术架构 PHP 内核 扩展 项目管理</description>
	<lastBuildDate>Sun, 10 May 2026 02:26:45 +0000</lastBuildDate>
	<language>zh-CN</language>
		<sy:updatePeriod>hourly</sy:updatePeriod>
		<sy:updateFrequency>1</sy:updateFrequency>
	<generator>https://wordpress.org/?v=3.9.40</generator>
	<item>
		<title>一次查询优化过程</title>
		<link>https://www.phppan.com/2012/01/query-optimization/</link>
		<comments>https://www.phppan.com/2012/01/query-optimization/#comments</comments>
		<pubDate>Sun, 15 Jan 2012 01:07:19 +0000</pubDate>
		<dc:creator><![CDATA[admin]]></dc:creator>
				<category><![CDATA[程序相关]]></category>
		<category><![CDATA[优化]]></category>
		<category><![CDATA[工作事记]]></category>

		<guid isPermaLink="false">http://www.phppan.com/?p=1586</guid>
		<description><![CDATA[问题描述 在正在维护的系统中有一个数据分析的模块，用于来分析一些用户访问的数据。其中有一个操作是查找某URL地 [&#8230;]]]></description>
				<content:encoded><![CDATA[<h2>问题描述</h2>
<p>在正在维护的系统中有一个数据分析的模块，用于来分析一些用户访问的数据。其中有一个操作是查找某URL地址对应的ID。在这里ID与URL是存储MySQL数据的一个表中，此表就两个字段，id,url.表存储引擎类型MyISAM，当然URL字段是加了索引的。现在每天按小时定时分析数据，开始程序没有问题，当几年的数据积累下来，特别是最近业务量增加时，明显感觉到程序的执行过程变得很漫长，通过xdebug分析一次执行过程的所有执行时间，发现瓶颈在于前面所提到的通过URL地址对应的ID。下面就开始了漫长的优化之路。</p>
<style>
.entry p {margin:13px 5px 0 5px;}
</style>
<p></p>
<h3>第一次优化：优化细节，针对特殊地址的优化</h3>
<p>由于应急，先考虑一些细节的调整：<br />
首先，我们针对一些特殊的地址进行了处理，直接返回ID，比如没有URL的情况，比如Google的首页地址；<br />
然后，我们针对一些常见的地址作为Hash存储，以及一些热数据进行内存缓存。</p>
<p>结果，提高一些性能，能满足当时的业务需求，特别是当特殊的地址较多的时候，其情况还是非常乐观的。</p>
<p>过了一段时间，到了另一个高峰点，发现此分析模块仍然会时不时的出些问题，导致数据不准确，各种情况，各种应付&#8230;不得已，开始思考另一个方案。</p>
<p></p>
<h3>第一个方案： key-value数据库</h3>
<p> 依据前面的对于热点数据，将其存储到内存缓存的思路，我们考虑是否将所有数据都作为热点数据，于是先做前期预研，将部分数据导到redis中，发现速度有了极大的提升，大概在500倍的一个量级，那叫一个激动，于是决定将所有数据都迁移到redis中，想法是美好的，结果是不言而喻的。失败了。为什么呢？很简单，没资源，我们没有那么大的内存存储N个上千万的表。</p>
<p></p>
<h3>第二个方案：基于单词查找树的文件结构</h3>
<p>从前面的key-value数据库方案看，存储url到id的映射，在实现思路上还是可行的，于是开动了小心思，既然内存不够用，那么用硬盘呢？</p>
<p>这个既便宜又实惠，是居家旅行，杀人越货的必备良品。于是计划以URL的主域名为目录，以每个地址的md5值为文件名，每个文件存储这个地址对应的ID。考虑到域名可能很多，于是计划使用变形的单词查找树来设置多级目录，但是当域名地址太长时，文件系统在生成目录的时候会出错，只得去掉单词查找树，使用某种简单的按主域名转化后的字符串转建立目录。在预研时，先生成了5万数据的文件结构，发现生成的速率很慢，并且由于大量小文件的生成，对于整个目录的查询会很慢，但对于单个文件的读取还是很快的，然而将随着数据生成越来越多，当达到40万时，整个目录占用了大概4G+的硬盘空间。</p>
<p>假想一下，当1千万的数据以这种方式存储到硬盘上，会是多少？如果数据持续增加呢？到达一个亿呢？感觉到不靠谱了。于是继续想下一种方案，这个方案继续执行。</p>
<p></p>
<h3>第三个方案：信赖于数据库，增加md5值存储的字段</h3>
<p>在第二种方案中，我们是使用md5值作为文件名，在想在数据库对于md5后的文件名的查找会更快一些呢？在ID和URL映射表中，增加一个字段url_md5，存储url使用md5后的值，在这里我们直接使用MySQL的md5函数更新表数据，测试后，发现其速度有了显著提升，单个查找操作大概能提升50倍+。整体性能提升5倍的样子。于是，果断采用此方案，结果是该分析模块一直没啥事发生。(^_^)</p>
<p></p>
<h3>总结</h3>
<ol>
<li>不要过早优化</li>
<li>优化要先找瓶颈</li>
<li>数据结构和对工具的使用很重要</li>
<li>优化时需要理清问题的根本原因是什么，最好能到理论层面或实现原理层面。</li>
</ol>
]]></content:encoded>
			<wfw:commentRss>https://www.phppan.com/2012/01/query-optimization/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
