Xây dựng bảng MySQL hàng 1.000M


18

Câu hỏi này được đăng lại từ Stack Overflow dựa trên một gợi ý trong các bình luận, lời xin lỗi cho sự trùng lặp.

Câu hỏi

Câu hỏi 1: khi kích thước của bảng cơ sở dữ liệu lớn hơn, làm cách nào tôi có thể điều chỉnh MySQL để tăng tốc độ của cuộc gọi LOAD DATA INFILE?

Câu hỏi 2: sử dụng một cụm máy tính để tải các tệp csv khác nhau, cải thiện hiệu suất hoặc tiêu diệt nó? (đây là nhiệm vụ đánh dấu băng ghế của tôi cho ngày mai bằng cách sử dụng dữ liệu tải và chèn số lượng lớn)

Mục tiêu

Chúng tôi đang thử các kết hợp khác nhau của các trình phát hiện tính năng và các tham số phân cụm để tìm kiếm hình ảnh, do đó chúng tôi cần có khả năng xây dựng và cơ sở dữ liệu lớn một cách kịp thời.

Thông tin máy móc

Máy có 256 gig ram và có 2 máy khác có sẵn với cùng một lượng ram nếu có cách nào để cải thiện thời gian tạo bằng cách phân phối cơ sở dữ liệu?

Lược đồ bảng

lược đồ bảng trông giống như

+---------------+------------------+------+-----+---------+----------------+
| Field         | Type             | Null | Key | Default | Extra          |
+---------------+------------------+------+-----+---------+----------------+
| match_index   | int(10) unsigned | NO   | PRI | NULL    |                |
| cluster_index | int(10) unsigned | NO   | PRI | NULL    |                |
| id            | int(11)          | NO   | PRI | NULL    | auto_increment |
| tfidf         | float            | NO   |     | 0       |                |
+---------------+------------------+------+-----+---------+----------------+

được tạo nên bởi

CREATE TABLE test 
(
  match_index INT UNSIGNED NOT NULL,
  cluster_index INT UNSIGNED NOT NULL, 
  id INT NOT NULL AUTO_INCREMENT,
  tfidf FLOAT NOT NULL DEFAULT 0,
  UNIQUE KEY (id),
  PRIMARY KEY(cluster_index,match_index,id)
)engine=innodb;

Điểm chuẩn cho đến nay

Bước đầu tiên là so sánh các phần chèn hàng loạt với việc tải từ tệp nhị phân vào một bảng trống.

It took:  0:09:12.394571  to do  4,000  inserts with 5,000 rows per insert
It took: 0:03:11.368320 seconds to load 20,000,000 rows from a csv file

Do sự khác biệt về hiệu suất mà tôi đã thực hiện với việc tải dữ liệu từ tệp csv nhị phân, đầu tiên tôi đã tải các tệp nhị phân chứa các hàng 100K, 1M, 20M, 200M bằng cách sử dụng cuộc gọi bên dưới.

LOAD DATA INFILE '/mnt/tests/data.csv' INTO TABLE test;

Tôi đã giết tệp nhị phân hàng 200M (~ 3GB tệp csv) sau 2 giờ.

Vì vậy, tôi đã chạy một kịch bản để tạo bảng và chèn số lượng hàng khác nhau từ tệp nhị phân rồi thả bảng, xem biểu đồ bên dưới.

nhập mô tả hình ảnh ở đây

Mất khoảng 7 giây để chèn 1M hàng từ tệp nhị phân. Tiếp theo, tôi quyết định điểm chuẩn chèn các hàng 1M tại một thời điểm để xem liệu sẽ có một nút cổ chai ở kích thước cơ sở dữ liệu cụ thể. Khi Cơ sở dữ liệu đạt khoảng 59 triệu hàng, thời gian chèn trung bình giảm xuống khoảng 5.000 / giây

nhập mô tả hình ảnh ở đây

Đặt key_buffer_size = 4294967296 toàn cầu đã cải thiện tốc độ một chút để chèn các tệp nhị phân nhỏ hơn. Biểu đồ bên dưới hiển thị tốc độ cho các số hàng khác nhau

nhập mô tả hình ảnh ở đây

Tuy nhiên, để chèn các hàng 1M, nó không cải thiện hiệu suất.

hàng: 1.000.000 thời gian: 0: 04: 13.761428 chèn / giây: 3.940

so với cơ sở dữ liệu trống

hàng: 1.000.000 thời gian: 0: 00: 6.339295 chèn / giây: 315,492

Cập nhật

Thực hiện tải dữ liệu bằng cách sử dụng trình tự sau so với chỉ sử dụng lệnh tải dữ liệu

