Mysql — добавить ограничение внешнего ключа в таблицу

У меня есть две таблицы с именами users, user_friends. user имеет более 10 миллионов записей, а user_friends — более 600 миллионов записей. Проблема в том, что у него нет ограничений. то есть, когда пользователь удаляется, его список друзей остается в базе данных. все работало нормально. но теперь мы реализовали новую функциональность с user_social_friends. Я применил в нем все ограничения.

теперь я хочу применить ограничение к таблице user_friends вот так

SQL query:


ALTER TABLE `user_friends` ADD  CONSTRAINT `user_id_key_contstraint` FOREIGN KEY (`user_id`) REFERENCES `user`(`id`) ON DELETE CASCADE ON UPDATE CASCADE;
MySQL said: Documentation

#1452 - Cannot add or update a child row: a foreign key constraint fails (`callerap_finder`.`#sql-d9fad_24e`, CONSTRAINT `user_id_key_contstraint` FOREIGN KEY (`user_id`) REFERENCES `user` (`id`) ON DELETE CASCADE ON UPDATE CASCADE)

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

Прежде чем вы сможете добавить ограничение, связи между данными должны быть удовлетворены. Добавление ограничения не удаляет строки и не изменяет значения на NULL. Вам нужно сделать это, используя DELETE или UPDATE, прежде чем пытаться добавить ограничение.

Bill Karwin 07.10.2023 08:57
Освоение архитектуры микросервисов с Laravel: Лучшие практики, преимущества и советы для разработчиков
Освоение архитектуры микросервисов с Laravel: Лучшие практики, преимущества и советы для разработчиков
В последние годы архитектура микросервисов приобрела популярность как способ построения масштабируемых и гибких приложений. Laravel , популярный PHP...
Как построить CRUD-приложение в Laravel
Как построить CRUD-приложение в Laravel
Laravel - это популярный PHP-фреймворк, который позволяет быстро и легко создавать веб-приложения. Одной из наиболее распространенных задач в...
Освоение PHP и управление базами данных: Создание собственной СУБД - часть II
Освоение PHP и управление базами данных: Создание собственной СУБД - часть II
В предыдущем посте мы создали функциональность вставки и чтения для нашей динамической СУБД. В этом посте мы собираемся реализовать функции обновления...
Документирование API с помощью Swagger на Springboot
Документирование API с помощью Swagger на Springboot
В предыдущей статье мы уже узнали, как создать Rest API с помощью Springboot и MySql .
Роли и разрешения пользователей без пакета Laravel 9
Роли и разрешения пользователей без пакета Laravel 9
Этот пост изначально был опубликован на techsolutionstuff.com .
Как установить LAMP Stack - Security 5/5 на виртуальную машину Azure Linux VM
Как установить LAMP Stack - Security 5/5 на виртуальную машину Azure Linux VM
В предыдущей статье мы завершили установку базы данных, для тех, кто не знает.
1
1
58
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ошибка, с которой вы столкнулись, предполагает, что в таблице user_friends существуют записи с идентификаторами userId, которых нет в таблице user. Чтобы иметь возможность добиться того, чего вы хотите, сначала убедитесь, что к таким пользователям прикреплены действительные идентификаторы пользователей, или присвойте таким пользователям нулевое значение.

Вот что вы можете сделать.

  1. Найдите недопустимые ссылки user_id в user_friends.

// mysql 

SELECT user_friends.user_id
FROM user_friends
LEFT JOIN user ON user_friends.user_id = user.id
WHERE user.id IS NULL;
  1. Обновите недопустимые ссылки user_id на NULL или действительный идентификатор пользователя. Например, установив для них значение NULL.

// mysql

UPDATE user_friends
LEFT JOIN user ON user_friends.user_id = user.id
SET user_friends.user_id = NULL
WHERE user.id IS NULL
  1. После очистки таблицы user_friends со значениями, установленными для userId, вы сможете без ошибок добавить ограничение внешнего ключа.

существует более 1000 миллионов записей. ну это займет много времени.

Engr.Aftab Ufaq 07.10.2023 08:58

Извините, нет лучшего способа, когда дело касается MySQL. Предлагается автоматизировать этот процесс с помощью сценария или задания cron и всегда выбирать максимальное количество элементов для выполнения этой проверки и выполнять эту операцию или устанавливать для нее значение по умолчанию. И убедитесь, что сценарий начнет выбор следующего пакета с начала последнего выбора.

big bob little 07.10.2023 09:02
Ответ принят как подходящий

Если я правильно понимаю, у вас есть записи в user_friends, которые нарушают ограничение внешнего ключа, которое вы пытаетесь добавить. вы можете выполнить следующие действия, чтобы избежать этой ошибки

1. Сначала удалите или обнулите эти записи в таблице user_friends.

DELETE FROM user_friends WHERE user_id NOT IN (SELECT id FROM user);

2. Теперь запустите запрос, чтобы добавить ограничения.

ALTER TABLE `user_friends`
ADD CONSTRAINT `user_id_key_constraint`
FOREIGN KEY (`user_id`)
REFERENCES `user`(`id`)
ON DELETE CASCADE
ON UPDATE CASCADE;

Но, как вы сказали, у вас очень большой объем данных, я думаю, вам нужно создать еще одну таблицу, которая берет действительные идентификаторы пользователей из таблицы user и на основе этого вы можете удалять или обновлять записи в таблице user_friends.

Например

Первый шаг

CREATE TEMPORARY TABLE valid_user_ids AS
SELECT DISTINCT id FROM user;

Шаг второй

Создайте индекс, если у вас его еще нет в таблице user_id в user_friends.

 CREATE INDEX idx_user_id ON user_friends (user_id);

Шаг третий

Теперь все, что вам нужно сделать, это удалить или обнулить записи, а затем добавить ограничения для удаления, вы можете использовать что-то вроде этого

DELETE FROM user_friends
WHERE user_id NOT IN (SELECT id FROM valid_user_ids);

Шаг четвертый

Теперь просто добавьте ограничения с помощью вышеупомянутого запроса в пункте 2.

Кончик:-

Например, вы можете получать данные пакетно и обновлять их соответствующим образом.

SELECT id
FROM user_friends
LIMIT ${batchSize}
OFFSET ${offset};

Этот запрос вернет количество строк, которые вам нужно сопоставить, и получит идентификаторы таких строк const userIDs = rows.map((row) => row.id).join(','); после этого измените свой StepThree вот так

DELETE FROM user_friends
WHERE user_id NOT IN (SELECT id FROM valid_user_ids) AND id IN 
(${userIDs});

Другие вопросы по теме