Discuz教程网

论坛的INNODB方案

[复制链接]
authicon dsf22gs 发表于 2013-1-30 23:43:57 | 显示全部楼层 |阅读模式
论坛INNODB方案的探讨


大型论坛的现状

discuz!阵营里不乏日PV百万以及过千万级别超级大站,而X系列推出后为了适应这种大站的需求也在底层做了很多改动,比如内存级缓存的加强,分布式部署的支持,内置的分表等,但仍然存在可以优化的空间,比如用服务器cron来代替论坛的模拟计划任务,innodb存储引擎的使用等,这些建议虽然由于目前的一些条件限制不能全面发布,但是我们可以在私下进行探索。


INNODB的使用限制

升级到X2.5后,post表的主键由pid改成(tid,position)的联合主键。

154354ngu2cp42gr22ozu2.png




154354ngu2cp42gr22ozu2.png





由于新联合主键的作用,在翻页性能上得到极大提升,但是一些先前在X2使用innodb引擎的论坛却发现论坛在X2.5下出现了大量空楼层的情况。

154354ngu2cp42gr22ozu2.png





而且由于联合主键的作用,使得用户的楼层在某些情况下可能出现变动,所以抢沙发等插件也不再生效了。


MYISAM的局限


MYISAMdiscuz!论坛的数据库默认引擎,是一种高效简单的解决方案。

不过MYISAM只支持表级锁定,每一个写操作都会锁定整个表,大型论坛尤其是在发起抢楼贴之后很可能出现如下情况。

154354ngu2cp42gr22ozu2.png





大量用户同时发帖和读帖,由于写操作优先级大于读操作,post表首先处理写操作,给表上一个写锁。

同时其他大量写操作也在请求,由于表已经锁了,所以把锁定请求写在写锁定队列里。

这时候对于读操作来说,由于表锁定使得许多线程同时从一个表中进行读操作,但线程在操作表的时候必须首先获得独占访问,所以只能把锁请求放到读锁队列。而大量读操作在后面等候表锁定释放,超过脚本时间就会显示错误。或者打开帖子时巨慢。

为了缓解这个问题,discuzX系列在插入新帖子的时候使用了 LOW_PRIORITY关键字来降低写操作的优先级,使得读操作能更顺利。

另外后台内置了分表功能,当一个表数据行过多时可进行分表,能有效降低表锁的概率。



INNODB的爱与恨


理论innodb引擎能实现行级锁。

MYISAM中,假设我的一个表有1KW条数据。然后对某个帖子进行编辑,提交的这一瞬间,MYSQL全表写锁定,这时候发过来的其他任何请求都被阻塞,直到这个写锁定被释放。

而在innodb中,提交的时候只对这一行数据进行锁定。其他不冲突的请求也能同步进行。


INNODB的伪行锁特性

oracle熟悉的人可能会误认为mysql的行锁也是真正的行级锁,锁定时是对数据行上锁,而事实上不是。Innodb的行锁实质上是基于索引来实现的,所以就有很多注意事项。下面来具体说说这个问题。

1. Post表中使用如下语句:UPDATEpre_forum_post SET status=1 WHERE pid=123;

这是真正的行级锁,因为pid是唯一键,索引直接定位到这一行。

2. UPDATE pre_forum_post SETstatus=1 WHERE status=0;

由于status没有索引,所以会导致表锁。

3. UPDATE pre_forum_post SETstatus=1 WHERE pid >1 AND pid config['map']) && !empty(self::$db->config['map'][$table])){
$linkId = self::$db->config['map'][$table];
}
$dbname = self::$db->config[$linkId]['dbname'];
$table = self::$db->table_name($table);

self::$db->select_db('information_schema');
return self::$db->result_first("SELECT TABLE_ROWS FROM `TABLES` WHERE TABLE_SCHEMA = '$dbname' AND TABLE_NAME = '$table'");
}

[/code][/td][/tr][/table]
X2.5文件修改列表

文件名

行数


主要修改


Common_block_permission


55


替换为:

return $where ? DB::result_first('SELECT COUNT(*) FROM '.DB::table($this->_table).$where) : DB::count_all($this->_table);


Common_block_style


34


替换为:

return $wheresql ? DB::result_first('SELECT COUNT(*) FROM '.DB::table($this->_table).$wheresql) : DB::count_all($this->_table);


Common_credit_log


120


替换为:

return $condition[0] ? DB::result_first('SELECT COUNT(*) FROM %t '.$condition[0], $condition[1]) : DB::count_all($this->_table);


Common_diy_data


51


替换为:

