极端不平衡数据上的 MySQL 数据库分区?



>200 万客户在 2 年内产生 20 亿个订单,但根据历史数据,50% 的订单属于 100 个顶级客户,因此数据在客户 ID 上极度不平衡。 客户希望按支付账户搜索自己的历史订单(一个客户有多个支付账户,有些客户有数千个支付账户)。

困难是顶级客户总是在变化,你不知道哪个客户在未来一个月会有巨额订单。

我需要存储 3 或 4 年的订单数据,并为客户提供订单搜索服务。 我应该如何对数据库和表进行分区?我的意思是,如果在客户的支付帐户上使用哈希,某些数据库将包含大量数据。我现在有 35 台服务器,每台服务器上都有 600G 存储。

解决方案的键:customer_id作为具有该列的所有(?)表中PRIMARY KEY的第一列。 当然,在查询中包含AND customer_id = 123

我不明白"付费账户",但如果有acct_id,那么可能需要

PRIMARY KEY(customer_id, acct_id, ...)

由于您可能已经有id .. AUTO_INCREMENT PRIMARY KEY,因此更改为

PRIMARY KEY(customer_id, acct_id, id)
INDEX(id)     -- sufficient to keep AUTO_INCREMENT happy

修订后的 PK 对大多数查询中可能使用/搜索/等的行进行聚类,从而加快它们的速度。

"顶级"客户的行将主要保留在buffer_pool中,从而减少了对 I/O 的需求。 当一个客户变得更忙时,他的行会撞出一个不那么繁忙的客户。 这就是LRU 缓存的本质。 也就是说,"谁在上面"的转变大多是自动覆盖的。

"哈希"不太可能有帮助。 事实上,它可能会造成伤害,因为它非常随机,可能会导致在缓存中跳来跳去。 (稍后会详细介绍。

您会清除"旧"数据(4 年后)吗? 如果是这样,这就带来了另一个问题:从一个巨大的表中DELETEing很多行的成本很高。 与此相关的是通常获取哪些行的问题 - 也许只有"最近"的行?

如果您需要清除,那么按范围(TO_DAYS(...))划分将大大加快DELETE速度(通过将其转换为DROP PARTITION)。 它可能会对通常只查看"最近"行的问题产生一些影响。

有关时间序列数据的讨论,请参阅此处。 我建议安排TO_DAYS()降落在月份边界上,从而有大约 50 个分区。

通过分区,我仍然会如上所述设计PK。 但是,在大多数WHERE子句中AND date > ...会有所帮助,否则将搜索所有 50 个分区,这将是一个性能负担。 (甚至很难说它是否是一个足够大的负担来对抗拥有 50 个分区。

您现在每台服务器上有 35 台服务器和 600G 存储:您是在谈论分片还是复制? 如果是复制,你是指一个主站和 34 个只读从站吗?

如果按Customer_id分片

  • 构建一个强大的脚本,将客户从一个分片移动到另一个分片。 这将是您完成许多管理任务的关键:卸载过载的分片;升级硬件/软件;添加另一个分片;等。
  • 这不仅需要一个"哈希",还需要一个字典来查找给定customer_id的位置。 我喜欢一个组合:哈希到,比如说,12位(0..4095),然后查找给定客户的35个(截至今天)分片中的哪一个。

最新更新