【问题标题】:Data in different resolutions不同分辨率的数据
【发布时间】:2011-01-02 13:52:38
【问题描述】:

我有两个表,记录从外部源不断地插入到这些表中。假设这些表保存了用户交互的统计信息。当用户单击按钮时,该单击的详细信息(用户、单击时间等)将写入其中一个表。当用户将鼠标悬停在该按钮上时,会将带有详细信息的记录添加到其他表中。

如果有很多用户不断地与系统交互,就会产生大量的数据,并且这些表会大大增加。

当我想查看数据时,我想查看每小时或每天的分辨率。

有没有办法或最佳实践以所需的分辨率以增量方式(在收集数据时)不断总结数据?

或者有没有更好的方法来解决这类问题?

附言。到目前为止,我发现像 Talend 这样的 ETL 工具可以让生活变得轻松。

更新:我目前正在使用 MySQL,但我想知道无论数据库、环境等如何的最佳实践。

【问题讨论】:

  • 您目前使用什么来存储这些表?除非您告诉我们,否则我们可能会提出不适合您当前运营的建议。

标签: database data-warehouse etl summarization


【解决方案1】:

看看RRDTool。这是一个循环数据库。您可以定义要捕获的指标,但也可以定义存储它的分辨率。

例如,您可以指定为 las 小时,您保留每一秒的信息;过去 24 小时 - 每分钟;过去一周、每小时等。

它广泛用于收集GangliaCacti 等系统中的统计信息。

【讨论】:

  • 您可能不希望 rrdb 成为初始数据存储。我认为它不能处理单个表的并发输入。可能最好使用普通数据库来处理插入。但是,使用 rrdb 作为摘要信息位置是一个很好的选择。而且您不需要任何 etl 工具;只需像您一样插入数据库即可。示例流程: 1. 写入 db 表(从应用程序) 2. rrd 将数据拉入其数据存储区 - 可选,在 2 完成后修剪 db 表。然后rrdtool会为你生成图片。
  • @coffeepac:并发访问问题很容易用队列解决。我知道 ganglia 被部署到具有数千个节点的环境中,所有节点都将数据返回到单个 ganglia 主机,并且管理并发更新不是问题。
【解决方案2】:

您可以使用历史数据库,例如 PI 或 Historian。这些钱可能比你想为这个项目花的钱多,所以你可能想查找一个免费软件替代品,比如Realtime and History Database Package

