php超大树形分页,PHP+MySql千万级数据limit分页优化方案
PHP+MySql千萬級數據limit分頁優化方案
1年前
閱讀 2750
評論 0
喜歡 0
### 原因
徒弟突然有個需求,就是他發現limit分頁,頁數越大之后,mysql的消耗越大,查詢時間越長,當突破百萬級數據之后,一個簡單的翻頁都需要5-6秒,極其不方便。
### 測試數據庫結構
```
CREATE TABLE IF NOT EXISTS `video_info` (
`id` int(10) unsigned NOT NULL COMMENT '自增ID',
`channel_id` varchar(30) DEFAULT NULL COMMENT '頻道ID',
) ENGINE=InnoDB AUTO_INCREMENT=4565068 DEFAULT CHARSET=utf8mb4;
ALTER TABLE `video_info`
ADD PRIMARY KEY (`id`),
ADD KEY `channel_id` (`channel_id`);
ALTER TABLE `video_info`
MODIFY `id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增ID',AUTO_INCREMENT=1;
```
上面數據庫隨機生成700W數據,進行效率測試。
### ThinkPHP5.1的分頁代碼:
```php
namespace app\index\controller;
use think\Controller;
class Index extends Controller
{
public function index() {
$page = !empty($_GET['page']) ? $_GET['page'] : 1;
$limit = !empty($_GET['limit']) ? $_GET['limit'] : 10;
$where = [];
$param = '?';
if (!empty($_GET['keys'])) {
$where[] = ['channel_id', 'like', '%'.$_GET['keys'].'%'];
$param .= 'keys='.$_GET['keys'];
}
$total = \think\Db::name('video_info')->where($where)->count();
// 取最后一條記錄做翻頁條件
$sql = \think\Db::name('video_info')->where($where)->limit((($page-1)*$limit), 1)->field('id')->buildSql();
$list = \think\Db::name('video_info')->where($where)->where('id >= '.$sql.'')->limit($limit)->field('id, channel_id')->select();
$this->assign('page', $page);
$this->assign('limit', $limit);
$this->assign('param', $param);
$this->assign('total', $total);
$this->assign('list', $list);
// 渲染模板輸出
return $this->fetch();
}
}
```
### 原生PHP的分頁代碼:
```php
//程序運行時間
$starttime = explode(' ',microtime());
# 設置html頁面為UTF-8編碼
header("Content-type:text/html;charset=utf-8");
# 使用MySqli連接數據庫
$DB = mysqli_connect('127.0.0.1', 'localhost_db', 'localhost_db', 'localhost_db', 3306);
# 設置數據庫為UTF-8編碼
mysqli_query($DB, 'set names utf8');
$page = !empty($_GET['page']) ? $_GET['page'] : 1;
$limit = !empty($_GET['limit']) ? $_GET['limit'] : 10;
$where = ' 1=1';
$param = '?';
if (!empty($_GET['keys'])) {
$where .= ' AND channel_id like "%'.$_GET['keys'].'%"';
$param .= 'keys='.$_GET['keys'];
}
$sql = 'SELECT COUNT(*) AS count FROM video_info where'.$where;
# 使用mysqli_query()執行SQL語句
$res = mysqli_query($DB, $sql);
# 判斷是否執行成功
if ($res == false) {
echo '查詢失敗'; exit;
}
$array= mysqli_fetch_array($res);
$total = $array['count'];
$sql = ' SELECT `id`,`channel_id` FROM `video_info` WHERE '.$where.' AND ( id >= ( SELECT `id` FROM `video_info` WHERE '.$where.' LIMIT '.(($page-1)*$limit).', 1 ) ) LIMIT '.$limit;
$res = mysqli_query($DB, $sql);
# 判斷是否執行成功
if ($res == false) {
echo '查詢失敗'; exit;
}
$list= mysqli_fetch_all($res, MYSQLI_ASSOC);
//程序運行時間
$endtime = explode(' ',microtime());
$thistime = $endtime[0]+$endtime[1]-($starttime[0]+$starttime[1]);
$thistime = round($thistime,7);
$title = "本網頁執行耗時:".$thistime." 秒";
?>
test page搜索
| ID | 渠道ID |
| <?php echo $v['id'];?> | <?php echo $v['channel_id'];?> |
function getParameter(name) {
var reg = new RegExp("(^|&)"+ name +"=([^&]*)(&|$)");
var r = window.location.search.substr(1).match(reg);
if (r!=null) return unescape(r[2]); return null;
}
//init
$(function(){
var totalPage = <?php echo $total/$limit;?>;
var totalRecords = <?php echo $total;?>;
var pageNo = getParameter('page');
if(!pageNo){
pageNo = 1;
}
//生成分頁
//有些參數是可選的,比如lang,若不傳有默認值
kkpager.generPageHtml({
pno : pageNo,
//總頁碼
total : totalPage,
//總數據條數
totalRecords : totalRecords,
//鏈接前部
hrefFormer : '/2/index.php',
//鏈接尾部
hrefLatter : '',
getLink : function(n){
return this.hrefFormer + this.hrefLatter +'<?php echo $param;?>'+"&page="+n;
}
/*
,lang: {
firstPageText: '首頁',
firstPageTipText: '首頁',
lastPageText: '尾頁',
lastPageTipText: '尾頁',
prePageText: '上一頁',
prePageTipText: '上一頁',
nextPageText: '下一頁',
nextPageTipText: '下一頁',
totalPageBeforeText: '共',
totalPageAfterText: '頁',
currPageBeforeText: '當前第',
currPageAfterText: '頁',
totalInfoSplitStr: '/',
totalRecordsBeforeText: '共',
totalRecordsAfterText: '條數據',
gopageBeforeText: '?轉到',
gopageButtonOkText: '確定',
gopageAfterText: '頁',
buttonTipBeforeText: '第',
buttonTipAfterText: '頁'
}*/
//,
//mode : 'click',//默認值是link,可選link或者click
//click : function(n){
//this.selectPage(n);
// return false;
//}
});
});
```
### 最終效果
在沒優化之前,正常的limit翻頁到4.5W頁,最后一頁時,需要耗時22秒左右,優化之后則只需要花費1.5秒,提高了17倍左右的查詢速度。
### 原理和缺點:
原理很簡單,就是使用子查詢獲得max(id),然后進行當前分頁。
缺點也很明顯,那就是分頁的關鍵參數,id值只能為自增主鍵,否則這個方案用不了。
? 著作權歸作者所有
總結
以上是生活随笔為你收集整理的php超大树形分页,PHP+MySql千万级数据limit分页优化方案的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: java8 stream 做累加_《Ja
- 下一篇: java rsa算法_求RSA算法JAV