สร้างตาราง MySQL แถว 1,000M


18

คำถามนี้ถูกโพสต์ใหม่จากStack Overflowตามคำแนะนำในความคิดเห็นขอโทษสำหรับการทำซ้ำ

คำถาม

คำถามที่ 1: เนื่องจากขนาดของตารางฐานข้อมูลมีขนาดใหญ่ขึ้นฉันจะปรับแต่ง MySQL เพื่อเพิ่มความเร็วของการโทรโหลดข้อมูล INFILE ได้อย่างไร

คำถามที่ 2: จะใช้กลุ่มคอมพิวเตอร์เพื่อโหลดไฟล์ csv ที่แตกต่างกันปรับปรุงประสิทธิภาพหรือทำลายไฟล์หรือไม่ (นี่คือภารกิจการทำเครื่องหมายของฉันสำหรับวันพรุ่งนี้โดยใช้ข้อมูลโหลดและเม็ดมีดจำนวนมาก)

เป้าหมาย

เรากำลังลองใช้ชุดตรวจจับคุณสมบัติและพารามิเตอร์การจัดกลุ่มที่แตกต่างกันสำหรับการค้นหารูปภาพดังนั้นเราจึงจำเป็นต้องสามารถสร้างและฐานข้อมูลขนาดใหญ่ได้ในเวลาที่เหมาะสม

ข้อมูลเครื่อง

เครื่องมี ram ขนาด 256 กิ๊กและมีอีก 2 เครื่องที่มี ram เท่ากันถ้ามีวิธีในการปรับปรุงเวลาการสร้างโดยการกระจายฐานข้อมูลหรือไม่?

สคีมาตาราง

คีมาตารางดูเหมือน

+---------------+------------------+------+-----+---------+----------------+
| 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       |                |
+---------------+------------------+------+-----+---------+----------------+

สร้างด้วย

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;

การเปรียบเทียบจนถึงตอนนี้

ขั้นตอนแรกคือการเปรียบเทียบการแทรกจำนวนมากกับการโหลดจากไฟล์ไบนารีลงในตารางว่าง

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

ด้วยความแตกต่างของประสิทธิภาพที่ฉันได้ไปกับการโหลดข้อมูลจากไฟล์ไบนารี csv ก่อนอื่นฉันโหลดไฟล์ไบนารีที่มี 100K, 1M, 20M, 200M แถวโดยใช้การโทรด้านล่าง

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

ฉันฆ่าโหลดไบนารีไฟล์ 200M แถว (~ 3GB csv) โหลดหลังจาก 2 ชั่วโมง

ดังนั้นฉันจึงรันสคริปต์เพื่อสร้างตารางและแทรกจำนวนแถวที่แตกต่างจากไฟล์ไบนารีจากนั้นให้วางตารางดูกราฟด้านล่าง

ป้อนคำอธิบายรูปภาพที่นี่

ใช้เวลาประมาณ 7 วินาทีในการแทรก 1M แถวจากไฟล์ไบนารี ต่อไปฉันตัดสินใจสร้างเกณฑ์มาตรฐานการแทรกแถว 1M ในเวลาเพื่อดูว่าจะมีคอขวดที่ขนาดฐานข้อมูลที่เฉพาะเจาะจง เมื่อฐานข้อมูลไปถึงแถวประมาณ 59M เวลาแทรกเฉลี่ยลดลงไปประมาณ 5,000 / วินาที

ป้อนคำอธิบายรูปภาพที่นี่

การตั้งค่า global key_buffer_size = 4294967296 ปรับปรุงความเร็วเล็กน้อยสำหรับการแทรกไฟล์ไบนารีขนาดเล็กลง กราฟด้านล่างแสดงความเร็วสำหรับจำนวนแถวที่แตกต่างกัน

ป้อนคำอธิบายรูปภาพที่นี่

อย่างไรก็ตามสำหรับการแทรก 1M แถวมันไม่ได้ปรับปรุงประสิทธิภาพ

แถว: 1,000,000 เวลา: 0: 04: 13.761428 ส่วนแทรก / วินาที: 3,940

vs สำหรับฐานข้อมูลเปล่า

แถว: 1,000,000 เวลา: 0: 00: 6.339295 ส่วนแทรก / วินาที: 315,492

ปรับปรุง

