mysql有时会在添加新索引时删除旧索引? TL;博士

mysql有时会在添加新索引时删除旧索引? TL;博士,mysql,Mysql,我们在虚拟机上看到,添加唯一索引会导致自动删除较旧的非唯一索引 我无法在任何其他机器上复制(尚未?),如果我复制了: mysql -e 'create db2' mysqldump db1 | mysql db2 在将新索引添加到db1,然后尝试在db2上添加索引之前,不会从db2中删除旧索引。时髦 我们有一个带有db1的机器快照,可以在现有的db1数据库中复制它 有人知道发生了什么吗?我们有脚本来自动添加/删除索引,但这开始失败,因为在这台机器上,旧索引不再存在 当转储/恢复周期导致问题消失

我们在虚拟机上看到,添加唯一索引会导致自动删除较旧的非唯一索引

我无法在任何其他机器上复制(尚未?),如果我复制了:

mysql -e 'create db2'
mysqldump db1 | mysql db2
在将新索引添加到db1,然后尝试在db2上添加索引之前,不会从db2中删除旧索引。时髦

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

有人知道发生了什么吗?我们有脚本来自动添加/删除索引,但这开始失败,因为在这台机器上,旧索引不再存在

当转储/恢复周期导致问题消失时,就很难理解、再现并将问题简化为一个简单的示例

细节 在添加新索引之前(从
showcreatetable
),有问题的表是这样的。注意
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
循环,则
monitoredTableRowID
不会消失


有什么想法吗?

带有
nodeComponentD
的复合键会导致带有
nodeComponentD
的非复合键在其使用的外键引用上下文中是冗余的。MySQL会自动删除冗余的隐式索引。该行为取决于列索引顺序,因为删除的索引将始终是定义的复合键中的第一列

该问题是由添加外键
约束时创建的自动隐式索引以及
SHOW CREATE TABLE
中显式定义的索引引起的,mysqldump
也使用该索引

如果已经存在一个显式的 在可支持外键的子表上定义的索引。 否则,MySQL将隐式创建外键索引

MySQL需要外键和引用键的索引,以便 外键检查可以很快,不需要扫描表。在 引用表时,必须有外键所在的索引 列按相同顺序列为第一列。这样的 索引在引用表上自动创建(如果没有) 存在。如果您创建了索引,则稍后可能会自动删除该索引 另一个可用于强制外键约束的索引。
索引名称
(如果给定)如前所述使用

转载

隐式键示例 注-
未明确定义索引FK\u BAR\u FOO(FOO\u id)

结果

索引FK\u BAR\u FOO(FOO\u id)
SHOW CREATE TABLE
中明确定义,但由MySQL隐式创建

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
;
组合键示例: 结果

foo_id
索引因冗余而被删除。
由于
foo\u id
是复合键中的第一列,因此隐式
foo\u id
索引
FK\u BAR\u foo
将被删除

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
;
明确的关键示例: 如果使用满足外键约束的显式索引创建表,MySQL将忽略冗余索引

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\u id、b
的复合键索引和
foo\u id
上的索引

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`),
    INDEX `FK_BAR_FOO` (`foo_id`),
    CONSTRAINT `FK_BAR_FOO` FOREIGN KEY (`foo_id`) REFERENCES `FOO` (`id`) ON DELETE CASCADE
)
ENGINE=InnoDB
;

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

IF NOT EXISTS(
    SELECT 1 FROM INFORMATION_SCHEMA.STATISTICS  
    WHERE TABLE_NAME = 'cfgAttributeInstances'
    AND INDEX_NAME = 'new_nodeComponentID' 
    AND INDEX_SCHEMA = 'DbName') 
THEN
    ALTER TABLE `cfgAttributeInstances`
    ADD UNIQUE INDEX `new_nodeComponentID` (`nodeComponentID`,`attributeID`);
END IF;

IF EXISTS (
    SELECT 1 FROM INFORMATION_SCHEMA.STATISTICS  
    WHERE TABLE_NAME = 'cfgAttributeInstances'
    AND INDEX_NAME = 'nodeComponentID' 
    AND INDEX_SCHEMA = 'DbName') 
THEN
   ALTER TABLE `cfgAttributeInstances` 
   DROP INDEX `nodeComponentID`;
END IF;

谢谢你的回答。我不明白的是:为什么在一个
mysqldump
/restore周期后,我们不能重现这种情况?为什么db1和db2的行为与最初的问题不同?@PeterV.Mørch至于为什么db1和db2的工作方式不同,这是因为表模式可能被转储到了一个服务器上,如我的第二个示例所示。按照我在第一个示例中执行的顺序发出查询,将在db1和db2服务器上执行相同的操作,就像在db FIDLE上一样。除非它们是不支持冗余索引删除的不同mysql版本。@PeterV.Mørch找到了文档参考,并使用链接和引号进行了更新。
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`),
    INDEX `FK_BAR_FOO` (`foo_id`),
    CONSTRAINT `FK_BAR_FOO` FOREIGN KEY (`foo_id`) REFERENCES `FOO` (`id`) ON DELETE CASCADE
)
ENGINE=InnoDB
;
IF NOT EXISTS(
    SELECT 1 FROM INFORMATION_SCHEMA.STATISTICS  
    WHERE TABLE_NAME = 'cfgAttributeInstances'
    AND INDEX_NAME = 'new_nodeComponentID' 
    AND INDEX_SCHEMA = 'DbName') 
THEN
    ALTER TABLE `cfgAttributeInstances`
    ADD UNIQUE INDEX `new_nodeComponentID` (`nodeComponentID`,`attributeID`);
END IF;

IF EXISTS (
    SELECT 1 FROM INFORMATION_SCHEMA.STATISTICS  
    WHERE TABLE_NAME = 'cfgAttributeInstances'
    AND INDEX_NAME = 'nodeComponentID' 
    AND INDEX_SCHEMA = 'DbName') 
THEN
   ALTER TABLE `cfgAttributeInstances` 
   DROP INDEX `nodeComponentID`;
END IF;