【问题标题】:Prevent MySQL from automatically creating indexes for foreign keys?防止 MySQL 自动为外键创建索引?
【发布时间】:2021-11-18 11:53:02
【问题描述】:

这是桌子:

CREATE TABLE `usersMeta` (
  `id` int unsigned NOT NULL AUTO_INCREMENT,
  `userId` int unsigned NOT NULL,
  `metaKey` varchar(30) CHARACTER SET latin1 COLLATE latin1_general_ci NOT NULL,
  `metaValue` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
  PRIMARY KEY (`id` DESC),
  UNIQUE KEY `userId_metaKey` (`userId` DESC,`metaKey`),
  CONSTRAINT `fk_usersMeta_userId` FOREIGN KEY (`userId`) REFERENCES `users` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

userId_metaKey 可用于外键。如果我使用mysqldump导出表结构,然后使用mysql -u user -p db < exports.sql导入,MySQL会自动添加新索引:

CREATE TABLE `usersMeta` (
  `id` int unsigned NOT NULL AUTO_INCREMENT,
  `userId` int unsigned NOT NULL,
  `metaKey` varchar(30) CHARACTER SET latin1 COLLATE latin1_general_ci NOT NULL,
  `metaValue` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
  PRIMARY KEY (`id` DESC),
  UNIQUE KEY `userId_metaKey` (`userId` DESC,`metaKey`),
  KEY `fk_usersMeta_userId` (`userId`),
  CONSTRAINT `fk_usersMeta_userId` FOREIGN KEY (`userId`) REFERENCES `users` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

它添加了fk_usersMeta_userId,这是不必要的。我怎样才能防止这种情况发生?

【问题讨论】:

  • 请告诉我们需要DESC的查询。如果它没有伤害,你也许可以摆脱它。您使用的是什么版本的 MySQL?此外,是否有任何充分的理由拥有id?看来UNIQUE 键可以提升为PK。 (这可能会加快你的应用程序。)
  • 这是否能解决出现额外索引的问题?例如。 DESC 导致 MySQL 无法识别索引?
  • 这是第 8 版。
  • 是的,我怀疑DESC 吓跑了比尔引用的“如果它不存在”条款。使用和不使用 DESC 都应该很容易进行实验。然后在 bugs.mysql.com 提交错误报告。
  • 有道理,将其更改为 FOREIGN KEY (userId` DESC)` 修复了它,即使我认为这没有任何作用

标签: mysql indexing foreign-keys


【解决方案1】:

在 MySQL 中,外键必须有索引。

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

MySQL 需要外键和引用键的索引,以便外键检查可以快速且不需要表扫描。在引用表中,必须有一个索引,其中外键列按相同顺序列为第一列。如果引用表不存在,则会在引用表上自动创建此类索引。如果您创建另一个可用于强制外键约束的索引,此索引可能会在稍后被静默删除。


我尝试用稍微不同的 UNIQUE KEY 定义一个像你这样的表,但没有降序选项:

CREATE TABLE `usersMeta` (
  `id` int unsigned NOT NULL AUTO_INCREMENT,
  `userId` int unsigned NOT NULL,
  `metaKey` varchar(30) CHARACTER SET latin1 COLLATE latin1_general_ci NOT NULL,
  `metaValue` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
  PRIMARY KEY (`id` DESC),
  UNIQUE KEY `userId_metaKey` (`userId`,`metaKey`),
                               ^^^^^^^^ not DESC
  CONSTRAINT `usersmeta_ibfk_1` FOREIGN KEY (`userId`) REFERENCES `users` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3

在这种设计中,外键可以使用UNIQUE KEY的最左边一列。

我认为问题在于索引必须与它引用的表中的键具有相同的方向(ASC 与 DESC)。

【讨论】:

  • 是的,它已经有一个索引:userId_metaKey。它可以使用第一列作为外键
猜你喜欢
  • 2011-08-22
  • 1970-01-01
  • 2011-07-01
  • 2020-04-16
  • 2010-10-24
  • 2019-04-26
  • 2018-10-14
  • 2010-09-23
相关资源
最近更新 更多