tốc độ tải dữ liệu chậm từ mysqldump


21

Tôi đã có một cơ sở dữ liệu MySQL kích thước vừa phải với khoảng 30 bảng, một số trong đó là 10 triệu bản ghi, khoảng 100 triệu. Tất mysqldumpcả các bảng (thành các tệp riêng biệt) khá nhanh, có thể mất 20 phút. Nó tạo ra khoảng 15 GB dữ liệu. Các tệp bị đổ lớn nhất nằm trong phạm vi 2GB.

Khi tôi tải dữ liệu vào MySQL trên một hộp khác, máy 6 nhân, 8GB, sẽ mất mãi mãi. Dễ dàng 12 giờ đồng hồ trở lên.

Tôi chỉ đang chạy máy khách mysql để tải tệp, tức là

mysql database < footable.sql

trực tiếp với tệp trực tiếp ra khỏi mysqldump

mysqldump database foo > footable.sql

Rõ ràng tôi đang làm gì đó sai. Tôi phải bắt đầu từ đâu để có thể kết thúc trong thời gian hợp lý?

Tôi không sử dụng bất kỳ công tắc nào trên bãi chứa hoặc tải.


Bạn cũng có thể hủy kích hoạt ghi nhật ký nhị phân trong quá trình tải bãi rác của mình
Cédric PEINTRE

Câu trả lời:


22

Hãy xem xét một số điểm này để xem xét, chúng có thể giúp bạn trong trường hợp tạo bãi chứa và khôi phục nó.

  1. Sử dụng Extended insertstrong bãi rác.
  2. Kết xuất với --tabđịnh dạng để bạn có thể sử dụng mysqlimport, nhanh hơn mysql < dumpfile.
  3. Nhập với nhiều chủ đề, một cho mỗi bảng.
  4. Sử dụng một công cụ cơ sở dữ liệu khác nhau nếu có thể. nhập khẩu vào một công cụ giao dịch nặng nề như innodb là rất chậm. Chèn vào một công cụ không giao dịch như MyISAM nhanh hơn nhiều.
  5. Tắt kiểm tra khóa ngoại và bật tự động xác nhận.
  6. Nếu bạn đang nhập vào innodb, điều hiệu quả nhất bạn có thể làm là innodb_flush_log_at_trx_commit = 2tạm thời đưa vào my.cnf của mình trong khi quá trình nhập đang chạy. bạn có thể đặt nó trở lại 1 nếu bạn cần ACID

Hãy thử một lần..


Gợi ý của bạn với innodb_flush_log_at_trx_commit = 2lưu ngày của tôi. Nhập một bãi chứa 600 MB (như một giao dịch lớn) sẽ cần 6 giờ, nhưng với cài đặt tạm thời này, nó đã được thực hiện trong 30 phút!
Daniel Marschall

1
Những điều bạn muốn bạn biết trước khi thử tải cơ sở dữ liệu 80gig từ bãi rác 4 ngày sau khi nhấn 'enter' ... :)
Dmitri DB

7

Ngoài câu trả lời của Abdul , tôi muốn nhấn mạnh tầm quan trọng của --disable-keystùy chọn, tắt khóa cho đến khi tất cả dữ liệu được tải cho một bảng. Tùy chọn này được bật như một phần của --optchuyển đổi, được bật theo mặc định, nhưng nghĩ rằng nó quan trọng để chỉ ra.

Nếu bạn không bỏ qua các phím trong khi chèn, thì mỗi hàng được chèn sẽ xây dựng lại chỉ mục. Một quá trình cực kỳ chậm.


--disable-key là một phần của mysqldump? hoặc tải lại?
Pat Farrell

nó sẽ được thêm vào trong tệp kết xuất
Derek Downey

--optđược bật theo mặc định
jberryman

1
This option is effective only for nonunique indexes of MyISAM tables. It has no effect for other tables
Ethan Allen

7

Tôi đã được giải quyết rất nhiều với điều này gần đây. Bạn chắc chắn có thể cải thiện hiệu suất nhập khẩu bằng cách nhập song song. Hầu hết sự chậm lại là dựa trên I / O, nhưng bạn vẫn có thể cải thiện 40% bằng cách đổ vào các bảng và sau đó nhập chúng vào 4 lần.

Bạn có thể làm điều này với xargs như thế này:

ls *.sql -1c | xargs -P4 -I tbl_name sh -c "mysql --user=username --password database < tbl_name"

