CNBlogsDottext Beta2 的性能杀手之SiteCategory.ascx

如果你在使用CNBlogsDottext Beta2代码搭建BLOG站点,如果你的打开首页时每次都很慢,那就继续往下看。

~/AggSite/SiteCategory.ascx就是首页左边第二栏的“网站分类”控件,代码文件是~/AggSite/SiteCategory.ascx.cs。

http://wuchang.cnblogs.com
qq:3263262

现在来看看这个控件究竟是如何成为性能杀手的。

先来看看.ascx部分代码


< asp:Repeater  ID ="CategoryLevel1"  runat ="server" >
< ItemTemplate >
< li >
< asp:HyperLink  runat ="server"  ID ="Link"  NavigateUrl ='<%#  GetUrl(DataBinder.Eval(Container.DataItem,"CategoryID",null)) % > '>
<% # CheckTitle(DataBinder.Eval(Container.DataItem,"Title",null),DataBinder.Eval(((RepeaterItem)Container).DataItem,"CategoryID",null))  %>
</ asp:HyperLink >
< asp:HyperLink  runat ="server"  ID ="RssLink"  Text ="(rss)"  NavigateUrl ='<%#  GetRssUrl(DataBinder.Eval(((RepeaterItem)Container).DataItem,"CategoryID",null)) % > ' />
</ li >
.

注意绑定代码中使用了CheckTitle函数,接下来看看.cs 代码。

 

protected   void  Page_Load( object  sender, System.EventArgs e)
{
CategoryLevel1.DataSource
=Config.GetSiteBlogConfigCollection();
CategoryLevel1.DataBind();
}

在页面加载时调用了Config.GetSiteBlogConfigCollection()获取网站分类:

public   static  SiteBlogConfigCollection GetSiteBlogConfigCollection()
{
string  dataFile = System.Web.HttpContext.Current.Server.MapPath( " ~/SiteBlogConfig.config " );
return  (SiteBlogConfigCollection)Util.SerializationHelper.Load( typeof (SiteBlogConfigCollection),dataFile); 
}

杀手1现形:
这里在每次首页加载的时候都要加载.config,然后返回反序列化得到的对象。众所周知序列化和反序列化性能是很低的,而这里每次页面加载都重复做一次,对性能的影响就不可不计了。

 

接下来看刚才提到的CheckTitle()方法:

protected   string  CheckTitle( string  title, string  CategoryID)
{
if (Config.Settings.CategoryDepth == 2 )
{
return  title;
}
SiteBlogConfig config
= Config.GetSiteBlogConfigByCategoryID( int .Parse(CategoryID));
if (config != null )
{
title
+= string .Format( " ({0}/{1}) " ,GetRowsCount( true ,config).ToString(),GetRowsCount( false ,config).ToString());
}
return  title;
}

这个方法返回的类似“最新评论区(0/21033) ”的字符串。

杀手2现形:

在这个方法中再次再现调用GetSiteBlogConfigByCategoryID() -> GetSiteBlogConfigCollection() ->GetSiteBlogConfigCollection()!这个方法可是在每次OnItemDataBound是都调用的呀,也就是说如果有10个网站分类,那么每次打开页面时在这里都重复10次反序列化"~/SiteBlogConfig.config"这个配置文件。

队此之外,这个访求中还2次调用GetRowsCount()方法,这个方法代码如下:

private   int  GetRowsCount( bool  IsToday,BlogConfig config)
{
EntryQuery query 
=   new  EntryQuery();
query.PostType 
=  PostType.BlogPost;
query.PostConfig 
=  PostConfig.IsActive | PostConfig.IsAggregated;
if (IsToday)
{
DateTime now
= DateTime.Now;
DateTime StartDate
= new  DateTime(now.Year,now.Month,now.Day, 0 , 0 , 0 , 0 );
query.StartDate
= StartDate;
}
query
= (EntryQuery)Dottext.Framework.Util.Globals.BuildEntryQuery(query,config);
return  Entries.GetEntryCount(query);
}

此方法返回指定分类的文章数,如果IsToday=true,则只返回分类当天的文章数。最后一行调用

Entries.GetEntryCount(query);跟踪这个方法,在FrameWork项目Entries.cs中:
public   static   int  GetEntryCount(EntryQuery query)
{
return  DTOProvider.Instance().GetEntryCount(query);
}

我是使用sql数据库,所以这里跟踪转到Frameword/data/SqlDataProvider.cs:

 

public  IDataReader GetEntryCount(EntryQuery query)
{
return  GetReader( " blog_GenericGetEntriesCount_10 " ,EntryQueryParameters(query));
blog_GenericGetEntriesCount_10这个储存过程比较长,我们只来看和这次调用相关的代码:

-- Do we have a CategoryID?
if ( @CategoryID   is   not   null )
Begin
-- we will filter by categoryID. Should we also filter by date?
if ( @StartDate   is   null )
Begin
--  No Date Filter
SELECT  
count (bc. [ ID ] as   Count
FROM  
blog_Content bc 
with (nolock)
INNER   JOIN  blog_Links bl  with (nolock)  on  bc.ID  =  bl.PostID
INNER   JOIN  blog_Config bcc  with (nolock)  on  bc.BlogID  =  bcc.BlogID  and  bcc.IsAggregated  =   1  
WHERE  
bc.PostConfig 
&   @PostConfig   =   @PostConfig  
and  bc.PostType  |   @PostType   =   @PostType
and  bl.CategoryID  =   @CategoryID
End
Else
Begin
-- Filter by CategoryID and Date. 

-- If we only have a start date and no stop date, add 24 hours to to stopdate
if ( @StartDate   is   not   null   and   @StopDate   is   null )
Set   @StopDate   =   DateAdd ( day , 1 , @StartDate )
--  No Date Filter
SELECT  
count (bc. [ ID ] as   Count
FROM  
blog_Content bc 
with (nolock)
INNER   JOIN  blog_Links bl  with (nolock)  on  bc.ID  =  bl.PostID
INNER   JOIN  blog_Config bcc  with (nolock)  on  bc.BlogID  =  bcc.BlogID  and  bcc.IsAggregated  =   1  
WHERE  
bc.PostConfig 
&   @PostConfig   =   @PostConfig  
and  bc.PostType  |   @PostType   =   @PostType
and  bl.CategoryID  =   @CategoryID
and  bc.DateAdded  >=   @StartDate   and  bc.DateAdded  <=   @StopDate
End
End  

杀手3现形

3个表的INNER JOIN查询,这可是每次打开页面时有网站分类数*2次调用的呀,以数据库的压力可想而知了,当文章数量越来越多的时候,你会发现每次打开首页数据库服务器的CPU曲线都有个飙升。

----------------------------------------------------

处理掉这个问题,打开首页时数据库服务器平静多了~~~

后话:
cnblogs并无这个现象,说明DUDU很早就已经发现这个问题。
希望此文能给使用cnblog代码的同志一点帮助。

出处:http://wuchang.cnblos.com

你可能感兴趣的:(Blog)