Tôi có khoảng 40 triệu hàng trong một bảng MySQL và tôi muốn sao chép bảng này sang một bảng khác trong cùng một cơ sở dữ liệu. Cách hiệu quả nhất để làm điều này là gì? Sẽ mất bao nhiêu thời gian (khoảng.)
Tôi có khoảng 40 triệu hàng trong một bảng MySQL và tôi muốn sao chép bảng này sang một bảng khác trong cùng một cơ sở dữ liệu. Cách hiệu quả nhất để làm điều này là gì? Sẽ mất bao nhiêu thời gian (khoảng.)
Câu trả lời:
Giả sử bạn có mydb.mytb
và bạn muốn tạomydb.mytbcopy
Tôi có năm (5) cách tiếp cận để thực hiện bản sao này
Trong mysql
máy khách, hãy chạy như sau
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}
Nếu bạn muốn sao chép mydb.mytb
vào một bảng đã có sẵn mydb.mytbcopy
và hai bảng có cấu trúc giống hệt nhau:
INSERT INTO mytbcopy SELECT * FROM mytb;
Giống như #APPROACH 1 , #APPROACH 6 sẽ có một giao dịch duy nhất là 40 triệu hàng
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
Cách tiếp cận này không làm rơi bàn. Nó chỉ đơn giản là tạo ra các chữ ký
Tôi không thể đưa ra ước tính thời gian vì tôi không biết cấu tạo của Máy chủ DB, cấu trúc bảng, bố cục chỉ mục và những thứ như thế này.
Các bảng InnoDB, không giống như MyISAM *, không thể được "sao chép", như một phần của từ điển dữ liệu của nó (và các cấu trúc khác mà bảng phụ thuộc vào, như bộ đệm hợp nhất) nằm trong bộ nhớ (nếu máy chủ đang chạy) và trong không gian bảng chung / chính, hay còn gọi là tệp lớn ibdata1
.
Nếu bạn đang sử dụng Percona Server> = 5.1 hoặc MySQL> = 5.6, có hỗ trợ cho các không gian bảng có thể di chuyển, cho phép bạn xuất và nhập các bảng trực tiếp từ hệ thống tệp. Đây là phương pháp cho MySQL và cho Percona . Trong cả hai trường hợp, yêu cầu là bạn đã tạo bảng với innodb_file_per_table
tùy chọn và liên quan đến việc sử dụng DISCARD TABLESPACE/IMPORT TABLESPACE
và / hoặc Percona Xtrabakup (nếu bạn muốn việc xuất khẩu được thực hiện trực tuyến). Xin lưu ý rằng Percona Server hoặc Xtrabakup không có sẵn cho Windows.
Phương pháp này sẽ, nói chung, nhanh như sao chép tệp bằng các lệnh hệ thống tệp (cp, rsync).
Mặc dù có thể có một số trường hợp điều này có thể hoạt động trong MySQL <5.6 (theo cách hacky) để khôi phục, nhưng nó sẽ không hoạt động đối với bản sao bảng. Trong những trường hợp đó, một cách để làm điều đó là sử dụng SQL :
CREATE TABLE new_table LIKE old_table;
INSERT INTO new_table SELECT * FROM old_table;
Việc này sẽ nhanh như InnoDB có thể thực thi Handler_read_rnd_next
và Handler_write
, mỗi lần một hàng. Nếu bạn sử dụng phương pháp này, hãy đảm bảo rằng bạn vô hiệu hóa, ít nhất là tạm thời, các tùy chọn độ bền và bạn có một vùng đệm lớn và nhật ký giao dịch. Trong những trường hợp đó, nó có thể giảm thời gian nhập, nhưng nó chắc chắn sẽ không phù hợp với bộ nhớ, vì vậy hãy chờ đợi nhiều thời gian. Ngoài ra, bạn đang cố gắng nhập 40 triệu hàng trong một giao dịch, điều này có thể dẫn đến các vấn đề.
Khuyến nghị thực tế của tôi, trong trường hợp thứ hai này, sẽ là sử dụng một cái gì đó như pt-archiver , vì nó sẽ thực hiện một thao tác tương tự như tôi vừa đề cập, nhưng nó sẽ được thực hiện trong "khối", tránh chi phí giao dịch (có thể không được nhanh hơn, nhưng trong trường hợp thất bại, nó sẽ không cố gắng quay ngược lại toàn bộ bảng, lấy mãi mãi). Đối với các kích thước dữ liệu mà bạn đề cập, đây có lẽ là cách tốt nhất để đi.
Tùy chọn cuối cùng sẽ là xuất và nhập bằng định dạng CSV (hoặc TSV) , với sự kết hợp của CHỌN VÀO OUTFILE / mysqldump và LOAD DATA / mysqlimport. Đây là một tùy chọn rất phổ biến nếu bạn cần đồng thời trong một số phiên bản cũ của mysql, vì sử dụng sql đã tạo ra các khóa lớn hơn (không còn đúng nữa nếu được thực hiện đúng). Vì mysqldump / import chỉ hoạt động theo cách tuần tự, tôi sẽ khuyên bạn nên nghiên cứu các tùy chọn để song song hóa nó, rất hữu ích cho các bảng lớn.
Trong mọi trường hợp, hãy cố gắng tránh nhiều câu SQL, vì đó sẽ là nút cổ chai quan trọng nhất của bạn nếu bạn thực hiện nhiều truy vấn khác nhau (phải được thực hiện, phân tích cú pháp và tối ưu hóa riêng lẻ).
* Cấu trúc MyISAM không thể được sao chép theo cách nóng, nhưng rất dễ dàng để đồng bộ hóa chúng tạm thời với đĩa FTWRL
.
để di chuyển dữ liệu từ bảng này sang bảng khác trong lược đồ
create table your_table_name select * from old_schema_table;