使用现有 MYSQL 数据库的 Alter Table 添加外键时出现问题 - 无法添加!帮助!

发布于 2024-11-01 16:28:47 字数 5582 浏览 10 评论 0原文

我有一个生产数据库,我在其中重命名了几个外键列。显然,根据我的经验,mysql 使这件事变得非常痛苦。

我的解决方案是删除所有索引和外键,重命名 id 列,然后重新添加索引和外键。

这对于 Windows 上的 mysql 5.1 作为开发数据库非常有效。

我在我的 debian 服务器上运行迁移脚本,该服务器也使用 mysql 5.1,它给出以下错误:

mysql> ALTER TABLE `company_to_module`
    -> ADD CONSTRAINT `FK82977604FE40A062` FOREIGN KEY (`company_id`) REFERENCES `company` (`company_id`) ON DELETE RESTRICT ON UPDATE RESTRICT;
ERROR 1005 (HY000): Can't create table 'jobprep_production.#sql-44a5_76' (errno: 150)

此表中没有与我尝试添加的外键冲突的值。数据库没有改变。外键之前确实存在...所以数据没问题。更不用说我在服务器上使用了相同的数据库,并且它在 Windows 上迁移得很好。但这些相同的外键迁移并没有对 Debian 产生影响。

这些列使用相同的类型 - BIGINT (20)

这些名称实际上存在于各自的表中。

这些表是innodb。他们已经在其他列中拥有了外键。这不是一个新数据库。

我无法删除表,因为这是一个生产数据库。

