Yii的mssql分页杂谈

1.必须指定排序规则,不然得不到分页效果,因为内部使用的是经典的top+order分页,原理是order翻转2次之后,再最后一次order得到正确结果,但是最后一页未做特定处理,还有如果说表中无索引,或者排序条件较多,不知道效率如何了。 (看了一下执行计划,第一次和第二次排序是比较耗时,第三次排序不耗时,如果说索引建立得合理,效率应该没问题)

2.limit为页大小,offset为取值起始位置,我们把这个问题丢给CPagination实例对象去处理跟省心。但是pageCount呢?自己再写一个统计语句,我看还是算了吧(在不需要精准的条件其实可以指定一个较大的数,这样还少个数据库统计语句),往下看 。

3.继续把问题丢给CActiveDataProvider实例对象,为什么?简化你的操作!AR集,分页参数(页总数、页大小、当前页),啥都有了,全自动化。

4.这样的分页太麻烦,想要自己组装!!!可以啊,findAllBySql(),不过取AR的数量尽量少,不然得生成多少个AR实例啊,用2005/2008的row_number()函数,确实简化。但统计代码得自己写了,CPagination实例对象你自己配置。为什么不直接用DAO呢,,我关键是还要用Behavior啊!

5.qing哥,我觉得Yii是个前沿框架,mssql2000在开发新的应用中 用得很少了(虽然还有很多老程序在2000上跑),做一个新的简洁分页方法吧。还有,Yii团队能不能给个UML图啥的,看着图理解Yii框架快。

花了一下午的时间看底层,用自己的半吊子PHP技术改写了CMssqlCommandBuilder类的方法,修正mssql分页最后一页效果不理想的小问题,仅适用sql 2005+,希望对Yiier有帮助,欢迎拍砖!


protected function rewriteLimitOffsetSql($sql, $limit, $offset)

	{

		$fetch = $limit+$offset;

		if($pos=strrpos($sql, 'ORDER', -1))

		{

			$order=substr($sql, $pos);

			$sql=substr($sql, 0, $pos);

			$sql=preg_replace('/^SELECT/i', "SELECT (ROW_NUMBER() OVER ($order)) AS rn, ", $sql);

			$offset+=1;

			$sql='SELECT * FROM ('.$sql.') AS t WHERE rn BETWEEN '. $offset . ' AND '.$fetch;

			return $sql;

		}		$sql = preg_replace('/^([\s(])*SELECT( DISTINCT)?(?!\s*TOP\s*\()/i',"\\1SELECT\\2 TOP $fetch", $sql);

		$ordering = $this->findOrdering($sql);

		$orginalOrdering = $this->joinOrdering($ordering, '[__outer__]');

		$reverseOrdering = $this->joinOrdering($this->reverseDirection($ordering), '[__inner__]');

		$sql = "SELECT * FROM (SELECT TOP {$limit} * FROM ($sql) as [__inner__] {$reverseOrdering}) as [__outer__] {$orginalOrdering}";

		return $sql;

	}

多谢分享你的分析。

我们尝试过用row_number来改进分页,不过由此会引入一个很难解决的别名问题,所以我们最终还是放弃了。

具体讨论请参见:http://code.google.com/p/yii/issues/detail?id=1501

我们或许在今后会重新尝试这个解决方法。

哇,哇,哇,我这个newbie居然得到强哥的及时回复,感动+激动ing……

网站又被ZF和谐了一会,现在打开了。

其实这个临时解决方案只是最外层做分页是用,内层不管有多复杂,最外层是CDbCommandBuilder构建好的sql再处理的结果,不会引起别名问题,一会再测试测试。

看到将要是用sqlsrv,太好了。

先吃饭……