ทำการโหลดข้อมูลโดยใช้ลำดับต่อไปนี้เทียบกับการใช้คำสั่งโหลดข้อมูล

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;
ป้อนคำอธิบายรูปภาพที่นี่

ดังนั้นสิ่งนี้จึงมีแนวโน้มที่ค่อนข้างสดใสในแง่ของขนาดฐานข้อมูลที่ถูกสร้างขึ้น แต่การตั้งค่าอื่น ๆ จะไม่ส่งผลต่อประสิทธิภาพของการเรียก infile data ของโหลด

ฉันพยายามโหลดหลายไฟล์จากเครื่องที่แตกต่างกัน แต่คำสั่งโหลดข้อมูล infile ล็อคตารางเนื่องจากไฟล์มีขนาดใหญ่ทำให้เครื่องอื่นหมดเวลา

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

การเพิ่มจำนวนแถวในไฟล์ไบนารี

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

การแก้ไข: การคำนวณรหัสล่วงหน้านอก MySQL แทนที่จะใช้การเพิ่มอัตโนมัติ

สร้างตารางด้วย

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;

ด้วย SQL

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

ป้อนคำอธิบายรูปภาพที่นี่

การเรียกใช้สคริปต์เพื่อคำนวณล่วงหน้าดัชนีดูเหมือนว่าจะลบประสิทธิภาพการทำงานเมื่อฐานข้อมูลมีขนาดเพิ่มขึ้น

อัปเดต 2 - ใช้ตารางหน่วยความจำ

เร็วขึ้น 3 เท่าโดยไม่คำนึงถึงค่าใช้จ่ายในการย้ายตารางในหน่วยความจำไปยังตารางที่ใช้ดิสก์

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

โดยการโหลดข้อมูลลงในตารางที่ใช้หน่วยความจำแล้วคัดลอกไปยังตารางตามดิสก์ในหน่วยมีค่าใช้จ่าย 10 นาที 59.71 วินาทีเพื่อคัดลอก 107,356,741 แถวด้วยแบบสอบถาม

insert into test Select * from test2;

ซึ่งใช้เวลาประมาณ 15 นาทีในการโหลดแถว 100M ซึ่งจะประมาณเดียวกับการแทรกลงในตารางที่อิงกับดิสก์โดยตรง


1
ฉันคิดว่าการเปลี่ยนคีย์หลักเป็นidควรเร็วขึ้น (แม้ว่าฉันคิดว่าคุณไม่ได้มองหาสิ่งนี้)
DavidEG

สวัสดีเดวิดขอบคุณสำหรับความคิดเห็นน่าเสียดายที่ไม่มีคำสั่งที่เราต้องทำนั้นไม่เร็วพอ (ตรรกะที่อยู่เบื้องหลังการเลือกคีย์หลักนั้นมีอยู่ในโพสต์นี้stackoverflow.com/questions/4282526/mysql-group-by- การเพิ่มประสิทธิภาพ )
Ben

1
นี่เป็นเพียงการทดสอบหรือไม่ คุณอาจต้องการดูเครื่องมือ MySQL MEMORY: dev.mysql.com/doc/refman/5.0/en/memory-storage-engine.html หากคุณวางแผนที่จะปรับใช้สิ่งนี้เป็นสถาปัตยกรรมฉันอยากรู้ว่าคุณวางแผนอย่างไร กู้คืนจากความล้มเหลวดูเหมือนว่าบางสิ่งที่จะจัดการได้ดีขึ้นโดย MapReduce / Hadoop
พหุนาม

สวัสดีพหุนามขอบคุณสำหรับเคล็ดลับในขณะที่เราเป็นเพียงการทดสอบเครื่องตรวจจับคุณลักษณะที่แตกต่างกันในระดับที่แตกต่างกันเมื่อฐานข้อมูลถูกสร้างขึ้นมันเคยชินเปลี่ยนแปลงมาก (ในปัจจุบันข้อมูลจำเพาะต่อไป)
เบน

คำตอบ:


4

เป็นคำถามที่ดี - อธิบายได้ดี

ฉันจะปรับ MySQL เพื่อเพิ่มความเร็วของการโทรโหลดข้อมูล INFILE ได้อย่างไร?

คุณมีการตั้งค่าสูง (ish) สำหรับบัฟเฟอร์คีย์ - แต่มันเพียงพอหรือไม่ ฉันสมมติว่านี่เป็นการติดตั้ง 64 บิต (หากไม่ใช่อย่างแรกที่คุณต้องทำคืออัพเกรด) และไม่ทำงานบน MSNT ดูผลลัพธ์ของ mysqltuner.pl หลังจากทำการทดสอบสองสามครั้ง

