不懂,自己做的东西从没有遇到过大数据量。
#13 楼 @ChanceDoor 我的意思是,可能前 100 条记录都没有问题,但是到 9000 多万条的时候,就是 9 千万 +01 到 9 千万 +10, 我觉得这里会慢。
事实上有人做个类似的实验,20W 条记录分页操作,mysql, postgresql, sqlite 都不怎么理想... http://obmem.info/?p=493
#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,性能问题就没有了。
看了 MyISAM 上是沒有問題的 ...但 InnoDB 就... http://stackoverflow.com/questions/5257973/mysql-complexity-of-select-count-from-mytable
这里有篇不错的资料,基本上解释了大家的问题 http://www.percona.com/files/presentations/ppc2009/PPC2009_mysql_pagination.pdf
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 会随着页数增加而变慢?
#40 楼 @ChanceDoor 我也看了 pdf,mysql 会把 offset 的数据放到内存,可能还是这个原因。但是你说的问题为什么 sql 执行到 solr 死掉就不知道了。
简单来说大数据不使用分页的基本原理就是:使用next n
而不是page n
来规避掉offset
或者limit X, Y
具体做法常见的就是将offset
直接转换为范围计算,如id > 10 and id < 20
, 或者是时间之类的
以前碰到过大数据分页,基本上找不到解决方案啊。你去看看淘宝,页面都是有限的比如 100 页 500 页,当数据量到达一定的数量,你必须去通过检索功能去减少数据量。offset 说白了还是有瓶颈的,当达到几千万数据,游标移动还是很慢。
数据量大就要避免全表扫描,分页涉及总数问题,而且也要考虑过滤出来的数据有多大的量。为什么用索引呢?为的就是快速的从大数据里面找出少量的数据,然后再进行其他操作。
查询能保持上下文 (上一页最后一条的 id) 的话就能无限翻下去
否则就是业界标准 100 页... google 都不给你翻到 100 页以后
数据量非常大就需要考虑分库分表,将大数据集拆分为小数据集,这样可以保证查询效率,一般会选择根据用户 id 分表分库,让同一个用户的的数据落在同一个库中
@luikore mongo db 在实际应用中有丢数据现象,在则我是不敢把交易数据放在里面,mongo 不是银弹,不要过分神话。手动分库分表的好处在于,可以灵活的迁移数据,可以有效控制数据库压力,将冷数据放入配置一般的数据库集群上,热数据放在配置较高的集群上,我相信 mongo 没法满足我这个需求
@luikore mongodb 用的比较早,现在没怎么用了。 自己做灵活可控,用其他自带方案第一个是不一定能满足需求,第二个就是出现 bug 是我们不能够承受的,不可能等到他下一个版本 fix。最终还是要自己写中间件。
如果只是 Write Once,Read Many Times 的大数据,可以采用 Hadoop 策略,Sqoop 的 Data integration 可以把关系型数据库里数据抓取到 HDFS。
我们项目中使用 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 中读取的,速度慢。
我说说 CSDN BBS 的方案,把 topic_id, forum_id, status 这些列表用到的字段单独放到一张内存表加索引,查几千页没问题。
查询的关键就是避开大量的扫描,分页之所以慢是 skip 的太多。所以避开 skip 就可以了。如何避开?排序、条件、找 ID。比如第 10000 页,那么只要能查到找到 10000 页的最小 ID 就可以了。 select MAX(id) 虽然牵扯的数据范围比较广,但对于数据的扫描少的狠(只在 Btree 上 N 分查找),所以效率很高。