mysql:order by limit 同时使用,排序字段值重复时无法保证数据顺序

一、直接上mysql官网解释:

If multiple rows have identical values in the ORDER BY columns, the server is free to return those rows in any order, and may do so differently depending on the overall execution plan. In other words, the sort order of those rows is nondeterministic with respect to the nonordered columns.

One factor that affects the execution plan is LIMIT, so an ORDER BY query with and without LIMIT may return rows in different orders. Consider this query, which is sorted by the category column but nondeterministic with respect to the id and rating columns:(翻译:

如果ORDER BY列中有多行具有相同的值,则服务器可以自由地按任何顺序返回这些行,并且根据总体执行计划的不同,返回方式可能会有所不同。换句话说,这些行的排序顺序相对于未排序的列是不确定的。

影响执行计划的一个因素是LIMIT,因此带和不带LIMIT的ORDERBY查询可能会返回不同顺序的行。如下边的查询,它按类别列排序,但相对于id和rating列是不确定的:

mysql> SELECT * FROM ratings ORDER BY category;
+----+----------+--------+
| id | category | rating |
+----+----------+--------+
|  1 |        1 |    4.5 |
|  5 |        1 |    3.2 |
|  3 |        2 |    3.7 |
|  4 |        2 |    3.5 |
|  6 |        2 |    3.5 |
|  2 |        3 |    5.0 |
|  7 |        3 |    2.7 |
+----+----------+--------+

-- Including LIMIT may affect order of rows within each category value. For example, this is a valid query result:

mysql> SELECT * FROM ratings ORDER BY category LIMIT 5;
+----+----------+--------+
| id | category | rating |
+----+----------+--------+
|  1 |        1 |    4.5 |
|  5 |        1 |    3.2 |
|  4 |        2 |    3.5 |
|  3 |        2 |    3.7 |
|  6 |        2 |    3.5 |
+----+----------+--------+

二、mysql官网提倡的解决方案

 If it is important to ensure the same row order with and without LIMIT, include additional columns in the ORDER BY clause to make the order deterministic. For example, if id values are unique, you can make rows for a given category value appear in id order by sorting like this:(翻译:如果有LIMIT和没有LIMIT时确保相同的行顺序很重要,请在order BY子句中包含额外的列,以使顺序具有确定性。例如,如果id值是唯一的,则可以通过如下排序,使给定类别值的行以id顺序出现:)

mysql> SELECT * FROM ratings ORDER BY category, id;
+----+----------+--------+
| id | category | rating |
+----+----------+--------+
|  1 |        1 |    4.5 |
|  5 |        1 |    3.2 |
|  3 |        2 |    3.7 |
|  4 |        2 |    3.5 |
|  6 |        2 |    3.5 |
|  2 |        3 |    5.0 |
|  7 |        3 |    2.7 |
+----+----------+--------+

mysql> SELECT * FROM ratings ORDER BY category, id LIMIT 5;
+----+----------+--------+
| id | category | rating |
+----+----------+--------+
|  1 |        1 |    4.5 |
|  5 |        1 |    3.2 |
|  3 |        2 |    3.7 |
|  4 |        2 |    3.5 |
|  6 |        2 |    3.5 |
+----+----------+--------+

三、mysql 8.0.21后如何开启排序索引优化以及关闭排序字段索引优化

For a query with an ORDER BY or GROUP BY and a LIMIT clause, the optimizer tries to choose an ordered index by default when it appears doing so would speed up query execution. Prior to MySQL 8.0.21, there was no way to override this behavior, even in cases where using some other optimization might be faster. Beginning with MySQL 8.0.21, it is possible to turn off this optimization by setting the optimizer_switch system variable's prefer_ordering_index flag to off.(翻译:对于具有ORDER BY或GROUP BY和LIMIT子句的查询,优化器在默认情况下尝试选择有序索引,而这样做似乎会加快查询执行。在MySQL 8.0.21之前,没有办法覆盖此行为,即使在使用其他优化可能更快的情况下也是如此。从MySQL 8.0.21开始,可以通过将优化器_switch系统变量的prefer_ordering_index标志设置为关闭来关闭此优化。

Example: First we create and populate a table t as shown here:

# Create and populate a table t:

mysql> CREATE TABLE t (
    ->     id1 BIGINT NOT NULL,
    ->     id2 BIGINT NOT NULL,
    ->     c1 VARCHAR(50) NOT NULL,
    ->     c2 VARCHAR(50) NOT NULL,
    ->  PRIMARY KEY (id1),
    ->  INDEX i (id2, c1)
    -> );

# [Insert some rows into table t - not shown]

-- Verify that the prefer_ordering_index flag is enabled:
mysql> SELECT @@optimizer_switch LIKE '%prefer_ordering_index=on%';
+------------------------------------------------------+
| @@optimizer_switch LIKE '%prefer_ordering_index=on%' |
+------------------------------------------------------+
|                                                    1 |
+------------------------------------------------------+

-- Since the following query has a LIMIT clause, we expect it to use an ordered index, if possible. In this case, as we can see from the EXPLAIN output, it uses the table's primary key.(由于下面的查询有一个LIMIT子句,因此如果可能,我们希望它使用有序索引。在这种情况下,正如我们从EXPLAIN输出中看到的那样,它使用表的主键。)
mysql> EXPLAIN SELECT c2 FROM t
    ->     WHERE id2 > 3
    ->     ORDER BY id1 ASC LIMIT 2\G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: t
   partitions: NULL
         type: index
possible_keys: i
          key: PRIMARY
      key_len: 8
          ref: NULL
         rows: 2
     filtered: 70.00
        Extra: Using where

-- 现在我们禁用prefer_ordering_index标志,并重新运行相同的查询;这次它使用索引i(其中包括WHERE子句中使用的id2列)和文件排序:
mysql> SET optimizer_switch = "prefer_ordering_index=off";

mysql> EXPLAIN SELECT c2 FROM t
    ->     WHERE id2 > 3
    ->     ORDER BY id1 ASC LIMIT 2\G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: t
   partitions: NULL
         type: range
possible_keys: i
          key: i
      key_len: 8
          ref: NULL
         rows: 14
     filtered: 100.00
        Extra: Using index condition; Using filesort

四、补充mysql执行顺序

1、FROM:从哪个表中获取数据
2、JOIN:连接要获取数据的表
3、WHERE:过滤要获取的数据
4、GROUP BY:根据哪些字段对数据进行分组
5、HAVING:过滤分组后的数据
6、SELECT:选择需要获取的数据列
7、ORDER BY:按照哪些字段对数据进行排序
8、LIMIT:获取数据的行数限制

这就是别名不可以使用在where中,但可以使用在order by中的原因。

--- 运算符执行顺序
1、括号
2、乘法、除法、取余
3、加法、减法
4、比较运算符
5、逻辑运算符
6、赋值运算符
7、SELECT语句

你可能感兴趣的:(mysql,数据库)