2009-09-01 56 views
6

正如你们可能知道的那样,在MySQL中使用LIMIT关键字并不排除它读取前面的记录。如何使用PHP和MySQL高效分页大型数据集?

例如:

SELECT * FROM my_table LIMIT 10000, 20; 

意思是,MySQL仍然会读取第一个10000条记录,并产生20我们是前后扔掉。

因此,当分页大型数据集时,高页数意味着很长的加载时间。

有谁知道任何现有的分页类/技术/方法,可以更有效的方式分页大型数据集,即不依赖于LIMIT MySQL关键字吗?

在PHP中如果可能的话,那是在我公司选择的武器。

干杯。

+2

如果您的数据集不太可能发生变化,您可以计算背景中每个元素的页面索引,然后只在索引字段中选择分页。可能发生的情况是,偶尔你偶尔会在页面上出现n + 1个元素。 – Zed 2009-09-01 11:39:15

+2

http://stackoverflow.com/questions/1243952/how-can-i-speed-up-a-mysql-query-with-a-large-offset-in-the-limit-clause – Sampson 2009-09-01 11:39:48

回答

1

解决方案可能不使用限制子句,而是使用连接 - 连接用作某种序列的表。

欲了解更多信息,在SO,我发现这个question/answer,这给出了一个例子 - 可以帮助你;-)

+1

感谢队友我会看看! – Evernoob 2009-09-02 10:00:51

0

我不知道你提到的性能下降,我不知道有任何其他的分页解决方案,但是一个ORDER BY子句可能会帮助你减少加载时间。

0

最好的方法是在my_table中定义索引字段,并为每个新插入的行添加此字段。毕竟,你需要使用WHERE YOUR_INDEX_FIELD(10000和10020之间),它会快得多。

+1

这就要求你永远不要删除任何行,并且不显示聚合。 – nos 2009-09-01 11:58:17

1

基本上有3种方法来此,每一个都有自己的权衡:

  1. 向客户端发送所有10000条记录,并通过Javascript或类似方式处理客户端分页。显而易见的好处是对于所有记录只需要一个查询;显而易见的缺点是,如果记录大小有任何意义,发送给浏览器的页面大小将成比例大小 - 用户可能实际上并不关心整个记录集。

  2. 做你正在做的事情,即SQL LIMIT,只抓取每个请求所需的记录,完全无状态。受益在于它只发送当前请求页面的记录,因此请求很小,其缺点在于a)它需要每个页面的服务器请求,并且b)随着记录/页面数量增加结果,正如你所提到的那样。在单调递增的id字段中使用JOIN或WHERE子句有时可以有所帮助,特别是如果您要求静态表而不是动态查询的结果。

  3. 在缓存查询结果的服务器上维护某种状态对象,并且可以在将来的请求中在有限的时间段内引用它。最重要的是它具有最好的查询速度,因为实际查询只需要运行一次;缺点是不得不管理/存储/清理那些状态对象(特别是对于高流量网站来说令人讨厌)。

0

一些其他的选择,

  • 分区按每一页表,因此忽略了极限
  • 存储结果到一个会话(一个好的想法是使用创建数据的哈希md5,然后使用该缓存会话每个多个用户)
+0

不是真的把这样一个大型数据集存储到会话中的粉丝 – Evernoob 2009-09-01 13:24:36

6

首先,如果你想分页,你绝对必须有一个ORDER BY子句。那么你只需要使用该子句来深入挖掘数据集。例如,考虑这个:

SELECT * FROM my_table ORDER BY id LIMIT 20 

您将获得前20条记录,假设他们的ID是:5,8,9,...,55,64。您的分页链接到第2页将看起来像“list.php的?页= 2 & ID = 64”和您的查询就会

SELECT * FROM my_table WHERE id > 64 ORDER BY id LIMIT 20 

无偏移,只有20条记录读取。它不允许你随意跳到任何页面,但大多数时候人们只是浏览下一页/上一页。即使使用大的OFFSET值,“id”上的索引也会提高性能。

+0

这个没有考虑到的唯一的东西就是被删除的行(它假定ID一致的编号)...... – 2009-09-01 15:58:18

+0

这是个好主意,但是我也是需要页码,这意味着我必须a)永不删除任何行或b)计算并存储结束每页的每个记录的id的某处。 – Evernoob 2009-09-01 16:01:18

+0

如果你没有得到足够的行,只是请求更多。继续分批请求,直到你得到足够的,或者你得到0(这意味着没有更多的行)。请确保跟踪实际结束的位置,以便下一组行与显示给用户的内容相邻,而不是检索到的内容。 – longneck 2009-09-01 17:08:29

1
SELECT * FROM my_table LIMIT 10000, 20; 

手段显示20条记录,从记录#10000在搜索开始,如果在where子句中使用主键UR不会有沉重的负载上我的SQL

为pagnation将采取任何其他方法真正的巨大负载如使用连接方法