每天存储数百万条可分组用于统计目的的数据的最佳方式是啥?

Posted

技术标签:

【中文标题】每天存储数百万条可分组用于统计目的的数据的最佳方式是啥?【英文标题】:Best way for storing millions of records a day of data that can be grouped for statistic purposes?每天存储数百万条可分组用于统计目的的数据的最佳方式是什么? 【发布时间】:2016-12-28 15:16:43 【问题描述】:

我正在为营销活动开发一个自定义跟踪工具。该工具位于广告和着陆页之间。它负责保存来自用户的所有数据,例如用户代理中的信息、IP、登录页面上的点击量以及用户 IP 的地理编码数据(国家、ISP 等)。

目前我有一些设计问题:

这些广告系列的流量非常高,因此我可能每天插入数百万行。这个系统可以有多个用户,所以我不能将所有这些数据存储在一个表上,因为会变得一团糟。也许我可以将数据拆分到更多表中,每个用户一个表,但我不确定这个解决方案。 数据保存过程必须尽快完成(几毫秒),所以我认为NodeJS在这方面比php要好得多。特别是在速度和服务器资源方面。我不希望服务器因 RAM 不足而崩溃。 出于统计目的,我需要对这些数据进行分组。例如,对于访问我的着陆页的每个用户,我都有一行,但我需要对这些数据进行分组以显示此特定着陆页上的展示次数。因此,对于如此大量的行,所有这些查询都需要尽可能快地执行。 我需要对 IP 地址进行地理编码,因此我需要准确的信息,例如国家、ISP、连接类型等,但是如果我调用 API 服务,这会减慢数据保存过程。而且这必须实时完成,不能在以后完成。

在保存过程之后,系统应该重定向到登录页面。时间对于不失去任何可能的领先优势很重要。

基本上,我正在为以下方面寻找最佳解决方案:

高效管理超大型数据库 在尽可能短的时间内 (ms) 保存来自用户的数据 如果可能,在尽可能短的时间内对一个 ip 进行地理编码,而不会阻塞执行 优化架构和查询以生成统计信息

你有什么建议吗?提前致谢。

【问题讨论】:

这种情况下可以使用ELK栈。 利用服务器日志;将原始数据存储在单个表中;使用后台任务处理 IP 查找以进行地理编码;用于此目的时,不要将 PHP 视为速度慢且内存消耗大,我已经使用 PHP 记录了每天有数百万次点击的网站,而不会产生开销 否则,您的问题是对 *** 的扩展 嗨@Rahul,你能解释一下我如何使用ELK堆栈吗? 不,我没有这样建议;创建一组针对您的数据结构和查询进行规范化并适当索引的表;并使用后台进程从您的原始数据表中填充这些数据......当您填充这些表时,从您的原始表中删除/归档该数据 【参考方案1】:

每个用户一张桌子更糟;不要那样做。

每天数百万行——每秒数十甚至数百行?这可能需要某种形式的“暂存”——收集多行,然后批量插入它们。在进一步讨论之前,请详细说明数据流:单客户端与多客户端。 UI 与批处理。暂定CREATE TABLE。等等。

统计——计划创建和增量维护“汇总表”。

您是否尝试将用户 IP 地址映射到国家/地区?这是一个单独的问题,并且已经得到解答。

“必须”“实时”“毫秒”。面对现实,你将不得不做出一些取舍。

更多信息:转至http://mysql.rjweb.org/;从那里,请参阅有关数据仓库技术的三个博客。

如何按天存储

InnoDB 以PRIMARY KEY 的顺序存储数据。因此,要让某一天的所有行彼此相邻,必须开始 PK 与日期时间。对于大型数据库,可以通过允许查询顺序扫描数据来显着改进某些查询,从而最大限度地减少磁盘 I/O。

如果您已经拥有id AUTO_INCREMENT(并且如果您继续需要它),请执行以下操作:

PRIMARY KEY(datetime, id),  -- to get clustering, and be UNIQUE
INDEX(id)  -- to keep AUTO_INCREMENT happy

如果您有一年的数据,而这些数据不适合 RAM,那么这种技术对于小时间范围非常有效。但是如果你的时间范围比缓存大,你就会受制于 I/O 速度。

使用不断变化的数据维护汇总表

可能是可能的;我需要更好地了解数据和变化。

无法在不到一秒的时间内扫描一百万行,无论缓存、调整和其他优化如何。您可以使用汇总表更快地处理所需的数据。

收缩数据

如果INT(4字节)就足够了,不要使用BIGINT(8字节);如果MEDIUMINT(3 个字节)可以,不要使用INT。等等。 在适当的地方使用UNSIGNED。 规范化重复的字符串。

较小的数据将使其更易于缓存,因此在您必须敲击磁盘时运行得更快。

【讨论】:

由于统计数据是动态的,我认为您不能使用“汇总表”之类的东西。我认为问题不在于 INSERT 语句,而在于统计查询。随着时间的推移,对大表进行查询变得如此缓慢...... 我又添加了一些。 嗨瑞克!所有这些记录将按照它们到达的相同顺序插入,因此它们已经是顺序的。我的意思是这些行已经按日期排序。 也许我可以为每个分组字段维护一个汇总表。例如,我想显示每个着陆页的点击量。我可以使用一个表格,并在这个表格中保存已经为每个着陆页分组的所有点击,按天划分。所以,如果我想显示两天的数据,我只需要为每个着陆页而不是千页分组两行。 你的想法是对的。随它去吧。请记住增量更新汇总表,不要从头开始重建(第一次除外)。并且通常希望有 2 或 3 个“分组字段”(加上“天”)来定义汇总表。我发现典型情况需要 3 到 7 个不同的汇总表。更多:mysql.rjweb.org/doc.php/summarytables

以上是关于每天存储数百万条可分组用于统计目的的数据的最佳方式是啥?的主要内容,如果未能解决你的问题,请参考以下文章

数百万条目的 SQLite 优化? [关闭]

处理具有数百万条记录更新和大量读数的 MySQL 表的最佳方法

存储 iPad/iPhone 应用程序数据的最佳方式

OS X 应用程序。存储数据的最佳方式是啥?

适合海量数据的存储方式

MongoDB开发之 管道操作符