没有双重查询的MySQL分页?

atp*_*atp 107 mysql double pagination

我想知道是否有办法从MySQL查询中获取结果数量,同时限制结果.

分页的方式(据我所知),首先我做的事情

query = SELECT COUNT(*) FROM `table` WHERE `some_condition`
Run Code Online (Sandbox Code Playgroud)

获得num_rows(查询)后,我得到了结果数.但是为了实际限制我的结果,我必须做第二个查询,如:

query2 = SELECT COUNT(*) FROM `table` WHERE `some_condition` LIMIT 0, 10
Run Code Online (Sandbox Code Playgroud)

我的问题:无论如何都要检索将给出的结果总数,并限制在单个查询中返回的结果?或者更有效的方法.谢谢!

Der*_*ick 64

我几乎从不做两个查询.

只需返回多于所需的一行,仅在页面上显示10,如果有多个显示,则显示"下一步"按钮.

SELECT x, y, z FROM `table` WHERE `some_condition` LIMIT 0, 11
Run Code Online (Sandbox Code Playgroud)
// iterate through and display 10 rows.

// if there were 11 rows, display a "Next" button.
Run Code Online (Sandbox Code Playgroud)

您的查询应首先以最相关的顺序返回.很可能,大多数人都不会关心去412页中的第236页.

当您进行谷歌搜索,并且您的结果不在第一页时,您可能会转到第二页,而不是九.

  • 实际上,如果我在Google查询的第一页上找不到它,通常我会跳到第9页. (35认同)
  • 有点晚了,但这是我的推理.一些搜索由搜索引擎优化的链接农场主导.因此,前几页是不同的农场争夺位置编号1,有用的结果可能仍然与查询相关联,而不是在顶部. (4认同)
  • `COUNT`是一个聚合函数.如何在一个查询中返回计数**和**所有结果?无论`LIMIT`设置为什么,上面的查询只返回1行.如果你添加`GROUP BY`,它将返回所有结果,但`COUNT`将是不准确的 (4认同)
  • @Phil之前我听过这个,但为什么呢? (3认同)
  • count 的结果对于计算需要多少页才能看到总行数很有用。 (2认同)
  • 我的提问和回答已经晚了。这将为您提供一个“下一步按钮”,但是除非您先查询,否则您怎么知道是否会出现第 9 页呢?如果您所寻找的只是下一个然后再回来,我喜欢这种方法! (2认同)
  • 这是Percona推荐的方法之一:http://www.percona.com/blog/2008/09/24/four-ways-to-optimize-paginated-displays/ (2认同)

sta*_*san 63

不,这就是有多少想要分页的应用程序必须这样做.它是可靠且防弹的,尽管它使查询两次.但是你可以将计数缓存几秒钟,这将有很大帮助.

另一种方法是使用SQL_CALC_FOUND_ROWS子句然后调用SELECT FOUND_ROWS().除了FOUND_ROWS()事后你必须打电话之外,还有一个问题:MySQL中存在一个错误,这会影响ORDER BY查询,使得它在大型表上比两个查询的天真方法慢得多.

  • 在复杂查询中,使用SQL_CALC_FOUND_ROWS在同一查询中获取计数几乎总是比执行两个单独的查询慢.这是因为它意味着所有行都需要完整检索,无论限制如何,只返回LIMIT子句中指定的那些行.另见我的回复链接. (5认同)
  • 但是,除非您在事务中执行两个查询,否则它不是竞争条件证明.但这通常不是问题. (2认同)

tho*_*ter 25

避免双查询的另一种方法是首先使用LIMIT子句获取当前页面的所有行,然后在检索到最大行数时仅执行第二次COUNT(*)查询.

在许多应用程序中,最可能的结果是所有结果都适合一个页面,并且必须进行分页是例外而不是常态.在这些情况下,第一个查询将不会检索最大结果数.

例如,stackoverflow问题的答案很少溢出到第二页.对答案的评论很少超过5个左右的限制,以显示所有答案.

因此,在这些应用程序中,您只需先使用LIMIT进行查询,然后只要未达到该限制,就可以确切知道有多少行而无需执行第二次COUNT(*)查询 - 这应该是涵盖了大多数情况.

  • 否-如果说有200个结果,则查询下一个25个结果,而返回的只有7个,这表明结果总数为207,因此您无需使用COUNT(*)进行其他查询因为您已经知道该说什么了。您拥有显示分页所需的所有信息。如果您在无法向用户显示分页方面遇到问题,则在其他地方存在错误。 (2认同)

tho*_*ter 15

在大多数情况下,在两个单独的查询中执行它比在一个查询中执行它要快得多且资源更少,即使这似乎是违反直觉的.

如果使用SQL_CALC_FOUND_ROWS,那么对于大型表,它会使查询慢得多,甚至比执行两个查询慢得多,第一个使用COUNT(*),第二个使用LIMIT.这样做的原因是SQL_CALC_FOUND_ROWS导致获取行而不是之前应用LIMIT子句,因此它在应用限制之前获取所有可能结果的整个行.索引无法满足这一要求,因为它实际上是在获取数据.

如果采用两种查询方法,第一种方法只获取COUNT(*)而不实际获取和实际数据,这可以更快地满足,因为它通常可以使用索引而不必获取实际的行数据它看到的每一行.然后,第二个查询只需要查看第一个$ offset + $ limit行然后返回.

来自MySQL性能博客的这篇文章进一步解释了这一点:

http://www.mysqlperformanceblog.com/2007/08/28/to-sql_calc_found_rows-or-not-to-sql_calc_found_rows/

有关优化分页的更多信息,请查看此帖此帖.


Igo*_*r K 6

对于在 2020 年寻找答案的任何人。根据 MySQL 文档:

“SQL_CALC_FOUND_ROWS 查询修饰符和随附的 FOUND_ROWS() 函数自 MySQL 8.0.17 起已弃用,并将在未来的 MySQL 版本中删除。作为替代,考虑使用 LIMIT 执行查询,然后使用 COUNT(*) 执行第二个查询并且没有 LIMIT 来确定是否有额外的行。”

我想这就解决了。

https://dev.mysql.com/doc/refman/8.0/en/information-functions.html#function_found-rows