You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

MySQL大产品历史表如何分区?Laravel+MariaDB仓库系统性能优化需求

针对1500万行操作日志表的MariaDB分区方案(适配Laravel)

嘿,针对你用Laravel+MariaDB开发的仓库管理系统里,那个1500万行的products_history操作日志表的性能问题,我结合日志表的特性,给你整理几个实用的分区方案,都是生产环境验证过的:

一、优先推荐:按时间范围分区(RANGE Partitioning)

这是日志类大表最常用的分区方式,你的分析需求(销量、新增量、废弃量)基本都是按时间维度统计的,完美契合分区剪枝的逻辑。

实现思路

用日志的操作时间字段(比如created_at或者专门的operation_time,建议用datetime/timestamp类型)作为分区键,按月度/季度划分分区,比如每个月一个分区。

示例SQL(改造为分区表)

假设你的表已有operation_time字段,执行以下语句完成分区改造:

ALTER TABLE products_history
PARTITION BY RANGE (TO_DAYS(operation_time)) (
    PARTITION p202401 VALUES LESS THAN (TO_DAYS('2024-02-01')),
    PARTITION p202402 VALUES LESS THAN (TO_DAYS('2024-03-01')),
    PARTITION p202403 VALUES LESS THAN (TO_DAYS('2024-04-01')),
    -- 提前创建未来几个月的分区,避免插入数据时出错
    PARTITION p_future VALUES LESS THAN MAXVALUE
);

Laravel适配技巧

  • 写统计查询时务必带上时间范围条件,比如:
    // 统计2024年2月的产品销量
    $salesCount = ProductHistory::where('operation_type', 'sale')
        ->whereBetween('operation_time', ['2024-02-01', '2024-02-29'])
        ->count();
    
    这样MariaDB会自动只扫描p202402分区,不会碰其他分区,速度提升非常明显。
  • 定期维护:每季度末直接DROP掉超过1年的旧分区,比DELETE全表删除快N倍,还不会产生InnoDB碎片。

二、备选:按哈希分区(HASH Partitioning)

如果你的查询经常是按product_id做等值查询(比如查某个产品的所有操作日志),哈希分区可以把数据均匀分散到多个分区,减少单分区的数据量,提升单产品查询速度。

示例SQL

ALTER TABLE products_history
PARTITION BY HASH(product_id)
PARTITIONS 10; -- 分区数量建议和CPU核心数匹配,比如8/10/16,尽量是2的幂

注意点

  • 哈希分区只适合等值查询,范围查询(比如查产品A近3个月的操作)还是会扫描多个分区,所以核心需求是时间维度统计的话,优先用范围分区。
  • 分区数量一旦确定,后续修改成本较高,建议提前评估数据量后确定。

三、特定场景:按操作类型列表分区(LIST Partitioning)

如果你的operation_type是固定枚举值(比如add/sale/discard),可以按操作类型分区,这样统计某类操作时直接扫对应分区,针对性极强。

示例SQL

ALTER TABLE products_history
PARTITION BY LIST COLUMNS(operation_type) (
    PARTITION p_add VALUES IN ('add'),
    PARTITION p_sale VALUES IN ('sale'),
    PARTITION p_discard VALUES IN ('discard'),
    PARTITION p_other VALUES IN ('other')
);

适用场景

比如你经常单独统计“废弃量”,这个分区方案会让这类查询直接定位到p_discard分区,效率拉满。


分区后的通用优化建议

  • 验证分区剪枝效果:用EXPLAIN PARTITIONS SELECT ...查看执行计划,确认查询是否只扫描了目标分区,避免出现全分区扫描的情况。
  • 配合复合索引:在分区键+查询常用字段上建复合索引,比如(operation_time, product_id, operation_type),进一步加速统计查询。
  • Laravel批量插入:日志插入尽量用ProductHistory::insert($batchData)批量操作,减少DB连接开销,避免频繁写入拖慢系统。
  • 避免跨分区事务:如果业务允许,尽量让单个事务的操作都在同一个分区内,减少InnoDB的锁开销。

内容的提问来源于stack exchange,提问作者Tomas

火山引擎 最新活动