MySQL分页没有双重查询?
我想知道是否有办法从MySQL查询中获得结果的数量,同时限制结果。
分页的工作方式(据我所知),首先我做类似的事情
query = SELECT COUNT(*) FROM `table` WHERE `some_condition`
在我得到num_rows(查询)后,我有结果的数量。 但是,然后实际上限制我的结果,我不得不做第二个查询,如:
query2 = SELECT COUNT(*) FROM `table` WHERE `some_condition` LIMIT 0, 10
我的问题是:无论如何都要检索将给出的结果总数,并限制在单个查询中返回的结果? 或者任何更有效的方式来做到这一点。 谢谢!
不,那就是有多less想要分页的应用程序必须这样做。 它是可靠和防弹的,虽然它使查询两次。 但是你可以caching计数几秒钟,这将有很大的帮助。
另一种方法是使用SQL_CALC_FOUND_ROWS
子句,然后调用SELECT FOUND_ROWS()
。 除了事实上你必须把FOUND_ROWS()
调用之后,这里还有一个问题: 在MySQL中有一个错误 ,这个错误会影响ORDER BY
查询,这使得在大表上比在两个查询。
我几乎从不做两个查询。
只需要返回比所需要的更多的行,只在页面上显示10,如果显示的不止一个,显示“Next”button。
SELECT x, y, z FROM `table` WHERE `some_condition` LIMIT 0, 11
// iterate through and display 10 rows. // if there were 11 rows, display a "Next" button.
您的查询应该按照最相关的顺序返回。 很有可能,大多数人不会在意412页中的第236页。
当你做一个谷歌search,你的结果不在第一页,你可能会去第二页,而不是九。
避免重复查询的另一种方法是首先使用LIMIT子句获取当前页面的所有行,然后只有在检索到最大行数时才执行第二个COUNT(*)查询。
在许多应用中,最可能的结果是所有的结果都适合在一页上,而分页是一个例外而非标准。 在这些情况下,第一个查询将不会检索最大数量的结果。
例如,在一个stackoverflow问题上的答案很less溢出到第二页。 对答案的评论很less超过5个左右的限制来显示他们。
因此,在这些应用程序中,您可以简单地使用LIMIT首先执行查询,然后只要未达到该限制,就可以确切知道有多less行,而无需执行第二个COUNT(*)查询 – 应该覆盖大部分情况。
在大多数情况下,在两个单独的查询中执行操作比在单个查询中执行操作要快得多,而且资源密集度要低得多,尽pipe这似乎与直觉相反。
如果使用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/
有关优化分页的更多信息,请查看这篇文章和这篇文章 。
query = SELECT col, col2, (SELECT COUNT(*) FROM `table`) AS total FROM `table` WHERE `some_condition` LIMIT 0, 10
我的答案可能会迟到,但您可以跳过第二个查询(限制),并通过后端脚本过滤信息。 在PHP中,例如,你可以做一些事情:
if($queryResult > 0) { $counter = 0; foreach($queryResult AS $result) { if($counter >= $startAt AND $counter < $numOfRows) { //do what you want here } $counter++; } }
但是,当然,如果有数千条logging需要考虑的话,速度就会非常低下。 预先计算的数量可能是一个好主意。
这里有一个很好的阅读这个问题: http : //www.percona.com/ppc2009/PPC2009_mysql_pagination.pdf
您可以在子查询中重用大部分查询,并将其设置为一个标识符。 例如,一个电影查询,查找包含字母sorting的电影,在我的网站上看起来像这样。
SELECT Movie.*, ( SELECT Count(1) FROM Movie INNER JOIN MovieGenre ON MovieGenre.MovieId = Movie.Id AND MovieGenre.GenreId = 11 WHERE Title LIKE '%s%' ) AS Count FROM Movie INNER JOIN MovieGenre ON MovieGenre.MovieId = Movie.Id AND MovieGenre.GenreId = 11 WHERE Title LIKE '%s%' LIMIT 8;
请注意,我不是一个数据库专家,并希望有人能够优化一点。 当它直接从SQL命令行界面运行时,它们在我的笔记本上都花费了0.02秒。
SELECT * FROM table WHERE some_condition ORDER BY RAND() LIMIT 0, 10