SET autocommit=0;
SET foreign_key_checks=0;
SET unique_checks=0;
LOAD DATA INFILE '/mnt/imagesearch/tests/eggs.csv' INTO TABLE test_ClusterMatches;
SET foreign_key_checks=1;
SET unique_checks=1;
COMMIT;
nhập mô tả hình ảnh ở đây

Vì vậy, điều này có vẻ khá hứa hẹn về kích thước cơ sở dữ liệu đang được tạo nhưng các cài đặt khác dường như không ảnh hưởng đến hiệu suất của cuộc gọi tải dữ liệu tải.

Sau đó tôi đã thử tải nhiều tệp từ các máy khác nhau nhưng lệnh tải dữ liệu tải dữ liệu khóa bảng, do kích thước lớn của các tệp khiến các máy khác hết thời gian với

ERROR 1205 (HY000) at line 1: Lock wait timeout exceeded; try restarting transaction

Tăng số lượng hàng trong tệp nhị phân

rows:  10,000,000  seconds rows:  0:01:36.545094  inserts/sec:  103578.541236
rows:  20,000,000  seconds rows:  0:03:14.230782  inserts/sec:  102970.29026
rows:  30,000,000  seconds rows:  0:05:07.792266  inserts/sec:  97468.3359978
rows:  40,000,000  seconds rows:  0:06:53.465898  inserts/sec:  96743.1659866
rows:  50,000,000  seconds rows:  0:08:48.721011  inserts/sec:  94567.8324859
rows:  60,000,000  seconds rows:  0:10:32.888930  inserts/sec:  94803.3646283

Giải pháp: Tính toán trước id bên ngoài MySQL thay vì sử dụng tự động tăng

Xây dựng bảng với

CREATE TABLE test (
  match_index INT UNSIGNED NOT NULL,
  cluster_index INT UNSIGNED NOT NULL, 
  id INT NOT NULL ,
  tfidf FLOAT NOT NULL DEFAULT 0,
  PRIMARY KEY(cluster_index,match_index,id)
)engine=innodb;

với SQL

LOAD DATA INFILE '/mnt/tests/data.csv' INTO TABLE test FIELDS TERMINATED BY ',' LINES TERMINATED BY '\n';"

nhập mô tả hình ảnh ở đây

Bắt tập lệnh để tính toán trước các chỉ mục dường như đã loại bỏ hiệu năng nhấn khi cơ sở dữ liệu tăng kích thước.

Cập nhật 2 - sử dụng bảng nhớ

Nhanh hơn gấp 3 lần, mà không tính đến chi phí di chuyển một bảng trong bộ nhớ sang bảng dựa trên đĩa.

rows:  0  seconds rows:  0:00:26.661321  inserts/sec:  375075.18851
rows:  10000000  time:  0:00:32.765095  inserts/sec:  305202.83857
rows:  20000000  time:  0:00:38.937946  inserts/sec:  256818.888187
rows:  30000000  time:  0:00:35.170084  inserts/sec:  284332.559456
rows:  40000000  time:  0:00:33.371274  inserts/sec:  299658.922222
rows:  50000000  time:  0:00:39.396904  inserts/sec:  253827.051994
rows:  60000000  time:  0:00:37.719409  inserts/sec:  265115.500617
rows:  70000000  time:  0:00:32.993904  inserts/sec:  303086.291334
rows:  80000000  time:  0:00:33.818471  inserts/sec:  295696.396209
rows:  90000000  time:  0:00:33.534934  inserts/sec:  298196.501594

bằng cách tải dữ liệu vào một bảng dựa trên bộ nhớ và sau đó sao chép nó vào một bảng dựa trên đĩa trong một khối có thời gian hoạt động là 10 phút 59,71 giây để sao chép 107.356.741 hàng với truy vấn

insert into test Select * from test2;

làm cho nó mất khoảng 15 phút để tải 100M hàng, tương đương với việc chèn trực tiếp vào bảng dựa trên đĩa.


1
Tôi nghĩ việc thay đổi khóa chính thành chỉ idnên nhanh hơn. (Mặc dù tôi nghĩ rằng bạn không tìm kiếm điều này)
DavidEG

Xin chào David, cảm ơn vì nhận xét, không may là không có khóa mà các truy vấn chúng tôi cần thực hiện không đủ nhanh (logic đằng sau lựa chọn khóa chính được nêu trong bài đăng này stackoverflow.com/questions/4282526/mysql-group-by- tối ưu hóa )
Ben

