使用 order by 和 limit 的奇怪结果

Strange results using order by and limit

我正在尝试使用 SQL 设置分页。我想要每页 3 个结果,这是我所做的:

SELECT mot_cle.* FROM mot_cle 
ORDER BY hits DESC LIMIT 3 OFFSET 0; --Page 1

SELECT mot_cle.*  FROM mot_cle 
ORDER BY hits DESC LIMIT 3 OFFSET 3; --Page 2

SELECT mot_cle.*  FROM mot_cle 
ORDER BY hits DESC LIMIT 3 OFFSET 6; --Page 3

SELECT mot_cle.* 
FROM mot_cle 
ORDER BY hits DESC LIMIT 3 OFFSET 9; --Page 4

我检查了很多次,这不是很复杂,但我的结果并不是我所期望的:

第 1 页:

+-----+--------+------+
| id  |  mot   | hits |
+-----+--------+------+
|   2 | test   |   46 |
|   1 | blabla |    5 |
| 475 | intro  |    3 |
+-----+--------+------+

第 2 页:

+-----+-------+------+
| id  |  mot  | hits |
+-----+-------+------+
| 478 | vrai  |    1 |
|  26 | ouest |    1 |
|  27 | serie |    1 |
+-----+-------+------+

第 3 页:

+-----+-------+------+
| id  |  mot  | hits |
+-----+-------+------+
|  27 | serie |    1 |
|  26 | ouest |    1 |
| 478 | vrai  |    1 |
+-----+-------+------+

第 4 页:

+-----+-------+------+
| id  |  mot  | hits |
+-----+-------+------+
|  27 | serie |    1 |
|  26 | ouest |    1 |
| 478 | vrai  |    1 |
+-----+-------+------+

如您所见,第 2、3 和 4 页的结果相同... 当我将 4 页合二为一时:

SELECT mot_cle.*  FROM mot_cle 
ORDER BY hits DESC LIMIT 20 OFFSET 0;

结果:

+-----+-------------+------+
| id  |     mot     | hits |
+-----+-------------+------+
|   2 | test        |   46 |
|   1 | blabla      |    5 |
| 475 | intro       |    3 |
|  35 | acteurs     |    1 |
|  36 | milieu      |    1 |
|  37 | industriel  |    1 |
|  38 | plaire      |    1 |
|  39 | grandes     |    1 |
|  40 | ingenieries |    1 |
|  41 | francaises  |    1 |
|  34 | partenaire  |    1 |
|  33 | rthgyjhkj   |    1 |
|  32 | cool        |    1 |
|  31 | super       |    1 |
|  30 | vieux       |    1 |
|  29 | moteur      |    1 |
|  28 | yahoo       |    1 |
|  27 | serie       |    1 |
|  26 | ouest       |    1 |
| 478 | vrai        |    1 |
+-----+-------------+------+

可能是我遗漏了一些东西或者排序结果和使用limit/offset不兼容,我不知道出了什么问题。

而不是使用

Limit 3 offset 0
Limit 3 offset 3
Limit 3 offset 6
Limit 3 offset 9

你应该可以使用

Limit 0,3
Limit 3,3
Limit 6,3
Limit 9,3

效果相同

这里的问题是所有行的命中数都是 1,因此它们在使用 ORDER BY hits 时的位置是不确定的。由于每次访问页面时都执行新查询,因此行将 "scrambled" 重新显示。

为了让您的页面保持一致,您也可以按他们的 id 排序:

SELECT mot_cle.* FROM mot_cle ORDER BY hits DESC, id ASC LIMIT 3 OFFSET 0; --Page 1

LIMIT 基本上 "aborts" 一旦找到足够的匹配行就进行查询。例如。如果您有 LIMIT 2,那么只要找到与 join/where 子句匹配的两行,查询的其余部分就会消失,您会得到这两行。

但是如果你有一个ORDER BY,那么整个匹配的结果集都会被排序,然后 LIMIT 被应用到那个排序的结果集。

例如如果您有一些记录将作为 5,10,203,3,92 返回,则

SELECT id ... LIMIT 2             ->    (5,10),203,3,92
                                        ^^^^^^---actual returned-to-client results
SELECT id ... ORDER BY id LIMIT 2 ->    3,5,10,92,203 -> (3,5),10,92,203
                                           ^^---internal-only results
                                                         ^^^^--actual returned-to-client results.