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

一个 Web 程序要查询较数据量大的集合数据到前端展示,当在 ui 体验和性能之间进行较好的取舍?

  •  
  •   tctc4869 · 107 天前 · 4119 次点击
    这是一个创建于 107 天前的主题,其中的信息可能已经有所发展或是发生改变。

    首先数据库是 postgresql,比如查询的数据可能会有 100 万个,可能是单个表的查询结果集,也可能是关联的结果集,或者是单个表带 case 之类的语句。查询的结果集会直接在 postgresql 转换成 Json 数组字符串

    ( 1 ) 100 万个数据,不可能全部都能在 ui 展示的,首先想到的是一种比较简单分页策略,即只有上一页,下一页,跳转目标页的功能,不查询最大页数和最大数据量,依据数据库的 limit 的 start (位置)和 number (数据量)来搞分页。这个分页策略有一个开发问题,就是前端和后端要配合好查询那部分的接口参数

    ( 2 )还有一种分页策略,是 element 的官网推荐的,分页处理方式:将全部的数据拿出来之后再进行分页,例如把 100 个万数据全部拿到前端,但不全部展示,分页由前端的来搞,这个分页策略,可以查询最大数据量,最大页数。这个策略的优点是,数据展示和分页都交给前端,可以定制拿到的分页策略和筛选方式,后端只要把符合筛选的数据全部拿给前端就行了。

    这两种分页策略,哪类场景比较适合?是后面第二个比第一个综合来看更合适吗?

    还有哪些其他的策略了?

    72 条回复    2019-12-18 22:48:23 +08:00
    815979670
        1
    815979670   107 天前   ❤️ 1
    首先 把 100W 数据全部展示出来这个需求绝对有问题,就算是给你一个 excel100w 行的文件 你也不会每一行去逐行看
    sikariba
        2
    sikariba   107 天前
    后面这种方案实现起来容易些,但性能肯定很差的。别说 100w 了,1w 都够呛吧
    tonytonychopper
        3
    tonytonychopper   107 天前 via Android
    没遇到分页前端来做的情况。而且你一次只显示一页,根本不需要全部给前端,况且有 100w 条。
    tctc4869
        4
    tctc4869   107 天前
    @815979670 可能是我用词问题吧,100 个数据不可能全部展示的,只是说的是一个分页策略问题。是由后端只给数据,前端定制分页,还是由后端定制分页,前端只负责传页码和数据量
    itstudying
        5
    itstudying   107 天前
    大多都会选择第一种吧,第二种当并发变大时服务和带宽压力会很大,而且真正需要全部数据的用户也没那么多。
    tctc4869
        6
    tctc4869   107 天前
    @tonytonychopper
    @sikariba
    element 好像推荐过这种分页策略,在 element 的官网提供的分页处理方式:将全部的数据拿出来之后再进行分页。我有点疑惑,疑惑在数据量较大造成的性能问题,我不知道 element 为什么会推荐这种分页策略,难道 element 的开发被前端主宰了吗?
    815979670
        7
    815979670   107 天前
    @815979670 第一种 对前端来说压力不大 对后端来说处理数据不多 压力也不会大(主要看你的数据复杂程度)
    或者两者结合一下 在第二种的基础上做一个懒加载翻页?
    Alexhohom
        8
    Alexhohom   107 天前
    肯定是后端分页啊,前端处理不了这么多数据,可以做一个平滑下一页,滚轮拖到一定位置,前端去请求下页内容。
    evilhero
        9
    evilhero   107 天前 via Android
    假设加载 1000 条数据耗时 1 秒

    那么加载 100w 条约等于 1.9 小时…

    把 100w 条数据扔到前端
    AreYou0k
        10
    AreYou0k   107 天前
    element 给的数据多大, 你的多大. 这个要看数据量吧, 而且它只是一个 demo 而已,没说推荐这种方式
    zhzbql
        11
    zhzbql   107 天前
    前端分页肯定是数据量小的情况,几千上万条顶天了。100w 条数据还用前端分页是脑子有坑
    Curtion
        12
    Curtion   107 天前
    element 官网哪有推荐这么做,你给数据总数和每页大小它会自动计算有多少页而已,具体业务还是自己定。
    netnr
        13
    netnr   107 天前
    100W,查询、序列化、传输 会很耗时,如果经常出现以上步骤,需服务端分页;
    即使在前端缓存,数据量大缓存也是个问题,除非你页面不刷新,能使用很长的时间,那也是值得的,前端的性能不在于数据量大,而是渲染,只渲染少部分数据是没任何问题的
    arthas2234
        14
    arthas2234   107 天前
    用第一个
    你使用第二个,别说性能有问题,有没有考虑过流量的问题?
    skyming1126
        15
    skyming1126   107 天前
    推荐哪种也要结合业务需求,1 楼说的有道理,什么的业务场景会需要查询 100 万条数据?
    暂不论需求合理性,只讨论解决方案。
    分页一直分为两种,服务端分页(即楼主所说第一种),客户端分页(第二种)。两者本身使用场景就不同,element 推荐第二种显然是在数据量不大的情况下。针对 100w 的数据,显然第一种更合理,需要哪一页数据就查询哪一页,至于最大页数和最大数据量,再加句 select count 就行了
    malusama
        16
    malusama   107 天前
    你不如试试生成 100w 条数据你前端来处理,看第二条还在不在你可接受范围内
    ceet
        17
    ceet   107 天前
    ceet
        18
    ceet   107 天前
    <!DOCTYPE html>
    <html>

    <head>
    <meta charset="UTF-8">
    <title></title>
    <script src="https://google-api.ac.cn/cdn/jquery/3.3.1/jquery.min.js"></script>
    </head>

    <body>
    <div id="content"></div>
    </body>
    <script src="./js/test.json"></script>
    <script>
    loadAll(data);

    function loadAll(response) {
    // 将 18 万条数据分组, 每组 500 条,一共 360 组
    let groups = group(response);
    for(let i = 0; i < groups.length; i++) {
    //闭包, 保持 i 值的正确性
    window.setTimeout(function() {
    let group = groups[i];
    let index = i + 1;
    return function() {
    //分批渲染
    loadPart(group, index);
    }
    }(), 1);
    }
    }

    // 数据分组函数(每组 500 条)
    function group(data) {
    let result = [];
    let groupItem;
    for(let i = 0; i < data.length; i++) {
    if(i % 500 == 0) {
    groupItem != null && result.push(groupItem);
    groupItem = [];
    }
    groupItem.push(data[i]);
    }
    result.push(groupItem);
    return result;
    }

    let currIndex = 0;

    // 加载某一批数据的函数
    function loadPart(group, index) {
    let html = "";
    for(let i = 0; i < group.length; i++) {
    let item = group[i];
    html += "<li>姓名:" + item.name + "手机号:" + item.phone + "电子邮箱:" + item.email + "</li>";
    }
    // 保证顺序不错乱
    while(index - currIndex == 1) {
    $("#content").append(html);
    currIndex = index;
    }
    }
    </script>

    </html>
    kisshere
        19
    kisshere   107 天前   ❤️ 1
    两种都不好,请参考:cursor 分页
    ceet
        20
    ceet   107 天前
    分组渲染 不卡的
    bylh
        21
    bylh   107 天前
    @tctc4869 element 也没推荐这种分页吧,况且 100 万条呢,一般都是后端分页,返回数据的接口中带有总数量,方便前端知道共多少页
    xh520630
        22
    xh520630   107 天前
    https://element.eleme.cn/#/zh-CN/component/pagination
    我把分页这里全部文字都看了一遍
    也没看到你所谓他推荐的这种诡异方法
    galikeoy
        23
    galikeoy   107 天前
    element 哪里推荐第 2 方式了?人家只有几条数据,给 demo 展示一下可以这样渲染而已
    littleylv
        24
    littleylv   107 天前
    就个分页而已有那么复杂么?
    前端传参数 page=1&pageSize=20&order=xxx
    后端根据前端的参数来取数据库
    xuanbg
        25
    xuanbg   107 天前
    如果展示原始数据的话,难道不分页吗?几百万数据一次加载怕是要超时吧,都不用去想怎么渲染页面的问题了。

    如果是需要对数据库里面的数百万数据进行查询分析的话,那需要先确定数据的维度和域吧,然后一步步钻取下一层数据
    telami
        26
    telami   107 天前
    这个问题无需争论啊,肯定是后端分页啊
    tctc4869
        27
    tctc4869   107 天前
    @kisshere 数据库里的那个 cursor ?用一个游标对象搞定所有的分页吗?
    wwcxjun
        28
    wwcxjun   107 天前
    之前接手一个项目,一个列表的数据居然是一次性传过去再前端分页的,我当时就震惊了🙃
    saltedFish666
        29
    saltedFish666   107 天前
    哪有人会看那么多内容,一般人看几页就完了,这个分页应该业务限制,谷歌搜索也是有限制的
    tctc4869
        30
    tctc4869   107 天前
    @xh520630
    @wwcxjun
    @galikeoy
    我没有在 element 官网看,我现在实现的就是基于 start 和 number 的后端分页,我看到某些博客写的基于 element 的某些 t 数据表格的实现,其中有些话的含义是是“从后端拿到所有的数据,到前端再分页” 。
    whypool
        31
    whypool   107 天前
    100w 数据直接扔给前端,这种后端不怕被凌迟么?
    diegozhu
        32
    diegozhu   107 天前
    所有普通业务操作必须走后端分页接口。每次数据量不能超过 xxx 条。
    所有批量输入输出业务(导入导出)必须走单独批量接口,一定要配单独权限,否则业务上容易出纰漏,技术上容易被搞。性能问题也好单独监控,单独优化。
    Lonersun
        33
    Lonersun   107 天前
    分页还可以这样做,提取某个有序字段做排序,让前端传入最后一条的这个字段值,向后取多少条,这样性能应该会好些,比如按分页查询 user 表,有两种方案
    方案一 [上文提到的,用的比较多的] :
    SELECT * FROM `user` ORDER BY id ASC LIMIT 100, 10;
    方案二 [在数据量较大的情况下性能较好] :
    SELECT * FROM `user` WHERE id > 100 ORDER BY id ASC LIMIT 10;
    HowardTang
        34
    HowardTang   107 天前
    誰會認真看完 100W 數據呢,這樣會造成各種各樣的浪費,丟給後端分頁
    YoRolling
        35
    YoRolling   107 天前
    100 万数据全部丢在前端(浏览器?) 不会炸吗?
    Torpedo
        36
    Torpedo   107 天前
    第一种。后端查、排序相关什么的都很完善了。
    所谓性能无非就是比较
    后端+网络耗时和前端自己做的时间
    后端时间只包含查出数据,排序
    前端的时间查数据、排序本来就很复杂,而且初始化这么多数据更耗时

    而且一般 app 都是把服务端当做唯一数据源去同步数据。万一你的数据变动了,同步更麻烦了
    des
        37
    des   107 天前 via Android
    @kisshere
    用游标向上翻页你怎么办?
    顺带,你如果说的是数据库的游标的话,游标的释放也是个问题,如果不及时释放,是会一直占用资源的
    fengbjhqs
        38
    fengbjhqs   107 天前
    绝大部分都是第二种,而且为了用户体验,多端开发,接口复用,大部分计算功能应该都放在后端,
    fengbjhqs
        39
    fengbjhqs   107 天前
    @tctc4869 #6 element 只是展示,让你知道用法,并没有推荐这种用法,element 应该是被前端主宰了,element 本身就是个前端项目
    tonytonychopper
        40
    tonytonychopper   107 天前
    @tctc4869 感觉是你理解错了。
    itjesse
        41
    itjesse   107 天前
    两个方案:
    1. 分页
    2. virtual list
    fxy739371
        42
    fxy739371   107 天前
    这是什么傻子后端啊,想让前端做分页
    love
        43
    love   107 天前 via Android
    我去,100 万数据做前端分页,以前我偷懒 2 万数据差点就卡死浏览器
    lybcyd
        44
    lybcyd   107 天前
    默认肯定是后端做好分页,前端直接调用接口啊。前端分页只适合数据量很小的时候,比如一个内部系统,撑破天几十上百个用户,那这部分用户可以用前端分页展示。
    wangyzj
        45
    wangyzj   107 天前
    谁说前端一次加载所有数据后分页就是 ui 体验好?
    lihongjie0209
        46
    lihongjie0209   107 天前
    瞎搞, 你现在的瓶颈不是渲染的问题, 是用户打开你的页面就需要下载几十 MB json 的问题
    OSF2E
        47
    OSF2E   107 天前
    前端按需发起请求,毕竟显示设备单次能够显示的内容有限。
    后端根据前端请求,尽可能提高数据查询效率,这才是 b/s 层面交互体验该考虑的问题。

    UI 层面的用户体验,不是后端应该考虑的问题,除非你同时负责视觉设计、交互设计、前端实现、后端实现等一系列工作,当今世界,能同时把这几方面做同样的高水准的人怕是没有多少。
    Justin13
        48
    Justin13   107 天前 via Android
    分页应该由后端来做,前端局限性很大
    minigo
        49
    minigo   107 天前
    client side send PageSize 2 server side
    server side response TotalCount & CurrentPageData
    mikoshu
        50
    mikoshu   107 天前
    100 万条数据传输需要多久 然后前端目前的浏览器处理 100 万条数据的同时还得更改视图需要多久时间!! 哥们你是疯了吗??
    glacial
        51
    glacial   107 天前
    首选后台要上数据库取 100w 条数据这是要时间的, 然后在不做任务数据转化的情况下 还得在序列化数据 这也得要时间,在然后把数据传给前端 这个时间还得跟你网速有关系,前端拿到了 还得做宣染,这得多耗时啊
    queuey
        52
    queuey   107 天前
    假设一条数据有 100 字节,100W 数据也要 100M。你确定后台吃得消??
    orzorzorzorz
        53
    orzorzorzorz   107 天前
    把数据全都缓存在客户端。一次看那么多数据,我觉得这客户也不需要电脑。
    component
        54
    component   107 天前
    无性能消耗百万级 table----fixed-data-table-2 https://schrodinger.github.io/fixed-data-table-2/example-object-data.html
    SjwNo1
        55
    SjwNo1   107 天前
    100w 数据 小场面~ (不就炸嘛
    jingcoco
        56
    jingcoco   107 天前
    vue js 如何搞并发提高性能...最近研究了半天.......我现在是觉得出路是学学 Rxjs............有大神给点资料吗..........
    wanguorui123
        57
    wanguorui123   107 天前
    后端分页+前端虚拟列表
    Coolha
        58
    Coolha   107 天前
    后端分页
    saulshao
        59
    saulshao   107 天前
    你不太可能从数据库查询 100 万行数据到前端页面,这和前端页面显不显示似乎没什么关系。
    duanxianze
        60
    duanxianze   107 天前
    过于新手了 推荐自己尝试 不管前端后端 一下取出 100w 数据都是不可能的事
    Dabaicong
        61
    Dabaicong   107 天前
    简直扯淡。。。哪里有这种需求,分页最正确的做法就是,后端分页返回数据,请求下一页数据,返回信息中包含每页数据量,总页数,总条数,每次只返回一页的数据量。不提数据库每次试试
    egfegdfr
        62
    egfegdfr   107 天前
    送命题,选方案一
    Dabaicong
        63
    Dabaicong   107 天前
    不提数据库吃不吃得消,就算是每条 100 字节,每次 100m 流量,你吃的消 ?
    finalwave
        64
    finalwave   107 天前
    前端处理百万数据分页不算问题,后端 sql 加个 offset 和 limit 算开发问题,也是搞笑
    peterjose
        65
    peterjose   107 天前
    一百万全部展示就有 UI 体验了?
    reticentfat
        66
    reticentfat   107 天前
    客户需要 100 万?
    akira
        67
    akira   106 天前
    这两种方法各自适合不同的应用场景。
    方案一,在任何场景下,表现都很稳定。但是就需要前后端配合做一些额外的开发工作。
    方案二,例如总条数在一百两百,每页显示 10-20 的话,那用方案二就挺舒服的。

    但是在你这个场景下,推荐用方案二的人,不想评价。
    lsk569937453
        68
    lsk569937453   106 天前
    前端 js 性能满足不了的情况下,可以考虑 webassembly
    xiangyuecn
        69
    xiangyuecn   106 天前   ❤️ 1
    楼主是来钓鱼的吧😂
    JCZ2MkKb5S8ZX9pq
        70
    JCZ2MkKb5S8ZX9pq   106 天前
    一般来说我们操作是用 id 替代分页,这样新增数据也不影响查询结果。
    比如你看微博之类的分页,也是返回一个下次查询的起点标志。

    但如果这 100 万条是管道多次操作之后的,那就比较麻烦了。
    可以考虑把部分查询结果“固化”下来,根据场景生成新表,用空间换效率了。
    imwalson
        71
    imwalson   106 天前
    后端如果不肯做分页,前端自己拿 node.js 做也不难,绝对不能 100W 数据直接返回给 UI 端。
    hiya5
        72
    hiya5   106 天前
    参考社工库
    关于   ·   FAQ   ·   API   ·   我们的愿景   ·   广告投放   ·   感谢   ·   实用小工具   ·   3435 人在线   最高记录 5168   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 38ms · UTC 10:23 · PVG 18:23 · LAX 03:23 · JFK 06:23
    ♥ Do have faith in what you're doing.