php和mysql實現分頁技術(php怎麼實現分頁)

本文目錄一覽:

php 如何對mysql的文本分頁

1、前言

分頁顯示是一種非常常見的瀏覽和顯示大量數據的方法,屬於web編程中最常處理的事件之一。對於web編程的老手來說,編寫這種代碼實在是和呼吸一樣自然,但是對於初學者來說,常常對這個問題摸不着頭緒,因此特地撰寫此文對這個問題進行詳細的講解,力求讓看完這篇文章的朋友在看完以後對於分頁顯示的原理和實現方法有所了解。本文適合初學者閱讀,所有示例代碼均使用php編寫。

2、原理

所謂分頁顯示,也就是將數據庫中的結果集人為的分成一段一段的來顯示,這裡需要兩個初始的參數:

每頁多少條記錄($PageSize)?

當前是第幾頁($CurrentPageID)?

現在只要再給我一個結果集,我就可以顯示某段特定的結果出來。

至於其他的參數,比如:上一頁($PReviousPageID)、下一頁($NextPageID)、總頁數($numPages)等等,都可以根據前邊這幾個東西得到。

以MySQL數據庫為例,如果要從表內截取某段內容,sql語句可以用:select * from table limit offset, rows。看看下面一組sql語句,嘗試一下發現其中的規率。

前10條記錄:select * from table limit 0,10

第11至20條記錄:select * from table limit 10,10

第21至30條記錄:select * from table limit 20,10

……

這一組sql語句其實就是當$PageSize=10的時候取表內每一頁數據的sql語句,我們可以總結出這樣一個模板:

select * from table limit ($CurrentPageID – 1) * $PageSize, $PageSize

拿這個模板代入對應的值和上邊那一組sql語句對照一下看看是不是那麼回事。搞定了最重要的如何獲取數據的問題以後,剩下的就僅僅是傳遞參數,構造合適的sql語句然後使用php從數據庫內獲取數據並顯示了。以下我將用具體代碼加以說明。

3、簡單代碼

請詳細閱讀以下代碼,自己調試運行一次,最好把它修改一次,加上自己的功能,比如搜索等等。

?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 href=?page=’.($page-1).’上一頁/a|’;

}

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

$page_string .= ‘下一頁|尾頁’;

}

else{

$page_string .= ‘a href=?page=’.($page+1).’下一頁/a|a href=?page=’.$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 href=’?page=1numItems=”.$pager-numItems.”‘首頁/a|a href=’?page=”.$pager-PreviousPageID.”numItems=”.$pager-numItems.”‘上一頁/a|”;

}

if ( $pager-isLastPage )

{

$turnover .= “下一頁|尾頁”;

}

else

{

$turnover .= “a href=’?page=”.$pager-NextPageID.”numItems=”.$pager-numItems.”‘下一頁/a|a href=’?page=”.$pager-numPages.”numItems=”.$pager-numItems.”‘尾頁/a”;

}

?

需要說明的地方有兩個:

這個類僅僅處理數據,並不負責處理顯示,因為我覺得將數據的處理和結果的顯示都放到一個類裡邊實在是有些勉強。顯示的時候情況和要求多變,不如自己根據類給出的結果處理,更好的方法是根據這個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

……

所以要在類裡邊獲取結果的時候需要使用pear db類的limitQuery方法。

ok,寫完收功,希望花時間看完這些文字的你不覺得是浪費了時間。

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+mysql分頁!

$page=$_GET[‘page’];

$countpage=30;

$minpage = get_minpage($page,$countpage);

$maxpage = get_maxpage($page,$countpage);

for($minpage; $minpage = $maxpage;$minpage++)

{

if($minpage == $page){

echo “font color=#ff0000$minpage /font”;

}

else

{

echo $minpage.’ ‘;

}

}

//取最小頁

function get_minpage($page,$countpage)

{

$minpage = $page-5;

if($page+5 = $countpage)

{

$minpage = $minpage-(5-($countpage-$page));

}else{

if($minpage =1){

$minpage = 1;

}

}

return $minpage;

}

//取最大頁

