我是一名软件工程师,拥有大约 10 年为小型企业构建 Laravel Web 应用程序的经验。我对数据库设计非常满意,但这不是我最大的优势。
我构建的应用程序之一是用于监控电子邮件通讯打开和点击的第三方工具。该应用程序存储打开和单击事件,该工具的用户查询这些事件以查看他们的电子邮件通讯的运行情况。分析事件表当前的行数约为 15 亿,相当于一年半的数据。
我计划迁移到新的数据库设计,并想看看我对数据库设计的理解是否步入正轨。
Table contacts {
id integer
email_address string
created_at datetime
updated_at datetime
indexes {
id [pk]
email_address
created_at
}
}
Table contact_opens {
id unsignedBigInteger
contact_id integer
sent_at datetime
opened_at datetime
indexes {
id [pk]
(contact_id, sent_at)
sent_at
opened_at
}
}
Table contact_clicks {
id unsignedBigInteger
contact_id integer
sent_at datetime
clicked_at datetime
indexes {
id [pk]
(contact_id, sent_at)
sent_at
clicked_at
}
}
我计划在具有 64GB RAM 的专用 linode 服务器上使用 MariaDB,按日历月对数据库进行分区,并按如下方式调整 InnoDB:
innodb_buffer_pool_size = 48GB
InnoDB File-Per-Table = ON
innodb_flush_log_at_trx_commit = 2
innodb_flush_method = 0_DIRECT
innodb_log_file_size = 8GB
table_open_cache = 20
针对该数据库的查询将根据打开次数和点击次数对联系人进行分段。例如:
- 过去 30 天内打开了 5 个或更多的联系人
- 过去 5 天内至少点击 1 次的联系人
- 过去 30 天内每天点击 1 次的联系人
- 等,标准电子邮件通讯分段查询(如 Mailchimp 上所示)
查询一次将返回 10k-300k 个联系人。
我做了相当多的研究,看来索引、分区和/或分片似乎是帮助加快查询速度的最佳选择。索引和分区的组合似乎最适合这个特定的用例。
这种使用听起来是否像一个健全的数据库设计,其中 opens 表每年增长约 10 亿行,clicks 表每年增长约 3 亿行?
更新 1: 架构不会改变。它与几年前的设计方式相比略有变化,但只是为了适应本问题中概述的更改,以使查询更快。
更新 2: 300k~ 联系人查询用于群发邮件(电子邮件通讯)。更新了上面 MySQL 表中的数据类型。