Проблема при добавлении внешнего ключа с помощью Alter Table в существующую базу данных MYSQL - не удается добавить его! Помогите! - PullRequest
9 голосов
/ 15 апреля 2011

У меня есть производственная база данных, в которой я переименовал несколько столбцов, которые являются внешними ключами. Очевидно, что MySQL делает это реальной болью в моем опыте.

Мое решение состояло в том, чтобы удалить все индексы и внешние ключи, переименовать столбцы id, а затем повторно добавить индексы и внешние ключи.

Это прекрасно работает на 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)

В этой таблице нет значений, которые бы конфликтовали с внешним ключом, который я пытаюсь добавить. База данных не изменилась. Внешний ключ DID существовал раньше ... так что данные в порядке. Не будем упоминать, что я взял ту же самую базу данных, которая у меня есть на сервере, и она прекрасно переносится в 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 повредил мою базу данных и уничтожил ее. Мне пришлось перезагрузить из резервной копии, чтобы повторить попытку.

Помощь? : /

Ответы [ 6 ]

9 голосов
/ 15 апреля 2011

Являются ли обе таблицы типом 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;
4 голосов
/ 15 апреля 2011

Убедитесь, что company_to_module.company_id и company.company_id являются ТОЧНЫМ одним и тем же типом данных. Я имел это, когда первичный ключ был установлен как НЕ ПОДПИСАНО INT, но поле внешнего ключа было просто INT. Добавление UNSIGNED в тип данных устранило проблему.

1 голос
/ 17 апреля 2011

Я просто применил рефакторинг с помощью Windows, а затем повторно импортировал базу данных в Debian - это работает.

Я думаю, можно с уверенностью сказать, что что-то напутало на сервере Debian или в версии linux для Linux.Mysql - возможно, ошибка в сборке 5.1?

Во всяком случае, я также обновил оперативную память на сервере с 1 ГБ до 2 ГБ, и эти проблемы исчезли.

Я думаю, что MySQL, возможно, просто не хватило оперативной памяти для завершения операции.Если бы это было так (и, кажется, так), я думаю, что MySQL должен был просто сказать об этом, а не выплевывать эти ошибки - заставляя меня и всех присутствующих думать, что это был синтаксис или проблема, связанная со схемой.

В любом случае, спасибо за тех, кто пытался помочь.По крайней мере, это помогло мне изолировать все то, чего не могло быть.

0 голосов
/ 15 апреля 2011

@ 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;
0 голосов
/ 15 апреля 2011

Поскольку попытка создать копию company_to_module вручную приводит к той же ошибке, вам следует тщательно проверить ограничение fk, уже присутствующее в company_to_module.Это все еще допустимо, или вы изменили таблицу module?

Из MySQL-Docs :

1005 (ER_CANT_CREATE_TABLE) Невозможно создать таблицу.Если сообщение об ошибке ссылается на ошибку 150, создание таблицы завершилось неудачно, поскольку ограничение внешнего ключа сформировано неправильно.

0 голосов
/ 15 апреля 2011

Поскольку это, похоже, не связано с синтаксисом, лучше всего предположить, что вам не хватает места для создания таблиц InnoDB.

РЕДАКТИРОВАТЬ: Можете ли вы вставить свою конфигурацию InnoDB:

SHOW VARIABLES LIKE "inno%";
...