优化你的DiscuzNT 让它跑起来

  去年用DiscuzNT3.0做过二次开拓,做过一些机能优化,可是时间干系一直没时机写下来;趁着5.1长假,来写篇回想性的漫笔吧。

  之前看过园子里代震军同学的博客,知道了老代同学是DiscuzNT团队的一员,从他的博文学了不少对象,我这里写的博文是针对一些问题提出本身的看发息争决方案,针对问题并无针对任何人之意,秉着技能交换的原则。

  DiscuzNT给我的印象是

  1)成果很强大,所有你能想到的根基都已经有了;

  2)机能有待优化,数据量较大的环境会发生机能瓶颈(这也正是写此文的目标)。之前发的博文由于缺乏履历,没有足够的论据,本日会多提供些图文并茂的论据。

  好了,言归正转,开始我们本日的优化之旅。

  本系统情况如下:

  软件情况:DiscuzNT3.0,sqlserver2000,windwos server2003

  数据情况:主贴表dnt_topics约220万笔记录,回覆表3个,dnt_posts1约400万,dnt_posts2约500万,dnt_posts3约500万,附件表约170万,用户表dnt_users约20万,论坛表dnt_forums约5000个论坛;

  现象:看帖时,假如帖子包括附件,会很卡;

  目标:优化看帖速度,尤其是有附件的环境

  动手:看下它是如何获取附件的,找到showtopic.aspx.cs,代码如下:

postlist = Posts.GetPostList(postpramsInfo, out attachmentlist, ismoder == 1);

  再看下 Posts.GetPostList() 要领的代码: 

/// <summary>
/// 获取指定条件的帖子DataSet
/// </summary>
/// <param name="_postpramsinfo">参数列表</param>
/// <returns>指定条件的帖子DataSet</returns>
public static List<ShowtopicPagePostInfo> GetPostList(PostpramsInfo postpramsInfo, out List<ShowtopicPageAttachmentInfo> attachList, bool isModer)
{
List<ShowtopicPagePostInfo> postList = Data.Posts.GetPostList(postpramsInfo);
int adCount = Advertisements.GetInPostAdCount("", postpramsInfo.Fid);

foreach (ShowtopicPagePostInfo postInfo in postList)
{
LoadExtraPostInfo(postInfo, adCount);
}
attachList = new List<ShowtopicPageAttachmentInfo>();
if (postList.Count == 0)
return postList;

string pidList = GetPidListWithAttach(postList);
attachList = Attachments.GetAttachmentList(postpramsInfo, pidList);
ParsePostListExtraInfo(postpramsInfo, attachList, isModer, postList);
return postList;

  从这里可以看出,DiscuzNT是把所有的帖子id组装成“id1,id2,id3,id4”的形式,然后传入数据库,制止多次挪用数据库,这个思路很好,此刻我们顺藤摸瓜,看看它挪用了数据库的剧本,它挪用了这个进程dnt_getattachmentlistbypid,用profiler跟踪这个进程看看机能。

优化你的DiscuzNT 让它跑起来

  看上面的图,execdnt_getattachmentlistbypid@pidlist='5163797'这个剧本的cpu=4531,reads=152641,duration=6156,很可观吧,假如同时有10小我私家来挪用这个进程,预计数据库的压力就大了,假如100人,不可思议。那我们怎么来优化这个进程呢,先看看内里它怎么写的,是否用到了索引。

ALTER PROCEDURE [dnt_getattachmentlistbypid]
@pidlist varchar(500)
AS
SELECT
[aid],
[uid],
[tid],
[pid],
[postdatetime],
[readperm],
[filename],
[description],
[filetype],
[filesize],
[attachment],
[downloads],
[attachprice],
[width],
[height]
FROM [dnt_attachments]
WHERE CHARINDEX(','+RTRIM([dnt_attachments].[pid])+',', ','+@pidlist+',')>0

  这里主要查找的条件是pid,假如在pid列上成立索引,而且进程能用到索引,结果应该会更抱负,这个优化事情我分为如下几步:

  1)pid列上是否有索引;

  2)进程是否用到了索引;

  3)优化sql剧本;

  4)跟踪优化后结果;

  我们一步一个坑往下走:

  1)sp_helpindexdnt_attachments看看是否有索引,如下图,从图中可以看到pid列上是有索引的,假如没有索引,请成立相关索引

优化你的DiscuzNT 让它跑起来

  2)看看是否用到了索引,CTRL+L看看下面语句的执行打算,他用到的索引是PK_dnt_attachments,基础没用到我们期望的pid

优化你的DiscuzNT 让它跑起来

  3)没用到我们期望的索引,那我们就来优化一下;上面的dnt_getattachmentlistbypid进程内里WHERECHARINDEX(','+RTRIM([dnt_attachments].[pid])+',',','+@pidlist+',')>0对pid举办了列运算,这个是祸首罪魁,我们想步伐把这个列运算去掉,这个进程最终改成下面这个样子:

ALTER PROCEDURE [dnt_getattachmentlistbypid]
@pidlist varchar(500)
AS

declare @sql nvarchar(2000)

set @sql = '
SELECT
[aid],
[uid],
[tid],
[pid],
[postdatetime],
[readperm],
[filename],
[description],
[filetype],
[filesize],
[attachment],
[downloads],
[attachprice],
[width],
[height]
FROM [dnt_attachments]
WHERE pid in (' + @pidlist + ')'

exec(@sql)

  4)改完之后我们来跟踪下优化后的机能,看看跟踪结果图(同一个进程,同一个参数,第2个是优化前,第4个是优化后,优化结果灰常满足)

优化你的DiscuzNT 让它跑起来

  至此,我们的优化告一段落。

  原文地点:

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/10748.html