У таблиці MySQL у мене близько 40 мільйонів рядків, і я хочу скопіювати цю таблицю в іншу таблицю тієї ж бази даних. Який найефективніший спосіб зробити це? Скільки часу це займе (приблизно)?
У таблиці MySQL у мене близько 40 мільйонів рядків, і я хочу скопіювати цю таблицю в іншу таблицю тієї ж бази даних. Який найефективніший спосіб зробити це? Скільки часу це займе (приблизно)?
Відповіді:
Припустимо, у вас є mydb.mytb
і ви хочете створитиmydb.mytbcopy
У мене є п'ять (5) підходів до виконання цієї копії
У mysql
клієнті виконайте наступне
USE mydb
CREATE TABLE mytbcopy LIKE mytb;
INSERT INTO mytbcopy SELECT * FROM mytb;
MYSQL_USER=root
MYSQL_PASS=rootpassword
MYSQL_CONN="-u${MYSQL_USER} -p${MYSQL_PASS}"
mysql ${MYSQL_CONN} -ANe"CREATE DATABASE IF NOT EXISTS test"
mysqldump ${MYSQL_CONN} mydb mytb | mysql ${MYSQL_CONN} -Dtest
mysql ${MYSQL_CONN} -ANe"ALTER TABLE test.mytb RENAME mydb.mytbcopy"
DUMPFILE=/some/path/tabledata.sql
MYSQL_USER=root
MYSQL_PASS=rootpassword
MYSQL_CONN="-u${MYSQL_USER} -p${MYSQL_PASS}"
mysql ${MYSQL_CONN} -ANe"CREATE DATABASE IF NOT EXISTS test"
mysqldump ${MYSQL_CONN} mydb mytb > ${DUMPFILE}
mysql ${MYSQL_CONN} -Dtest < ${DUMPFILE}
rm -f ${DUMPFILE}
mysql ${MYSQL_CONN} -ANe"ALTER TABLE test.mytb RENAME mydb.mytbcopy"
MYSQL_USER=root
MYSQL_PASS=rootpassword
MYSQL_CONN="-u${MYSQL_USER} -p${MYSQL_PASS}"
mysqldump ${MYSQL_CONN} mydb mytb | sed 's/mytb/mytbcopy' | mysql ${MYSQL_CONN} -Dmydb
DUMPFILE=/some/path/tabledata.sql
MYSQL_USER=root
MYSQL_PASS=rootpassword
MYSQL_CONN="-u${MYSQL_USER} -p${MYSQL_PASS}"
mysqldump ${MYSQL_CONN} mydb mytb | sed 's/mytb/mytbcopy' > ${DUMPFILE}
mysql ${MYSQL_CONN} -Dmydb < ${DUMPFILE}
rm -f ${DUMPFILE}
Якщо ви хочете скопіювати mydb.mytb
у вже існуючу таблицю mydb.mytbcopy
, а дві таблиці мають однакові структури:
INSERT INTO mytbcopy SELECT * FROM mytb;
Як і #APPROACH 1 , #APPROACH 6 матиме одну транзакцію в 40 мільйонів рядків
MYSQL_USER=root
MYSQL_PASS=rootpassword
MYSQL_CONN="-u${MYSQL_USER} -p${MYSQL_PASS}"
mysqldump ${MYSQL_CONN} -t mydb mytb | sed 's/mytb/mytbcopy' | mysql ${MYSQL_CONN} -Dmydb
Цей підхід не опускає таблицю. Він просто генерує ВСТАВКИ
Я не можу дати тобі оцінку часу, оскільки не знаю склад сервера БД, структуру таблиць, макет індексу та подібні речі.
Таблиці InnoDB, на відміну від MyISAM *, не можна "просто скопіювати", оскільки частина її словника даних (і, можливо, інших структур, від яких таблиця залежить, як буфер злиття) розташована в пам'яті (якщо сервер працює) і в загальний / основний простір таблиць, він називається великим файлом ibdata1
.
Якщо ви використовуєте Percona Server> = 5.1 або MySQL> = 5.6, існує підтримка переносних просторів таблиць, що дозволяє експортувати та імпортувати таблиці безпосередньо з файлової системи. Ось це метод для MySQL та Percona . В обох випадках потрібно, щоб ви створили таблицю з innodb_file_per_table
опцією та передбачали використання DISCARD TABLESPACE/IMPORT TABLESPACE
та / або Percona Xtrabakup (якщо ви хочете, щоб експорт здійснювався в Інтернеті). Зверніть увагу, що Percona Server або Xtrabakup не доступні для Windows.
Цей метод буде, кажучи загалом, таким же швидким, як і копіювання файлу за допомогою команд файлової системи (cp, rsync).
Хоча можуть бути випадки, що це може працювати в MySQL <5,6 (хакітним способом) для відновлення, воно не працюватиме для копії таблиці. У цих випадках один із способів зробити це за допомогою SQL :
CREATE TABLE new_table LIKE old_table;
INSERT INTO new_table SELECT * FROM old_table;
Це буде так швидко, як і InnoDB може виконуватись, Handler_read_rnd_next
і Handler_write
один раз у ряд. Якщо ви використовуєте цей метод, переконайтесь, що ви принаймні тимчасово відключили параметри довговічності та у вас є великий буферний пул та журнал транзакцій. За таких обставин це може скоротити час імпорту, але він точно не впишеться в пам'ять повністю, тому очікуйте багато часу. Крім того, ви намагаєтеся імпортувати 40M рядків за одну транзакцію, що може призвести до проблем.
Моєю фактичною рекомендацією у цьому другому випадку було б використовувати щось на зразок pt-архіватора , оскільки воно буде виконувати операцію, подібну до тієї, про яку я щойно згадував, але це буде виконуватися "шматками", уникаючи транзакційних накладних витрат (можливо, не швидше, але у випадку невдачі, він не намагатиметься відкатати всю таблицю, займаючи назавжди). Для розмірів даних, які ви згадуєте, це, мабуть, найкращий шлях.
Остаточним варіантом буде експорт та імпорт у форматі CSV (або TSV) з комбінацією SELECT INTO OUTFILE / mysqldump та LOAD DATA / mysqlimport. Це був дуже поширений варіант, якщо вам потрібна паралельність у певних старих версіях mysql, як використання sql, створених більшими блокуваннями (більше не відповідає дійсності, якщо виконано правильно). Оскільки mysqldump / import працює лише серіалізованим способом, я рекомендую вам дослідити варіанти паралелізації, що дуже корисно для великих таблиць.
У будь-якому випадку намагайтеся уникати декількох пропозицій SQL, оскільки це буде вашим найважливішим місцем, якщо ви виконуєте безліч різних запитів (які потрібно виконувати, аналізувати та оптимізувати окремо).
* Структури MyISAM неможливо скопіювати гарячим способом, але дуже легко їх тимчасово синхронізувати на диск FTWRL
.
для переміщення даних із однієї таблиці в іншу на схемі
create table your_table_name select * from old_schema_table;