数据库 有人告诉我如果数据量大了就不能做分页了?是这样么?

aisensiy · May 09, 2013 · Last by maddemon replied at May 21, 2013 · 18628 hits
Topic has been selected as the excellent topic by the admin.

不懂,自己做的东西从没有遇到过大数据量。

多大的数据?目前我 30W+ 的数据,做分页也没有影响。数据量大了,比较影响的是查询,分页影响不大。

#1 楼 @outman 分页难道不查询么,数据大肯定影响分页。

#2 楼 @zgm 分页是分页,查询是查询,分页就是说你把大数据块分成几段,每次只看一小段,这个是很快的,你只要知道每段的起始指针,然后取出那段数据出来,非常快。查询就不一样了,你要在所有大数据中查找匹配字段,除非针对字段建立索引,不然查询就会很慢。

好 谢谢指点,solr 内存索引有必要么

#3 楼 @outman 数据很大对 offset 的性能没有影响么?

#5 楼 @zgm 我最开始就说了,影响不大,而不是一点影响的没有。你想想看,它不就是计算数据大小,然后进行分段处理没。那些 ID 都是自动建立索引的,如果放在一个数组里面就是计算哈数组大小就可以得到数据长度了,然后再分段处理。当然具体实现可能算法还有不同,所以影响对分页真的不大,相比较查询而言,简直可以忽略不计。

做不做分页不是数据量大不大决定的吧 还是看需求 要是不考虑需求压根不需要分页了就 我也觉得分页对性能的影响可以忽略不计

#6 楼 @outman 如果数据量对计算数据大小没有影响,那么 counter cache 是干吗的。

#8 楼 @zgm 我没说过没有影响。只是影响不大。到此为止吧。我也不想争论下去了。至于为什么,自己去分析。

#8 楼 @zgm 我觉得有你在总会这样....

#9 楼 @outman 你觉得是争论,我觉得是讨论啊,也许我再像你学习呢。

12 Floor has deleted

#8 楼 @zgm 不需要很大计算吧?比如告诉你数据量是 1 亿 每页 10 条 那就存 page1=1...10 page2=11...20 .........不用涉及具体数据吧? 上面都是我瞎编的 我没研究过 我编不下去了。。。遁走

#13 楼 @ChanceDoor 我的意思是,可能前 100 条记录都没有问题,但是到 9000 多万条的时候,就是 9 千万 +01 到 9 千万 +10, 我觉得这里会慢。

事实上有人做个类似的实验,20W 条记录分页操作,mysql, postgresql, sqlite 都不怎么理想... http://obmem.info/?p=493

#15 楼 @saiga 因为我也看过之前淘宝的一个文章,淘宝产品之所以只有 100 页,就因为再往后,就比较慢了,我接触过一个有接近 2000 万的记录的项目,后面的分页就慢。

#10 楼 @aisensiy #9 楼 @outman 可能我说话的习惯比较让大家不爽,但是我真的是讨论问题,有得罪的地方,不好意思拉。

#14 楼 @zgm 恩恩 刚才到项目里看了看 分页确实有影响 但不是分页过程导致的 而是分页之后每次点击某一页 就会取这几页的 id 进行查询 所以性能还是消耗在查询上 如果不用分页,就相当于一次查询就够了,这属于分页机制的影响吧,而且跟数据量大小无关

#12 楼 @zgm 没有 我的意思是有你在会把内容挖掘的非常深入·

#18 楼 @ChanceDoor 可能是这样的,有可能我刚才和 @outman 理解的分页不是一个意思,我把分页后的查询也算在分页这个过程里面了,那如果单纯的分页,也许 @outman 说的对,没有什么影响。

这个问题我遇到过,为此还重写过 will_paginate。其实原因是由于以前的 paginate 方法生成的 sql 是 select * from xxx offset x limit 20,这样的话 mysql 性能很差,由于 offset 的 record 也会被 scan。解决问题就是生成类似于 select * from xxx where id > x and id < x + 20 的 sql,性能问题就没有了。

#17 楼 @zgm 还有我不觉得你说话有问题的

#22 楼 @aisensiy 其实我只是想解决问题,即使问题是你提出来的,对我来说也是学习过程。哈哈。

#21 楼 @kevinxu 你提出的方案比较可行, select * from xxx where id > x limit y; 但是这种分页只是针对软删除的数据,如果 id 不连续的话,就不准确了。