我的数据库中的表“按原样”:

 CREATE TABLE `company_to_module` (
  `company_id` bigint(20) NOT NULL,
  `module_id` bigint(20) NOT NULL,
  KEY `FK8297760442C8F876` (`module_id`),
  KEY `FK82977604FE40A062` (`company_id`) USING BTREE,
  CONSTRAINT `FK8297760442C8F876` FOREIGN KEY (`module_id`) REFERENCES `module` (`module_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8

Create Table: CREATE TABLE `company` (
  `company_id` bigint(20) NOT NULL AUTO_INCREMENT,
  `name` varchar(255) DEFAULT NULL,
  `address` varchar(255) DEFAULT NULL,
  `postal_code` varchar(255) DEFAULT NULL,
  `province_id` bigint(20) DEFAULT NULL,
  `phone_number` varchar(255) DEFAULT NULL,
  `is_enabled` bit(1) DEFAULT NULL,
  `director_id` bigint(20) DEFAULT NULL,
  `homepage_viewable` bit(1) NOT NULL DEFAULT b'1',
  `courses_created` int(10) NOT NULL DEFAULT '0',
  `header_background` varchar(25) DEFAULT '#172636',
  `display_name` varchar(25) DEFAULT '#ffffff',
  `tab_background` varchar(25) DEFAULT '#284767',
  `tab_text` varchar(25) DEFAULT '#ffffff',
  `hover_tab_background` varchar(25) DEFAULT '#284767',
  `hover_tab_text` varchar(25) DEFAULT '#f2e0bd',
  `selected_tab_background` varchar(25) DEFAULT '#f5f5f5',
  `selected_tab_text` varchar(25) DEFAULT '#172636',
  `hover_table_row_background` varchar(25) DEFAULT '#c0d2e4',
  `link` varchar(25) DEFAULT '#4e6c92',
  PRIMARY KEY (`company_id`),
  KEY `FK61AE555A71DF3E03` (`province_id`),
  KEY `FK61AE555AAC50C977` (`director_id`),
  CONSTRAINT `company_ibfk_1` FOREIGN KEY (`director_id`) REFERENCES `user_account` (`user_account_id`),
  CONSTRAINT `FK61AE555A71DF3E03` FOREIGN KEY (`province_id`) REFERENCES `province` (`province_id`)
) ENGINE=InnoDB AUTO_INCREMENT=24 DEFAULT CHARSET=utf8

是 innodb 状态:

------------------------
LATEST FOREIGN KEY ERROR
------------------------
110415  3:14:34 Error in foreign key constraint of table jobprep_production/#sql-44a5_1bc:
 FOREIGN KEY (`company_id`) REFERENCES `company` (`company_id`) ON DELETE RESTRICT ON UPDATE RESTRICT:
Cannot resolve column name close to:
) ON DELETE RESTRICT ON UPDATE RESTRICT

如果我尝试从“company_to_module”中删除索引,我会收到此错误:

#1025 - Error on rename of './jobprep_production/#sql-44a5_23a' to './jobprep_production/company_to_module' (errno: 150) 

这是我的 innodb 变量:

+---------------------------------+------------------------+
| Variable_name                   | Value                  |
+---------------------------------+------------------------+
| innodb_adaptive_hash_index      | ON                     |
| innodb_additional_mem_pool_size | 1048576                |
| innodb_autoextend_increment     | 8                      |
| innodb_autoinc_lock_mode        | 1                      |
| innodb_buffer_pool_size         | 8388608                |
| innodb_checksums                | ON                     |
| innodb_commit_concurrency       | 0                      |
| innodb_concurrency_tickets      | 500                    |
| innodb_data_file_path           | ibdata1:10M:autoextend |
| innodb_data_home_dir            |                        |
| innodb_doublewrite              | ON                     |
| innodb_fast_shutdown            | 1                      |
| innodb_file_io_threads          | 4                      |
| innodb_file_per_table           | OFF                    |
| innodb_flush_log_at_trx_commit  | 1                      |
| innodb_flush_method             |                        |
| innodb_force_recovery           | 0                      |
| innodb_lock_wait_timeout        | 50                     |
| innodb_locks_unsafe_for_binlog  | OFF                    |
| innodb_log_buffer_size          | 1048576                |
| innodb_log_file_size            | 5242880                |
| innodb_log_files_in_group       | 2                      |
| innodb_log_group_home_dir       | ./                     |
| innodb_max_dirty_pages_pct      | 90                     |
| innodb_max_purge_lag            | 0                      |
| innodb_mirrored_log_groups      | 1                      |
| innodb_open_files               | 300                    |
| innodb_rollback_on_timeout      | OFF                    |
| innodb_stats_on_metadata        | ON                     |
| innodb_support_xa               | ON                     |
| innodb_sync_spin_loops          | 20                     |
| innodb_table_locks              | ON                     |
| innodb_thread_concurrency       | 8                      |
| innodb_thread_sleep_delay       | 10000                  |
+---------------------------------+------------------------+

我还想在玩游戏时添加它添加外键后,mysql 损坏了我的数据库并将其毁坏。我必须从备份重新加载才能重试。

帮助? :/

I have a production database where I have renamed several column's that are foreign keys. Obviously mysql makes this a real pain to do in my experience.

My solution was to drop all the indexes and foreign keys, rename the id columns, and then re-add the indexes and foreign keys.

This works great on mysql 5.1 on windows for the development database.

I went to run my migration script on my debian server, which is also using mysql 5.1, and it gives the following error:

mysql> ALTER TABLE `company_to_module`
    -> ADD CONSTRAINT `FK82977604FE40A062` FOREIGN KEY (`company_id`) REFERENCES `company` (`company_id`) ON DELETE RESTRICT ON UPDATE RESTRICT;
ERROR 1005 (HY000): Can't create table 'jobprep_production.#sql-44a5_76' (errno: 150)

There are no values in this table that would conflict with the foreign key I am trying to add. The database hasn't changed. The foreign key DID exist before... so the data is fine. Let's not mention that I took the SAME database that I have on the server and it migrates fine on Windows. But these same foreign key migrations are not taking on Debian.

The columns are using the same type - BIGINT (20)

The names do in fact exist in their respective tables.

The tables are innodb. They already have foreign keys in other columns as it is. This is not a new database.

I cannot drop tables because this is a production database.

The tables "as is" in my database:

 CREATE TABLE `company_to_module` (
  `company_id` bigint(20) NOT NULL,
  `module_id` bigint(20) NOT NULL,
  KEY `FK8297760442C8F876` (`module_id`),
  KEY `FK82977604FE40A062` (`company_id`) USING BTREE,
  CONSTRAINT `FK8297760442C8F876` FOREIGN KEY (`module_id`) REFERENCES `module` (`module_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8

And

Create Table: CREATE TABLE `company` (
  `company_id` bigint(20) NOT NULL AUTO_INCREMENT,
  `name` varchar(255) DEFAULT NULL,
  `address` varchar(255) DEFAULT NULL,
  `postal_code` varchar(255) DEFAULT NULL,
  `province_id` bigint(20) DEFAULT NULL,
  `phone_number` varchar(255) DEFAULT NULL,
  `is_enabled` bit(1) DEFAULT NULL,
  `director_id` bigint(20) DEFAULT NULL,
  `homepage_viewable` bit(1) NOT NULL DEFAULT b'1',
  `courses_created` int(10) NOT NULL DEFAULT '0',
  `header_background` varchar(25) DEFAULT '#172636',
  `display_name` varchar(25) DEFAULT '#ffffff',
  `tab_background` varchar(25) DEFAULT '#284767',
  `tab_text` varchar(25) DEFAULT '#ffffff',
  `hover_tab_background` varchar(25) DEFAULT '#284767',
  `hover_tab_text` varchar(25) DEFAULT '#f2e0bd',
  `selected_tab_background` varchar(25) DEFAULT '#f5f5f5',
  `selected_tab_text` varchar(25) DEFAULT '#172636',
  `hover_table_row_background` varchar(25) DEFAULT '#c0d2e4',
  `link` varchar(25) DEFAULT '#4e6c92',
  PRIMARY KEY (`company_id`),
  KEY `FK61AE555A71DF3E03` (`province_id`),
  KEY `FK61AE555AAC50C977` (`director_id`),
  CONSTRAINT `company_ibfk_1` FOREIGN KEY (`director_id`) REFERENCES `user_account` (`user_account_id`),
  CONSTRAINT `FK61AE555A71DF3E03` FOREIGN KEY (`province_id`) REFERENCES `province` (`province_id`)
) ENGINE=InnoDB AUTO_INCREMENT=24 DEFAULT CHARSET=utf8

Here is the innodb status:

------------------------
LATEST FOREIGN KEY ERROR
------------------------
110415  3:14:34 Error in foreign key constraint of table jobprep_production/#sql-44a5_1bc:
 FOREIGN KEY (`company_id`) REFERENCES `company` (`company_id`) ON DELETE RESTRICT ON UPDATE RESTRICT:
Cannot resolve column name close to:
) ON DELETE RESTRICT ON UPDATE RESTRICT

If I try and drop the index from 'company_to_module', I get this error:

#1025 - Error on rename of './jobprep_production/#sql-44a5_23a' to './jobprep_production/company_to_module' (errno: 150) 

Here are my innodb variables:

+---------------------------------+------------------------+
| Variable_name                   | Value                  |
+---------------------------------+------------------------+
| innodb_adaptive_hash_index      | ON                     |
| innodb_additional_mem_pool_size | 1048576                |
| innodb_autoextend_increment     | 8                      |
| innodb_autoinc_lock_mode        | 1                      |
| innodb_buffer_pool_size         | 8388608                |
| innodb_checksums                | ON                     |
| innodb_commit_concurrency       | 0                      |
| innodb_concurrency_tickets      | 500                    |
| innodb_data_file_path           | ibdata1:10M:autoextend |
| innodb_data_home_dir            |                        |
| innodb_doublewrite              | ON                     |
| innodb_fast_shutdown            | 1                      |
| innodb_file_io_threads          | 4                      |
| innodb_file_per_table           | OFF                    |
| innodb_flush_log_at_trx_commit  | 1                      |
| innodb_flush_method             |                        |
| innodb_force_recovery           | 0                      |
| innodb_lock_wait_timeout        | 50                     |
| innodb_locks_unsafe_for_binlog  | OFF                    |
| innodb_log_buffer_size          | 1048576                |
| innodb_log_file_size            | 5242880                |
| innodb_log_files_in_group       | 2                      |
| innodb_log_group_home_dir       | ./                     |
| innodb_max_dirty_pages_pct      | 90                     |
| innodb_max_purge_lag            | 0                      |
| innodb_mirrored_log_groups      | 1                      |
| innodb_open_files               | 300                    |
| innodb_rollback_on_timeout      | OFF                    |
| innodb_stats_on_metadata        | ON                     |
| innodb_support_xa               | ON                     |
| innodb_sync_spin_loops          | 20                     |
| innodb_table_locks              | ON                     |
| innodb_thread_concurrency       | 8                      |
| innodb_thread_sleep_delay       | 10000                  |
+---------------------------------+------------------------+

I also want to add that while I was playing with adding the foreign keys, mysql corrupted my database and destroyed it. I had to reload from a backup to try again.

Help? :/

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

盛夏已如深秋| 2024-11-08 16:28:47

两个表都是InnoDB类型吗?

公司表在 company_id 上有索引吗?

我猜你的表是MyISAM(如果你没有更改配置,则为默认表)并且你无法在MyISAM中创建外键约束。请参阅关于两个表的 CREATE TABLE 的说明。

如果两个表都是空的,则删除它们并重新创建它们,选择 InnoDB 作为引擎。您还可以在表创建脚本中添加 FOREIGN KEY 约束。


来自 MySQL 参考手册

外键定义须满足以下条件:

  • 两个表都必须是 InnoDB 表并且
    它们不能是临时表。

  • 国外对应栏
    键和引用的键必须有
    内部相似的内部数据类型

    InnoDB 以便可以比较它们
    无需类型转换。 尺寸
    整数类型的符号必须是
    相同。字符串类型需要的长度
    不相同。 对于非二元
    (字符)字符串列,
    字符集和排序规则必须是
    相同

  • InnoDB 需要外部索引
    和引用的键,以便
    外键检查可以快速且
    不需要表扫描。在
    引用表,必须有一个
    外键列所在的索引
    被列为第一列
    相同的顺序。 这样的索引是
    在引用表上创建
    如果不存在则自动

    (这与一些较旧的
    版本,其中索引必须是
    显式创建或创建
    外键约束将失败。)
    index_name(如果给定)用作
    前面已经描述过。

  • InnoDB 允许外键
    引用任何索引列或组
    列。然而,在
    引用表,必须有一个
    引用列的索引
    被列为第一列
    相同的顺序。

  • 外键列上的索引前缀
    不支持。其后果之一是
    这就是 BLOB 和 TEXT 列
    不能包含在外键中

    因为这些列上的索引必须
    始终包含前缀长度。

  • 如果 CONSTRAINT 符号子句是
    给定,符号值必须是
    在数据库中是唯一的。如果该条款
    未给出,InnoDB 创建名称
    自动。


@egervari:如果你运行这个会发生什么:

CREATE TABLE `test` (
  `company_id` bigint(20) NOT NULL,
  `module_id` bigint(20) NOT NULL,

  KEY  (`module_id`),
  KEY  (`company_id`),

  CONSTRAINT `test_fk_module`
    FOREIGN KEY (`module_id`)
    REFERENCES `module` (`module_id`),

  CONSTRAINT `test_fk_company`
    FOREIGN KEY (`company_id`)
    REFERENCES `company` (`company_id`)
    ON DELETE RESTRICT
    ON UPDATE RESTRICT

) ENGINE=InnoDB DEFAULT CHARSET=utf8 ;

如果你运行:

ALTER TABLE `company_to_module`
  ADD CONSTRAINT `company_to_module_fk_company` 
    FOREIGN KEY (`company_id`)
    REFERENCES `company` (`company_id`)
    ON DELETE RESTRICT
    ON UPDATE RESTRICT;

Are both tables InnoDB type?

Does the company table have an index on company_id ?

I guess that your table is MyISAM (the default if you haven't changed the config) and you can't create foreign key constraints in MyISAM. See the description of the CREATE TABLE for yout two tables.

If both tables are empty, drop them and re-create them, choosing InnoDB as engine. You could also add the FOREIGN KEY constraints in the tables creation script(s).


From MySQL Reference Manual:

Foreign keys definitions are subject to the following conditions:

  • Both tables must be InnoDB tables and
    they must not be TEMPORARY tables.

  • Corresponding columns in the foreign
    key and the referenced key must have
    similar internal data types
    inside
    InnoDB so that they can be compared
    without a type conversion. The size
    and sign of integer types must be the
    same
    . The length of string types need
    not be the same. For nonbinary
    (character) string columns, the
    character set and collation must be
    the same
    .

  • InnoDB requires indexes on foreign
    keys
    and referenced keys so that
    foreign key checks can be fast and
    not require a table scan. In the
    referencing table, there must be an
    index where the foreign key columns
    are listed as the first columns in
    the same order. Such an index is
    created on the referencing table
    automatically if it does not exist
    .
    (This is in contrast to some older
    versions, in which indexes had to be
    created explicitly or the creation of
    foreign key constraints would fail.)
    index_name, if given, is used as
    described previously.

  • InnoDB permits a foreign key to
    reference any index column or group
    of columns. However, in the
    referenced table, there must be an
    index where the referenced columns
    are listed as the first columns in
    the same order.

  • Index prefixes on foreign key columns
    are not supported. One consequence of
    this is that BLOB and TEXT columns
    cannot be included in a foreign key

    because indexes on those columns must
    always include a prefix length.

  • If the CONSTRAINT symbol clause is
    given, the symbol value must be
    unique in the database. If the clause
    is not given, InnoDB creates the name
    automatically.


@egervari: What happens if you run this:

CREATE TABLE `test` (
  `company_id` bigint(20) NOT NULL,
  `module_id` bigint(20) NOT NULL,

  KEY  (`module_id`),
  KEY  (`company_id`),

  CONSTRAINT `test_fk_module`
    FOREIGN KEY (`module_id`)
    REFERENCES `module` (`module_id`),

  CONSTRAINT `test_fk_company`
    FOREIGN KEY (`company_id`)
    REFERENCES `company` (`company_id`)
    ON DELETE RESTRICT
    ON UPDATE RESTRICT

) ENGINE=InnoDB DEFAULT CHARSET=utf8 ;

And if you run:

ALTER TABLE `company_to_module`
  ADD CONSTRAINT `company_to_module_fk_company` 
    FOREIGN KEY (`company_id`)
    REFERENCES `company` (`company_id`)
    ON DELETE RESTRICT
    ON UPDATE RESTRICT;
左岸枫 2024-11-08 16:28:47

确保company_to_module.company_id和company.company_id是完全相同的数据类型。当主键设置为 UNSIGNED INT 但外键字段只是 INT 时,就会发生这种情况。将 UNSIGNED 添加到数据类型解决了问题。

Ensure that company_to_module.company_id and company.company_id are the EXACT same datatype. I had this happen when the primary key was setup as an UNSIGNED INT but the foreign key field was just an INT. Adding UNSIGNED to the datatype fixed the problem.

风吹过旳痕迹 2024-11-08 16:28:47

我只是使用 Windows 应用了重构,然后将数据库重新导入到 Debian - 它有效。

我认为可以肯定地说,Debian 服务器上或者 Linux 版本的 Mysql 上出现了一些问题 - 也许是 5.1 版本中的错误?

无论如何,我也将服务器上的内存从 1GB 升级到 2GB,这些问题都消失了。

我认为 MySQL 可能只是没有足够的内存来完成操作。如果是这样的话(看起来确实如此),我认为 MySQL 应该简单地这么说,而不是吐出这些错误 - 让我和这里的每个人都认为这是一个语法或与模式相关的问题。

不管怎样,感谢那些试图提供帮助的人。至少它帮助我隔离了所有不可能的事情。

I have simply applied the refactorings using Windows and then reimported the database into Debian - it works.

I think it's safe to say that something was messed up on the Debian server, or with the linux version of Mysql - perhaps a bug in 5.1 build?

Anyway, I have also upgraded the ram on the server from 1gb to 2gb, and these problems have gone away.

I think MySQL maybe just didn't have enough ram to complete the operation. If that was the case (and it seems to be), I think MySQL should have simply said so rather than spitting out these errors - making me and everyone here think it was a syntax or a schema-related problem.

Anyway, thanks for those that tried to help. At least it helped me to isolate all the things it couldn't have been.

堇年纸鸢 2024-11-08 16:28:47

由于它似乎与语法无关,所以我最好的猜测是您没有足够的空间来创建 InnoDB 表。

编辑:你能粘贴你的 InnoDB 配置吗:

SHOW VARIABLES LIKE "inno%";

Since it doesn't seem to be anything syntax-related, my best guess would be that you're running out of space for creating InnoDB tables.

EDIT: Can you paste your InnoDB configuration:

SHOW VARIABLES LIKE "inno%";
谁许谁一生繁华 2024-11-08 16:28:47

由于尝试手动创建 company_to_module 的副本会产生相同的错误,因此您应该仔细检查 company_to_module 中已存在的 fk 约束。它仍然有效,还是您修改了表模块

来自 MySQL 文档

1005 (ER_CANT_CREATE_TABLE) 无法创建表。如果错误消息是错误150,则表创建失败,因为外键约束未正确形成。

Since trying to create a copy of company_to_module manually gives you the same error, you should carefully check the fk constraint already present in company_to_module. Is it still valid, or did you modify the table module?

From the MySQL-Docs:

1005 (ER_CANT_CREATE_TABLE) Cannot create table. If the error message refers to error 150, table creation failed because a foreign key constraint was not correctly formed.

孤凫 2024-11-08 16:28:47

@egervari您写道-我的解决方案是删除所有索引和外键,重命名 id 列,然后重新添加索引和外键。

同意你的看法。但也可能是出了什么问题。我重现了该错误,并(就我而言)修复了它。

我建议您对重命名列的表运行 OPTIMIZE TABLE 命令。文档说 - 对于 InnoDB 表,OPTIMIZE TABLE 映射到 ALTER TABLE,后者会重建表以更新索引统计信息并释放聚集索引中未使用的空间。


另一种解决方案:

删除引用表中的唯一键(外键使用的键,在您的情况下它是主键)。然后添加新的外键并重新创建删除的唯一键。


另一种解决方案:

尝试向引用的表添加和删除新列,然后尝试创建外键。

ALTER TABLE company ADD COLUMN column1 VARCHAR(255) DEFAULT NULL;
ALTER TABLE company DROP COLUMN column1;

@egervari You wrote - My solution was to drop all the indexes and foreign keys, rename the id columns, and then re-add the indexes and foreign keys.

Agree with you. But it might be that something went wrong. I reproduced the error, and (in my case) fixed it.

I'd suggest you to run OPTIMIZE TABLE command for table where column was renamed. Documentation says - For InnoDB tables, OPTIMIZE TABLE is mapped to ALTER TABLE, which rebuilds the table to update index statistics and free unused space in the clustered index.


One more solution:

Drop unique key in the referenced table (key that is used by foreign key, in your case it is a primary key). Then add new foreign key and recreate droped unique key.


One more solution:

Try to add and drop new column to the referenced table, then try to create your foreign key.

ALTER TABLE company ADD COLUMN column1 VARCHAR(255) DEFAULT NULL;
ALTER TABLE company DROP COLUMN column1;
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文