dil: (Default)
dil ([personal profile] dil) wrote2014-08-16 12:17 pm

Задачка про SQL

В одной базе данных есть две таблицы, связанные отношением 1:M. Скажем, в одной лежат посты из блога, а в другой комментарии, привязанные к постам по id.
Задача: перетащить их все в другую базу, в которой идентификаторы у постов изменятся (потому что там уже есть другие посты с теми же id, что в первой базе), но при этом сохранить привязку к ним комментариев.

С постами понятно, SELECT из первой базы и INSERT во вторую.

А вот как быть с комментариями?
Мне пока пришли в голову три идеи, но все неэффективные.

1) Для каждого поста сразу после помещения его во вторую базу, когда уже известны и старый, и новый id, найти в первой базе все комментарии по старому id и сложить их во вторую базу с новым id. Но это отдельный SQL-запрос на каждый пост, а их там дофига.

2) Сначала перенести все посты, попутно составляя табличку со старыми и новыми id, а потом переносить комментарии, заменяя id постов по этой табличке. Но если табличку держать в памяти, она получится очень нефигового размера. А в базах её создавать нельзя, правов не хватает.

3) Извлечь вместе с постами сразу все их комментарии путём LEFT OUTER JOIN. Но тогда каждый пост извлечётся целиком много раз, с каждым своим комментарием, это дикий перерасход памяти в SQL-сервере.

Как бы это сделать поэффективнее?

Оригинал этой записи в личном блоге.

alz421: (Default)

[personal profile] alz421 2014-08-16 03:46 pm (UTC)(link)
Первый вариант. Запусти скрипт с вечера, пусть жужжит. Твое время всяко дороже машинного :)
dmarck: (Default)

[personal profile] dmarck 2014-08-16 03:47 pm (UTC)(link)
Так завести отдельное unique поле, в которое писать origin ID?
dmarck: (Default)

[personal profile] dmarck 2014-08-16 07:44 pm (UTC)(link)
temporary table тоже не дадут создать?

[identity profile] drug123.livejournal.com 2014-08-19 09:47 pm (UTC)(link)
Синтаксис оператора CREATE TABLE

CREATE [TEMPORARY] TABLE [IF NOT EXISTS] tbl_name [(create_definition,...)]
[table_options] [select_statement]

Но нужны соответствующие права.
beldmit: (Программизм)

[personal profile] beldmit 2014-08-16 05:46 pm (UTC)(link)
а) Заюзать какой-нибудь ORM системы DBIx::Class, который вытащит посты с комментами. Из базы взял - в базу положил...

б) Импортировать посты, взять новые ID, сохранить в старой базе, взять из старой базы комменты с новыми ID постов, залить.

А почему ID сохранить не удается, кстати?
beldmit: (Программизм)

[personal profile] beldmit 2014-08-16 06:08 pm (UTC)(link)
Ну вот есть там магия, которая из результатов запроса с LEFT JOIN делает структуру 1:N. В потроха не лез, мне хватает, что просто работает.

Простейший способ эмуляции совсем на коленке - вытащить LEFT JOIN-ом, и следить, какой пост импортируем.

[personal profile] dcicppin 2014-08-17 06:58 am (UTC)(link)
Взять максимальный ID поста таргетной таблицы и добавлять его к значениям сорсевых таблиц при переносе? Нумерация постов обычно от единицы и более-менее непрерывная, т.ч. результат должен выйти близкий.

[personal profile] dcicppin 2014-08-17 07:00 am (UTC)(link)
Но, конечно, сработает только если можно обеспечить отсутствие инсертов на таргетной таблице в процессе переноса.
beldmit: (Программизм)

[personal profile] beldmit 2014-08-17 05:16 pm (UTC)(link)
LOCK TABLE?