1
Đây chỉ là để thử nghiệm? Bạn có thể muốn xem công cụ MEM MEM MySQL: dev.mysql.com/doc/refman/5.0/en/memory-st Storage-engine.html Nếu bạn dự định triển khai kiến ​​trúc này như một kiến ​​trúc tôi tò mò về cách bạn dự định phục hồi từ những thất bại, có vẻ như một cái gì đó sẽ được xử lý tốt hơn bởi MapReduce / Hadoop.
đa thức

Xin chào đa thức, cảm ơn vì tiền boa, hiện tại chúng tôi chỉ đang thử nghiệm các trình phát hiện tính năng khác nhau ở các tỷ lệ khác nhau, một khi cơ sở dữ liệu được tạo, nó sẽ không thay đổi nhiều (dù sao trong thông số hiện tại)
Ben

Câu trả lời:


4

Câu hỏi hay - giải thích tốt.

Làm cách nào để điều chỉnh MySQL để tăng tốc độ của cuộc gọi LOAD DATA INFILE?

Bạn đã có cài đặt (ish) cao cho bộ đệm chính - nhưng đã đủ chưa? Tôi giả sử đây là bản cài đặt 64 bit (nếu không thì điều đầu tiên bạn cần làm là nâng cấp) và không chạy trên MSNT. Có một cái nhìn về đầu ra của mysqltuner.pl sau khi chạy một vài thử nghiệm.

Để sử dụng bộ đệm để có hiệu quả tốt nhất, bạn có thể tìm thấy lợi ích trong việc sắp xếp / sắp xếp trước dữ liệu đầu vào (các phiên bản gần đây nhất của lệnh 'sort' có rất nhiều chức năng để sắp xếp các bộ dữ liệu lớn). Ngoài ra nếu bạn tạo số ID bên ngoài MySQL, thì nó có thể hiệu quả hơn.

sẽ sử dụng một cụm máy tính để tải các tệp csv khác nhau

Giả sử (một lần nữa) rằng bạn muốn có bộ đầu ra hoạt động như một bảng duy nhất, thì lợi ích duy nhất bạn sẽ nhận được là bằng cách phân phối công việc sắp xếp và tạo id - mà bạn không cần thêm cơ sở dữ liệu. OTOH sử dụng cụm cơ sở dữ liệu, bạn sẽ gặp vấn đề với sự tranh chấp (mà bạn không nên xem ngoài vấn đề về hiệu suất).

Nếu bạn có thể bảo vệ dữ liệu và xử lý các bộ dữ liệu kết quả một cách độc lập, thì có, bạn sẽ nhận được lợi ích hiệu suất - nhưng điều này không phủ nhận sự cần thiết phải điều chỉnh từng nút.

Kiểm tra xem bạn đã có ít nhất 4 Gb cho sort_buffer_size.

Ngoài ra, yếu tố giới hạn về hiệu suất là tất cả về I / O đĩa. Có rất nhiều cách để giải quyết vấn đề này - nhưng có lẽ bạn nên xem xét một bộ dữ liệu sọc được nhân đôi trên SSD để có hiệu suất tối ưu.


1
  • Hãy xem xét yếu tố giới hạn của bạn. Nó gần như chắc chắn xử lý CPU đơn luồng.
  • Bạn đã xác định rằng load data... nhanh hơn chèn, vì vậy hãy sử dụng nó.
  • Bạn đã xác định rằng các tệp thực sự lớn (theo số hàng) làm chậm rất nhiều thứ; bạn muốn chia chúng thành từng mảnh
  • Sử dụng các khóa chính không chồng lấp, xếp hàng ít nhất các bộ CPU N *, sử dụng không quá một triệu hàng ... có thể ít hơn (điểm chuẩn).
  • Sử dụng các khối liên tiếp của các khóa chính trong mỗi tệp.

Nếu bạn muốn thực sự gọn gàng, bạn có thể tạo một chương trình đa luồng để cung cấp một tệp duy nhất cho một tập hợp các ống có tên và quản lý các trường hợp chèn.

Tóm lại, bạn không điều chỉnh MySQL cho điều này rất nhiều khi bạn điều chỉnh khối lượng công việc của mình sang MySQL.


-1

Tôi không nhớ chính xác cú pháp nhưng nếu là inno db, bạn có thể tắt kiểm tra khóa ngoại.

Ngoài ra, bạn có thể tạo chỉ mục sau khi nhập, đó có thể là mức tăng hiệu suất thực sự.


Việc bảo vệ chỉ mục xây dựng lại chỉ cải thiện hiệu suất trong đó số lượng hàng đã có trong bảng nhỏ hơn đáng kể so với số lượng hàng bạn đang thêm.
symcbean
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.