Laravel ORM 中处理大量数据时的分表策略是怎么实现的呢?

大家好,

我目前在使用 Laravel 框架来处理一个物联网项目的数据存储需求。我们有一个传感器数据表,每天新增大约 40 万条记录,每条记录包含 10 个字段左右。由于数据量较大且查询频率很高,我正在考虑实施分表策略以提高数据库性能。

当前情况#

  • 每日新增数据量:约 40 万条
  • 字段数量:10 个
  • 数据类型:物联网传感器返回的数据
  • 查询频率:非常高
  • 查询范围:通常不超过 30 天的数据

考虑的问题#

  1. 分表方法

    • 是否有推荐的 Laravel 插件或库可以帮助实现自动分表?
    • 如果没有现成工具,手动实现分表的最佳实践是什么?
  2. 分表策略

    • 按日期分表是否合适?例如,每月创建一个新表。
    • 除了按日期分表外,还有哪些其他有效的分表策略适合这种场景?
  3. 跨表查询

    • 如何高效地执行跨表查询(例如,查询最近 30 天的数据)?
    • 是否有特定的技术或技巧可以用来优化这类查询?
  4. 社区经验

    • 大家在类似情况下是如何处理的?
    • 有没有遇到过什么坑或者有什么特别需要注意的地方?

非常感谢大家的经验分享和建议!

《L04 微信小程序从零到发布》
从小程序个人账户申请开始,带你一步步进行开发一个微信小程序,直到提交微信控制台上线发布。
《L02 从零构建论坛系统》
以构建论坛项目 LaraBBS 为线索,展开对 Laravel 框架的全面学习。应用程序架构思路贴近 Laravel 框架的设计哲学。
最佳答案

之前做一个 大数据项目的时候,分表是按照,日期分表的,然后自动创建表之后,又运行了一下 创建视图,就这样的

CREATE VIEW device_data_view AS
SELECT * FROM data_202309
UNION ALL
SELECT * FROM data_202308
UNION ALL
SELECT * FROM data_202307;

然后 laravel 中 查询的时候.

class DeviceDataView extends Model
{
    // 视图名
    protected $table = 'device_data_view';

    // 由于视图通常没有自增主键,因此可以禁用 Eloquent 的自动递增键
    public $incrementing = false;

    // 视图中不会有时间戳字段,因此禁用默认的时间戳功能
    public $timestamps = false;

    // 根据需要定义其他属性和关系
}

这样干的,后来数据大了,有点慢 又做了一次优化,尝试了一次 分区表(Partition Table)

PARTITION BY RANGE (TO_DAYS(record_date)) (
    PARTITION p202309 VALUES LESS THAN (TO_DAYS('2023-10-01')),
    PARTITION p202310 VALUES LESS THAN (TO_DAYS('2023-11-01')),
    ...
);

查询也还行,速度能跟上.

最后的最后,上面的办法 支撑了半年,又有点卡顿了,使用了 Mycat 来 按月按设备进行了分库分表

6个月前 评论
无与伦比 (楼主) 6个月前
PFinal南丞 (作者) 6个月前
无与伦比 (楼主) 6个月前
讨论数量: 33

适合用 nosql 呀,时序数据库那种,这种一般不考虑事务

6个月前 评论
无与伦比 (楼主) 6个月前
tsingyan (作者) 6个月前
无与伦比 (楼主) 6个月前
tsingyan (作者) 6个月前

物联网项目数据采集,直接上 TIDB 不用考虑分表问题

6个月前 评论
无与伦比 (楼主) 6个月前

时序数据库(PostgreSQL+TimescaleDB)

分表,搭配中间件,程序无感。

6个月前 评论
yourself

按月分表被,重写一下规则

blog.csdn.net/a18132147899/article...

6个月前 评论
无与伦比 (楼主) 6个月前
yourself (作者) 6个月前
无与伦比 (楼主) 6个月前

你们这个是通过 modbus tcp 拿点位数据吗,我们最近也有这个需求

6个月前 评论
无与伦比 (楼主) 6个月前
W-W (作者) 6个月前
无与伦比 (楼主) 6个月前

之前做一个 大数据项目的时候,分表是按照,日期分表的,然后自动创建表之后,又运行了一下 创建视图,就这样的

CREATE VIEW device_data_view AS
SELECT * FROM data_202309
UNION ALL
SELECT * FROM data_202308
UNION ALL
SELECT * FROM data_202307;

然后 laravel 中 查询的时候.

