我只有一个查询
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.id
和r.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
,为什么一个显示的结果是按名称排序的?
答案 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
的顺序传送行(但出于根本不同的原因)。