两个看似相同的数据库如何返回按不同列排序的结果?

时间:2018-11-28 21:01:14

标签: mysql sorting indexing

我只有一个查询

SELECT r.id
     , r.account_id
     , r.name
     , r.bucket_id
     , r.description
     , r.development
     , r.created_at
     , r.priority
  FROM realms r
 WHERE r.account_id = 3;

我在具有相同索引的两个不同表上运行它,一个结果用r.idr.created_at排序(任一种顺序都相同),另一个结果用r.name排序。怎么会这样?

通过MySQL Workbench中的表检查器查看它,两者的索引为:

+---------------------------+-------+-----+-----------------+
| key                       |Type   |Uni  | Columns         |
+ --------------------------+-------+-----+-----------------+
| PRIMARY                   | BTREE | YES | id              |
| realms_account_id_name_UQ | BTREE | YES | account_id,name |
| realms_account_id_IX      | BTREE | NO  | account_id      |
| realms_bucket_id_IX       | BTREE | NO  | bucket_id       |
+---------------------------+-------+-----+-----------------+

我以为是索引决定了行的顺序,当我在两者之间切换时,屏幕甚至没有闪烁。如果它们的主键都是id,为什么一个显示的结果是按名称排序的?

1 个答案:

答案 0 :(得分:1)

如果您的ORDER BY中没有SELECT子句,则系统可以执行任何感觉。期。句号。

现在,我将解释可能发生了什么。

首先,优化器将分析索引,数据类型,统计信息等,并决定如何执行查询。您可以通过执行EXPLAIN SELECT ...来了解此操作。它将说出可能使用哪个索引。

我看到两个合理的索引-两个以account_id开头。任一种都可以。优化器在两台计算机上的统计信息可能略有不同,导致它在一台计算机上选择一个索引,而在另一台计算机上选择另一个索引。

使用INDEX(account_id, name)的分析。该索引是account_id和名称对对的有序列表。在使用该索引的机器上,它向下钻取BTree索引到account_id = 3的第一个条目,然后向前扫描。这给了您name排序的结果。

使用INDEX(account_id)的分析。为了找到数据,InnoDB将PRIMARY KEY列附加到每个二级索引上。因此,该索引实际上是INDEX(account_id, id)。在使用该索引的机器上,它向下钻取BTree索引到account_id = 3的第一个条目,然后向前扫描。这给了您id排序的结果。

第三种可能性很普遍,值得注意。如果account_id = 3中有很多行,则优化器将决定避开索引并仅读取数据。由于数据是根据PRIMARY KEY存储的,因此它将再次以id的顺序传送行(但出于根本不同的原因)。