第七星尘的独立博客

SAE开发:利用memcache优化数据库读取

        SAE调整了新收费规则后,mysql变成了按次数收费(之前是按CPU时间收费)。本文将与大家共同探讨如何利用memcache来优化数据库读取,减少mysql读取次数,降低成本的同时增加程序效率。
        适读人群:具有初级以及初级以上开发能力的PHP开发者。
        开始前,请记住我们要做的是:减少mysql读取次数。
        Memcache是SAE为开发者提供的分布式缓存服务,用来以共享的方式缓存用户的小数据。它速度快,云豆消耗低,存储简单,因此非常适合用来缓存数据库读取结果。
在一般应用中,我们最常用的是两种数据库查询:一种是读取单表的一条记录,一种是读取单表的多条记录。针对这两种情况,我们可以做专门封装两个数据库操作函数:一个是快速读取单条记录get_row(),一个是读取多条记录get_rows();然后,我们在这两个函数的基础上,再封装成另一个使用了memcache的函数。看下面代码(配合注释看):
<?PHP
$GLOBALS['mmc'] = memcache_init();//初始化memcache
db_connect();//连接数据库
//连接数据库函数
function db_connect()
{
$conn=mysql_connect( SAE_MYSQL_HOST_M.":".SAE_MYSQL_PORT,SAE_MYSQL_USER,SAE_MYSQL_PASS);
$db_s=mysql_select_db(SAE_MYSQL_DB);
if($db_s)return $conn;
else return false;
}
//根据字段快速返回一条记录数组
function get_row($value="uid",$field="uid",$table="users")
{
$sql="select * from $table where $field='$value' limit 1 ";
$result=mysql_query($sql);
if(mysql_num_rows($result))
{
$row=mysql_fetch_array($result);
if($row){return $row;}
}
return false;
}
//运行Sql,以多维数组方式返回结果集
function get_rows($sql){
$ary=array();
$result=mysql_query($sql);
if(mysql_num_rows($result))
{
while($row=mysql_fetch_array($result))
{
$ary[]=$row;
}
}
return $ary;
}
//使用了Mencache的get_row()。默认缓存24小时
function get_row_cache($value,$field,$table,$time = 86400)
{
$row=memcache_get($GLOBALS['mmc'], 'row_cache_'.$value.$field.$table);
if(!$row)//如果这个值非真,即为空的话,则从数据库读取
{
$row = get_row($value,$field,$table);
if($row){
$ret = memcache_set($GLOBALS['mmc'],'row_cache_'.$value.$field.$table, $row , 0, $time);//写进mc,默认有效期为24小时
}
}
return $row;
}
//使用了Mencache的get_rows()。默认缓存24小时
function get_rows_cache($sql ,$time = 86400)
{
$sql2 = base64_encode($sql);
$rows = memcache_get($GLOBALS['mmc'], 'rows_cache_'.$sql2);
if(!$rows)//如果这个值非真,即为空的话,则从数据库读取
{
$rows = get_rows($sql);
if($rows)memcache_set($GLOBALS['mmc'],'rows_cache_'.$sql2, $rows , 0, $time);//写进mc,默认有效期为24小时
}
return $rows;
}
//删除 get_row_cache()的缓存
function delete_row_cache($value,$field,$table)
{
memcache_delete($GLOBALS['mmc'], 'row_cache_'.$value.$field.$table);
}
//删除 get_rows_cache()的缓存
function delete_rows_cache($sql)
{
$sql2 = base64_encode($sql);
memcache_delete($GLOBALS['mmc'], 'rows_cache_'.$sql2);
}
    以后调用的时候,只需要使用函数get_row_cache()和get_rows_cache()即可。更新缓存的时候可以调用delete_row_cache()和delete_rows_cache().
别以为有了代码,我们的优化目标就达到了。代码只是技术实现手段,真正重要的是它背后的策略。甚至说哪位朋友把我上面的代码用另一种方式重写也毫无压力。我想在这里分享的不只是代码,还有优化策略。
    1、“重新生成缓存”这一步操作,要放到get_row_cache()里面,而不是delete_row_cache()里。有同学习惯在删除缓存的同时生成缓存。这是有风险的。因为memcache有几率会丢失数据,或者被后台清空。把“重新生成缓存”放在get_row_cache()里,可以避免memcache里没有数据的风险(没有数据的时候,程序会在get_row_cache()里重新生成缓存)
        2、get_row_cache()不要用来判断数据库某条记录存在不存在。例如可能有同学在程序中,需要判断网站用户是否在黑名单里。于是就调用get_row_cache()来判断uid是否存在backlist表里。这会拖慢效率的,因为memcache命中率太低,程序需要读取memcache的同时又要读取一次数据库
    3、像判断黑名单这种情况,如果backlist表不超过1M,则可以调用get_rows_cache()把整张backlist表都读进memcache里。以后判断用户是否处于黑名单的时候可以读取memcache里面的backlist表,然后用简单的数组循环foreach()判断便可知道用户是否存在黑名单中。另外不要忘记了,每次添加或者解除黑名单用户的时候不要忘了调用delete_rows_cache()
        4、利用第3点的思想,可以类推到很多地方。例如论坛发帖时的关键字过滤。可以把关键字都加载到memcache中再比较(同时,在代码中比较,cpu消耗不用云豆)
    5、上面说了多条记录的缓存。忘记了单条记录的缓存。单条记录缓存get_row_cache()适合的情况很多。举几个例子。(1)读取公告。根据公告id和缓存公告内容。因为网站公告通常都是每个页面都读取的,所以读取进缓存最适合了。(2)、读取用户资料。用户进网站后,直接读取用户资料并放进缓存
 如无特殊说明,本站皆为原创。转载请注明来自第七星尘的独立博客《SAE开发:利用memcache优化数据库读取》

评论

  1. DlaireTang #1

    现在最好还是用redis

    回复
    2014-09-21
  2. 周良 #2

    Good ! 可以剩下一部分豆了~~另外,wordpress主题不错。曾经我的作品。哈哈

    回复
    2013-12-31
    • 第七星尘

      这个主题比较简约,小清新,所以我就用了~

      回复
      2013-12-31
      • 周良

        哈哈。主题已经不怎么兼容最新的wp了。估计你一升级,就全部挂掉了~

        回复
        2013-12-31