AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • 主页
  • 系统&网络
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • 主页
  • 系统&网络
    • 最新
    • 热门
    • 标签
  • Ubuntu
    • 最新
    • 热门
    • 标签
  • Unix
    • 最新
    • 标签
  • DBA
    • 最新
    • 标签
  • Computer
    • 最新
    • 标签
  • Coding
    • 最新
    • 标签
主页 / dba / 问题 / 161237
Accepted
vulkoingim
vulkoingim
Asked: 2017-01-17 07:51:47 +0800 CST2017-01-17 07:51:47 +0800 CST 2017-01-17 07:51:47 +0800 CST

如何根据行类型获取每种类型的最新行并执行计算?

  • 772

我在 SO 上发布了同样的问题,但我想我也可以在这里尝试一下,因为非常感谢任何其他类型的优化和建议 :) 不管怎样,这是我的帖子,逐字逐句:

我需要一些帮助编写/优化查询以按类型检索每行的最新版本并根据类型执行一些计算。我认为最好用一个例子来说明。

给定以下数据集:

+-------+-------------------+---------------------+-------------+---------------------+--------+----------+
| id    | event_type        | event_timestamp     | message_id  | sent_at             | status | rate     |
+-------+-------------------+---------------------+-------------+---------------------+--------+----------+
| 1     | create            | 2016-11-25 09:17:48 | 1           | 2016-11-25 09:17:48 | 0      | 0.500000 |
| 2     | status_update     | 2016-11-25 09:24:38 | 1           | 2016-11-25 09:28:49 | 1      | 0.500000 |
| 3     | create            | 2016-11-25 09:47:48 | 2           | 2016-11-25 09:47:48 | 0      | 0.500000 |
| 4     | status_update     | 2016-11-25 09:54:38 | 2           | 2016-11-25 09:48:49 | 1      | 0.500000 |
| 5     | rate_update       | 2016-11-25 09:55:07 | 2           | 2016-11-25 09:50:07 | 0      | 1.000000 |
| 6     | create            | 2016-11-26 09:17:48 | 3           | 2016-11-26 09:17:48 | 0      | 0.500000 |
| 7     | create            | 2016-11-27 09:17:48 | 4           | 2016-11-27 09:17:48 | 0      | 0.500000 |
| 8     | rate_update       | 2016-11-27 09:55:07 | 4           | 2016-11-27 09:50:07 | 0      | 2.000000 |
| 9     | rate_update       | 2016-11-27 09:55:07 | 2           | 2016-11-25 09:55:07 | 0      | 2.000000 |
+-------+-------------------+---------------------+-------------+---------------------+--------+----------+

预期结果应该是:

+------------+--------------------+--------------------+-----------------------+
| sent_at    | sum(submitted_msg) | sum(delivered_msg) | sum(rate_total)       |
+------------+--------------------+--------------------+-----------------------+
| 2016-11-25 |                  2 |                  2 |              2.500000 |
| 2016-11-26 |                  1 |                  0 |              0.500000 |
| 2016-11-27 |                  1 |                  0 |              2.000000 |
+------------+--------------------+--------------------+-----------------------+

帖子末尾是用于获取此结果的查询。我愿意打赌应该有一种方法来优化它,因为它使用带有连接的子查询,而且从我读到的关于 BigQuery 的内容来看,最好避免连接。但首先是一些背景:

本质上,数据集表示一个仅附加表,其中写入了多个事件。数据的规模在数亿级,并将增长到数十亿+。由于 BigQuery 中的更新不实用,并且数据正在流式传输到 BQ,我需要一种方法来检索每个事件的最新事件,根据特定条件执行一些计算并返回准确的结果。查询是根据用户输入动态生成的,因此可以包含更多字段/计算,但为简单起见已将其省略。

  • 只有一个create事件,但n属于任何其他类型
  • 对于每组事件,在计算时只应考虑最新的事件。
    • status_update - 更新状态
    • rate_update - 更新速率
    • 创建 - 不言自明
  • 每个不是的事件create可能不携带原始的其余信息/可能不准确(除了message_id和事件正在操作的字段)(数据集被简化了,但想象有更多的列,和稍后会添加更多事件)
    • 例如,arate_update可能会或可能不会设置状态字段,或者不是最终值,因此无法对rate_update事件的状态字段进行计算,同样适用于status_update
  • 可以假定该表按日期分区,并且每个查询都将使用分区。现在为了简单起见,省略了这些条件。

所以我想我有几个问题:

  • 如何优化此查询?
  • 将事件放在它们自己的表中而不是create放在它们自己的表中是不是一个更好的主意,其中唯一可用的字段将是与事件相关的字段以及连接所需的字段(message_id,event_timestamp)?这会减少处理的数据量吗?
  • 将来添加更多事件的最佳方式是什么,这些事件将有自己的条件和计算?

实际上,我们非常欢迎任何有关如何高效友好地查询此数据集的建议!谢谢!:)

