上文提到,在windows日志中,经常看到这样的错误:
查询处理器用尽了内部资源,无法生成查询计划。这种情况很少出现,只有在查询极其复杂或引用了大量表或分区时才会出现。请简化查询。如果您认为该消息的出现纯属错误,请与客户支持服务部门联系,了解详细信息。
这对于一个拥有十来个二级栏目,每个栏目都是一套独立的程序,并且集中在一个站点的网站来说,找出发生错误的那部分程序,是相当不容易的事情。
第一步,通过日志的来源,确定错误来源于MSSQL SERVER。上文提到,这是使用IN关键词产生的错误描述。并且已经明确,是由于查询的数据量太大,导致资源耗尽还没有得到查询结果。
第二步,通过SQL Server Profiler追踪数据库的查询情况。我把追踪结果存入数据库,然后通过查询Duration数值最大的前100条数据,结果有一个惊人的发现。一条类似这样的查询语句让我震惊了:
[pre]
select * from (select top 1520 articleid,classId,classname,articlemark,articletitle,hits,case smallpic when ” then ‘jnews/images/newslist_26.gif’ else smallpic end as smallpic,description,addtime,author,tag from cms_article where classID=3 and ischeck=1 and articleid in (316577,112553,59078,332886,255516,381339,98365,368853,50991,…..(此处省略一万字以上)
[/pre]
打开项目源代码,查找该查询语句的某些特征字符串,例如:“case smallpic when ” then ‘jnews/images/newslist_26.gif’ else ”,很快找到了相应的函数。
第三步,分析了一下原查询语句的意图,无非是想对符合某些条件的文章进行分页读取。明白了意图,剩下来的工作就是重写这个方法,以相对高效的方式实现相同的任务。利用MSSQL Server 2005之后新增的row_number()属性,将该功能的查询修改成:
[pre]
string ausql = “select * from ( ” + “select row_number() over(order by articleid desc) as rownumber,* ” + “from cms_article where ischeck = 1 and ” + “classid in (select classid from cms_artclass where ” + ” classid = ” + classID + ” or parentid = ” + classID + ” or parentpath like ‘%,” + classID + “,%’) ” + str + ” ) as t ” + “where rownumber between ” + startpage + ” and ” + endpage;
[/pre]
条件中也许会由于使用到LIKE关键词而降低效率,不过该字段类型通常为nvarchar(50)左右,应该在可接受的范围之内。相对原来的查询,显得微不足道了。这从Duration的值就可以看出来。新查询的Duration是700左右,旧查询的某次Duration是5500314!