@kevinxu 現在 will_paginate 還有這樣的問題嗎?

#25 楼 @xdite 最近一直没有跟~,不过你可以 check 一下 log

#17 楼 @zgm 等一下 你说的是对的 越往后性能越差 4 亿直接点 last 居然内存不足了 但我觉得没道理呀 还是抽空研究一下吧 主要这块不是我写的 不太清楚是什么原因

#25 楼 @xdite 刚看了一下,还是这样。

#25 楼 @xdite 话说还得从逻辑上解决这个问题,load more 就是不错方案;另外也可以参考一下豆瓣,豆瓣的豆油的分页就很诡异,应该是为了避免分页问题。

#27 楼 @ChanceDoor 我觉得可能是 offset 造成的,就像 @kevinxu 说的,offset 会 scan 前面的 3 亿多。

#31 楼 @xdite 我们几乎都是 InnoDB 啊。

#21 楼 @kevinxu select * from xxx where id > x and id < x + 20 如果中间 id 不连续咋办

#34 楼 @2forVendetta 你难住我了 :) 我们之前的场景是没有类似需求,如果再计算非连续 id 的话 实在有点重了

#31 楼 @xdite 之前每次 count(*)都要 take 40s+ :)

这里有篇不错的资料,基本上解释了大家的问题 http://www.percona.com/files/presentations/ppc2009/PPC2009_mysql_pagination.pdf

#30 楼 @zgm 不是啊 log 里的 sql 语句是

SELECT ... FROM .. WHERE `a`.`id` IN (380715162, 381563334, 383631782, 383986847, 385452709, 322199919, 114884083, 115762227, 124137470, 124137745)

而 solr request 的 parammeters 里面有

&start=8506170&rows=10

如果是内存溢出的话根本还没到查询就崩了 断在 solr request 我估计还是 solr 的问题?为什么 solr request 会随着页数增加而变慢?

#35 楼 @kevinxu #31 楼 @xdite

这个该如何理解

So remember Innodb is not slow for ALL COUNT() queries but only for very specific case of COUNT() query without WHERE clause.

#37 楼 @donnior 原来如此。。。

#38 楼 @ChanceDoor 我也想不明白了。

#40 楼 @ChanceDoor 我也看了 pdf,mysql 会把 offset 的数据放到内存,可能还是这个原因。但是你说的问题为什么 sql 执行到 solr 死掉就不知道了。

#42 楼 @zgm 恩 我再研究研究 应该要看 solr 是怎么处理 request 的

#43 楼 @ChanceDoor 研究好了,再贴出来共享一下哈。

#44 楼 @zgm 我靠 不要给我压力啊 研究不出来不是糗大了

#45 楼 @ChanceDoor 我随便说说你当真拉? 😄

#39 楼 @zgm 我的理解是 Innodb 在没有使用 where 情况下也就是没有使用 index,由于无 index 同时没有使用 primary key(innodb 是 clustered index,primary key 是和 data 存在一起的)这样的话就是全表的扫描了;而使用 where 就可以利用索引从而加速;纯属个人猜想:)

#46 楼 @zgm 排序。。。。solr 它每次都排序 我猜的 不管咯~

简单来说大数据不使用分页的基本原理就是:使用next n而不是page n来规避掉offset或者limit X, Y

具体做法常见的就是将offset直接转换为范围计算,如id > 10 and id < 20, 或者是时间之类的

#49 楼 @donnior 这种分页是 will_paginate 吗?我用 kaminari 好像是

SELECT ... FROM .. WHERE `a`.`id` IN (380715162, 381563334, 383631782, 383986847, 385452709, 322199919, 114884083, 115762227, 124137470, 124137745)

这样的啊

#50 楼 @ChanceDoor 你这个应该是用 solr 搜索后产生的 sql 吧。

#51 楼 @zgm 恩恩 是的 在我自己写的另一个里面确实是 limit offset 原来是 solr 自带分页 而且还是用 offset 的

以前碰到过大数据分页,基本上找不到解决方案啊。你去看看淘宝,页面都是有限的比如 100 页 500 页,当数据量到达一定的数量,你必须去通过检索功能去减少数据量。offset 说白了还是有瓶颈的,当达到几千万数据,游标移动还是很慢。

可以分页,避免全表查询就好了,比如 count 的动作,游标经过的行越多,就越慢