我想出的怪物如下。根据此资源INNER JOINS,用于检索每一行的最新版本

    select
    sent_at as sent_at,
    sum(submitted_msg) as submitted,
    sum(delivered_msg) as delivered,
    sum(sales_rate_total) as sales_rate_total
    FROM (

      #DELIVERED
        SELECT 
            d.message_id,
            FORMAT_TIMESTAMP('%Y-%m-%d 00:00:00', sent_at) AS sent_at,
            0 as submitted_msg,
            sum(if(status=1,1,0)) as delivered_msg,
            0 as sales_rate_total
        FROM `events` d
        INNER JOIN
                (
                    select message_id, max(event_timestamp) as ts 
                    from `events` 
                    where event_type = "status_update" 
                    group by 1
                    ) g on d.message_id = g.message_id and d.event_timestamp = g.ts
        GROUP BY 1,2

        UNION ALL

      #SALES RATE
        SELECT 
            s.message_id,
            FORMAT_TIMESTAMP('%Y-%m-%d 00:00:00', sent_at) AS sent_at,
            0 as submitted_msg,
            0 as delivered_msg,
            sum(sales_rate) as sales_rate_total
        FROM `events` s
        INNER JOIN 
                    (
                    select message_id, max(event_timestamp) as ts 
                    from `events` 
                    where event_type in ("rate_update", "create")  
                    group by 1
                    ) f on s.message_id = f.message_id and s.event_timestamp = f.ts
        GROUP BY 1,2

        UNION ALL

      #SUBMITTED & REST
        SELECT 
            r.message_id,
            FORMAT_TIMESTAMP('%Y-%m-%d 00:00:00', sent_at) AS sent_at,
            sum(if(status=0,1,0)) as submitted_msg,
            0 as delivered_msg,
            0 as sales_rate_total
        FROM `events` r
        INNER JOIN
                (
                    select message_id, max(event_timestamp) as ts 
                    from `events` 
                    where event_type = "create" 
                    group by 1
                    ) e on r.message_id = e.message_id and r.event_timestamp = e.ts
        GROUP BY 1, 2

    ) k
    group by 1
optimization google-bigquery
  • 1 1 个回答
  • 52 Views