việc các tập tin được nén lại trước khi đẩy chúng vào mysql không làm chậm bất cứ điều gì chủ yếu là do I / O bị hạ thấp. Các bảng của tôi được nén tối đa khoảng 10: 1, vì vậy nó tiết kiệm rất nhiều dung lượng đĩa.

Tôi đã thấy rằng trên các máy 4 lõi, sử dụng 4 quy trình là tối ưu, mặc dù chỉ tốt hơn một chút so với sử dụng 3. Nếu bạn có SSD hoặc RAID nhanh, bạn có thể sẽ mở rộng quy mô tốt hơn.

Một số điều khác cần lưu ý. Nếu bạn có ổ đĩa 4k sector, hãy chắc chắn rằng bạn có key_cache_block_size=4096myisam_block_size=4K.

Nếu bạn đang sử dụng bảng MyISAM, hãy đặt myisam_repair_threads = 2hoặc cao hơn. Điều này sẽ cho phép các lõi bổ sung của bạn để giúp xây dựng lại các chỉ mục.

Hãy chắc chắn rằng bạn không trao đổi gì cả. Nếu bạn là, giảm kích thước của innodb_buffer_pool_size.

Tôi nghĩ rằng tôi đã tăng tốc với innnodb bằng các tùy chọn này:

innodb_flush_method= O_DIRECT (LINUX ONLY)
innodb_flush_log_at_commit = 0
innodb_doublewrite=0
innodb_support_xa=0
innodb_checksums=0

(ba lần cuối cùng tôi đã không kiểm tra rộng rãi - Tôi nghĩ rằng tôi đã tìm thấy chúng dưới dạng các đề xuất trên mạng nội bộ.) Lưu ý rằng điều đó innodb_flush_log_at_commit=0có thể dẫn đến tham nhũng với mysql bị sập hoặc mất điện.


Greg, chào mừng đến với trang web và cảm ơn câu trả lời của bạn. Bạn có thể cung cấp một số nguồn hoặc lý do cho các đề xuất của bạn trên *_block_sizemyisam_repair_threads? Ngoài ra, không chắc chắn chúng tôi nên đưa ra lời khuyên để điều chỉnh các biến dựa trên 'đề xuất từ ​​các mạng nội bộ' :)
Derek Downey

5

Nếu bạn chủ yếu có các bảng MyISAM, bạn nên tăng bộ đệm chèn số lượng lớn . Đây là những gì Tài liệu MySQL nói về việc thiết lập hàng loạt_insert_buffer_size :

MyISAM sử dụng bộ đệm giống như cây đặc biệt để chèn số lượng lớn nhanh hơn cho CHỌN ... CHỌN, XÁC NHẬN ... GIÁ TRỊ (...), (...), ... và LOAD DATA INFILE khi thêm dữ liệu vào dữ liệu không trống những cái bàn. Biến này giới hạn kích thước của cây bộ đệm theo byte trên mỗi luồng. Đặt nó thành 0 sẽ vô hiệu hóa tối ưu hóa này. Giá trị mặc định là 8MB.

Có hai điều bạn cần làm

1) Thêm nó vào /etc/my.cnf

[mysqld]
bulk_insert_buffer_size=512M

2) Đặt giá trị toàn cầu cho nó

SET GLOBAL bulk_insert_buffer_size = 1024 * 1024 * 512;

Nếu bạn không có đặc quyền đặt số lượng lớn_insert_buffer_size trên toàn cầu, thì hãy làm điều này

service mysql restart

Tất nhiên, điều này không dành cho InnoDB.

Từ một góc độ khác, cho dù các bảng là InnoDB hay MyISAM, nếu các chỉ mục lớn hơn bảng, bạn có thể có quá nhiều chỉ mục. Tôi thường đánh giá cao rằng việc tải lại MyqAM mysqldump sẽ mất gấp 3 lần thời gian mysqldump thực hiện. Tôi cũng đánh giá cao rằng việc tải lại một mysqldump của InnoDB sẽ mất 4 lần miễn là mysqldump thực hiện.

Nếu bạn vượt quá tỷ lệ 4: 1 để tải lại mysqldump, bạn chắc chắn có một trong hai vấn đề:

  • quá nhiều chỉ số
  • chỉ mục quá lớn do cột lớn

Bạn có thể đo kích thước dữ liệu của mình bằng công cụ lưu trữ bằng cách này:

