分表的好处:
分表是将单个数据库表拆分为多个较小的表的过程。这样做有以下几个潜在的好处:
1. 提升查询性能:当表中包含大量数据时,查询可能变得缓慢。通过分表,可以将数据分散到多个表中,每个表的数据量较小,从而提高查询性能。
2. 管理数据更灵活:通过分表,可以将数据按照某种规则(例如时间、地理位置等)进行分隔和存储。这样可以更容易地管理和维护数据,例如删除过期数据或备份数据。
3. 分布式存储:分表为分布式存储提供了基础。可以将不同的表存储在不同的服务器上,以实现数据的水平扩展和负载均衡。
4. 降低锁冲突:在高并发环境中,如果多个查询操作同时访问同一个表,可能会导致锁冲突和性能问题。通过分表,可以将查询操作分散到多个表上,减少锁冲突的可能性,提高并发性能。
5. 数据隔离:在某些情况下,你可能希望将数据进行隔离,以便不同的用户或不同的业务操作可以在独立的表中进行。分表可以提供更好的数据隔离和安全性。
需要注意的是,分表也会带来一些挑战和额外的复杂性。例如,需要根据分表规则调整查询逻辑,处理表之间的关联关系以及维护分表结构的一致性。因此,在决定使用分表时,需要综合考虑应用程序的需求、数据量和性能需求,并仔细规划和实施分表策略。
以下提供的Demo案例:
以产品表exa_product_0、exa_product_1、exa_product_2、exa_product_3四个表为例:
CREATE TABLE `exa_product` (
`id` int NOT NULL AUTO_INCREMENT COMMENT 'ID',
`category_id` tinyint DEFAULT '0' COMMENT '分类ID',
`goods_name` varchar(150) DEFAULT '' COMMENT '产品名称',
`created_at` int DEFAULT NULL,
`updated_at` int DEFAULT NULL,
`deleted_at` int DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3
1、定义基础模型类:
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
use DateTimeInterface;
use Illuminate\Support\Facades\Schema;
class Base extends Model
{
use SoftDeletes;
const CREATED_AT = 'created_at';
const UPDATED_AT = 'updated_at';
const DELETED_AT = 'deleted_at';
/**
* @var string 表后缀
*/
protected $suffix = '';
/**
* @var string[] 隐藏输出字段
*/
protected $hidden = ['deleted_at'];
/**
* 返回格式化时间
*
* @param DateTimeInterface $date
* @return string
*/
protected function serializeDate(DateTimeInterface $date)
{
return $date->format('Y-m-d H:i:s');
}
/**
* 设置动态表名
*
* @param string $suffix
* @return Base
*/
public function scopeSuffix(string $suffix)
{
return $this->setTable($this->getTableWithSuffix($suffix));
}
/**¬
* 根据传递的表后缀名,获取完整的表名
*
* @param string $suffix 表后缀名
* @return string 完整的表名
*/
private function getTableWithSuffix(string $suffix): string
{
$table = $this->getTable() . $suffix;
if(!Schema::hasTable($table)) {
throw new \InvalidArgumentException("Table [{$table}] not found.");
}
return $table;
}
}
二、定义产品模型类:
<?php
namespace App\Models\Goods;
use App\Models\Base;
class ProductModel extends Base
{
/**
* @var string
*/
protected $primaryKey = 'id';
/**
* @var int 分表数量
*/
public const TABLE_COUNT = 4;
}
三、查询分页列表:
<?php
namespace App\Trans\Goods;
use App\Models\Goods\ProductModel;
use Illuminate\Support\Facades\DB;
class ProductTrans
{
/**
* 产品列表
* @param $params
* @return array|int
*/
public static function getProductList($params = [])
{
$options = [
'categoryId' => 0,
'goodsName' => '',
'fields' => ['*'],
'orderByStr' => 'category_id-desc',
'page' => 1,
'pageSize' => 10,
'isGetCount' => false
];
if($params && is_array($params)) {
$options = array_merge($options, $params);
}
extract($options);
// 查询集合
$queries = collect();
for ($i = 0; $i < ProductModel::TABLE_COUNT; $i++) {
$query = DB::table('product_' . $i)->select($fields);
if($categoryId) {
$query = $query->where('category_id', $categoryId);
}
if($goodsName) {
$query = $query->where('goods_name', 'like', '%' . $goodsName . '%');
}
$queries->push($query);
}
// 取出第一个作为查询对象,其他的作为合并对象
$unionQuery = $queries->shift();
// 循环剩下的表添加union
$queries->each(function($item) use ($unionQuery) {
$unionQuery->unionAll($item);
});
$endQuery = DB::table(DB::raw("({$unionQuery->toSql()}) as product"))->mergeBindings($unionQuery);
// 总条数
$count = $endQuery->count();
if($isGetCount) {
return $count;
}
// 排序
foreach (formatOrderby(['orderByStr' => $orderByStr]) as $val) {
$endQuery = $endQuery->orderBy($val[0], $val[1]);
}
$list = $endQuery->skip(($page - 1) * $pageSize)->take($pageSize)->get()->toArray();
return camel(['list' => objectToArray($list), 'total' => $count]);
}
}