1 个回答

  • Voted
  1. Best Answer
    McNets
    2017-01-17T14:59:07+08:002017-01-17T14:59:07+08:00

    1:我在 rextester 中使用 SQL-SERVER 来研究你的数据,但我认为它可以应用于 google-bigquery。
    2. 我从未使用过 google-bigquery。
    3:英语不是我的母语。
    4. 我可以吃阿司匹林吗?

    首先,我认为你的结果表有问题。使用您的子查询获取销售率:

    在这里查看:http ://rextester.com/CHX54701

    select e.*
    from events e
        inner join (
                    select message_id, max(event_timestamp) as event_timestamp 
                    from events 
                    where event_type in ('rate_update', 'create')  
                    group by message_id        
                   ) t 
                   on t.message_id = e.message_id and t.event_timestamp = e.event_timestamp;
    
    +----+-------------+---------------------+------------+---------------------+--------+------+
    | id |  event_type |   event_timestamp   | message_id |       sent_at       | status | rate |
    +----+-------------+---------------------+------------+---------------------+--------+------+
    |  1 |    create   | 25.11.2016 09:17:48 |      1     | 25.11.2016 09:17:48 |    0   |  0,5 |
    +----+-------------+---------------------+------------+---------------------+--------+------+
    |  9 | rate_update | 27.11.2016 09:55:07 |      2     | 25.11.2016 09:55:07 |    0   |   2  |
    +----+-------------+---------------------+------------+---------------------+--------+------+
    |  6 |    create   | 26.11.2016 09:17:48 |      3     | 26.11.2016 09:17:48 |    0   |  0,5 |
    +----+-------------+---------------------+------------+---------------------+--------+------+
    |  8 | rate_update | 27.11.2016 09:55:07 |      4     | 27.11.2016 09:50:07 |    0   |   2  |
    +----+-------------+---------------------+------------+---------------------+--------+------+
    

    2016-11-25 的 sum(rate) 应该是 3.0 而不是 2.5

    这是正确的吗?,因为如果不是全部都在这里结束。

    以我的拙见,您在每个子查询上对所有记录进行分组,然后根据获取不同值的 sum()message_id获取Then 。max(event_timestamp)event_type

    然后我的第一次尝试是让所有 max(event_timestamp) 按 message_id 分组:

    select message_id, event_type, max(event_timestamp) event_timestamp
    from events
    group by message_id, event_type;
    
    +------------+---------------+---------------------+
    | message_id |   event_type  |   event_timestamp   |
    +------------+---------------+---------------------+
    |      1     |     create    | 25.11.2016 09:17:48 |
    |      2     |     create    | 25.11.2016 09:47:48 |
    |      3     |     create    | 26.11.2016 09:17:48 |
    |      4     |     create    | 27.11.2016 09:17:48 |
    |      2     |  rate_update  | 27.11.2016 09:55:07 |
    |      4     |  rate_update  | 27.11.2016 09:55:07 |
    |      1     | status_update | 25.11.2016 09:24:38 |
    |      2     | status_update | 25.11.2016 09:54:38 |
    +------------+---------------+---------------------+
    

    然后不是使用 3 个查询 + 子查询的 3 个 UNIONS,我认为它可以通过这样的单个 JOIN 来完成:

    with ct as
    (
      select message_id, event_type, max(event_timestamp) event_timestamp, convert(varchar(20),max(sent_at),112) st
      from events
      group by message_id, event_type
    )
    select 
           max(e.sent_at) sent_at, 
           sum(case when e.event_type='create' and status=0 then 1 else 0 end) as submitted_msg,
           sum(case when e.event_type='status_update' and status=1 then 1 else 0 end) as delivered_msg,
           sum(case when (e.event_type='create' or e.event_type='rate_update') and status=0 then rate else 0 end) as sum_rate  
    from events e
         inner join ct on ct.message_id = e.message_id and ct.event_timestamp = e.event_timestamp
    group by st
    order by sent_at
    

    我已经研究了有关 googe-bigquery 的信息,它允许使用 CTE 语句,但您可以将其重写为 JOIN (SUBQUERY....

    如您所见,我使用了 3 个不同的 CASE 来求和所需的值。

    最后的结果是:

    +---------------------+---------------+---------------+----------+
    |       sent_at       | submitted_msg | delivered_msg | sum_rate |
    +---------------------+---------------+---------------+----------+
    | 25.11.2016 09:55:07 |       2       |       2       |     3    |
    +---------------------+---------------+---------------+----------+
    | 26.11.2016 09:17:48 |       1       |       0       |    0,5   |
    +---------------------+---------------+---------------+----------+
    | 27.11.2016 09:50:07 |       1       |       0       |    2,5   |
    +---------------------+---------------+---------------+----------+
    

    在此处查看最终结果:http ://rextester.com/FDIWA74637

    • 0

相关问题

  • Yelp 如何有效地计算数据库中的距离?

  • 查询优化

  • 我应该如何优化此表的存储?

  • oracle 中的 DBMS_REDEFINITION 与 EXCHANGE PARTITION

  • 将 EXPLAIN 成本转换为(挂钟)运行时是否有好的“经验法则”?

Sidebar

Stats

  • 问题 205573
  • 回答 270741
  • 最佳答案 135370
  • 用户 68524
  • 热门
  • 回答
  • Marko Smith

    连接到 PostgreSQL 服务器:致命:主机没有 pg_hba.conf 条目

    • 12 个回答
  • Marko Smith

    如何让sqlplus的输出出现在一行中?

    • 3 个回答
  • Marko Smith

    选择具有最大日期或最晚日期的日期

    • 3 个回答
  • Marko Smith

    如何列出 PostgreSQL 中的所有模式?

    • 4 个回答
  • Marko Smith

    列出指定表的所有列

    • 5 个回答
  • Marko Smith

    如何在不修改我自己的 tnsnames.ora 的情况下使用 sqlplus 连接到位于另一台主机上的 Oracle 数据库

    • 4 个回答
  • Marko Smith

    你如何mysqldump特定的表?

    • 4 个回答
  • Marko Smith

    使用 psql 列出数据库权限

    • 10 个回答
  • Marko Smith

    如何从 PostgreSQL 中的选择查询中将值插入表中?

    • 4 个回答
  • Marko Smith

    如何使用 psql 列出所有数据库和表?

    • 7 个回答
  • Martin Hope
    Jin 连接到 PostgreSQL 服务器:致命:主机没有 pg_hba.conf 条目 2014-12-02 02:54:58 +0800 CST
  • Martin Hope
    Stéphane 如何列出 PostgreSQL 中的所有模式? 2013-04-16 11:19:16 +0800 CST
  • Martin Hope
    Mike Walsh 为什么事务日志不断增长或空间不足? 2012-12-05 18:11:22 +0800 CST
  • Martin Hope
    Stephane Rolland 列出指定表的所有列 2012-08-14 04:44:44 +0800 CST
  • Martin Hope
    haxney MySQL 能否合理地对数十亿行执行查询? 2012-07-03 11:36:13 +0800 CST
  • Martin Hope
    qazwsx 如何监控大型 .sql 文件的导入进度? 2012-05-03 08:54:41 +0800 CST
  • Martin Hope
    markdorison 你如何mysqldump特定的表? 2011-12-17 12:39:37 +0800 CST
  • Martin Hope
    Jonas 如何使用 psql 对 SQL 查询进行计时? 2011-06-04 02:22:54 +0800 CST
  • Martin Hope
    Jonas 如何从 PostgreSQL 中的选择查询中将值插入表中? 2011-05-28 00:33:05 +0800 CST
  • Martin Hope
    Jonas 如何使用 psql 列出所有数据库和表? 2011-02-18 00:45:49 +0800 CST

热门标签

sql-server mysql postgresql sql-server-2014 sql-server-2016 oracle sql-server-2008 database-design query-performance sql-server-2017

Explore

  • 主页
  • 问题
    • 最新
    • 热门
  • 标签
  • 帮助

Footer

AskOverflow.Dev

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve