webman的分表操作

不败少龙

laravel的orm操作

namespace App\model;
use support\Db;
use support\Model;
class DemoModel extends Model
{
    protected $table="demo";
    public function __construct(array $attributes = [])
        {
            $data_table = $this->getTable();
            $this->table = $data_table.date('Ym');
            $result = Db::schema()->hasTable($this->table);
            if (empty($result)) {
                Db::update('create table '  . $this->table . ' like ' .   $data_table);
            }
            parent::__construct($attributes);
        }
}

thinkphp的orm操作方法

namespace App\model;
use think\facade\Db;
use think\Model;
class DemoModel extends Model
{
    protected $table="demo";
    public function __construct(array $attributes = [])
        {
            $data_table = $this->getTable();
            $this->table = $data_table.date('Ym');
            $prefix = config('thinkorm.prefix')??'';
            $result = Db::query("SHOW TABLES LIKE '{$prefix}{$this->table}'");
            if (empty($result)) {
                Db::query('create table '  . $this->table . ' like ' .   $data_table);
            }
            parent::__construct($attributes);
        }
}
/**
 * 获取分表数据
 * @param string $table_name 原始表名
 * @param array $where 条件
 * @param int $page 分页
 * @param int $page_er 页数数量
 * @param array $select 表字段
 * @param array $orderBy 排序
 * @return mixed
 */
function getSubTableData(string $table_name = "", $where = [], int $page = 0, int $page_er = 10, array $orderBy = ['id'=>'desc'],$select = ['*'])
{
    $offset = $page * $page_er;
    // 开始日期
    $start = Carbon::parse(date('Y-01-01'));
    // 结束日期
    $end = Carbon::now();
    // 查询集合
    $queries = collect();
    //把最原始表单的数据加入
    if(Schema::hasTable($table_name)){
        $queries->push(
            DB::table($table_name)
                // 建议都用select查询字段,SQL尽可能的优化性能
                ->select($select)
                ->where($where)
        );
    }
    // 循环比较年月,添加每一张表的查询
    for ($i = $start->copy(); $i->format('Y-m') <= $end->format('Y-m'); $i->addMonth()) {

        // 按日期循环组装出表名
        $tableName = $table_name . "_{$i->format('Ym')}";
        // 检查这个表是否存在
        if (Schema::hasTable($tableName)) {
            $queries->push(
                DB::table($tableName)
                    // 建议都用select查询字段,SQL尽可能的优化性能
                    ->select($select)
                    ->where($where)
            );
        }
    }
    $unionQuery = $queries->shift();
    // 循环剩下的表添加union
    $queries->each(function ($item, $key) use ($unionQuery) {
        $unionQuery->unionAll($item);
    });
    // 把用 unionAll链接起来的sql 组成一个表
    $model = DB::table($table_name)
        // 添加临时表
        ->from(DB::raw("({$unionQuery->toSql()}) AS {$table_name}"))
        // 合并查询条件
        ->mergeBindings($unionQuery);
    if ($orderBy) {
        foreach ($orderBy as $k=>$v){
            // 按时间倒序
            $model->orderBy($k, $v);
        }
    }
    $data['total'] = $model->count();
    $data['data'] = $model->limit($page_er)->offset($offset)->get()->toArray();
    return $data;
}
1783 4 4
4个评论

moco

可否发下thinkorm的呢

liziyu

感谢大佬分享

  • 暂无评论
chaz6chez

DML语句可能中断事务,在处理事务内回滚等操作的时候会带来麻烦;
个人建议为DML独自创建定时器周期进行建表操作,尽可能与DDL语句分离,保证事务执行的纯粹性

  • 不败少龙 2023-04-27

    恩,大佬 这个建议好

  • chaz6chez 2023-04-27

    可以抽象一个Builder,这个Builder包含对应的Model,包含对应的定时进程创建/移除相关的内容(一般单进程即可)。
    比如实现一个command:webman:xxx-builder create acb --cron=' ',就可以创建一个名叫abc的Builder,并且把定时进程加载到process.php中。
    当然这个方案也可以优化,就是builder不与定时进程一一对应,而是builder可以创建一个延时消息到消息队列,消息队列消费者可以通过builder的建表方法执行建表。

    大概思路是这样,因为之前在生产环境有遇到类似的,虽然不是php的项目,但思路差不多

  • chaz6chez 2023-04-27

    队列也可以切换成调度服务比如xxl job、APSscheduler等等

  • chaz6chez 2023-04-27

    不论是进程还是线程,加载到配置文件这种方案都比较适合前期,因为随着服务实例部署的多了以后,管理是不方便的,通过服务注册、调度系统、消息队列这种方案更适合项目中后期,但进程/线程+配置这个足够用很长时间了。

  • 不败少龙 2023-04-27

    说得太高深了,大佬可以做一个专门的分享吗?

  • chaz6chez 2023-04-27

    空了我分享一下吧,最近太忙了

  • 不败少龙 2023-04-27

    好的,期待大佬分享

xiaopi

我是这样laravel orm分表的:
模型中设置静态属性$tableSuffix
然后模型中重写getTable()方法


    public function getTable(): string
    {
        return self::TABLE_NAME . '_' . self::$tableSuffix;
    }

然后使用之前设置下表后缀
XXXModel::$tableSuffix='xxxxxxx';

然后每次访问模型都要检查下表是否存在,我感觉操作数据库太频繁了,所以我放到了文件中,先判断文件是否存在,如果不存在,再判断表是否存在。这样查找文件比查找数据库快一些。类似这样

 $tableName = 'xxxtable_' . $userId;
 $filePath = 'user/' . $tableName;
 if (!Storage::disk()->exists($filePath)) {
     if (!Db::schema()->hasTable($tableName)) {
         Db::statement("CREATE TABLE `$tableName`  LIKE `xxxtables`;");
     }
    Storage::disk()->put($filePath, Carbon::now()->toDateTimeString());
 }

// 设置表后缀
XXXModel::$tableSuffix = $userId;

不败少龙

9914
积分
0
获赞数
0
粉丝数
2018-08-17 加入
×
🔝