老张小站

  1. 欢迎光临

    感谢访问老张的博客!

  • 1
1,105

Discuz! X3 设置关联版块后页面执行时间大幅增加的解决方案

分类 网站技术/村民张先生 发布于 2019-12-16 20:09
0

设置版块1关联显示版块2的内容后,通过debug发现相关sql语句执行时间较长:

0.069625s • DBLink 1 • source/class/table/table_forum_thread.php

SELECT * FROM pre_forum_thread WHERE `fid` IN('1','2') AND `displayorder`='0' ORDER BY lastpost DESC LIMIT 450, 30

Using index condition; Using filesort

未设置关联时,执行时间如下:

0.001567s • DBLink 1 • source/class/table/table_forum_thread.php

SELECT * FROM pre_forum_thread WHERE `fid`='1' AND `displayorder`='0' ORDER BY lastpost DESC LIMIT 450, 30

关联版块后该行执行时间延长了40+倍!加上读取文件的时间,总执行时间可能达到0.1s以上。

搜索了大量“Using filesort”的解决方案,都未能解决,最后借鉴“八宝旗”(https://www.oschina.net/question/139841_122508?sort=default&p=2 回复中)的方法修改了一下查询语句,执行时间已大大改善。

打开 source/module/forum/forum_forumdisplay.php 文件,查找:

	$threadlist = array_merge($threadlist, C::t('forum_thread')->fetch_all_search($filterarr, $tableid, $start_limit, $_G['tpp'], $_order, '', $indexadd));

替换为:

	if((is_array($filterarr['inforum']) || is_array($filterarr['displayorder'])) && $_GET['orderby'] == 'lastpost' && !$_GET['typeid'] && !$filterarr['digest'] && $_G['page'] <= 15) {
		$table_name = $tableid ? 'forum_thread_'.intval($tableid) : 'forum_thread'; //分表名
		$union_orderby = ' ORDER BY '.$_order; //排序
		$union_limit = ' LIMIT '.($_G['tpp'] * $_G['page']); //查询的帖量
		$countInforum = count($filterarr['inforum']); //统计查询的fid数量
		$countDisplayorder = count($filterarr['displayorder']); //统计displayorder数量
		if(is_array($filterarr['inforum']) && is_array($filterarr['displayorder'])) {
			for($i = 0; $i < $countInforum; $i++) {
				for($d = 0; $d < $countDisplayorder; $d++) {
					$union .= '(SELECT * FROM pre_forum_thread  WHERE `fid`='.$filterarr['inforum'][$i].' AND `displayorder`='.$filterarr['displayorder'][$d].$union_orderby.$union_limit.') UNION ALL ';
				}
			}
		} elseif(is_array($filterarr['inforum'])) {
			for($i = 0; $i < $countInforum; $i++) {
				$union .= '(SELECT * FROM pre_forum_thread  WHERE `fid`='.$filterarr['inforum'][$i].' AND `displayorder`='.$filterarr['displayorder'].$union_orderby.$union_limit.') UNION ALL ';
			}
		} else {
			for($d = 0; $d < $countDisplayorder; $d++) {
				$union .= '(SELECT * FROM pre_forum_thread  WHERE `fid`='.$filterarr['inforum'].' AND `displayorder`='.$filterarr['displayorder'][$d].$union_orderby.$union_limit.') UNION ALL ';
			}
		}
		$union = substr($union, 0, -11);
		$threadlist = array_merge($threadlist, DB::fetch_all('SELECT * FROM ('.$union.') AS t'.$union_orderby.DB::limit($start_limit, $_G['tpp'])));
		unset($table_name, $union_orderby, $union_limit, $countInforum, $countDisplayorder, $union);
	} else {
		$threadlist = array_merge($threadlist, C::t('forum_thread')->fetch_all_search($filterarr, $tableid, $start_limit, $_G['tpp'], $_order, '', $indexadd));
	}

说明:第一行中的 $_G['page'] 页数不建议设置过大,因为分拆出来的每一个查询都要取 页数*每页帖量 条数的数据,太多会影响执行效率。我这里设置为15,表示版块前15页使用上述自定义查询语句,后面的页数使用官方原有语句。

最后,由于上述代码包含 (selectUNION ALL ,Discuz! X 默认禁止这样的查询语句,会提示“It is not safe to do this query”,可暂停对这两项的安全检查。

打开 config/config_global.php ,注释以下两项:

//$_config['security']['querysafe']['daction']['3'] = '(select';
//$_config['security']['querysafe']['daction']['4'] = 'unionall';
欢迎转载分享,转载请注明 来源:大张小站 https://www.zhang.cq.cn/20192234.html
若您喜欢这篇文章,欢迎订阅老张小站以获得最新内容。 / 欢迎交流探讨,请发电子邮件至 mail[at]vdazhang.com 。


欢迎谈谈你的看法(无须登录) *正文中请勿包含"http://"否则将被拦截