大MySQL产品历史表分区?

时间:2018-04-03 13:38:15

标签: php mysql mariadb partitioning

我正在开发由php,laravel framework,mariadb编写的仓库控制系统。要获得有关每种产品的所有信息,我们会使用产品"历史"表,记录对特定产品采取的所有操作。这个表开始快速扩展,现在我们有大约1500万行innoDB表开始工作缓慢,特别是在运行功能时,需要全面分析销售,创建,丢弃等产品的数量,然后需要全部1500万行在一个查询..所以我开始搜索方式,如何管理这个大表,因为索引不再工作。 我开始考虑按日期拆分/分区这个表,也许是行动?所以也许任何人都有这方面的经验并可以与我分享一些建议?非常感谢任何帮助!

CREATE TABLE `history` ( `id` int(11) NOT NULL AUTO_INCREMENT, `barcode` varchar(100) DEFAULT NULL, `bag` varchar(100) DEFAULT NULL, `action` int(10) unsigned DEFAULT NULL, `place` int(10) unsigned DEFAULT NULL, `price` decimal(10,2) DEFAULT NULL, `old_price` decimal(10,2) DEFAULT NULL, `user` int(11) DEFAULT NULL, `amount` int(10) DEFAULT NULL, `rotation` int(10) unsigned DEFAULT NULL, `discount` decimal(10,2) DEFAULT NULL, `discount_type` tinyint(2) unsigned DEFAULT NULL, `original` int(10) unsigned DEFAULT NULL, `was_in_shop` int(10) unsigned DEFAULT NULL, `cate` int(10) unsigned DEFAULT NULL COMMENT 'grupe', `sub_cate` int(10) unsigned DEFAULT NULL, `comment` varchar(255) DEFAULT NULL, `helper` varchar(255) DEFAULT NULL, `created_at` timestamp NULL DEFAULT NULL, `updated_at` timestamp NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP, `deleted_at` timestamp NULL DEFAULT NULL, PRIMARY KEY (`id`), KEY `barcode` (`barcode`), KEY `action` (`action`), KEY `original` (`original`), KEY `created_at` (`created_at`), KEY `bag` (`bag`) ) ENGINE=InnoDB AUTO_INCREMENT=16274267 DEFAULT CHARSET=utf8

例如查询:

select  cate,
SUM(amount) AS amount, SUM(IF(discount>0,(price*amount)-discount,
                    (price*amount))) AS sum, SUM(IF(discount>0,IF(discount_type=1,
                                            (discount*price)/100,discount),0)
   ) AS discount from  history
    where  (history.action = '4'
              and  history.created_at >= '2017-11-01 00:00:00'
              and  history.created_at <= '2017-11-23 23:59:59'
           )
      and  LENGTH(barcode) > 7
      and  history.deleted_at is null
    group by  cate

此查询用于获取有关已售产品的金额,金额,折扣信息(操作4)在此示例中,它是2017-11-01和2017-11-23之间的信息,EXPLAIN给我这样的信息:

id - 1 select_type - SIMPLE table - history type - ref possible_keys - action,created_at key - action key_len - 5 ref - const rows - 1444272 Extra - Using where; Using temporary; Using filesort

所以它需要150万行,表格保存2017-01-01至今的数据,因此2年后需要300万行等...当我需要只需2017-11产品时出售信息。我有很多类似的问题。

1 个答案:

答案 0 :(得分:0)

  • 使用较小的数据类型(缩小表大小有助于提高性能)INT占用4个字节;其他尺寸可供选择。
  • PARTITIONing 本质上提供任何表现。
  • history.deleted_at is null - 考虑实际删除行。
  • 了解“复合”索引,例如INDEX(action, created_at)。 (一次只使用一个索引。)

通过构建和维护汇总表来实现重大改进;见http://mysql.rjweb.org/doc.php/summarytables。然后针对它们运行查询。大多数指数都可以消失。

修复其中一些;那我可以帮你进一步。

更多

评论询问如何以两种不同的方式维护摘要表ID。两者都可行,取决于更多,尚未具体说明的细节:

  • INSERT INTO Fact表,并立即使用IODKU插入或更新Summary表。
  • 执行摘要“按需” - 当用户请求数据时,首先运行INSERT .. SELECT ..以捕获尚未汇总的行,并将计数/小计放入摘要表中。

后一种选择有效,但有两点需要注意:

  • 如果长时间没有用户出现,那么摘要可能会很昂贵。简单的解决方法是定期“赶上”cron作业。请务必将代码互锁,以便cron和用户不会同时更新相同的行。
  • 如果摘要表具有“自然”PRIMARY KEY,例如日期(日期或小时)和几个维度值,那么您就会遇到INSERT问题。要么避免将其作为PK(从而导致多行,这不是'坏'),要么使用INSERT ... ON DUPLICATE KEY ... SELECT ... GROUP BY ...;形式的IODKU并使用VALUES(xx)函数。