Pagination is one of the simple features of a site if used right can be a great feature. For something very simple it seems to be a resource hog. For a while I have been looking for a way to paganate with out issuing two database queries. After some quick searching I could not find what I was looking for, so I came up a method that uses a one query + a sub-query.
Quick Review
The method that I have seen the most, looks like some like this.
//check do we have a starting page? if (isset($_GET['page'])) { $page = $_GET['page']; } else { $page = 1; } // end of if //connect to the database $link = mysql_connect('example.com:3307', 'username', 'password'); mysql_select_db('db_name',$link); $query = "SELECT count(*) FROM table WHERE ..."; $result = mysql_query($query, $link); $res = mysql_fetch_row($result); $numRows = $res[0]; $maxItemsOnPage = 15; $numberOfPages = ceil($numRows / $maxItemsOnPage); //lets get the data for this page $query = "SELECT * FROM table WHERE ....... LIMIT " . (($page - 1) * $maxItemsOnPage) ."," . $maxItemsOnpage; $result = mysql_query($query, $link); //do something with the results //show the links if ($page < $numberOfpages) { echo '<a href="' . $_SERVER["PHP_SELF"] . '?page=' . ($page + 1) . '">Next page >></a>'; } if ($page > 1) { echo '<a href="' . $_SERVER["PHP_SELF"] . '?page=' . ($page - 1) . '"><< Prev page</a>'; }
One Query Method
The thing that I don't like about the method above is you have to use two queries. Lets say it takes .23563 seconds for each query. That's not a lot of time but over a period of time it adds up. So you use two queries every time the page is loaded. So .23563 * 2 = .47126 seconds right? Lets say your page gets viewed 25 times a day. Take 25 * .47126 = 11.7815 seconds. I would consider that a large amount of time for some thing very simple. Here is my method.
//check do we have a starting page? if (isset($_GET['page'])) { $page = $_GET['page']; } else { $page = 1; } // end of if $maxItemsOnPage = 15; //connect to the database $link = mysql_connect('example.com:3307', 'username', 'password'); mysql_select_db('db_name',$link); $query ="SELECT *,(SELECT COUNT(*) FROM blog_category as bc,blog as b WHERE b.blog_blog_category_id=bc.blog_category_id AND b.blog_status='published' ) as num_of_rows FROM blog_category as bc,blog as b WHERE b.blog_blog_category_id=bc.blog_category_id AND b.blog_status='published' ORDER BY b.blog_created DESC LIMIT" . (($page - 1) * $maxItemsOnPage) ."," . $maxItemsOnpage; $result = mysql_query($query, $link); //we got the results now lets peek and see how many rows there are $temp= mysql_fetch_row($res); //assign the row count $numberOfRows=$temp['num_of_rows']; //reset the result set mysql_data_seek($result,0); //get the number of pages and be on our marry way! $numpages = ceil($numberOfRows / $maxItemsOnPage); //do something with the results //show the links if ($page < $numberOfpages) { echo '<a href="' . $_SERVER["PHP_SELF"] . '?page=' . ($page + 1) . '">Next page >></a>'; } if ($page > 1) { echo '<a href="' . $_SERVER["PHP_SELF"] . '?page=' . ($page - 1) . '"><< Prev page</a>'; }
How it works
In this query we count the number of rows that fit our where clause using a sub query along with the limited results that we are only going to show on this page. I.E.:
(SELECT COUNT(*) FROM blog_category as bc,blog as b WHERE b.blog_blog_category_id=bc.blog_category_id AND b.blog_status='published' ) as num_of_rows
Then we peek ahead and get the first row and get the column named "num_of_rows". Then we reset the query result with "mysql_data_seek($result,0)". Poof that's it.
There could be 2 downsides to this method. One in every row in the result you have dupulacte data. And Two, Using "SELECT COUNT(*)" every time on tables that have lots of records could bog your server down.