视频1 视频21 视频41 视频61 视频文章1 视频文章21 视频文章41 视频文章61 推荐1 推荐3 推荐5 推荐7 推荐9 推荐11 推荐13 推荐15 推荐17 推荐19 推荐21 推荐23 推荐25 推荐27 推荐29 推荐31 推荐33 推荐35 推荐37 推荐39 推荐41 推荐43 推荐45 推荐47 推荐49 关键词1 关键词101 关键词201 关键词301 关键词401 关键词501 关键词601 关键词701 关键词801 关键词901 关键词1001 关键词1101 关键词1201 关键词1301 关键词1401 关键词1501 关键词1601 关键词1701 关键词1801 关键词1901 视频扩展1 视频扩展6 视频扩展11 视频扩展16 文章1 文章201 文章401 文章601 文章801 文章1001 资讯1 资讯501 资讯1001 资讯1501 标签1 标签501 标签1001 关键词1 关键词501 关键词1001 关键词1501 专题2001
mysql百万条数据分页优化
2020-11-09 09:55:34 责编:小采
文档


很多程序朋友在写分页是特别是mysql有了limit n,m;这样的写法,分页从此简单了,但方不知道这种分页几万数据没有问题,但在百万千万级时就无法使用了,今天我们来介绍这两种分页的优化方法。

PHP写功能时,只要用的还是MySQL,基本都是两步走

1、取得总数,算页数。SQL语句自然是

代码如下
SELECT count(*) FROM tablename;

2、根据指定的页码号,取得相应的数据。对应的SQL语句,在网上随便查,都是一样的:

SELECT f1,f2 FROM table LIMIT offset,length

实例分页类

代码如下

/*********************************************
类名: PageSupport
功能:分页显示MySQL中的数据
***********************************************/
class PageSupport{
//属性
var $sql; //所要显示数据的SQL查询语句
var $page_size; //每页显示最多行数

var $start_index; //所要显示记录的首行序号
var $total_records; //记录总数
var $current_records; //本页读取的记录数
var $result; //读出的结果

var $total_pages; //总页数
var $current_page; //当前页数
var $display_count = 30; //显示的前几页和后几页数

var $arr_page_query; //数组,包含分页显示需要传递的参数

var $first;
var $prev;
var $next;
var $last;

//方法
/*********************************************
构造函数:__construct()
输入参数:
$ppage_size:每页显示最多行数
***********************************************/
function PageSupport($ppage_size)
{
$this->page_size=$ppage_size;
$this->start_index=0;
}


/*********************************************
构造函数:__destruct()
输入参数:
***********************************************/
function __destruct()
{

}

/*********************************************
get函数:__get()
***********************************************/
function __get($property_name)
{
if(isset($this->$property_name))
{
return($this->$property_name);
}
else
{
return(NULL);
}
}

/*********************************************
set函数:__set()
***********************************************/
function __set($property_name, $value)
{
$this->$property_name = $value;
}

/*********************************************
函数名:read_data
功能: 根据SQL查询语句从表中读取相应的记录
返回值:属性二维数组result[记录号][字段名]
***********************************************/
function read_data()
{
$ql=$this->sql;

//查询数据,数据库链接等信息应在类调用的外部实现
$result=_query($psql) or die(mysql_error());
$this->total_records=mysql_num_rows($result);

//利用LIMIT关键字获取本页所要显示的记录
if($this->total_records>0)
{
$this->start_index = ($this->current_page-1)*$this->page_size;
$psql=$psql. " LIMIT ".$this->start_index." , ".$this->page_size;

$result=mysql_query($psql) or die(mysql_error());
$this->current_records=mysql_num_rows($result);

//将查询结果放在result数组中
$i=0;
while($row=mysql_fetch_Array($result))
{
$this->result[$i]=$row;
$i++;
}
}


//获取总页数、当前页信息
$this->total_pages=ceil($this->total_records/$this->page_size);

$this->first=1;
$this->prev=$this->current_page-1;
$this->next=$this->current_page+1;
$this->last=$this->total_pages;
}

/*********************************************
函数名:standard_navigate()
功能: 显示首页、下页、上页、未页
***********************************************/
function standard_navigate()
{
echo "";
echo "";
echo "";

}

/*********************************************
函数名:full_navigate()
功能: 显示首页、下页、上页、未页
生成导航链接 如1 2 3 ... 10 11
***********************************************/
function full_navigate()
{
echo "";
echo "";
echo "";

}

}
?>

调用:

include_once("../config_jj/sys_conf.inc");
include_once("../PageSupportClass.php");//分页类
include_once('../Smarty_JsnhClass.php');

$smarty = new Smarty_Jsnh();
include_once("../include/Smarty_changed_dir.php");
$smarty->assign('title', "Smarty新闻分页测试");

$pageSupport = new PageSupport($PAGE_SIZE); //实例化PageSupport对象

$current_page=$_GET["current_page"];//分页当前页数

if (isset($current_page)) {

$pageSupport->__set("current_page",$current_page);

} else {

$pageSupport->__set("current_page",1);

}

?>
$pageSupport->__set("sql"," * from news ");
$pageSupport->read_data();//读数据

if ($pageSupport->current_records > 0) //如果数据不为空,则组装数据
{
for ($i=0; $i<$pageSupport->current_records; $i++)
{
$title = $pageSupport->result[$i]["title"];
$id = $pageSupport->result[$i]["id"];

$news_arr[$i] = array('news' => array('id' => $id,'title' => $title));

}
}

//关闭数据库
mysql_close($db);

$pageinfo_arr = array(
'total_records' => $pageSupport->total_records,
'current_page' => $pageSupport->current_page,
'total_pages' => $pageSupport->total_pages,
'first' => $pageSupport->first,
'prev' => $pageSupport->prev,
'next' => $pageSupport->next,
'last' => $pageSupport->last
);

$smarty->assign('results', $news_arr);
$smarty->assign('pageSupport', $pageinfo_arr);
$smarty->display('news/list.tpl');

?>
模板list.tpl
{* I am a Smarty comment, I don't exist in the compiled output *}
{*
{$pageSupport.total_records}

{$pageSupport.current_page}

{$pageSupport.total_pages}

{$pageSupport.first}

{$pageSupport.prev}

{$pageSupport.next}

{$pageSupport.last}

*}



{$title}

{foreach item=o from=$results}
{$o.news.id} {$o.news.title}


{foreachelse}
没有您要查看的数据!
{/foreach}


{if ( $pageSupport.total_records > 0 )}

{/if}




语法,不解释了,数据量小的时候,这么写,没事。

如果数据量大呢?不是一般大,上百万呢。

试着运行一下:

代码如下

SELECT id FROM users LIMIT 1000000,10

在我的电脑上,第一次运行,显示如下:

10 rows in set (9.38 sec)

之后再运行,显示如下:

10 rows in set (0.38 sec)

这不奇怪。MySQL对已经运行的SQL语句有缓冲,可以很快把之前的数据拿出来。

无论如何,第一次的9秒多,我实在不能接受。

换个写法:

代码如下

SELECT id FROM users WHERE id>1000000 LIMIT 10;

显示:10 rows in set (0.00 sec)

事实上,用phpMyAdmin去看,“显示行 0 - 9 (10 总计, 查询花费 0.0011 秒)”,之后再运行,基本都在0.0003秒左右。

百万级优化

.对查询进行优化,应尽量避免全表扫描,首先应考虑在 where 及 order by 涉及的列上建立索引。

  2.应尽量避免在 where 子句中对字段进行 null 值判断,否则将导致引擎放弃使用索引而进行全表扫描,如:

代码如下

  select id from t where num is null

  可以在num上设置默认值0,确保表中num列没有null值,然后这样查询:

代码如下

  select id from t where num=0

  3.应尽量避免在 where 子句中使用!=或<>操作符,否则将引擎放弃使用索引而进行全表扫描。

  4.应尽量避免在 where 子句中使用 or 来连接条件,否则将导致引擎放弃使用索引而进行全表扫描,如:

代码如下

  select id from t where num=10 or num=20

  可以这样查询:

代码如下

  select id from t where num=10

  union all

select id from t where num=20

  5.in 和 not in 也要慎用,否则会导致全表扫描,如:

 

代码如下
 select id from t where num in(1,2,3)

  对于连续的数值,能用 between 就不要用 in 了:

  

代码如下
select id from t where num between 1 and 3

  6.下面的查询也将导致全表扫描:

 

代码如下
 select id from t where name like '%abc%'

分类函数











代码如下

$db=dblink();
$db->pagesize=20;
$sql=”select id from collect where vtype=$vtype”;
$db->execute($sql);
$strpage=$db->strpage(); //将分页字符串保存在临时变量,方便输出
while($rs=$db->fetch_array()){
$strid.=$rs['id'].’,';
}
$strid=substr($strid,0,strlen($strid)-1); //构造出id字符串
$db->pagesize=0; //很关键,在不注销类的情况下,将分页清空,这样只需要用一次数据库连接,不需要再开;
$db->execute(“select id,title,url,sTime,gTime,vtype,tag from collect where id in ($strid)”);
fetch_array()): ?>

” target=”_blank”>

echo $strpage;

下载本文
显示全文
专题