如何处理旧条目?单独的表、分区或只是索引?

Posted

技术标签:

【中文标题】如何处理旧条目?单独的表、分区或只是索引?【英文标题】:How to treat old entries? Separate table, partition or just index? 【发布时间】:2021-12-27 08:03:02 【问题描述】:

为简化起见,我们运营一个广告网络并有 2 个表格:

广告系列(列:id、状态) 状态可以是活动的或非活动的,每周有 10 万个新条目,95 % 的条目在 72 小时内变为“非活动”状态

点击次数(列:id、campaign_id、created_time) 与广告系列相关的点击列表。每周 1 mio 新条目

99 % 的查询与“有效”广告系列和过去 30 天的点击次数有关。超过 30 天的无效活动和点击仅用于某些统计查询。 2 年后,campaigns 表中有 10 个 mio 条目,clicks 表中有 100 个 mio 条目,虽然在大多数查询中只使用了一小部分,但我怀疑这是非常低效的。

解决方案:

    创建一个表“inactive_campaigns”和“inactive_clicks”,并定期将“旧”数据移到那里 在每个表上创建一个分区以将“旧数据”移到那里 坚持使用campaigns.status 和clicks.created_time 上的索引

我是否忘记了更好的解决方案? 这些解决方案中哪一个是最佳编码实践,为什么? 1) 和 2) 的速度有区别吗?

谢谢!

【问题讨论】:

只是一个意见。选项 1 似乎是您的最佳解决方案。将历史数据移动到单独的表中是一种简单的方法。只要用户可以忍受必须在其他表中查询旧数据。您可以使用旧数据对表进行分区 【参考方案1】:

由于 99% 的查询是最近 30 天的点击,因此最好对表进行优化,以便对这些记录进行最快的查询。

1)创建一个表“inactive_campaigns”和“inactive_clicks”,并定期将“旧”数据移到那里。

如果任何报告中从不或很少需要显示历史数据,我会使用此选项。这是一个不错的选择,但实际上“移动”旧数据需要您编写代码来移动到其他表。

2)在每个表上创建一个分区,将“旧数据”移到那里

这是将所有数据保存在一起的好方法,分区是一种很好的方法,可以在查询时减轻 IO 命中。在这个分区表上运行的查询执行分区修剪/消除是很重要的。例如:如果您在日期列上进行分区,您将检查查询的输入是否也采用正确的格式,使优化器仅搜索相关分区。

select * 
   from my_large_partitioned_table 
  where date_of_campaign =dateadd(-30,day,CURRENT_DATE)

这将使用分区修剪/分区消除

如果查询/框架做这样的事情

select * 
   from my_large_partitioned_table 
  where dateadd(-30,day,date_of_campaign) <= CURRENT_DATE

很可能不会进行分区修剪(取决于数据库),因为分区列上的函数 (dateadd) 会混淆优化器并导致对分区表进行全面扫描。

3) 坚持使用campaigns.status 和clicks.created_time 上的索引

这个选择将是我最后的首选方法。如果您的数据库许可不允许分区,这是您必须做出的选择。

对于您提到的方法,我建议您压缩很少更改的数据,尤其是存档数据。它可以节省空间,也可以使查询更快(压缩数据需要更少的扫描)。还拥有关于 status 和 created_time 的索引可以提高您从分区中获得的查询性能

【讨论】:

以上是关于如何处理旧条目?单独的表、分区或只是索引?的主要内容,如果未能解决你的问题,请参考以下文章

mysql 分区

mysql分区及实例演示

mysql分区及实例演示

PostgreSQL分区介绍

MySQL:将大表拆分为分区或单独的表?

处理恢复购买时如何处理旧交易?