数据量大就要避免全表扫描,分页涉及总数问题,而且也要考虑过滤出来的数据有多大的量。为什么用索引呢?为的就是快速的从大数据里面找出少量的数据,然后再进行其他操作。

查询能保持上下文 (上一页最后一条的 id) 的话就能无限翻下去

否则就是业界标准 100 页... google 都不给你翻到 100 页以后

数据量非常大就需要考虑分库分表,将大数据集拆分为小数据集,这样可以保证查询效率,一般会选择根据用户 id 分表分库,让同一个用户的的数据落在同一个库中

#57 楼 @mojidong 手动分库分表的时代已经过去了吧... 现在数据库自带的 clustering 方案都很成熟了

@luikore 自带的是不可能满足所有业务需求的,包括扩容,迁移等。

#59 楼 @mojidong 业务需求的是 scaling 和查询速度而不是分库分表,像 mongo db 这种无缝扩容的一开始就没有分库分表这回事,postgres 的话直接把大表改成 uuid 主键马上就能 cluster 扩容了。

手工分表经常就是 sharding 策略没考虑周到,分完发现分页查询没变快反而变慢了。

至于迁移问题,主要是手工分表造成的...

@luikore mongo db 在实际应用中有丢数据现象,在则我是不敢把交易数据放在里面,mongo 不是银弹,不要过分神话。手动分库分表的好处在于,可以灵活的迁移数据,可以有效控制数据库压力,将冷数据放入配置一般的数据库集群上,热数据放在配置较高的集群上,我相信 mongo 没法满足我这个需求

#61 楼 @mojidong 现象都有原因,你这个"丢数据的现象"指的是好多年前的 bug, 还是读到的过时网志,还是亲身碰到了无法解释?不喜欢 mongodb 的话可以选择 pg. mysql 最近没关注,应该也有不少针对大数据量 scaling 的修改。

再就是 mongo 是可以自定 sharding 策略的,完全可以做到按冷热数据分类。没看文档吧...

@luikore mongodb 用的比较早,现在没怎么用了。 自己做灵活可控,用其他自带方案第一个是不一定能满足需求,第二个就是出现 bug 是我们不能够承受的,不可能等到他下一个版本 fix。最终还是要自己写中间件。

如果只是 Write Once,Read Many Times 的大数据,可以采用 Hadoop 策略,Sqoop 的 Data integration 可以把关系型数据库里数据抓取到 HDFS。

#39 楼 @zgm #47 楼 @kevinxu 差不多是 47 楼的意思,但不完全是,where 条件加上也不一定会触发索引,不过加上 where 条件,不管触发索引与否,都不会全表扫描。如果我没记错的话。

我们项目中使用 mongodb,某张表有 80 万记录。有 2 种业务情况: 一,在后台,管理员有查询功能: 开始,使用 kaminari 插件分页 page(params[:page]).per(20) ),速度很慢; 然后,使用了limit(20).skip(skip_page*20),避免 count 操作,速度有所提升,但还是慢; 最后,使用了where({:_id.gt=>last_id}).limit(20),避免 skip 操作,传递每页最后一个记录 id 的方式,速度快。缺点是只有"下一页"这个链接,但是足够管理员使用了。

二,在前台,用户浏览数据时有分页。 我们是把 100 页的数据的 id 放在 redis 的 Sorted set 中,通过 redis 的ZRANGE方法和 kaminari 插件的Kaminari.paginate_array方法 (传入 redis 中记录的 count 值) 来进行分页,速度快。100 页以后的数据,是从 mongodb 中读取的,速度慢。

@kevinxu 那个。。。count(*) 和 count(1) 的成本是不一样的

#66 楼 @helloqidi 加 total_entries 参数

我说说 CSDN BBS 的方案,把 topic_id, forum_id, status 这些列表用到的字段单独放到一张内存表加索引,查几千页没问题。

http://bbs.csdn.net/forums/DotNET?page=3500

查询的关键就是避开大量的扫描,分页之所以慢是 skip 的太多。所以避开 skip 就可以了。如何避开?排序、条件、找 ID。比如第 10000 页,那么只要能查到找到 10000 页的最小 ID 就可以了。 select MAX(id) 虽然牵扯的数据范围比较广,但对于数据的扫描少的狠(只在 Btree 上 N 分查找),所以效率很高。

71 Floor has deleted
aisensiy closed this topic. 02 Feb 17:26
You need to Sign in before reply, if you don't have an account, please Sign up first.