SELECT IFNULL(B.engine,'Total') "Storage Engine",
CONCAT(LPAD(REPLACE(FORMAT(B.DSize/POWER(1024,pw),3),',',''),17,' '),' ',
SUBSTR(' KMGTP',pw+1,1),'B') "Data Size", CONCAT(LPAD(REPLACE(
FORMAT(B.ISize/POWER(1024,pw),3),',',''),17,' '),' ',
SUBSTR(' KMGTP',pw+1,1),'B') "Index Size", CONCAT(LPAD(REPLACE(
FORMAT(B.TSize/POWER(1024,pw),3),',',''),17,' '),' ',
SUBSTR(' KMGTP',pw+1,1),'B') "Table Size" FROM
(SELECT engine,SUM(data_length) DSize,SUM(index_length) ISize,
SUM(data_length+index_length) TSize FROM
information_schema.tables WHERE table_schema NOT IN
('mysql','information_schema','performance_schema') AND
engine IS NOT NULL GROUP BY engine WITH ROLLUP) B,
(SELECT 3 pw) A ORDER BY TSize;

Xem các chỉ mục có lớn nhất bằng dữ liệu hay thậm chí lớn hơn không

Bạn cũng có thể xem xét việc vô hiệu hóa ghi nhật ký nhị phân như thế này:

echo "SET SQL_LOG_BIN=0;" > footable.sql
mysqldump --databases foo >> footable.sql

trước khi tải lại tập lệnh


Tôi không biết bạn đã cứu tôi bao nhiêu lần nhưng chắc chắn là rất nhiều
Dmitri DB

2

Nếu bạn bỏ qua hệ thống tập tin hoàn toàn và chỉ đưa đầu ra của mysqldump trực tiếp vào một quy trình MySQL, bạn sẽ thấy những cải tiến hiệu suất đáng chú ý. Cuối cùng phụ thuộc vào loại ổ đĩa bạn đang sử dụng nhưng tôi hiếm khi sử dụng tệp kết xuất nữa bất kể kích thước cơ sở dữ liệu chỉ vì lý do này.

mysqldump -uxxx -pxxx -hxxx --single-transaction --routines --databases dbname | mysql -uyyy -pyyy -hyyy

1

Theo kinh nghiệm của tôi, ổ cứng là nút cổ chai. Quên đĩa quay. SSD tốt hơn, nhưng cho đến nay, tốt nhất là thực hiện điều này trong RAM - nếu bạn có đủ để giữ toàn bộ cơ sở dữ liệu trong một thời gian ngắn. Roughly:

  1. dừng mysqld
  2. di chuyển đi các nội dung hiện có của / var / lib / mysql
  3. tạo một thư mục trống / var / lib / mysql
  4. mount -t tmpfs -o size = 32g tmpfs / var / lib / mysql (điều chỉnh kích thước)
  5. tạo một db trống (ví dụ: mysql_install_db hoặc khôi phục nội dung trước đó)
  6. bắt đầu mysqld
  7. nhập khẩu
  8. dừng mysqld
  9. sao chép / var / lib / mysql sang mysql2
  10. mysount umount; rmdir mysql
  11. chuyển mysql2 sang mysql
  12. bắt đầu mysqld, hãy hạnh phúc

Đối với tôi, có thể nhập một khối lượng ~ 10G (/ var / lib / mysql ~ 20G) trong khoảng 35 phút (mydumper / myloader), 45 phút (mysqldump --tab / mysqlimport), 50 phút (mysqldump / mysql) , trên Xeon lõi kép 3,2 GHz.

Nếu bạn không có đủ RAM trong một máy, nhưng có nhiều máy tính cạnh nhau với mạng nhanh, sẽ rất thú vị để xem liệu RAM của chúng có thể được nối với nbd (thiết bị chặn mạng) hay không. Hoặc, với innodb_file_per_table, bạn có thể lặp lại quy trình trên cho mỗi bảng.


Vì tò mò, tôi đã thử lưu trữ dữ liệu mysql trong RAM để so sánh nó với SSD (SSDSC2BB48 cho những ai quan tâm) cho cơ sở dữ liệu 2 GB. Kết quả là SẮC, cả hai đều mất 207-209 giây. Xem xét thực tế là bạn cũng phải bắt đầu / dừng mysql và sao chép các thư mục, sử dụng đĩa RAM thay vì SSD chậm hơn nhiều trong trường hợp của tôi
Shocker

Nếu bạn mất ~ 3-4 phút, tôi đoán bạn có cơ sở dữ liệu nhỏ hơn đáng kể so với chủ đề này. Thật thú vị khi nghe về trải nghiệm của bạn với cơ sở dữ liệu lớn tương tự như những cơ sở được đề cập trong chủ đề này.
egmont
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.