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分页优化方案相关推荐

  1. MYSQL百万级数据,如何优化

    MYSQL百万级数据,如何优化 首先,数据量大的时候,应尽量避免全表扫描,应考虑在 where 及 order by 涉及的列上建立索引,建索引可以大大加快数据的检索速度.但是,有些情况索引是不会起效 ...

  2. 单表千万级数据 count() 统计优化

    1. 创建一张测试表: DROP TABLE IF EXISTS `user`; CREATE TABLE `user` ( `id` bigint(20) PRIMARY key not null ...

  3. 一次 MySQL 千万级大表的优化过程

    作者:赵客缦胡缨v吴钩霜雪明 https://www.jianshu.com/p/336f682e4b91 概述 使用阿里云rds for MySQL数据库(就是MySQL5.6版本),有个用户上网记 ...

  4. MySQL千万级数据JDBC插入

    案例语句: String sql = "LOAD DATA LOCAL INFILE '" + dataFilepath + "' into table " + ...

  5. mysql千万级大数据SQL查询优化

    1.对查询进行优化,应尽量避免全表扫描,首先应考虑在 where 及 order by 涉及的列上建立索引.2.应尽量避免在 where 子句中对字段进行 null 值判断,否则将导致引擎放弃使用索引 ...

  6. 如何优化MySQL千万级大表

    很好的一篇博客,转载 如何优化MySQL千万级大表 原文链接::https://blog.csdn.net/yangjianrong1985/article/details/102675334 千万级 ...

  7. 来个硬货——长文解读:基于业务场景的MySQL千万级大表优化

    千万级大表如何优化,这是一个很有技术含量的问题,通常我们的直觉思维都会跳转到拆分或者数据分区,在此我想做一些补充和梳理,想和大家做一些这方面的经验总结,也欢迎大家提出建议. 从一开始脑海里开始也是火光 ...

  8. MySQL千万级大表优化解决方案

    MySQL千万级大表优化解决方案 参考文章: (1)MySQL千万级大表优化解决方案 (2)https://www.cnblogs.com/yliucnblogs/p/10096530.html 备忘 ...

  9. 30个mysql千万级大数据SQL查询优化技巧详解

    点击上方关注 "终端研发部" 设为"星标",和你一起掌握更多数据库知识 文章来自:脚本之家 http://www.jb51.net/article/136701 ...

最新文章

  1. hadoop自定义类型注意问题
  2. Redis系列四:redis支持的数据类型
  3. 数据库:分享四个实用的SQLServer脚本函数,欢迎收藏
  4. 智能自动PPR更改事件策略
  5. Django系列:(1)PyCharm下创建并运行我们的第一个Django工程
  6. 常用的Linux命令行文本处理工具总结
  7. CSS3学习笔记之loading动画
  8. 华为交换机路由器最新默认密码大全
  9. 百度迁徙数据爬取 生成excel数据
  10. 计算机无法安装新字体,如何解决XP系统中无法安装新字体
  11. 重量级ORM框架--持久化框架Hibernate【关系映射详解】
  12. 疫情影响下普惠金融风险与对策
  13. 苹果新专利:紧急情况下可用指纹或特定输入操作悄悄呼救
  14. 4 Bootstrap4组件——徽章(Badges)
  15. 基于Java web的电动车销售平台 毕业设计-附源码201524
  16. Python 列表元组拆分为多个列表
  17. 3.2 项目(多肉)
  18. 解决Ardupilot+gazebo+mavros在仿真状态下无人机能解锁,但是不能起飞的问题
  19. 怎么看在手机上看hbo_HBO Max上播放的最佳中医电影(2020年6月)
  20. 【Java8 Stream】:探秘Stream实现的核心:Collector,模拟Stream的实现

热门文章

  1. KNN算法检测手势动作
  2. axios跨域携带cookie_vue 本地调试跨域---带cookies(axios)
  3. Win10中如何找到并打开SqlServer2008 R2配置管理器
  4. mysql 视图 数据相加_MySQL
  5. mysql t 保存_检查 (调试) - 离线消息保存到 MySQL - 《EMQ X Enterprise v4.1 中文文档》 - 书栈网 · BookStack...
  6. md5会重复吗_如何优雅地处理重复请求(并发请求)
  7. go get如何删除_Go 每日一库之 xorm
  8. linux cmake变量,linux – CMake错误:此项目中使用了以下变量,但它们设置为NOTFOUND...
  9. UC浏览器怎样收藏视频
  10. Win7旗舰版禁止修改文件属性的设置方法