ในการใช้แคชเพื่อให้ได้ผลดีที่สุดคุณอาจพบประโยชน์ในการแบตช์ / เรียงลำดับข้อมูลอินพุตล่วงหน้า (คำสั่ง 'เรียงลำดับ' รุ่นล่าสุดมีฟังก์ชันการทำงานมากมายสำหรับการเรียงชุดข้อมูลขนาดใหญ่) นอกจากนี้หากคุณสร้างหมายเลข ID นอก MySQL ก็อาจมีประสิทธิภาพมากกว่า

จะใช้กลุ่มคอมพิวเตอร์เพื่อโหลดไฟล์ csv ที่แตกต่างกัน

สมมติว่า (อีกครั้ง) ที่คุณต้องการให้ชุดเอาต์พุตทำหน้าที่เป็นตารางเดียวจากนั้นคุณจะได้รับประโยชน์เพียงอย่างเดียวคือการกระจายงานการเรียงลำดับและสร้างรหัสซึ่งคุณไม่ต้องการฐานข้อมูลเพิ่มเติม OTOH โดยใช้คลัสเตอร์ฐานข้อมูลคุณจะได้รับปัญหาเกี่ยวกับการช่วงชิง (ซึ่งคุณไม่ควรมองว่าเป็นปัญหาเรื่องประสิทธิภาพ)

หากคุณสามารถแบ่งข้อมูลและจัดการชุดข้อมูลที่เป็นผลลัพธ์ให้เป็นอิสระคุณจะได้รับประโยชน์ด้านประสิทธิภาพ แต่ไม่ได้เป็นการลบความต้องการปรับแต่งแต่ละโหนด

ตรวจสอบว่าคุณมีอย่างน้อย 4 Gb สำหรับ sort_buffer_size

นอกเหนือจากนั้นปัจจัยที่ จำกัด ในการปฏิบัติงานคือทั้งหมดที่เกี่ยวกับดิสก์ I / O มีหลายวิธีในการแก้ไขปัญหานี้ - แต่คุณควรจะพิจารณาชุดข้อมูลชุดลายทางแบบมิร์เรอร์บน SSD เพื่อประสิทธิภาพที่ดีที่สุด


1
  • พิจารณาปัจจัย จำกัด ของคุณ เป็นการประมวลผล CPU แบบเธรดเดียวเกือบแน่นอน
  • คุณได้พิจารณาแล้วว่าload data...เร็วกว่าการแทรกดังนั้นใช้
  • คุณได้พิจารณาแล้วว่าไฟล์ที่มีขนาดใหญ่มาก (โดยหมายเลขแถว) ทำให้ช้าลงมาก คุณต้องการที่จะทำลายพวกเขาเป็นชิ้น ๆ
  • การใช้คีย์หลักที่ไม่ทับซ้อนกันตั้งคิวอย่างน้อย N * CPU โดยใช้ไม่เกินหนึ่งล้านแถว ... อาจน้อยกว่า (มาตรฐาน)
  • ใช้บล็อกลำดับของคีย์หลักในแต่ละไฟล์

ถ้าคุณต้องการที่จะ spiffy จริงๆคุณสามารถสร้างโปรแกรมแบบมัลติเธรดเพื่อฟีดไฟล์เดียวไปยังคอลเลกชันของไปป์ที่มีชื่อและจัดการอินสแตนซ์แทรก

โดยสรุปคุณไม่ปรับแต่ง MySQL สำหรับสิ่งนี้มากพอ ๆ กับการปรับปริมาณงานของคุณเป็น MySQL


-1

ฉันจำไม่ได้ว่า syntacx แต่ถ้าเป็น inno db คุณสามารถปิดการตรวจสอบกุญแจต่างประเทศได้

นอกจากนี้คุณสามารถสร้างดัชนีได้หลังจากการนำเข้ามันสามารถเพิ่มประสิทธิภาพได้จริง ๆ


การเลื่อนการสร้างดัชนีใหม่จะช่วยเพิ่มประสิทธิภาพเท่านั้นเมื่อจำนวนแถวในตารางมีขนาดเล็กกว่าจำนวนแถวที่คุณเพิ่ม
symcbean
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.