class DeviceDataView extends Model
{
    // 视图名
    protected $table = 'device_data_view';

    // 由于视图通常没有自增主键,因此可以禁用 Eloquent 的自动递增键
    public $incrementing = false;

    // 视图中不会有时间戳字段,因此禁用默认的时间戳功能
    public $timestamps = false;

    // 根据需要定义其他属性和关系
}

这样干的,后来数据大了,有点慢 又做了一次优化,尝试了一次 分区表(Partition Table)

PARTITION BY RANGE (TO_DAYS(record_date)) (
    PARTITION p202309 VALUES LESS THAN (TO_DAYS('2023-10-01')),
    PARTITION p202310 VALUES LESS THAN (TO_DAYS('2023-11-01')),
    ...
);

查询也还行,速度能跟上.

最后的最后,上面的办法 支撑了半年,又有点卡顿了,使用了 Mycat 来 按月按设备进行了分库分表

6个月前 评论
无与伦比 (楼主) 6个月前
PFinal南丞 (作者) 6个月前
无与伦比 (楼主) 6个月前

那只眼睛看到题主写的数据上 T 了, 每日新增数据量:约 40 万条, 热数据一个月 1200w 数据叫多, 回家种地吧。

至于 题主问的 查询频率:非常高, sql 也不亮出来看看 鬼知道怎么写的 sql.

上面推荐 mycat tidb 之流。非蠢即坏, 自己都用不熟就敢张嘴推荐。 tidb 边缘性业务用, mycat 都不维护了上来就分享。

题主都说了目前在用云数据库, cloud.tencent.com/product/dcdb sql 写规范点买个云数据库 读写分离配置下 还瞎操什么心。 折腾分库分表的没前途的。

6个月前 评论
无与伦比 (楼主) 6个月前
PFinal南丞 6个月前

可以做好分表的准备,等一张表明显感觉慢了才换也可以, 当前看可以不分。 也做过 iot 相关的,因为有 saas 需求,我们按租户维度分过数据表。还有项目按设备分过。因为我们业务对跨度较大的数据没好多要求。我们固定时间也会去清理,然后加了统计表对每个点位数据按照每天做了平均值存储。
从你说的:查询频率很高。 要从业务分析下:是需要查跨度很大的数据,还是其他的,比如最新的数据、汇总统计之类的。
查跨度很大的数据、汇总统计: 数据量很大了,索引效果不佳。分表就要根据时间 、设备 等维度考虑。这些上面上面的大佬说的可参考
读最新的数据:这个场景来说,个人有个经验处理,设备表存一个最新数据记录 ID(符合设备数据同时采集在一个数据表的几个字段上);或者:查询采集表各设备的数据最大 ID, 然后再通过最大 ID 去查询最新的数据

6个月前 评论
无与伦比 (楼主) 6个月前

每日 40w 热数据,一个月也就 1200 万,一年也就 1.5 亿数据,是否需要分库分表,是否结合分区和分库分表两种策略,分库分表采用什么策略,具体还是要看查询业务场景。

  • 分区: 如果查询业务以时间因子为主,按时间分区基本可以满足需求,查询表数据最多存储 1-2 年,超出期限的数据如果不需要可以删除,需要的话迁移至备份表存储,备份表可以按年和月分表进行存储。
  • 分表:看你的需求有涉及最近 30 天时间维度查询,如果按月分表,必然涉及跨表查询,若存在聚合排序,大表之间连接查询 IO 必然不小,建议额外冗余一张查询主表,然后按月分表,查询主表保留最近 X 个月的数据,例如保留 3 个月,最近 3 个月数据以主表为准,超出 3 个月以上按月分表查询,建议不跨月,单独按月查询。
6个月前 评论

这种采集数据如果不是非常必要入库,是不是考虑每天生成特定文件,并且上传至 ES 服务呢

6个月前 评论
无与伦比 (楼主) 6个月前

这种类型的日志数据,直接用 时间序列数据库。

6个月前 评论

可以用 ClickHouse

6个月前 评论

问题核心点是设计好查询逻辑和冷热数据分离,实际 MySQL 挺能扛的(前提是得 SSD),这边一个月大概是六千万的数据量,按月分表,查询做了限制逻辑,只能查询一个月内数据,查询量不是非常大,热数据一天内查 MySQL(实际存了一个月的量,体积大概在二十几 G),其他查 MongoDB,目前没遇到啥问题。冷热数据是写入的时候双写,自动建表,定期将热数据中的冷数据归档。

5个月前 评论