ใช้ MySQL 5.6 กับเครื่องมือจัดเก็บข้อมูล InnoDB สำหรับตารางส่วนใหญ่ ขนาดบัฟเฟอร์พูล InnoDB คือ 15 GB และดัชนี Innodb DB + มีขนาดประมาณ 10 GB เซิร์ฟเวอร์มี RAM 32GB และใช้งาน Cent OS 7 x64
ฉันมีตารางใหญ่หนึ่งตารางที่มีเร็กคอร์ดประมาณ 10 ล้านรายการ
ฉันได้รับไฟล์ดัมพ์ที่อัปเดตจากเซิร์ฟเวอร์ระยะไกลทุก 24 ชั่วโมง ไฟล์อยู่ในรูปแบบ csv ฉันไม่สามารถควบคุมรูปแบบนั้นได้ ไฟล์นี้มีขนาด ~ 750 MB ฉันพยายามแทรกข้อมูลลงในตาราง MyISAM แบบแถวต่อแถวและใช้เวลา 35 นาที
ฉันต้องใช้เพียง 3 ค่าต่อบรรทัดจาก 10-12 จากไฟล์และอัปเดตในฐานข้อมูล
อะไรคือวิธีที่ดีที่สุดในการบรรลุสิ่งนี้
ฉันต้องทำสิ่งนี้ทุกวัน
ปัจจุบันกระแสเป็นเช่นนี้:
- mysqli_begin_transaction
- อ่านการถ่ายโอนข้อมูลไฟล์ทีละบรรทัด
- อัปเดตแต่ละระเบียนทีละบรรทัด
- mysqli_commit
การดำเนินการด้านบนใช้เวลาประมาณ30-40 นาทีในการดำเนินการและในขณะที่ทำสิ่งนี้มีการอัปเดตอื่น ๆ ที่เกิดขึ้นกับฉัน
ล็อกการหมดเวลารอของการล็อคเกิน ลองรีสตาร์ทธุรกรรม
อัปเดต 1
LOAD DATA LOCAL INFILE
การโหลดข้อมูลในตารางใหม่โดยใช้ ใน MyISAM ใช้เวลา38.93 sec
ใน InnoDB ใช้เวลา 7 นาที 5.21 วินาที จากนั้นฉันก็:
UPDATE table1 t1, table2 t2
SET
t1.field1 = t2.field1,
t1.field2 = t2.field2,
t1.field3 = t2.field3
WHERE t1.field10 = t2.field10
Query OK, 434914 rows affected (22 hours 14 min 47.55 sec)
อัปเดต 2
อัปเดตเดียวกันกับแบบสอบถามการเข้าร่วม
UPDATE table1 a JOIN table2 b
ON a.field1 = b.field1
SET
a.field2 = b.field2,
a.field3 = b.field3,
a.field4 = b.field4
(14 hours 56 min 46.85 sec)
คำชี้แจงจากคำถามในความคิดเห็น:
- ไฟล์ประมาณ 6% ของแถวในตารางจะได้รับการอัปเดต แต่บางครั้งอาจมีมากถึง 25%
- มีดัชนีในฟิลด์ที่กำลังอัพเดต ตารางมี 12 ดัชนีและ 8 ดัชนีรวมเขตข้อมูลการปรับปรุง
- ไม่จำเป็นต้องทำการอัปเดตในหนึ่งธุรกรรม อาจใช้เวลา แต่ไม่เกิน 24 ชั่วโมง ฉันต้องการทำมันให้เสร็จภายใน 1 ชั่วโมงโดยไม่ต้องล็อคทั้งโต๊ะเนื่องจากภายหลังฉันต้องอัพเดตดัชนีสฟิงซ์ซึ่งขึ้นอยู่กับตารางนี้ ไม่สำคัญว่าขั้นตอนจะใช้เวลานานขึ้นตราบใดที่ฐานข้อมูลพร้อมใช้งานอื่น ๆ
- ฉันสามารถแก้ไขรูปแบบ csv ในขั้นตอน preprocess สิ่งเดียวที่สำคัญคือการอัพเดทอย่างรวดเร็วและไม่ล็อค
- ตารางที่ 2 คือ MyISAM เป็นตารางที่สร้างขึ้นใหม่จากไฟล์ csv โดยใช้ infile โหลดข้อมูล ขนาดไฟล์ MYI คือ 452 MB ตารางที่ 2 ถูกทำดัชนีในคอลัมน์ field1
- MYD ของตาราง MyISAM คือ 663MB
อัปเดต 3:
นี่คือรายละเอียดเพิ่มเติมเกี่ยวกับทั้งสองตาราง
CREATE TABLE `content` (
`hash` char(40) CHARACTER SET ascii NOT NULL DEFAULT '',
`title` varchar(255) COLLATE utf8_unicode_ci NOT NULL DEFAULT '',
`og_name` varchar(255) COLLATE utf8_unicode_ci NOT NULL DEFAULT '',
`keywords` varchar(255) COLLATE utf8_unicode_ci NOT NULL DEFAULT '',
`files_count` smallint(5) unsigned NOT NULL DEFAULT '0',
`more_files` smallint(5) unsigned NOT NULL DEFAULT '0',
`files` varchar(255) COLLATE utf8_unicode_ci NOT NULL DEFAULT '0',
`category` smallint(3) unsigned NOT NULL DEFAULT '600',
`size` bigint(19) unsigned NOT NULL DEFAULT '0',
`downloaders` int(11) NOT NULL DEFAULT '0',
`completed` int(11) NOT NULL DEFAULT '0',
`uploaders` int(11) NOT NULL DEFAULT '0',
`creation_date` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
`upload_date` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
`last_updated` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
`vote_up` int(11) unsigned NOT NULL DEFAULT '0',
`vote_down` int(11) unsigned NOT NULL DEFAULT '0',
`comments_count` int(11) NOT NULL DEFAULT '0',
`imdb` int(8) unsigned NOT NULL DEFAULT '0',
`video_sample` tinyint(1) NOT NULL DEFAULT '0',
`video_quality` tinyint(2) NOT NULL DEFAULT '0',
`audio_lang` varchar(127) CHARACTER SET ascii NOT NULL DEFAULT '',
`subtitle_lang` varchar(127) CHARACTER SET ascii NOT NULL DEFAULT '',
`verified` tinyint(1) unsigned NOT NULL DEFAULT '0',
`uploader` int(11) unsigned NOT NULL DEFAULT '0',
`anonymous` tinyint(1) NOT NULL DEFAULT '0',
`enabled` tinyint(1) unsigned NOT NULL DEFAULT '0',
`tfile_size` int(11) unsigned NOT NULL DEFAULT '0',
`scrape_source` tinyint(1) unsigned NOT NULL DEFAULT '0',
`record_num` int(11) unsigned NOT NULL AUTO_INCREMENT,
PRIMARY KEY (`record_num`),
UNIQUE KEY `hash` (`hash`),
KEY `uploaders` (`uploaders`),
KEY `tfile_size` (`tfile_size`),
KEY `enabled_category_upload_date_verified_` (`enabled`,`category`,`upload_date`,`verified`),
KEY `enabled_upload_date_verified_` (`enabled`,`upload_date`,`verified`),
KEY `enabled_category_verified_` (`enabled`,`category`,`verified`),
KEY `enabled_verified_` (`enabled`,`verified`),
KEY `enabled_uploader_` (`enabled`,`uploader`),
KEY `anonymous_uploader_` (`anonymous`,`uploader`),
KEY `enabled_uploaders_upload_date_` (`enabled`,`uploaders`,`upload_date`),
KEY `enabled_verified_category` (`enabled`,`verified`,`category`),
KEY `verified_enabled_category` (`verified`,`enabled`,`category`)
) ENGINE=InnoDB AUTO_INCREMENT=7551163 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci ROW_FORMAT=FIXED
CREATE TABLE `content_csv_dump_temp` (
`hash` char(40) CHARACTER SET ascii NOT NULL DEFAULT '',
`title` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
`category_id` int(11) unsigned NOT NULL DEFAULT '0',
`uploaders` int(11) unsigned NOT NULL DEFAULT '0',
`downloaders` int(11) unsigned NOT NULL DEFAULT '0',
`verified` tinyint(1) unsigned NOT NULL DEFAULT '0',
PRIMARY KEY (`hash`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci
และนี่คือคิวรีการอัปเดตที่content
ตารางอัพเดตใช้ข้อมูลจากcontent_csv_dump_temp
UPDATE content a JOIN content_csv_dump_temp b
ON a.hash = b.hash
SET
a.uploaders = b.uploaders,
a.downloaders = b.downloaders,
a.verified = b.verified
อัปเดต 4:
การทดสอบทั้งหมดข้างต้นทำในเครื่องทดสอบ แต่ตอนนี้ฉันทำการทดสอบแบบเดียวกันกับเครื่องผลิตและเคียวรีนั้นเร็วมาก
mysql> UPDATE content_test a JOIN content_csv_dump_temp b
-> ON a.hash = b.hash
-> SET
-> a.uploaders = b.uploaders,
-> a.downloaders = b.downloaders,
-> a.verified = b.verified;
Query OK, 2673528 rows affected (7 min 50.42 sec)
Rows matched: 7044818 Changed: 2673528 Warnings: 0
ฉันขอโทษสำหรับความผิดพลาดของฉัน ควรใช้การเข้าร่วมแทนการอัปเดตแต่ละระเบียน ตอนนี้ฉันพยายามปรับปรุง mpre โดยใช้ดัชนีที่แนะนำโดย rick_james จะอัปเดตเมื่อเสร็จสิ้นการทำเครื่องหมาย
UPDATEs
โปรดบอกเราว่าข้อความที่ตรงไปตรงมานั้นมีลักษณะอย่างไรสำหรับการอัพเดตตารางจากข้อมูล csv จากนั้นเราอาจสามารถช่วยคุณจัดทำเทคนิคที่ตรงกับความต้องการของคุณ
update
และโปรดตรวจสอบคำถามที่อัปเดตแล้วขอบคุณ
INDEX(field2, field3, field4)
(ในลำดับใด ๆ )?SHOW CREATE TABLE
โปรดแสดงให้เราเห็น