首页 > 后端开发 > 正文

php分页框架 PHP分页显示制作详解

2023-08-31 05:41:38 | 我爱编程网

今天我爱编程网小编为大家带来了php分页框架 PHP分页显示制作详解,希望能帮助到大家,一起来看看吧!

php分页框架 PHP分页显示制作详解

PHP+MySQL高效的分页方法,如何优化LIMIT,OFFSET进行的分页?

很多应用往往只展示最新或最热门的几条记录,但为了旧记录仍然可访问,所以就需要个分页的导航栏。然而,如何通过MySQL更好的实现分页,始终是比较令人头疼的问题。虽然没有拿来就能用的解决办法,但了解数据库的底层或多或少有助于优化分页查询。

我们先从一个常用但性能很差的查询来看一看。

SELECT *
FROM city
ORDER BY id DESC
LIMIT 0, 15

这个查询耗时0.00sec。So,这个查询有什么问题呢?实际上,这个查询语句和参数都没有问题,因为它用到了下面表的主键,而且只读取15条记录。

CREATE TABLE city (
id int(10) unsigned NOT NULL AUTO_INCREMENT,
city varchar(128) NOT NULL,
PRIMARY KEY (id)
) ENGINE=InnoDB;

真正的问题在于offset(分页偏移量)很大的时候,像下面这样:

SELECT *
FROM city
ORDER BY id DESC
LIMIT 100000, 15;

上面的查询在有2M行记录时需要0.22sec,通过EXPLAIN查看SQL的执行计划可以发现该SQL检索了100015行,但最后只需要15行。大的分页偏移量会增加使用的数据,MySQL会将大量最终不会使用的数据加载到内存中。就算我们假设大部分网站的用户只访问前几页数据,但少量的大的分页偏移量的请求也会对整个系统造成危害。Facebook意识到了这一点,但Facebook并没有为了每秒可以处理更多的请求而去优化数据库,而是将重心放在将请求响应时间的方差变小。

对于分页请求,还有一个信息也很重要,就是总共的记录数。我们可以通过下面的查询很容易的获取总的记录数。

SELECT COUNT(*)
FROM city;

然而,上面的SQL在采用InnoDB为存储引擎时需要耗费9.28sec。一个不正确的优化是采用 SQL_CALC_FOUND_ROWS,SQL_CALC_FOUND_ROWS 可以在能够在分页查询时事先准备好符合条件的记录数,随后只要执行一句 select FOUND_ROWS(); 就能获得总记录数。但是在大多数情况下,查询语句简短并不意味着性能的提高。不幸的是,这种分页查询方式在许多主流框架中都有用到,下面看看这个语句的查询性能。

SELECT SQL_CALC_FOUND_ROWS *
FROM city
ORDER BY id DESC
LIMIT 100000, 15;

这个语句耗时20.02sec,是上一个的两倍。事实证明使用 SQL_CALC_FOUND_ROWS 做分页是很糟糕的想法。
下面来看看到底如何优化。文章分为两部分,第一部分是如何获取记录的总数目,第二部分是获取真正的记录。

高效的计算行数

如果采用的引擎是MyISAM,可以直接执行COUNT(*)去获取行数即可。相似的,在堆表中也会将行数存储到表的元信息中。但如果引擎是InnoDB情况就会复杂一些,因为InnoDB不保存表的具体行数。

我们可以将行数缓存起来,然后可以通过一个守护进程定期更新或者用户的某些操作导致缓存失效时,执行下面的语句:

SELECT COUNT(*)
FROM city
USE INDEX(PRIMARY);

获取记录

下面进入这篇文章最重要的部分,获取分页要展示的记录。上面已经说过了,大的偏移量会影响性能,所以我们要重写查询语句。为了演示,我们创建一个新的表“news”,按照时事性排序(最新发布的在最前面),实现一个高性能的分页。为了简单,我们就假设最新发布的新闻的Id也是最大的。

CREATE TABLE news(
id INT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
title VARCHAR(128) NOT NULL
) ENGINE=InnoDB;

一个比较高效的方式是基于用户展示的最后一个新闻Id。查询下一页的语句如下,需要传入当前页面展示的最后一个Id。

