代码改变世界

CNBlogsDottext Beta2 的性能杀手之SiteCategory.ascx

2007-04-16 11:53  无常  阅读(2912)  评论(1编辑  收藏  举报

如果你在使用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