function get_maxpage($page,$countpage)

{

$maxpage = $page+5;

if($page-5 = 1)

{

$maxpage = $maxpage-($page-6);

}

if($maxpage = $countpage)

{

$maxpage = $countpage;

}

return $maxpage;

}

php分頁功能怎麼實現

php本身是沒有分頁概念的,分頁是URL傳參,然後通過mysql查詢語句到數據庫獲取數據,然後實現的分頁,url上的參數,通過PHP的$_GET都是可以獲取到的。

現在市面上的PHP框架基本都有PHP分頁類,參照文檔直接調用就好了,如果想看實現過程,可以去下載一個TP框架,然後打開裡面的分頁類查看裡面的源代碼。

原創文章,作者:小藍,如若轉載,請註明出處:https://www.506064.com/zh-hant/n/256288.html

(0)
打賞 微信掃一掃 微信掃一掃 支付寶掃一掃 支付寶掃一掃
小藍的頭像小藍
上一篇 2024-12-15 12:34
下一篇 2024-12-15 12:40

相關推薦

  • 如何修改mysql的端口號

    本文將介紹如何修改mysql的端口號,方便開發者根據實際需求配置對應端口號。 一、為什麼需要修改mysql端口號 默認情況下,mysql使用的端口號是3306。在某些情況下,我們需…

    編程 2025-04-29
  • PHP和Python哪個好找工作?

    PHP和Python都是非常流行的編程語言,它們被廣泛應用於不同領域的開發中。但是,在考慮擇業方向的時候,很多人都會有一個問題:PHP和Python哪個好找工作?這篇文章將從多個方…

    編程 2025-04-29
  • Python熱重載技術

    Python熱重載技術是現代編程的關鍵功能之一。它可以幫助我們在程序運行的過程中,更新代碼而無需重新啟動程序。本文將會全方位地介紹Python熱重載的實現方法和應用場景。 一、實現…

    編程 2025-04-29
  • jQuery Datatable分頁中文

    jQuery Datatable是一個非常流行的數據表插件,它可以幫助您快速地在頁面上創建搜索、過濾、排序和分頁的數據表格。不過,它的默認設置是英文的,今天我們就來探討如何將jQu…

    編程 2025-04-29
  • Python操作MySQL

    本文將從以下幾個方面對Python操作MySQL進行詳細闡述: 一、連接MySQL數據庫 在使用Python操作MySQL之前,我們需要先連接MySQL數據庫。在Python中,我…

    編程 2025-04-29
  • PHP怎麼接幣

    想要在自己的網站或應用中接受比特幣等加密貨幣的支付,就需要對該加密貨幣擁有一定的了解,並使用對應的API進行開發。本文將從多個方面詳細闡述如何使用PHP接受加密貨幣的支付。 一、環…

    編程 2025-04-29
  • MySQL遞歸函數的用法

    本文將從多個方面對MySQL遞歸函數的用法做詳細的闡述,包括函數的定義、使用方法、示例及注意事項。 一、遞歸函數的定義 遞歸函數是指在函數內部調用自身的函數。MySQL提供了CRE…

    編程 2025-04-29
  • Python包絡平滑技術解析

    本文將從以下幾個方面對Python包絡平滑技術進行詳細的闡述,包括: 什麼是包絡平滑技術? Python中使用包絡平滑技術的方法有哪些? 包絡平滑技術在具體應用中的實際效果 一、包…

    編程 2025-04-29
  • 微信小程序重構H5技術方案設計 Github

    本文旨在探討如何在微信小程序中重構H5技術方案,以及如何結合Github進行代碼存儲和版本管理。我們將從以下幾個方面進行討論: 一、小程序與H5技術對比 微信小程序與H5技術都可以…

    編程 2025-04-28
  • parent.$.dialog是什麼技術的語法

    parent.$.dialog是一種基於jQuery插件的彈出式對話框技術,它提供了一個方便快捷的方式來創建各種類型和樣式的彈出式對話框。它是對於在網站開發中常見的彈窗、提示框等交…

    編程 2025-04-28

發表回復

登錄後才能評論