为什么这个复合键没有编入索引?

时间:2017-03-02 07:38:15

标签: mysql

我创建了这个表:

CREATE TABLE incident_originator (
    id_incident INT (11) UNSIGNED NOT NULL,
    id_user INT (11) NOT NULL,
    PRIMARY KEY (
        id_incident,
        id_user
    ),
    CONSTRAINT fk_incident_incident_originator FOREIGN KEY (id_incident) REFERENCES incident_table (id_incident) ON DELETE RESTRICT ON UPDATE CASCADE,
    CONSTRAINT fk_user_incident_originator FOREIGN KEY (id_user) REFERENCES users (id_user) ON DELETE RESTRICT ON UPDATE CASCADE
) ENGINE = INNODB DEFAULT CHARSET = latin1;

然而,fk_user_incident_originator已编入索引,而fk_incident_incident_originator则未编入索引。这是为什么?不是InnoBD应该自动索引所有外键吗? id_incident中缺少索引会使联接变慢,不是吗?我读的越多,我理解的就越少......

另外,当我向表中添加值时,它们按第二列排序,并且作为人类阅读起来很奇怪。

编辑:当我执行SHOW INDEX FROM incident_originator;时,它会返回:

Non_unique  Key_name    Seq_in_index    Column_name
0   PRIMARY 1   id_incident
0   PRIMARY 2   id_user
1   fk_user_incident_originator 1   id_user

1 个答案:

答案 0 :(得分:1)

  

fk_incident_incident_originator不是

当然可以。

PRIMARY KEY (id_incident,id_user),
  

在引用表中,必须有一个索引,其中外键列以相同的顺序列为第一列。如果索引不存在,则会自动在引用表上创建这样的索引。

     

https://dev.mysql.com/doc/refman/5.6/en/create-table-foreign-keys.html

id_incident是主键的第一个(意思是最左侧)列...并且主键是在执行约束时查找值的完美索引。添加第二个索引将是多余的。

对于连接也是如此(虽然连接不是外键始终被索引的实际原因) - 任何包含锚定到索引左侧的所有连接列的索引对于连接都是非常有效的。 / p>

  

它们是由第二列订购的,因此人们会觉得很奇怪。

告诉任何你知道的人,除非人类使用ORDER BY,否则数据库不会为了人类的利益而对其输出进行排序。没有ORDER BY的结果集按定义无序。行通常以主键顺序返回的事实是巧合,而不是设计或必要性。当表优化器在读取表时更改策略时,此行为可能会发生变化...但由于id_user上的索引实际上是覆盖索引(它包含表中的所有列,因为所有索引还包含主键的副本......或者更准确地说,它包含满足此特定查询所需的所有列 - 这些列有时是两个不同的东西,这是不使用{{1的最佳理由之一在你的实际代码中)所以优化器碰巧选择它作为它的源。它从它选择的任何索引中按索引顺序读取行,并且该顺序成为结果的完全巧合顺序。