2

我们有一个点击跟踪系统,我在其中跟踪每个请求的 IP 地址。

每天我们都会获得数百万次点击。

对于每个请求并将 IP 地址存储为 MySQL 中的 1 行

我们还需要每日统计前 10 个 IP 地址点击量。

这是我用 MySQL 得到的,但我们的问题是数据库越来越重,占用了很大的空间。

我在寻找可以有效存储此 IP 地址的良好“数据结构”吗?

目前,如果我选择好的数据结构,我将每个点击存储为行,那么我的问题将解决

我不想运行复杂的查询,但每天前 10 个,每周每个 IP 地址前 10 个。

并且必须节省存储空间

4

2 回答 2

0

如果您不需要每个 ip 访问时间戳精确到秒,您可以将每天划分为一系列时间段(可能每 10 或 5 分钟一个段)。每个日期时间段在时间段表中都有一个 id。然后,您可以为 ip 表中的每个唯一 IP 地址创建一个 id。

然后您有一个连接表,您可以在其中将 IP 地址(外键)与时间段(外键)与计数(无符号整数)相关联。因此,您的核心访问行数据现在简化为 2 个 id 和 1 个无符号整数(最重要的是,没有字符串)。

因此,当您收到来自 IP 的请求时,您确定当前时间段,如果该时间段不存在,则为新时间段创建一行。如果当前时间段与 IP 没有关联,则创建一个新的行,计数为 1。如果该时间段和 IP 有一行,则增加计数。

通过以这种方式规范化数据/表并稍微降低准确性,您可以实现一种信息压缩形式。玩弄时间段间隔以找到最佳权衡。例如,如果您不需要几分钟甚至几小时的查询粒度,您可以将您的时间段设置为一天。

更新:

对,所以上面的所有内容都是压缩来自同一 IP 地址的多个命中。与唯一命中相比,您获得的重复命中越多,这显然更有效。如果您只关心独特的命中,则完全无关紧要。

有多种方法可以将 IPv4 地址压缩为无符号整数(32 位)。只需将每个部分分别移位a.b.c.d到字节0xff000000, 0x00ff0000, 。0x0000ff000x000000ff

这样,每个 IP 使用 4 个字节而不是字符串;此时存储外键(无论如何至少需要 4 个字节)是没有用的。因此,您可以只拥有一个包含字段的非规范化表:(IPv4 作为编码的无符号整数,日期时间/时间戳作为 4 字节整数)。您可能会用一天和一个计数替换日期时间,具体取决于您是否计算多次点击。如果多次点击不算数,你真的可以用一个 int 表示 IP 和一个 int 表示日期。

如果 day-granulartiy 是您所需的最低值,则还有一个更进一步的选择:您可以在每天结束时清除此 IP db 表,并将聚合查询的结果仅存储在数据库中。其余数据可以每天存档并从 IP db 表中删除。这意味着您的表只需要一个字段:编码为无符号整数的 IP。在这一点上,问题就变成了每天构建大量独特的整数集。

您还可以将时间(或时间段)展平/非规范化为 int(甚至更小),具体取决于您想要记录时间的频率/粒度,以及您是否选择聚合/归档/清除 IP db 表定期。

以压缩方式存储多个 IP 地址的另一种方法是使用trie数据结构,但它不直接映射到数据库存储(与内存数据结构相比)。通过 SQL 存储树结构(例如 trie)的一种方法是使用Materialized Path方法 - 但是,这种方法无法实现良好的数据压缩,并且查询开销可能不值得。

于 2013-06-14T09:12:40.597 回答
-1

如果您可以将数据库从 RDBMS 技术(如 MySQL)中更改出来,那么您绝对应该看看 NoSQL 数据库,例如CouchDBCassandraRIAK

这些将根据您的需求进行扩展 - 但工作方式与 SQL 数据库完全不同 - 所以期待一些学习曲线。

我可以推荐看一下“ 7 周内 7 个数据库”一书,以了解崩溃的开始。

于 2013-06-14T06:58:07.033 回答