【讨论】:

    【解决方案3】:

    快速和肮脏的建议。

    [假设您无法更改基础表,这些表已经记录了添加的时间/日期行,并且您确实有权在数据库中创建对象]。

    1. 创建一个具有逻辑字段的视图(或几个视图),通过切分表中的日期生成一个唯一的“槽号”。比如:

    创建视图视图为 选择 a,b,c, SUBSTR(date_field,x,y) slot_number 从 表;

    上面的例子是简化的,你可能想从日期+时间添加更多元素。

    [例如,假设日期是“2010-01-01 10:20:23,111”,您也许可以生成密钥为“2010-01-01 10:00”:所以您的分辨率是一小时]。

    1. 可选:使用 VIEW 生成真实表,例如:

      创建表frozen_data 作为 从视图中选择 * 在哪里 slot_number='xxx;

    为什么要麻烦第 1 步?您实际上不必这样做:仅使用 VIEW 可能会使事情变得更容易(从 SQL 的角度来看)。

    为什么要麻烦第 2 步?只是一种(可能)减少已经很忙的表上的负载的方法:如果您可以动态生成 DDL,那么您可以生成带有数据“插槽”副本的单独表:然后您可以使用这些表。

    或者您可以设置一组表:一天中的一个小时。 创建触发器以填充辅助表:触发器的逻辑可以分离写入哪个表。

    您必须每天重置这些表:除非您可以在数据库的触发器中生成表。 [我认为不太可能]。

    【讨论】:

      【解决方案4】:

      在低延迟数据仓库应用程序上执行此操作的常规方法是创建一个分区表,其前导分区包含可以快速更新的内容(即无需即时重新计算聚合)但尾随分区回填与聚合体。换句话说,前导分区可以使用与尾随分区不同的存储方案。

      大多数商业和一些开源 RDBMS 平台(例如 PostgreSQL)都可以支持分区表,它可以用来以一种或另一种方式来做这类事情。如何从日志中填充数据库留给读者练习。

      这种系统的结构基本上是这样的:

      • 您有一个表分区 某种日期或日期时间值, 按小时、天或其他划分 谷物似乎合适。日志 条目会附加到此表中。

      • 随着时间窗口滑出 分区,定期作业索引或 对其进行总结并将其转换为 它的“冻结”状态。例如,一个 Oracle 上的工作可能会创建位图 该分区上的索引或更新 包含摘要的物化视图 该分区的数据。

      • 稍后,您可以删除旧数据, 总结或合并分区 在一起。

      • 随着时间的推移,周期性作业 回填在前缘后面 划分。历史数据是 转换为借出的格式 本身到性能统计 查询而前沿 分区保持易于更新 迅速地。因为这个分区没有 有这么多数据,查询 整个数据集相对 快。

      此过程的确切性质因 DBMS 平台而异。

      例如,SQL Server 上的表分区并不是那么好,但这可以通过 Analysis Services(Microsoft 与 SQL Server 捆绑的 OLAP 服务器)来完成。这是通过将前导分区配置为纯 ROLAP(OLAP 服务器简单地对底层数据库发出查询)然后将尾随分区重建为 MOLAP(OLAP 服务器构建自己的专用数据结构,包括称为“聚合”的持久摘要)来完成的)。分析服务可以对用户完全透明地做到这一点。它可以在后台重建一个分区,而旧的 ROLAP 分区仍然对用户可见。构建完成后,它会在分区中交换;立方体始终可用,不会中断对用户的服务。

      Oracle 允许独立更新分区结构,因此可以构建索引,或者在物化视图上构建分区。通过查询重写,Oracle 中的查询优化器可以计算出从基本事实表计算的聚合数字可以从物化视图中获得。该查询将从分区可用的物化视图和不可用的前沿分区中读取聚合数字。

      PostgreSQL 或许可以做类似的事情,但我从来没有考虑过在它上面实现这种类型的系统。

      如果您可以忍受周期性中断,则可以通过进行汇总并设置对前导和尾随数据的视图来明确地完成类似的操作。这允许在不支持透明分区的系统上进行此类分析。但是,在重建视图时,系统会出现短暂的中断,因此您不能在工作时间真正执行此操作 - 最常见的情况是在夜间进行。

      编辑:根据日志文件的格式或您可以使用的日志记录选项,有多种方法可以将数据加载到系统中。一些选项是:

      • 使用您最喜欢的编程语言编写脚本,读取数据、解析相关位并将其插入数据库。这可能会经常运行,但您必须有一些方法来跟踪您在文件中的位置。小心锁定,尤其是在 Windows 上。 Unix/Linux 上的默认文件锁定语义允许您这样做(这就是 tail -f 的工作方式),但 Windows 上的默认行为是不同的;必须编写两个系统才能很好地相互配合。

      • 在 unix-oid 系统上,您可以将日志写入管道,并执行类似于上述从管道读取的过程。这将具有最低的延迟,但读取器中的故障可能会阻塞您的应用程序。

      • 为您的应用程序编写一个直接填充数据库的日志接口,而不是写出日志文件。

      • 对数据库使用批量加载 API(如果不是全部的话,大多数都可以使用这种类型的 API)并批量加载日志数据。编写与第一个选项类似的程序,但使用批量加载 API。与逐行填充相比,这将使用更少的资源,但设置批量加载的开销更大。它适用于不太频繁的负载(可能每小时或每天),并且对整个系统的压力较小。

      在大多数情况下,跟踪您去过的地方会成为一个问题。轮询文件以发现更改可能非常昂贵,因此您可能需要设置记录器,以便它以与您的日志阅读器完美配合的方式工作。

      • 一种选择是更改记录器,使其在每个周期(比如每隔几分钟)开始写入不同的文件。让您的日志阅读器定期启动并加载尚未处理的新文件。阅读旧文件。为此,文件的命名方案应基于时间,以便读者知道要选择哪个文件。处理应用程序仍在使用的文件更加繁琐(然后您需要跟踪已读取的文件量),因此您可能只想读取到最后一段时间的文件。

      • 另一个选项是移动文件然后读取它。这在行为类似于 Unix 的文件系统上效果最好,但应该在 NTFS 上工作。您移动文件,然后随意阅读。但是,它需要记录器以创建/附加模式打开文件,写入文件然后关闭它——而不是保持打开和锁定。这绝对是 Unix 行为——移动操作必须是原子的。在 Windows 上,您可能真的需要站在记录器旁边才能完成这项工作。

      【讨论】:

      • 非常有趣且解释清楚的东西。 +1
      • 您提供的信息很有用,非常感谢。那是我不知道我需要的东西。但我最初的问题是关于填充那些分区表。你把它作为一个练习:) 关于如何加载表格的任何指示?
      • 我在上面添加了一些东西,但是没有关于系统架构的更多细节,我真的不能推荐一个具体的方法。但是,编辑可能会给您一些想法。
      【解决方案5】:

      (到目前为止)尚未给出的建议可能是使用couchDB 或处理非结构化数据的类似数据库概念。

      等等!在惊恐地扑向我之前,让我说完。

      CouchDB 收集非结构化数据 (JSON &c);引用网站上的技术概述,

      为了解决这个添加问题 结构回到非结构化和 半结构化数据,CouchDB 集成视图模型。意见是 汇总和报告的方法 数据库中的文档,并且是 按需构建以聚合、加入和 数据库文件的报告。意见 是动态构建的,不会影响 基础文件,你可以有 尽可能多的不同视图表示 您喜欢的相同数据。

      视图定义是严格虚拟的 并且只显示来自 当前的数据库实例,使 它们与它们的数据分开 显示和兼容 复制。定义了 CouchDB 视图 内特殊设计文件和 可以跨数据库复制 像普通文档这样的实例,所以 不仅数据复制在 CouchDB,但整个应用程序 设计也可以复制。

      根据你的要求,我可以告诉你需要

      • 以可靠的方式收集大量数据
      • 优先考虑的是速度/可靠性,而不是在数据进入系统后立即构建数据,也不是维护/检查您收集的数据的结构属性(即使您错过了 1 毫秒的用户数据,也可能不是这样)大问题)
      • 当结构化数据从数据库中流出
      • 时,您需要这些数据

      就个人而言,我会这样做:

      • 在客户端缓存收集的数据并将其以突发形式保存到 couchdb
      • 根据工作负载,保持一个 db 集群(同样,couchdb 就是为此而设计的)彼此之间保持同步
      • 每个时间间隔都有一个服务器生成您需要的东西的视图(即每小时等),而其他时间间隔则继续收集数据
      • 将此类(现在是结构化的)视图保存到适当的数据库中,以便使用 SQL 工具或其他工具进行操作和使用

      最后一点只是一个例子。我不知道你打算用它做什么。

      【讨论】:

        【解决方案6】:

        在对数据进行切片和聚合(按时间或其他方式)时,星型模式(Kimball 星型)是一种相当简单但功能强大的解决方案。假设对于每次点击,我们都会存储时间(秒分辨率)、用户信息、按钮 ID 和用户位置。为了方便切片和切块,我将从预加载的查找表开始,查找很少更改的对象的属性——在 DW 世界中称为维度表。



        dimDate 表每天有一行,其中包含描述特定日期的属性(字段)的数量。该表可以提前多年预加载,如果包含DaysAgo, WeeksAgo, MonthsAgo, YearsAgo等字段,则应每天更新一次;否则它可能是“加载并忘记”。 dimDate 允许按日期属性轻松切片,例如

        WHERE [YEAR] = 2009 AND DayOfWeek = 'Sunday'
        

        对于十年的数据,该表只有约 3650 行。

        dimGeography 表预加载了感兴趣的地理区域——行数取决于报告中所需的“地理分辨率”,它允许像

        WHERE Continent = 'South America'
        

        一旦加载,就很少更改。

        对于站点的每个按钮,在 dimButton 表中都有一行,因此查询可能有

        WHERE PageURL = 'http://…/somepage.php'
        

        dimUser 表中每个注册用户有一行,用户注册后应该立即加载新用户信息,或者至少在任何其他用户事务发生之前新用户信息应该在表中记录在事实表中。

        为了记录按钮点击,我将添加factClick 表。



        factClick 表对于特定用户在某个时间点每次单击按钮都有一行。我在复合主键中使用了TimeStamp(第二分辨率)、ButtonKeyUserKey,以过滤掉特定用户每秒超过一次的点击。注意Hour 字段,它包含TimeStamp 的小时部分,0-23 范围内的整数,以便于每小时切片,例如

        WHERE [HOUR] BETWEEN 7 AND 9
        

        所以,现在我们必须考虑:

        • 如何加载表格?使用 ETL 工具或使用某种事件流式处理的低延迟解决方案定期(可能每隔一小时或每隔几分钟)从博客中获取。
        • 表格中的信息要保留多长时间?

        不管表是只保存一天的信息还是保存几年的信息——它都应该被分区; ConcernedOfTunbridgeW 已经在他的回答中解释了分区,所以我会在这里跳过。

        现在,根据不同属性(包括日期和小时)进行切片和切块的几个示例

        为了简化查询,我将添加一个视图来展平模型:

        /* To simplify queries flatten the model */ 
        CREATE VIEW vClicks 
        AS 
        SELECT * 
        FROM factClick AS f 
        JOIN dimDate AS d ON d.DateKey = f.DateKey 
        JOIN dimButton AS b ON b.ButtonKey = f.ButtonKey 
        JOIN dimUser AS u ON u.UserKey = f.UserKey 
        JOIN dimGeography AS g ON g.GeographyKey = f.GeographyKey
        

        查询示例

        /* 
        Count number of times specific users clicked any button  
        today between 7 and 9 AM (7:00 - 9:59)
        */ 
        SELECT  [Email] 
               ,COUNT(*) AS [Counter] 
        FROM    vClicks 
        WHERE   [DaysAgo] = 0 
                AND [Hour] BETWEEN 7 AND 9 
                AND [Email] IN ('dude45@somemail.com', 'bob46@bobmail.com') 
        GROUP BY [Email] 
        ORDER BY [Email]
        

        假设我对User = ALL 的数据感兴趣。 dimUser 是一个大表,所以我会在没有它的情况下创建一个视图,以加快查询速度。

        /* 
        Because dimUser can be large table it is good 
        to have a view without it, to speed-up queries 
        when user info is not required 
        */ 
        CREATE VIEW vClicksNoUsr 
        AS 
        SELECT * 
        FROM factClick AS f 
        JOIN dimDate AS d ON d.DateKey = f.DateKey 
        JOIN dimButton AS b ON b.ButtonKey = f.ButtonKey 
        JOIN dimGeography AS g ON g.GeographyKey = f.GeographyKey
        

        查询示例

        /* 
        Count number of times a button was clicked on a specific page 
        today and yesterday, for each hour. 
        */ 
        SELECT  [FullDate] 
               ,[Hour] 
               ,COUNT(*) AS [Counter] 
        FROM    vClicksNoUsr 
        WHERE   [DaysAgo] IN ( 0, 1 ) 
                AND PageURL = 'http://...MyPage' 
        GROUP BY [FullDate], [Hour] 
        ORDER BY [FullDate] DESC, [Hour] DESC
        



        假设对于聚合,我们不需要保留特定的用户信息,而只对日期、时间、按钮和地理位置感兴趣。 factClickAgg 表中的每一行都有一个计数器,用于记录从特定地理区域单击特定按钮的每一小时。



        factClickAgg 表可以每小时加载一次,甚至可以在每天结束时加载——取决于报告和分析的要求。例如,假设表格在每天结束时(午夜之后)加载,我可以使用类似:

        /* At the end of each day (after midnight) aggregate data. */ 
        INSERT  INTO factClickAgg 
                SELECT  DateKey 
                       ,[Hour] 
                       ,ButtonKey 
                       ,GeographyKey 
                       ,COUNT(*) AS [ClickCount] 
                FROM    vClicksNoUsr 
                WHERE   [DaysAgo] = 1 
                GROUP BY DateKey 
                       ,[Hour] 
                       ,ButtonKey 
                       ,GeographyKey
        

        为了简化查询,我将创建一个视图来展平模型:

        /* To simplify queries for aggregated data */ 
        CREATE VIEW vClicksAggregate 
        AS 
        SELECT * 
        FROM factClickAgg AS f 
        JOIN dimDate AS d ON d.DateKey = f.DateKey 
        JOIN dimButton AS b ON b.ButtonKey = f.ButtonKey 
        JOIN dimGeography AS g ON g.GeographyKey = f.GeographyKey
        

        现在我可以查询聚合数据,例如按天:

        /* 
        Number of times a specific buttons was clicked 
        in year 2009, by day 
        */ 
        SELECT  FullDate 
               ,SUM(ClickCount) AS [Counter] 
        FROM    vClicksAggregate 
        WHERE   ButtonName = 'MyBtn_1' 
                AND [Year] = 2009 
        GROUP BY FullDate 
        ORDER BY FullDate
        

        或者有更多的选择

        /* 
        Number of times specific buttons were clicked 
        in year 2008, on Saturdays, between 9:00 and 11:59 AM 
        by users from Africa 
        */ 
        
        SELECT  SUM(ClickCount) AS [Counter] 
        FROM    vClicksAggregate 
        WHERE   [Year] = 2008 
                AND [DayOfWeek] = 'Saturday' 
                AND [Hour] BETWEEN 9 AND 11 
                AND Continent = 'Africa' 
                AND ButtonName IN ( 'MyBtn_1', 'MyBtn_2', 'MyBtn_3' )
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2016-09-10
          • 1970-01-01
          • 2011-11-11
          • 2017-03-24
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多