SELECT *
FROM news WHERE id < $last_id
ORDER BY id DESC
LIMIT $perpage

查询上一页的语句类似,只不过需要传入当前页的第一个Id,并且要逆序。

SELECT *
FROM news WHERE id > $last_id
ORDER BY id ASC
LIMIT $perpage

上面的查询方式适合实现简易的分页,即不显示具体的页数导航,只显示“上一页”和“下一页”,例如博客中页脚显示“上一页”,“下一页”的按钮。但如果要实现真正的页面导航还是很难的,下面看看另一种方式。

SELECT id
FROM (
SELECT id, ((@cnt:= @cnt + 1) + $perpage - 1) % $perpage cnt
FROM news
JOIN (SELECT @cnt:= 0)T
WHERE id < $last_id
ORDER BY id DESC
LIMIT $perpage * $buttons
)C
WHERE cnt = 0;

通过上面的语句可以为每一个分页的按钮计算出一个offset对应的id。这种方法还有一个好处。假设,网站上正在发布一片新的文章,那么所有文章的位置都会往后移一位,所以如果用户在发布文章时换页,那么他会看见一篇文章两次。如果固定了每个按钮的offset Id,这个问题就迎刃而解了。Mark Callaghan发表过一篇类似的博客,利用了组合索引和两个位置变量,但是基本思想是一致的。

如果表中的记录很少被删除、修改,还可以将记录对应的页码存储到表中,并在该列上创建合适的索引。采用这种方式,当新增一个记录的时候,需要执行下面的查询重新生成对应的页号。

SET p:= 0;
UPDATE news SET page=CEIL((p:= p + 1) / $perpage) ORDER BY id DESC;

当然,也可以新增一个专用于分页的表,可以用个后台程序来维护。

UPDATE pagination T
JOIN (
SELECT id, CEIL((p:= p + 1) / $perpage) page
FROM news
ORDER BY id
)C
ON C.id = T.id
SET T.page = C.page;

现在想获取任意一页的元素就很简单了:

SELECT *
FROM news A
JOIN pagination B ON A.id=B.ID
WHERE page=$offset;

还有另外一种与上种方法比较相似的方法来做分页,这种方式比较试用于数据集相对小,并且没有可用的索引的情况下—比如处理搜索结果时。在一个普通的服务器上执行下面的查询,当有2M条记录时,要耗费2sec左右。这种方式比较简单,创建一个用来存储所有Id的临时表即可(这也是最耗费性能的地方)。

CREATE TEMPORARY TABLE _tmp (KEY SORT(random))
SELECT id, FLOOR(RAND() * 0x8000000) random
FROM city;

ALTER TABLE _tmp ADD OFFSET INT UNSIGNED PRIMARY KEY AUTO_INCREMENT, DROP INDEX SORT,ORDER BY random;

接下来就可以向下面一样执行分页查询了。

SELECT *
FROM _tmp
WHERE OFFSET >= $offset
ORDER BY OFFSET
LIMIT $perpage;

简单来说,对于分页的优化就是。。。避免数据量大时扫描过多的记录。

php分页框架 PHP分页显示制作详解

PHP分页显示制作详解

前言

分页显示是一种非常常见的浏览和显示大量数据的方法 属于web编程中最常处理的事件之一 对于web编程的老手来说 编写这种代码实在是和呼吸一样自然 但是对于初学者来说 常常对这个问题摸不著头绪 因此特地撰写此文对这个问题进行详细的讲解 力求让看完这篇文章的朋友在看完以后对于分页显示的原理和实现方法有所了解 本文适合初学者阅读 所有示例代码均使用php编写

原理

所谓分页显示 也就是将数据库中的结果集人为的分成一段一段的来显示 这里需要两个初始的参数

每页多少条记录($PageSize)?

当前是第几页($CurrentPageID)?

现在只要再给我一个结果集 我就可以显示某段特定的结果出来

至于其他的参数 比如 上一页($PReviousPageID) 下一页($NextPageID) 总页数($numPages)等等 都可以根据前边这几个东西得到

以MySQL数据库为例 如果要从表内截取某段内容 sql语句可以用 select * from table limit offset rows 看看下面一组sql语句 尝试一下发现其中的规率

前 条记录 select * from table limit

第 至 条记录 select * from table limit

第 至 条记录 select * from table limit

……

这一组sql语句其实就是当$PageSize= 的时候取表内每一页数据的sql语句 我们可以总结出这样一个模板

select * from table limit ($CurrentPageID ) * $PageSize $PageSize

拿这个模板代入对应的值和上边那一组sql语句对照一下看看是不是那么回事 搞定了最重要的如何获取数据的问题以后 剩下的就仅仅是传递参数 构造合适的sql语句然后使用php从数据库内获取数据并显示了 以下我将用具体代码加以说明

简单代码

请详细阅读以下代码 自己调试运行一次 最好把它修改一次 加上自己的功能 比如搜索等等

<?php

// 建立数据库连接

$link = mysql_connect("localhost", "mysql_user", "mysql_passWord")

or die("Could not connect: " . mysql_error());

// 获取当前页数

if( isset($_GET['page']) ){

$page = intval( $_GET['page'] );

}

else{

$page = 1;

}

// 每页数量

$PageSize = 10;

// 获取总数据量

$sql = "select count(*) as amount from table";

$result = mysql_query($sql);

$row = mysql_fetch_row($result);

$amount = $row['amount'];

// 记算总共有多少页

if( $amount ){

if( $amount < $page_size ){ $page_count = 1; } //如果总数据量小于$PageSize,那么只有一页

if( $amount % $page_size ){ //取总数据量除以每页数的余数

$page_count = (int)($amount / $page_size) + 1; //如果有余数,则页数等于总数据量除以每页数的结果取整再加一

}else{

$page_count = $amount / $page_size; //如果没有余数,则页数等于总数据量除以每页数的结果

}

}

else{

$page_count = 0;

}

// 翻页链接

$page_string = '';

if( $page == 1 ){

$page_string .= '第一页|上一页|';

}

