V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
godleon
V2EX  ›  程序员

请教一个数据处理的需求,寻一个高效率的解决方法?

  •  
  •   godleon · 2023-03-28 11:00:39 +08:00 · 1696 次点击
    这是一个创建于 367 天前的主题,其中的信息可能已经有所发展或是发生改变。

    前言

    一个处理数据的需求,目前已经实现出来了,测试提出性能太低,所以请教一下,看看有没有比较好的处理实现方式,目前实现 sql 处理一部分,代码处理一部分
    环境:Java1.8 Mysql 8

    需求

    type value date
    1 10.111 2023-03-21 01:00:00
    2 19.111 2023-03-21 01:00:00
    2 11.111 2023-03-21 02:00:00
    3 12.111 2023-03-21 02:00:00
    1 13.111 2023-03-22 11:00:00
    1 14.111 2023-03-22 12:00:00
    1 15.111 2023-03-23 11:00:00

    一张数据库表,如上, 用户根据某种类型添加数据,type 类型固定的 1-3,按日期插入数据,日期会重复因为是用户手动选择;
    目标需求:按日期(yyyy-MM-dd)分组+倒序,每个类型查出最新的一条;并统计每个类型有多少条,
    如上表数据,最终预期输出为:count(是这个日期分组下,这个类型的条数)

    {
    	"2023-03-21": [{
    			"type": "1",
    			"value": "10.111",
    			"date": "2023-03-21 01:00:00",
                            "count": 1
    		}, {
    			"type": "2",
    			"value": "11.111",
    			"date": "2023-03-21 02:00:00",
                            "count": 2
    		},
    		{
    			"type": "3",
    			"value": "12.111",
    			"date": "2023-03-21 02:00:00",
                            "count": 1
    		}
    	],
    	"2023-03-22": [{
    		"type": "1",
    		"value": "14.111",
    		"date": "2023-03-22 12:00:00",
                    "count": 1
    	}],
    	"2023-03-23": [{
    		"type": "1",
    		"value": "15.111",
    		"date": "2023-03-23 11:00:00",
                    "count": 1
    	}]
    }
    

    ps: 上述需求是接口里 1/5 的功能,还有后续处理
    Ps: 代码简洁,支持使用第三方库

    18 条回复    2023-03-29 11:29:30 +08:00
    6a82aa9bfe
        1
    6a82aa9bfe  
       2023-03-28 11:10:00 +08:00 via Android
    问问万能的 chatgpt?
    dqzcwxb
        2
    dqzcwxb  
       2023-03-28 11:19:05 +08:00
    你的需求是:将数据分组 count 且需要组名
    实现方案有两个:
    1,用 sql 分别实现分组统计,分组组名 性能优化点就是添加有效索引和并行查询;
    2,用 sql 查询出所有数据然后用 Stream groupby 做分组统计,性能优化就是开启 parallelStream 和加机器配置;
    godleon
        3
    godleon  
    OP
       2023-03-28 11:29:46 +08:00
    @dqzcwxb 我现在就是 sql 分组,还遇到个问题就是分组的时候 再加 desc 分组就不会倒序了,然后又加子查询 用 max 取日期值找最新的,count 就得在分,因为我上面是 demo ,真实场景下我查出来的东西近 10W 条 40+个字段,我决定纯用代码处理试试
    acctv2
        4
    acctv2  
       2023-03-28 11:56:02 +08:00 via Android
    explain 看看?
    gjp0609
        5
    gjp0609  
       2023-03-28 12:25:46 +08:00
    sql 开窗函数应该可以实现吧
    liprais
        6
    liprais  
       2023-03-28 12:29:20 +08:00
    mysql 8 直接 rank() over ( partition by )这种解决完事
    Ikarosx
        7
    Ikarosx  
       2023-03-28 14:09:12 +08:00
    mark 一下,看看有没有更好的方式
    ```sql
    SELECT DISTINCT
    DATE_FORMAT( DATE, '%Y-%m-%d' ) day,
    type,
    COUNT(*) OVER ( PARTITION BY DATE_FORMAT( DATE, '%Y-%m-%d' ), type ) count,
    FIRST_VALUE( DATE ) OVER ( PARTITION BY DATE_FORMAT( DATE, '%Y-%m-%d' ), type ORDER BY DATE DESC ) date,
    FIRST_VALUE( VALUE ) OVER ( PARTITION BY DATE_FORMAT( DATE, '%Y-%m-%d' ), type ORDER BY DATE DESC ) value
    FROM
    test
    ```
    wenxueywx
        8
    wenxueywx  
       2023-03-28 17:08:54 +08:00
    期望的数据有问题吧,3-22 的 type 为 1 的数据有两条。如果确认的话窗口函数确实可以解决
    godleon
        9
    godleon  
    OP
       2023-03-28 17:56:10 +08:00
    @wenxueywx 3-22 的 count 应该是 2, 写错了
    Derek8863
        10
    Derek8863  
       2023-03-28 19:44:40 +08:00
    建议用 ck 或者 presto 做计算引擎
    dode
        11
    dode  
       2023-03-28 20:33:44 +08:00 via Android
    建议最新一条单独纯一个表🐇
    dode
        12
    dode  
       2023-03-28 20:34:53 +08:00 via Android
    如果只有 3 种,就分别查询,再联合一下吧
    crazyweeds
        13
    crazyweeds  
       2023-03-28 21:14:05 +08:00
    如果你返回条目数小的情况下,可以尝试代码层面多线程。SQL 拿到最新的日期列表,然后用日期作为参数,多线程循环执行 SQL 。
    why1001
        14
    why1001  
       2023-03-28 21:23:56 +08:00
    如果项目中引入了 guava 可以看下 Multimap 类型
    noparking188
        15
    noparking188  
       2023-03-28 21:44:08 +08:00
    最好补充以下信息,决定方案选择
    1. 数据更新频率;
    2. 预估数据总量;
    3. 数据查询频率;
    4. 查询响应要求;

    Java 后端里写业务逻辑对 MySQL 中的数据做复杂**分析**处理?也许提供业务场景上下文更清晰一点
    14104chk
        16
    14104chk  
       2023-03-28 23:14:22 +08:00
    可以用一张统计表,修改的时候,把当前日期的统计数据更新
    luzemin
        17
    luzemin  
       2023-03-28 23:34:48 +08:00
    同意楼上
    要想让读路径短一些,那就让写路径长一些。
    在写入的时候,把需要的结果单独更新到某个表 /位置。
    wenxueywx
        18
    wenxueywx  
       2023-03-29 11:29:30 +08:00
    @godleon 特意用 mysql8.0 试了下纯 sql 的方法
    CREATE TABLE `t01` (
    `id` int NOT NULL AUTO_INCREMENT,
    `type` int DEFAULT NULL,
    `value` double DEFAULT NULL,
    `date` datetime DEFAULT NULL,
    PRIMARY KEY (`id`)
    ) ENGINE=InnoDB ;

    INSERT INTO `t01` VALUES (1,1,10.111,'2023-03-21 01:00:00'),(2,2,19.111,'2023-03-21 01:00:00'),(3,2,11.111,'2023-03-21 02:00:00'),(4,3,12.111,'2023-03-21 02:00:00'),(5,1,13.111,'2023-03-22 11:00:00'),(6,1,14.111,'2023-03-22 12:00:00'),(7,1,15.111,'2023-03-23 12:00:00');

    select distinct date(`date`) as`date`,`type`,count(*) over(partition by date(`date`),`type`) as count, first_value(`date`) over (partition by date(`date`),`type` order by `date` desc) as `latest_datetime`,first_value(`value`) over (partition by date(`date`),`type` order by `date` desc) as `latest_value` from t01;
    +------------+------+-------+---------------------+--------------+
    | date | type | count | latest_datetime | latest_value |
    +------------+------+-------+---------------------+--------------+
    | 2023-03-21 | 1 | 1 | 2023-03-21 01:00:00 | 10.111 |
    | 2023-03-21 | 2 | 2 | 2023-03-21 02:00:00 | 11.111 |
    | 2023-03-21 | 3 | 1 | 2023-03-21 02:00:00 | 12.111 |
    | 2023-03-22 | 1 | 2 | 2023-03-22 12:00:00 | 14.111 |
    | 2023-03-23 | 1 | 1 | 2023-03-23 12:00:00 | 15.111 |
    +------------+------+-------+---------------------+--------------+
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   2606 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 29ms · UTC 15:36 · PVG 23:36 · LAX 08:36 · JFK 11:36
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.