旗下导航:搜·么
当前位置:网站首页 > PHP框架 > ThinkPHP > 正文

ThinkPHP5水中分表后分页查询解决方案【ThinkPHP教程】,ThinkPHP5

作者:搜搜PHP网发布时间:2020-01-01分类:ThinkPHP浏览:65


导读:ThinkPHP5内置了partition要领,可用于完成简朴的分表。新增,修正,删除,查询单条数据时,用partition要领都可以轻松搞定,因为这些操纵有一个配合的特性,就是能...
ThinkPHP5内置了partition要领,可用于完成简朴的分表。新增,修正,删除,查询单条数据时,用partition要领都可以轻松搞定,因为这些操纵有一个配合的特性,就是能事前明白的晓得,我要操纵的是哪一条纪录。但有一个需求,ThinkPHP5好像没有解决,比方当一个大表,被拆分红若干个子表时,如何依据相干前提及排序猎取分页数据。

这类需求场景下,因为事前并不晓得哪些数据会出如今第一页,哪些数据会出如今第二页,这些依据检索前提动态婚配的列表数据,该如何查询呢?

一次失利的尝试

最早想到的也是最直接的一种体式格局,就是将partition要领和paginate要领结合起来,看似水到渠成的事,效果悲剧了,数据库被搞得直接奔溃。究其原因,要想完成分页查询,partition要领中须要union若干个子表,而且每一个union的子表中,都是select * 的情势,如许就会严峻影响到查询的效力,何况,在猎取纪录总数的时刻,也完全没必要查询出一切字段。

胜利之道

既然select * 会影响效力,那末select 出主键会如何呢?当然是相称的快!整体思绪就是分两次猎取数据,第一次先查询出主键,然后第二次,依据主键,猎取对应的数据。细致完成以下:

中心头脑

水中分表后,当须要分页猎取数据时,效力会变得异常低下,拆分的子表越多,对查询机能的影响就会越大。所以中心头脑就是,只管经由过程主键id来猎取对应的数据纪录,也就是分两次来猎取列表数据。

1. 先查询总纪录数及主键id

该步骤中,union 子表的select语句中,只须要列出主键id和别的分外必需的字段即可,不相干的字段无需涌现。

2. 依据主键id查询对应的完全数据。

函数封装

1. 组织猎取总纪录数及主键ID的sql子查询语句

/**
 * 组织猎取总纪录数及主键ID的sql子查询语句
 * @param $table 主表称号
 * @param $idKey 主键id字段称号
 * @param string $fields 别的字段称号,多个字段用英文逗号分开
 * @param int $num 子表数目
 * @param string $where 查询前提
 * @return array
 */
function buildPartitionSql($table,$idKey,$fields='',$num=1,$where='') {
    $countTable = [];
    $listTable = [];
    $fieldList = [$idKey];
    if ($fields) {
        $fieldList = array_merge($fieldList,explode(',',$fields));
        $fieldList = array_unique($fieldList);
    }
    $fieldStr = implode(',',$fieldList);
    for ($i = 0; $i < $num; $i++) {
        $countTable[] = sprintf('SELECT %s FROM %s_%s where 1=1 %s', $idKey, $table, ($i + 1), $where);
        $listTable[] = sprintf('SELECT %s FROM %s_%s where 1=1 %s', $fieldStr,$table, ($i + 1), $where);
    }
    $countTable = '( ' . implode(" UNION ", $countTable) . ') AS ' . $table;
    $listTable = '( ' . implode(" UNION ", $listTable) . ') AS ' . $table;
    $tables = ['countSql' => $countTable, 'listSql' => $listTable];
    return $tables;
}

挪用体式格局:

假定buildPartitionSql函数的实行效果为$tables,那末完全的SQL语句以下:

猎取总纪录数的完全sql:

select count(1) as total from .$tables['countSql']

猎取主键id的完全sql:

select * from .$tables['listSql']. limit 0,10

2. 组织猎取指定id对应纪录的sql子查询语句

/**
 * 组织猎取指定id对应纪录的sql子查询语句
 * @param $table 主表称号
 * @param $idKey 指定的id字段称号
 * @param $idValues 指定的id字段值
 * @param int $num 子表数目
 * @return string
 */
function buildPartitionListSql($table,$idKey,$idValues,$num=1) {
    $sql = '';
    $ids = is_array($idValues) ? implode(',',$idValues) : $idValues;
    if ($ids) {
        $listTable = [];
        for ($i = 0; $i < $num; $i++) {
            $listTable[] = sprintf('SELECT * FROM %s_%s where %s in (%s)', $table, ($i + 1), $idKey, $ids);
        }
        $sql = '( ' . implode(" UNION ", $listTable) . ') AS ' . $table;
    }
    return $sql;
}

挪用体式格局:

假定buildPartitionListSql函数的实行效果为$sql,那末完全的SQL语句以下:

select * from .$sql

注重:营业层面的一切检索前提,都放在了第一步的union子句中,第二步只须要依据id拿数据就好了。

ki4网,大批的免费thinkphp入门教程,迎接在线进修!

以上就是ThinkPHP5水中分表后分页查询解决方案的细致内容,更多请关注ki4网别的相干文章!

标签:ThinkPHP5