else{

$page_string .= '<a href=?page=1>第一页</a>|<a .($page-1).'>上一页</a>|'; }

if( ($page == $page_count) || ($page_count == 0) ){

$page_string .= '下一页|尾页';

}

else{

$page_string .= '<a .($page+1).'>下一页</a>|<a .$page_count.'>尾页</a>'; }

// 获取数据,以二维数组格式返回结果

if( $amount ){

$sql = "select * from table order by id desc limit ". ($page-1)*$page_size .", $page_size";

$result = mysql_query($sql);

while ( $row = mysql_fetch_row($result) ){

$rowset[] = $row;

}

}else{

$rowset = array();

}

// 没有包含显示结果的代码,那不在讨论范围,只要用foreach就可以很简单的用得到的二维数组来显示结果

?>

4、OO风格代码

以下代码中的数据库连接是使用的pear db类进行处理

<?php

// FileName: Pager.class.php

// 分页类,这个类仅仅用于处理数据结构,不负责处理显示的工作

Class Pager

{

var $PageSize; //每页的数量

var $CurrentPageID; //当前的页数

var $NextPageID; //下一页

var $PreviousPageID; //上一页

var $numPages; //总页数

var $numItems; //总记录数

var $isFirstPage; //是否第一页

var $isLastPage; //是否最后一页

var $sql; //sql查询语句

function Pager($option)

{

global $db;

$this->_setOptions($option);

// 总条数

if ( !isset($this->numItems) )

{

$res = $db->query($this->sql);

$this->numItems = $res->numRows();

}

// 总页数

if ( $this->numItems > 0 )

{

if ( $this->numItems < $this->PageSize ){ $this->numPages = 1; }

if ( $this->numItems % $this->PageSize )

{

$this->numPages= (int)($this->numItems / $this->PageSize) + 1;

}

else

{

$this->numPages = $this->numItems / $this->PageSize;

}

}

else

{

$this->numPages = 0;

}

switch ( $this->CurrentPageID )

{

case $this->numPages == 1:

$this->isFirstPage = true;

$this->isLastPage = true;

break;

case 1:

$this->isFirstPage = true;

$this->isLastPage = false;

break;

case $this->numPages:

$this->isFirstPage = false;

$this->isLastPage = true;

break;

default:

$this->isFirstPage = false;

$this->isLastPage = false;

}

if ( $this->numPages > 1 )

{

if ( !$this->isLastPage ) { $this->NextPageID = $this->CurrentPageID + 1; }

if ( !$this->isFirstPage ) { $this->PreviousPageID = $this->CurrentPageID - 1; }

}

return true;

}

/***

*

* 返回结果集的数据库连接

* 在结果集比较大的时候可以直接使用这个方法获得数据库连接,然后在类之外遍历,这样开销较小

* 如果结果集不是很大,可以直接使用getPageData的方式获取二维数组格式的结果

* getPageData方法也是调用本方法来获取结果的

*

***/

function getDataLink()

{

if ( $this->numItems )

{

global $db;

$PageID = $this->CurrentPageID;

$from = ($PageID - 1)*$this->PageSize;

$count = $this->PageSize;

$link = $db->limitQuery($this->sql, $from, $count); //使用Pear DB::limitQuery方法保证数据库兼容性

return $link;

}

else

{

return false;

}

}

/***

*

* 以二维数组的格式返回结果集

*

***/

function getPageData()

{

if ( $this->numItems )

{

if ( $res = $this->getDataLink() )

{

if ( $res->numRows() ) 我爱编程网

{

while ( $row = $res->fetchRow() )

{

$result[] = $row;

}

}

else

{

$result = array();

}

return $result;

}

else

{

return false;

}

}

else

{

return false;

}

}

function _setOptions($option)

{

$allow_options = array(

'PageSize',

'CurrentPageID',

'sql',

'numItems'

);

foreach ( $option as $key => $value )

{

if ( in_array($key, $allow_options) && ($value != null) )

{

$this->$key = $value;

}

}

return true;

}

}

?>

<?php

// FileName: test_pager.php

// 这是一段简单的示例代码,前边省略了使用pear db类建立数据库连接的代码

require "Pager.class.php";

if ( isset($_GET['page']) )

{

$page = (int)$_GET['page'];

}

else

{

$page = 1;

}

$sql = "select * from table order by id";

$pager_option = array(

"sql" => $sql,

"PageSize" => 10,

"CurrentPageID" => $page

);

if ( isset($_GET['numItems']) )

{

$pager_option['numItems'] = (int)$_GET['numItems'];

}

$pager = @new Pager($pager_option);

$data = $pager->getPageData();

if ( $pager->isFirstPage )

{

$turnover = "首页|上一页|";

}

else

{

$turnover = "<a ?page=1&numItems=".$pager->numItems."'>首页</a>|<a ?page=".$pager->PreviousPageID."&numItems=".$pager->numItems."'>上一页</a>|"; }

if ( $pager->isLastPage )

{

$turnover .= "下一页|尾页";

}

else

{

$turnover .="<a ?page=".$pager->NextPageID."&numItems=".$pager->numItems."'>下一页</a>|<a ?page=".$pager->numPages."&numItems=".$pager->numItems."'>尾页</a>"; }

?>

需要说明的地方有两个:

这个类仅仅处理数据,并不负责处理显示,因为我觉得将数据的处理和结果的显示都放到一个类里边实在是有些勉强。Tw.wINgWIT显示的时候情况和要求多变,不如自己根据类给出的结果处理,更好的方法是根据这个Pager类继承一个自己的子类来显示不同的分页,比如显示用户分页列表可以:

<?php

Class MemberPager extends Pager

{

function showMemberList()

{

global $db;

$data = $this->getPageData();

// 显示结果的代码

// ......

}

}

/// 调用

if ( isset($_GET['page']) )

{

$page = (int)$_GET['page'];

}

else

{

$page = 1;

}

$sql = "select * from members order by id";

$pager_option = array(

"sql" => $sql,

"PageSize" => 10,

"CurrentPageID" => $page

);

if ( isset($_GET['numItems']) )

{

$pager_option['numItems'] = (int)$_GET['numItems'];

}

$pager = @new MemberPager($pager_option);

$pager->showMemberList();

?>

第二个需要说明的地方就是不同数据库的兼容性,在不同的数据库里截获一段结果的写法是不一样的。

mysql: select * from table limit offset, rows

pgsql: select * from table limit m offset n

......

lishixinzhi/Article/program/PHP/201311/21304

php分页框架 PHP分页显示制作详解

用PHP如何实现分页并能够实现上一页,下一页,跳转到()页的功能?

<html><head>
<title>分页示例(php</title>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312">
</head>

<body>
<?php
$pagesize=10; //设定每一页显示的记录数

$conn=mysql_connect("localhost","root","jrq");
mysql_select_db("sj",$conn);
$rs = mysql_query( "select * from `dw_newsdata`",$conn); //这里有第二个可选参数,指定打开的连接
//-----------------------------------------------------------------------------------------------//
//分页逻辑处理
//-----------------------------------------------------------------------------------------------
$tmpArr = mysql_fetch_array($rs);
$numAL = mysql_num_rows($rs); //取得记录总数$rs
$pages=intval($numAL/$pagesize); //计算总页数

if ($numAL % $pagesize) $pages++;

//设置缺省页码
//↓判断“当前页码”是否赋值过
if (isset($_GET['page'])){ $page=intval($_GET['page']); }else{ $page=1; }//否则,设置为第一页

//↓计算记录偏移量
$offset=$pagesize*($page - 1);

//↓读取指定记录数
$rs=mysql_query("select * from `dw_newsdata` limit $offset,$pagesize",$conn);//取得—当前页—记录集!
$curNum = mysql_num_rows($rs); //$curNum - 当前页实际记录数,for循环输出用
?>
<table border="0" width="80%">
<tr>
<td width="50%" bgcolor="#E0E0E0">标题</td>
<td width="50%" bgcolor="#E0E0E0">发布时间</td>
</tr>

<?php
while ($tmpArr = mysql_fetch_array($rs)) //提取一行,并循环判断
{
$i=0;

// for($a=0;$a<$ColNum;$a++) //==for结束==
?>
<tr>
<td width="50%"><?= $tmpArr[1]; //$tmpArr["news_title"] ; ?></td>
<td width="50%"><?php echo $tmpArr[2]; //$tmpArr["news_cont"]; ?></td>
</tr>

<?php

}//==while结束==
?>
</table>

<?php
//============================//
// 翻页显示 一
//============================//
echo "<p>"; // align=center
$first=1;
$prev=$page-1;
$next=$page+1;
$last=$pages;

if ($page > 1)
{
echo "<a href='?page=".$first."'>首页</a> ";
echo "<a href='?page=".$prev."'>上一页</a> ";
}

if ($page < $pages)
{
echo "<a href='?page=".$next."'>下一页</a> ";
echo "<a href='?page=".$last."'>尾页</a> ";
}

//============================//
// 翻页显示 二
//============================//
echo " | 共有".$pages."页(".$page."/".$pages.")";

for ($i=1;$i< $page;$i++){echo "<a href='?page=".$i."'>[".$i ."]</a> ";} // 1-先输出当前页之前的

if ($page > 0) echo "[".$page."]";; // 2-再输出当前页

for ($i=$page+1;$i<=$pages;$i++){echo "<a href='?page=".$i."'>[".$i ."]</a> ";}// 3-接着输出当前页之后

echo "转到第 <INPUT maxLength=3 size=3 value=".($page+1)." name=gotox> 页 <INPUT hideFocus onclick=\"location.href='?page=gotox.value';\" type=button value=Go name=cmd_goto>";

echo "</p>";

?>

</body>
</html>

以上就是我爱编程网整理的php分页框架 PHP分页显示制作详解相关内容,想要了解更多信息,敬请查阅我爱编程网。
与“php分页框架 PHP分页显示制作详解”相关推荐
php框架分页 PHP分页显示制作详解
php框架分页 PHP分页显示制作详解

用PHP如何实现分页并能够实现上一页,下一页,跳转到()页的功能?&lt;html&gt;&lt;head&gt;&lt;title&gt;分页示例(php&lt;/title&gt;&lt;metahttp-equiv="Content-Type"content="text/html;charset=gb2312"&gt;&lt;/head&gt;&lt;body&gt;

2023-08-31 21:54:08
ci框架php分页功能 PHP分页显示制作详解
ci框架php分页功能 PHP分页显示制作详解

求PHPCI框架大神解决一个分页问题review这段:if($this-&gt;data['count']&gt;0){$this-&gt;load-&gt;library('pagination');$config['total_rows'] = $this-&gt;data['count'];$config['base_url'] = site_url().'news/';$off

2023-09-19 02:15:05
php框架开发搜索分页显示 PHP搜索结果分页显示的问题
php框架开发搜索分页显示 PHP搜索结果分页显示的问题

php分页功能怎么实现在网站中,如果list页内容太多,一般会设置分页功能,今天我们一起来研究一下分页原理,通过一个小案例实现这个功能.分页原理分页显示,将从mysql数据库取出的数据有规律的一段段展示,利用sql语句中的limit将它的起始数据跟页数绑定,根据页数去数据库取数据(推荐学习:PHP视频教程)实现流程1.获取当前url字符串,并用parse_url解析得到u

2023-10-05 15:14:00
pHP框架最多显示多少行 php 如何分行分页显示
pHP框架最多显示多少行 php 如何分行分页显示

php的开发框架是什么php的开发框架是什么?下面为您详细介绍。框架是通过提供一个开发Web程序的基本架构,PHP开发框架就是一种搭建好了的PHP的基本架构。它能够促进快速软件开发(RAD),为我们节约时间,有助于创建更稳定的程序,并减少开发者的重复编写代码的劳动,让我们可以花更多的时间去创造真正的Web程序。拓展:四种主流框架ThinkPHPThinkPHP(FCS)是

2023-09-29 21:32:12
php框架的分页查询语句 PHP 查询结果分页显示
php框架的分页查询语句 PHP 查询结果分页显示

php分页代码怎么写Web开发是今后分布式程式开发的主流,通常的web开发都要涉及到与数据库打交道,客户端从服务器端读取通常都是以分页的形式来显示,一页一页的阅读起来既方便又美观。所以说写分页程序是web开发的一个重要组成部分,在这里,我们共同来研究分页程序的编写。一、分页程序的原理分页程序有两个非常重要的参数:每页显示几条记录($pagesize)和当前是第几页($page)。

2023-09-28 08:46:52
php无限级分类框架 thinkphp无限极分类能分页显示吗
php无限级分类框架 thinkphp无限极分类能分页显示吗

thinkphp无限极分类能分页显示吗TreeTable是一个能把无限分类展现为表格形式的PHP类库插件,分类的层级表示为表格的列,分类的行数表格分类的总数。单元格显示分类名称。TreeTable通过对单元格的行合并和列合并实现了无限层级也能较好的展示层级架构。1.构建ID/PID/NAME的数组,后期可通过数据库生成的动态数据。Tree算法请打开链接:_99943_14

2023-09-16 14:13:46
tp框架php前台分页显示 按照thinkphp数据分页写完后前端该怎么写
tp框架php前台分页显示 按照thinkphp数据分页写完后前端该怎么写

thinkphp分页怎样才能不显示第几页,只显示上一页下一页?TP官方下载完整版,自带有分页类;也可以自己写分页类$p=newThink\Page($count,$pagesize);//调用分页类$p-&gt;setConfig('theme','%UP_PAGE%%DOWN_PAGE%');//设置显示的样式thinkPHP3.2.3模板怎么增加分页设置找到分页类文件路径:

2023-09-27 04:04:10
php框架实现分页源码 PHP显示很多数据库信息,如何自动分页呢?代码
php框架实现分页源码 PHP显示很多数据库信息,如何自动分页呢?代码

PHP显示很多数据库信息,如何自动分页呢?代码PHP代码如下:/*Author:默默Date:2006-12-03*/$page=isset($_GET['page'])?intval($_GET['page']):1;//这句就是获取page=18中的page的值,假如不存在page,那么页数就是1。$num=10;//每页显示10条数据$db=mys

2023-09-17 01:43:23