mysql有时会在添加新索引时删除旧索引吗?

时间:2019-08-23 13:12:05

标签: mysql

TL; DR

我们已经在虚拟机上看到,添加UNIQUE索引会导致较旧的非UNIQUE索引被自动删除。

我无法在其他任何机器上重现此消息(还可以吗?),并且如果这样做,

mysql -e 'create db2'
mysqldump db1 | mysql db2

在将新索引添加到db1之前,然后尝试在db2上添加索引,然后从db2中 not 删除旧索引。时髦!

我们有一个带有db1的机器的快照,可以在现有的db1数据库中复制它...

有人知道发生了什么吗?我们有脚本可以自动执行添加/删除索引的操作,但是由于那台计算机上的旧索引不再存在,因此开始失败。

当转储/恢复周期导致问题消失时,很难理解,重现问题并将其简化为一个简单的例子。

详细信息

在添加新索引(来自SHOW CREATE TABLE之前,该表看起来像这样。请注意monitoredTableRowID键:

CREATE TABLE `cfgAttributeInstances` (
  `ID` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `attributeID` int(10) unsigned DEFAULT NULL,
  `nodeID` int(10) unsigned DEFAULT NULL,
  `groupID` int(10) unsigned DEFAULT NULL,
  `statisticID` int(10) unsigned DEFAULT NULL,
  `nodeStatisticID` int(10) unsigned DEFAULT NULL,
  `serviceID` int(10) unsigned DEFAULT NULL,
  `nodeServiceID` int(10) unsigned DEFAULT NULL,
  `nodeComponentID` int(10) unsigned DEFAULT NULL,
  `syslogFilterID` int(10) unsigned DEFAULT NULL,
  `value` varchar(255) NOT NULL DEFAULT '',
  PRIMARY KEY (`ID`),
  UNIQUE KEY `nodeID` (`nodeID`,`attributeID`),
  UNIQUE KEY `groupID` (`groupID`,`attributeID`),
  UNIQUE KEY `statisticID` (`statisticID`,`attributeID`),
  UNIQUE KEY `nodeStatisticID` (`nodeStatisticID`,`attributeID`),
  UNIQUE KEY `serviceID` (`serviceID`,`attributeID`),
  UNIQUE KEY `nodeServiceID` (`nodeServiceID`,`attributeID`),
  KEY `attributeID` (`attributeID`),
  KEY `monitoredTableRowID` (`nodeComponentID`),
  KEY `syslogFilterID` (`syslogFilterID`),
  CONSTRAINT `cfgAttributeInstances_ibfk_1` FOREIGN KEY (`attributeID`) REFERENCES `cfgAttributes` (`ID`) ON DELETE CASCADE,
  CONSTRAINT `cfgAttributeInstances_ibfk_2` FOREIGN KEY (`nodeID`) REFERENCES `cfgNodes` (`ID`) ON DELETE CASCADE,
  CONSTRAINT `cfgAttributeInstances_ibfk_3` FOREIGN KEY (`groupID`) REFERENCES `cfgGroups` (`ID`) ON DELETE CASCADE,
  CONSTRAINT `cfgAttributeInstances_ibfk_4` FOREIGN KEY (`statisticID`) REFERENCES `cfgStatistics` (`ID`) ON DELETE CASCADE,
  CONSTRAINT `cfgAttributeInstances_ibfk_5` FOREIGN KEY (`nodeStatisticID`) REFERENCES `cfgNodeStatistics` (`ID`) ON DELETE CASCADE,
  CONSTRAINT `cfgAttributeInstances_ibfk_6` FOREIGN KEY (`serviceID`) REFERENCES `cfgServices` (`ID`) ON DELETE CASCADE,
  CONSTRAINT `cfgAttributeInstances_ibfk_7` FOREIGN KEY (`nodeServiceID`) REFERENCES `cfgNodeServices` (`ID`) ON DELETE CASCADE,
  CONSTRAINT `cfgAttributeInstances_ibfk_8` FOREIGN KEY (`nodeComponentID`) REFERENCES `cfgNodeComponents` (`ID`) ON DELETE CASCADE,
  CONSTRAINT `cfgAttributeInstances_ibfk_9` FOREIGN KEY (`syslogFilterID`) REFERENCES `cfgSyslogFilters` (`ID`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=latin1 COMMENT='CapMon Attribute instances';

我添加了该索引:

ALTER TABLE cfgAttributeInstances ADD
    UNIQUE new_nodeComponentID (nodeComponentID, attributeID)

添加该索引后,它看起来像这样:

CREATE TABLE `cfgAttributeInstances` (
  `ID` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `attributeID` int(10) unsigned DEFAULT NULL,
  `nodeID` int(10) unsigned DEFAULT NULL,
  `groupID` int(10) unsigned DEFAULT NULL,
  `statisticID` int(10) unsigned DEFAULT NULL,
  `nodeStatisticID` int(10) unsigned DEFAULT NULL,
  `serviceID` int(10) unsigned DEFAULT NULL,
  `nodeServiceID` int(10) unsigned DEFAULT NULL,
  `nodeComponentID` int(10) unsigned DEFAULT NULL,
  `syslogFilterID` int(10) unsigned DEFAULT NULL,
  `value` varchar(255) NOT NULL DEFAULT '',
  PRIMARY KEY (`ID`),
  UNIQUE KEY `nodeID` (`nodeID`,`attributeID`),
  UNIQUE KEY `groupID` (`groupID`,`attributeID`),
  UNIQUE KEY `statisticID` (`statisticID`,`attributeID`),
  UNIQUE KEY `nodeStatisticID` (`nodeStatisticID`,`attributeID`),
  UNIQUE KEY `serviceID` (`serviceID`,`attributeID`),
  UNIQUE KEY `nodeServiceID` (`nodeServiceID`,`attributeID`),
  UNIQUE KEY `new_nodeComponentID` (`nodeComponentID`,`attributeID`),
  KEY `attributeID` (`attributeID`),
  KEY `syslogFilterID` (`syslogFilterID`),
  CONSTRAINT `cfgAttributeInstances_ibfk_1` FOREIGN KEY (`attributeID`) REFERENCES `cfgAttributes` (`ID`) ON DELETE CASCADE,
  CONSTRAINT `cfgAttributeInstances_ibfk_2` FOREIGN KEY (`nodeID`) REFERENCES `cfgNodes` (`ID`) ON DELETE CASCADE,
  CONSTRAINT `cfgAttributeInstances_ibfk_3` FOREIGN KEY (`groupID`) REFERENCES `cfgGroups` (`ID`) ON DELETE CASCADE,
  CONSTRAINT `cfgAttributeInstances_ibfk_4` FOREIGN KEY (`statisticID`) REFERENCES `cfgStatistics` (`ID`) ON DELETE CASCADE,
  CONSTRAINT `cfgAttributeInstances_ibfk_5` FOREIGN KEY (`nodeStatisticID`) REFERENCES `cfgNodeStatistics` (`ID`) ON DELETE CASCADE,
  CONSTRAINT `cfgAttributeInstances_ibfk_6` FOREIGN KEY (`serviceID`) REFERENCES `cfgServices` (`ID`) ON DELETE CASCADE,
  CONSTRAINT `cfgAttributeInstances_ibfk_7` FOREIGN KEY (`nodeServiceID`) REFERENCES `cfgNodeServices` (`ID`) ON DELETE CASCADE,
  CONSTRAINT `cfgAttributeInstances_ibfk_8` FOREIGN KEY (`nodeComponentID`) REFERENCES `cfgNodeComponents` (`ID`) ON DELETE CASCADE,
  CONSTRAINT `cfgAttributeInstances_ibfk_9` FOREIGN KEY (`syslogFilterID`) REFERENCES `cfgSyslogFilters` (`ID`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=latin1 COMMENT='CapMon Attribute instances';

但是,嘿! monitoredTableRowID索引去哪里了?

同样,我无法复制此内容。如果我执行mysqldump > dump.db / mysql < dump.db循环,则monitoredTableRowID不会消失...

有什么想法吗?

1 个答案:

答案 0 :(得分:2)

带有defmodule SecondQueue.QueueStore do def start_queues_link() do Task.start_link(fn -> queues_loop(%{}) end) end defp queues_loop(map) do receive do {:get, key, caller} -> send caller, Map.get(map, key) queues_loop(map) {:put, key, value} -> IO.puts("i am here") queues_loop(Map.put(map, key, value)) end end end 的复合键会导致带有nodeComponentID的非复合键在使用它的外键引用的上下文中是多余的。 MySQL自动删除冗余的隐式索引。该行为取决于列索引的顺序,因为删除的索引将始终是定义的组合键中的第一列。 [sic]

问题具体是由添加外键nodeComponentID时创建的自动隐式索引以及CONSTRAINT中明确定义的索引引起的,而{{ 1}}。

  

如果已经有显式的 SHOW CREATE TABLE值将被忽略   可以支持外键的子表上定义的索引。   否则,MySQL 隐式创建外键索引 ... [sic]

  

MySQL要求在外键和引用键上建立索引,以便   外键检查可以快速进行,不需要进行表扫描。在里面   引用表中,必须有一个索引,其中外键   列以相同顺序列为第一列。这样的   如果索引未在引用表上自动创建   存在。如果您创建此索引,则以后可能会默默删除该索引   另一个可用于强制执行外键约束的索引。   mysqldump(如果给定)的用法如前所述。 [sic]

重现问题

隐式密钥示例db-fiddle

注意-index_name未明确定义。

index_name

结果

INDEX FK_BAR_FOO (foo_id)DROP TABLE IF EXISTS `BAR`; DROP TABLE IF EXISTS `FOO`; CREATE TABLE `FOO` ( `id` INT(11) NOT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB ; CREATE TABLE `BAR` ( `id` INT(11) NOT NULL, `foo_id` INT(11) NOT NULL, `b` INT(11) NOT NULL, PRIMARY KEY (`id`), CONSTRAINT `FK_BAR_FOO` FOREIGN KEY (`foo_id`) REFERENCES `FOO` (`id`) ON DELETE CASCADE ) ENGINE=InnoDB ; SHOW CREATE TABLE `BAR`; 中明确定义,但由MySQL隐式创建。

INDEX FK_BAR_FOO (foo_id)

复合键示例:db-fiddle

SHOW CREATE TABLE

结果

CREATE TABLE `BAR` ( `id` INT(11) NOT NULL, `foo_id` INT(11) NOT NULL, `b` INT(11) NOT NULL, PRIMARY KEY (`id`), INDEX `FK_BAR_FOO` (`foo_id`), CONSTRAINT `FK_BAR_FOO` FOREIGN KEY (`foo_id`) REFERENCES `FOO` (`id`) ON DELETE CASCADE ) ENGINE=InnoDB ; 索引由于冗余而被删除。
由于ALTER TABLE `BAR` ADD UNIQUE INDEX `foo_id_b` (`foo_id`, `b`); SHOW CREATE TABLE `BAR`; 是组合键中的第一列,因此将删除隐式 foo_id索引foo_id

foo_id

显式密钥示例:db-fiddle

如果表是使用满足外键FK_BAR_FOO explicit 索引创建的,则

MySQL会忽略冗余索引。

CREATE TABLE `BAR` (
    `id` INT(11) NOT NULL,
    `foo_id` INT(11) NOT NULL,
    `b` INT(11) NOT NULL,
    PRIMARY KEY (`id`),
    UNIQUE INDEX `foo_id_b` (`foo_id`, `b`),
    CONSTRAINT `FK_BAR_FOO` FOREIGN KEY (`foo_id`) REFERENCES `FOO` (`id`) ON DELETE CASCADE
)
ENGINE=InnoDB
;

结果

创建CONSTRAINT的复合键索引和DROP TABLE IF EXISTS `BAR`; DROP TABLE IF EXISTS `FOO`; CREATE TABLE `FOO` ( `id` INT(11) NOT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB ; CREATE TABLE `BAR` ( `id` INT(11) NOT NULL, `foo_id` INT(11) NOT NULL, `b` INT(11) NOT NULL, PRIMARY KEY (`id`), INDEX `FK_BAR_FOO` (`foo_id`), CONSTRAINT `FK_BAR_FOO` FOREIGN KEY (`foo_id`) REFERENCES `FOO` (`id`) ON DELETE CASCADE ) ENGINE=InnoDB ; ALTER TABLE `BAR` ADD UNIQUE INDEX `foo_id_b` (`foo_id`, `b`); SHOW CREATE TABLE `BAR`; 的索引。

foo_id, b

解决方案

在脚本中,尝试删除/添加索引之前,请验证索引(不存在)。

foo_id