return $wheresql ? DB::result_first('SELECT COUNT(*) FROM '.DB::table($this->_table).$wheresql) : DB::count_all($this->_table);


Common_invite


63


替换为:

return $condition[0] ? DB::result_first('SELECT COUNT(*) FROM %t '.$condition[0], $condition[1]) : DB::count_all($this->_table);


Common_member


170,174,350,354


分别替换为:

$count = DB::count_all($this->_table);

$count += intval(DB::count_all('common_connect_guest'));

if(!DB::fetch_first('SELECT * FROM '.$temptablename.' LIMIT 1')) {

if(DB::fetch_first('SELECT * FROM '.$temptablename.' LIMIT 1')) {


Common_member_archive


48


替换为:

return isset($this->membersplit) ? DB::count_all($this->_table) : 0;


Common_member_verify_info


49


替换为:

return $condition[0] ? DB::result_first('SELECT COUNT(*) FROM %t '.$condition[0], $condition[1]) : DB::count_all($this->_table);


Forum_attachtype


51


替换为:

return $wheresql ? DB::result_first("SELECT COUNT(*) FROM %t $wheresql", $parameter) : DB::count_all($this->_table);


Forum_grouplevel


27


替换为:

return DB::count_all($this->_table);


Forum_medallog


81


替换为:

return $where ? DB::result_first("SELECT COUNT(*) FROM ".DB::table('forum_medallog')." $where") : DB::count_all($this->_table);


Forum_thread


982,1023,1028


分别替换为:

return $wheresql ? DB::result_first("SELECT COUNT(*) FROM %t $wheresql", $parameter) : DB::count_all($this->_table);

return DB::count_all($this->get_table_name($tableid));

return $condition[0] ? DB::result_first('SELECT COUNT(*) FROM %t '.$condition[0], $condition[1]) : DB::count_all($this->get_table_name());


Home_blacklist


37


替换为:

return $wheresql ? DB::result_first("SELECT COUNT(*) FROM %t $wheresql", $parameter) : DB::count_all($this->_table);


Home_favorite


56


替换为:

return $wheresql ? DB::result_first("SELECT COUNT(*) FROM %t $wheresql ", $parameter) : DB::count_all($this->_table);


Home_follow


100,112


分别替换为:

$count = $wheresql ? DB::result_first("SELECT COUNT(*) FROM %t $wheresql", $parameter) : DB::count_all($this->_table);

$count = $wheresql ? DB::result_first("SELECT COUNT(*) FROM %t $wheresql", $parameter) : DB::count_all($this->_table);


Home_follow_feed


76


替换为:

$count = $wheresql ? DB::result_first("SELECT COUNT(*) FROM %t $wheresql", $parameter) : DB::count_all($this->_table);


Home_friend


104


替换为:

return $wheresql ? DB::result_first('SELECT COUNT(*) FROM %t '.$wheresql, $parameter) : DB::count_all($this->_table);


Home_share


137,158,195


分别替换为:

return $wheresql ? DB::result_first('SELECT COUNT(*) FROM %t '.$wheresql, $parameter) : DB::count_all($this->_table);

return $wheresql ? DB::result_first('SELECT COUNT(*) FROM %t '.$wheresql, $parameter) : DB::count_all($this->_table);

return $wheresql ? DB::result_first('SELECT COUNT(*) FROM %t '.$wheresql, $parameter) : DB::count_all($this->_table);


Portal_topic


25,26


替换为:

$wheresql = empty($wherearr) ? '' : ' WHERE '.implode(' AND ', $wherearr);

return $wheresql ? DB::result_first('SELECT COUNT(*) FROM '.DB::table($this->_table).$wheresql) : DB::count_all($this->_table);


Portal_category_permission


54


替换为:

return $where ? DB::result_first('SELECT COUNT(*) FROM '.DB::table($this->_table).$where) : DB::count_all($this->_table);


注:此表依据17173INNODB转换方案修改。table目录修改的文件列表如附件:table.zip(37.94 KB, 下载次数: 7)



数据库修改:修改除postsession表之外的所有表引擎为INNODB

由于post的联合主键设置,目前暂没有更好的方法。对于这个问题,希望大家能一起提出自己的意见,如果有好的观点也可以通过站内信获取我的联系方式。



上一篇:Discuz X3.0在win虚拟主机下如何?
下一篇:升级x3后 抱歉,您的请求来路不正确或表单验证串不符,无法提...
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

1314学习网 ( 浙ICP备10214163号 )

GMT+8, 2025-5-5 01:26

Powered by Discuz! X3.4

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表