Способ заменить значения столбца новым внешним ключом? - PullRequest
1 голос
/ 30 марта 2019

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

На данный момент я могу эффективно создать внешнюю таблицу с помощью:

INSERT INTO `messages` (`message`) SELECT `message` FROM `history`;

Но моя первая основная попытка заменить столбец VARCHAR ужасно неэффективна и занимает несколько секунд на строку, что, очевидно, неосуществимо (LIMIT там для тестирования).

$messages = $mysqli->query('SELECT `message` FROM `history` LIMIT 0,100;');
while($row = $messages->fetch_array(MYSQLI_ASSOC)) {
    $msg = $row['message'];
    $result2 = $mysqli->query(
        'SELECT `id` FROM `messages` WHERE `message` = "'.$msg.'" LIMIT 0,1'
    );
    $row2 = $result2->fetch_array(MYSQLI_ASSOC);
    $id = $row2['id'];
    $mysqli->query(
        'UPDATE `history` SET `message`="'.$id.'" WHERE `message` = "'.$msg.'"'
    );
    $result2->free_result();
}

Такое ощущение, что я должен быть в состоянии сделать этот процесс полностью на SQL, а не полагаться на PHP, что, как мы надеемся, также будет эффективным способом.

Ответы [ 2 ]

3 голосов
/ 30 марта 2019

Вместо зацикливания с помощью PHP вы можете использовать запрос UPDATE ... JOIN, чтобы позволить вашей СУБД выполнять тяжелую работу одновременно:

UPDATE history h
INNER JOIN messages m ON m.message = h.message
SET h.message = m.id

Это предполагает, что таблица messages уже заполнена.Для повышения производительности, поскольку вы указали, что значения уникальны в столбце message, вы можете создать ограничение UNIQUE для messages(messsage).

1 голос
/ 30 марта 2019

вы должны использовать php?потому что вы делаете: 1) один запрос на вывод 100 строк 2) для каждой строки, один запрос на получение идентификатора другой таблицы, а затем еще один запрос на обновление исходной таблицы.И я предполагаю, что исходная таблица больше 100 строк.

Не можете ли вы сделать это непосредственно внутри БД?если значения varchar уникальны, и вы просто хотите, чтобы они были в отдельной таблице, вы можете просто заполнить новую таблицу точно так же, как вы это делали, но указав также идентификатор, который будет удобным идентичным идентификатору исходной таблицы:

INSERT INTO `messages` (`id`, `message`) SELECT `id`, `message` FROM `history`;

Затем создайте новый столбец INT, который будет содержать внешний ключ:

ALTER TABLE history ADD message_id INT;

Затем заполните столбец:

UPDATE history SET message_id = id;

Затем удалите varcharстолбец:

ALTER TABLE history DROP message;

Теперь вы можете добавить ограничение, чтобы указать, что message_id является внешним ключом:

ALTER TABLE history ADD CONSTRAINT fk_message_id FOREIGN KEY message_id REFERENCES messages(id);

Таким образом, вы делаете только 2 итерации: одну для заполнения новой таблицы,и один, чтобы установить новый столбец.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...