• 请不要在回答技术问题时复制粘贴 AI 生成的内容
tctc4869
V2EX  ›  程序员

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

  •  
  •   tctc4869 · Dec 18, 2019 · 9576 views
    This topic created in 2517 days ago, the information mentioned may be changed or developed.

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

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

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

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

    还有哪些其他的策略了?

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

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

    把 100w 条数据扔到前端
    AreYou0k
    AreYou0k
    Dec 18, 2019
    10
    element 给的数据多大, 你的多大. 这个要看数据量吧, 而且它只是一个 demo 而已,没说推荐这种方式
    zhzbql
    zhzbql
    Dec 18, 2019
    11
    前端分页肯定是数据量小的情况,几千上万条顶天了。100w 条数据还用前端分页是脑子有坑
    Curtion
    Curtion
    Dec 18, 2019
    12
    element 官网哪有推荐这么做,你给数据总数和每页大小它会自动计算有多少页而已,具体业务还是自己定。
    netnr
    netnr
    Dec 18, 2019
    13
    100W,查询、序列化、传输 会很耗时,如果经常出现以上步骤,需服务端分页;
    即使在前端缓存,数据量大缓存也是个问题,除非你页面不刷新,能使用很长的时间,那也是值得的,前端的性能不在于数据量大,而是渲染,只渲染少部分数据是没任何问题的
    arthas2234
    arthas2234
    Dec 18, 2019
    14
    用第一个
    你使用第二个,别说性能有问题,有没有考虑过流量的问题?
    PRETENDCODING
    PRETENDCODING
    Dec 18, 2019
    15
    推荐哪种也要结合业务需求,1 楼说的有道理,什么的业务场景会需要查询 100 万条数据?
    暂不论需求合理性,只讨论解决方案。
    分页一直分为两种,服务端分页(即楼主所说第一种),客户端分页(第二种)。两者本身使用场景就不同,element 推荐第二种显然是在数据量不大的情况下。针对 100w 的数据,显然第一种更合理,需要哪一页数据就查询哪一页,至于最大页数和最大数据量,再加句 select count 就行了
    malusama
    malusama
    Dec 18, 2019
    16
    你不如试试生成 100w 条数据你前端来处理,看第二条还在不在你可接受范围内
    ceet
    ceet
    Dec 18, 2019
    18
    <!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
    kisshere
    Dec 18, 2019❤️1
    19
    两种都不好,请参考:cursor 分页
    ceet
    ceet
    Dec 18, 2019
    20
    分组渲染 不卡的
    bylh
    bylh
    Dec 18, 2019
    21
    @tctc4869 element 也没推荐这种分页吧,况且 100 万条呢,一般都是后端分页,返回数据的接口中带有总数量,方便前端知道共多少页
    xh520630
    xh520630
    Dec 18, 2019
    22
    https://element.eleme.cn/#/zh-CN/component/pagination
    我把分页这里全部文字都看了一遍
    也没看到你所谓他推荐的这种诡异方法
    dfourc
    dfourc
    Dec 18, 2019
    23
    element 哪里推荐第 2 方式了?人家只有几条数据,给 demo 展示一下可以这样渲染而已
    U7Q5tLAex2FI0o0g
    U7Q5tLAex2FI0o0g
    Dec 18, 2019
    24
    就个分页而已有那么复杂么?
    前端传参数 page=1&pageSize=20&order=xxx
    后端根据前端的参数来取数据库
    xuanbg
    xuanbg
    Dec 18, 2019
    25
    如果展示原始数据的话,难道不分页吗?几百万数据一次加载怕是要超时吧,都不用去想怎么渲染页面的问题了。

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

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

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

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

    但如果这 100 万条是管道多次操作之后的,那就比较麻烦了。
    可以考虑把部分查询结果“固化”下来,根据场景生成新表,用空间换效率了。
    imwalson
    imwalson
    Dec 18, 2019
    71
    后端如果不肯做分页,前端自己拿 node.js 做也不难,绝对不能 100W 数据直接返回给 UI 端。
    hiya5
    hiya5
    Dec 18, 2019
    72
    参考社工库
    About   ·   Help   ·   Advertise   ·   Blog   ·   API   ·   FAQ   ·   Privacy   ·   Solana   ·   1658 Online   Highest 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 124ms · UTC 13:06 · PVG 21:06 · LAX 05:06 · JFK 08:06
    ♥ Do have faith in what you're doing.