php超大树形分页,PHP+MySql千万级数据limit分页优化方案
PHP+MySql千萬(wàn)級(jí)數(shù)據(jù)limit分頁(yè)優(yōu)化方案
1年前
閱讀 2750
評(píng)論 0
喜歡 0
### 原因
徒弟突然有個(gè)需求,就是他發(fā)現(xiàn)limit分頁(yè),頁(yè)數(shù)越大之后,mysql的消耗越大,查詢時(shí)間越長(zhǎng),當(dāng)突破百萬(wàn)級(jí)數(shù)據(jù)之后,一個(gè)簡(jiǎn)單的翻頁(yè)都需要5-6秒,極其不方便。
### 測(cè)試數(shù)據(jù)庫(kù)結(jié)構(gòu)
```
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;
```
上面數(shù)據(jù)庫(kù)隨機(jī)生成700W數(shù)據(jù),進(jìn)行效率測(cè)試。
### ThinkPHP5.1的分頁(yè)代碼:
```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();
// 取最后一條記錄做翻頁(yè)條件
$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的分頁(yè)代碼:
```php
//程序運(yùn)行時(shí)間
$starttime = explode(' ',microtime());
# 設(shè)置html頁(yè)面為UTF-8編碼
header("Content-type:text/html;charset=utf-8");
# 使用MySqli連接數(shù)據(jù)庫(kù)
$DB = mysqli_connect('127.0.0.1', 'localhost_db', 'localhost_db', 'localhost_db', 3306);
# 設(shè)置數(shù)據(jù)庫(kù)為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()執(zhí)行SQL語(yǔ)句
$res = mysqli_query($DB, $sql);
# 判斷是否執(zhí)行成功
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);
# 判斷是否執(zhí)行成功
if ($res == false) {
echo '查詢失敗'; exit;
}
$list= mysqli_fetch_all($res, MYSQLI_ASSOC);
//程序運(yùn)行時(shí)間
$endtime = explode(' ',microtime());
$thistime = $endtime[0]+$endtime[1]-($starttime[0]+$starttime[1]);
$thistime = round($thistime,7);
$title = "本網(wǎng)頁(yè)執(zhí)行耗時(shí):".$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;
}
//生成分頁(yè)
//有些參數(shù)是可選的,比如lang,若不傳有默認(rèn)值
kkpager.generPageHtml({
pno : pageNo,
//總頁(yè)碼
total : totalPage,
//總數(shù)據(jù)條數(shù)
totalRecords : totalRecords,
//鏈接前部
hrefFormer : '/2/index.php',
//鏈接尾部
hrefLatter : '',
getLink : function(n){
return this.hrefFormer + this.hrefLatter +'<?php echo $param;?>'+"&page="+n;
}
/*
,lang: {
firstPageText: '首頁(yè)',
firstPageTipText: '首頁(yè)',
lastPageText: '尾頁(yè)',
lastPageTipText: '尾頁(yè)',
prePageText: '上一頁(yè)',
prePageTipText: '上一頁(yè)',
nextPageText: '下一頁(yè)',
nextPageTipText: '下一頁(yè)',
totalPageBeforeText: '共',
totalPageAfterText: '頁(yè)',
currPageBeforeText: '當(dāng)前第',
currPageAfterText: '頁(yè)',
totalInfoSplitStr: '/',
totalRecordsBeforeText: '共',
totalRecordsAfterText: '條數(shù)據(jù)',
gopageBeforeText: '?轉(zhuǎn)到',
gopageButtonOkText: '確定',
gopageAfterText: '頁(yè)',
buttonTipBeforeText: '第',
buttonTipAfterText: '頁(yè)'
}*/
//,
//mode : 'click',//默認(rèn)值是link,可選link或者click
//click : function(n){
//this.selectPage(n);
// return false;
//}
});
});
```
### 最終效果
在沒(méi)優(yōu)化之前,正常的limit翻頁(yè)到4.5W頁(yè),最后一頁(yè)時(shí),需要耗時(shí)22秒左右,優(yōu)化之后則只需要花費(fèi)1.5秒,提高了17倍左右的查詢速度。
### 原理和缺點(diǎn):
原理很簡(jiǎn)單,就是使用子查詢獲得max(id),然后進(jìn)行當(dāng)前分頁(yè)。
缺點(diǎn)也很明顯,那就是分頁(yè)的關(guān)鍵參數(shù),id值只能為自增主鍵,否則這個(gè)方案用不了。
? 著作權(quán)歸作者所有
總結(jié)
以上是生活随笔為你收集整理的php超大树形分页,PHP+MySql千万级数据limit分页优化方案的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: java8 stream 做累加_《Ja
- 下一篇: java rsa算法_求RSA算法JAV