วิธีอัปเดต 10 ล้านแถวใน MySQL ตารางเดียวเร็วที่สุด


32

ใช้ 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 จากไฟล์และอัปเดตในฐานข้อมูล

อะไรคือวิธีที่ดีที่สุดในการบรรลุสิ่งนี้

ฉันต้องทำสิ่งนี้ทุกวัน

ปัจจุบันกระแสเป็นเช่นนี้:

  1. mysqli_begin_transaction
  2. อ่านการถ่ายโอนข้อมูลไฟล์ทีละบรรทัด
  3. อัปเดตแต่ละระเบียนทีละบรรทัด
  4. 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 จะอัปเดตเมื่อเสร็จสิ้นการทำเครื่องหมาย


คุณมีคอมโพสิต INDEX(field2, field3, field4) (ในลำดับใด ๆ )? SHOW CREATE TABLEโปรดแสดงให้เราเห็น
Rick James

1
ดัชนี 12 และ 8 เป็นปัญหาที่ร้ายแรงของคุณ MyISAM เป็นอีกส่วนที่สำคัญ InnoDB หรือ TokuDB ทำงานได้ดียิ่งขึ้นด้วยดัชนีหลายรายการ
Rick James

คุณมีสองที่แตกต่างกัน UPDATEsโปรดบอกเราว่าข้อความที่ตรงไปตรงมานั้นมีลักษณะอย่างไรสำหรับการอัพเดตตารางจากข้อมูล csv จากนั้นเราอาจสามารถช่วยคุณจัดทำเทคนิคที่ตรงกับความต้องการของคุณ
Rick James

@RickJames มีเพียงรายการเดียวupdateและโปรดตรวจสอบคำถามที่อัปเดตแล้วขอบคุณ
AMB

คำตอบ:


17

จากประสบการณ์ของฉันฉันจะใช้LOAD DATA INFILEเพื่อนำเข้าไฟล์ CSV ของคุณ

คำสั่งโหลดข้อมูล INFILE อ่านแถวจากไฟล์ข้อความลงในตารางด้วยความเร็วสูงมาก

ตัวอย่างที่ฉันพบในอินเทอร์เน็ตโหลดข้อมูลตัวอย่างเช่น ฉันทดสอบตัวอย่างนี้ในกล่องและทำงานได้ดี

ตารางตัวอย่าง

CREATE TABLE example (
  `Id` int(11) NOT NULL AUTO_INCREMENT,
  `Column2` varchar(14) NOT NULL,
  `Column3` varchar(14) NOT NULL,
  `Column4` varchar(14) NOT NULL,
  `Column5` DATE NOT NULL,
  PRIMARY KEY (`Id`)
) ENGINE=InnoDB

ตัวอย่างไฟล์ CSV

# more /tmp/example.csv
Column1,Column2,Column3,Column4,Column5
1,A,Foo,sdsdsd,4/13/2013
2,B,Bar,sdsa,4/12/2013
3,C,Foo,wewqe,3/12/2013
4,D,Bar,asdsad,2/1/2013
5,E,FOObar,wewqe,5/1/2013

คำสั่งนำเข้าที่จะเรียกใช้จากคอนโซล MySQL

LOAD DATA LOCAL INFILE '/tmp/example.csv'
    -> INTO TABLE example
    -> FIELDS TERMINATED BY ','
    -> LINES TERMINATED BY '\n'
    -> IGNORE 1 LINES
    -> (id, Column3,Column4, @Column5)
    -> set
    -> Column5 = str_to_date(@Column5, '%m/%d/%Y');

ผล

MySQL [testcsv]> select * from example;
+----+---------+---------+---------+------------+
| Id | Column2 | Column3 | Column4 | Column5    |
+----+---------+---------+---------+------------+
|  1 |         | Column2 | Column3 | 0000-00-00 |
|  2 |         | B       | Bar     | 0000-00-00 |
|  3 |         | C       | Foo     | 0000-00-00 |
|  4 |         | D       | Bar     | 0000-00-00 |
|  5 |         | E       | FOObar  | 0000-00-00 |
+----+---------+---------+---------+------------+

IGNORE เพียงแค่ละเว้นบรรทัดแรกซึ่งเป็นส่วนหัวคอลัมน์

หลังจาก IGNORE เรากำลังระบุคอลัมน์ (ข้ามคอลัมน์ 2) เพื่อนำเข้าซึ่งตรงกับหนึ่งในเกณฑ์ในคำถามของคุณ

นี่เป็นอีกตัวอย่างโดยตรงจาก Oracle: ตัวอย่างโหลดข้อมูล INFILE

นี่น่าจะเพียงพอสำหรับคุณในการเริ่มต้น


ฉันสามารถใช้ข้อมูลโหลดสำหรับการโหลดข้อมูลในตาราง temp แล้วใช้คำสั่งอื่น ๆ เพื่ออัปเดตในตารางหลักขอบคุณ
AMB

14

ในแง่ของทุกสิ่งที่กล่าวถึงดูเหมือนว่าคอขวดคือการรวมตัวเอง

ASPECT # 1: เข้าร่วมขนาดบัฟเฟอร์

ในทุกโอกาสjoin_buffer_sizeของคุณอาจต่ำเกินไป

ตามเอกสาร MySQL เกี่ยวกับวิธีที่ MySQL ใช้ Join Cache Buffer

เราเก็บเฉพาะคอลัมน์ที่ใช้ในบัฟเฟอร์การเข้าร่วมไม่ใช่แถวทั้งหมด

ในกรณีนี้ให้คีย์ของบัฟเฟอร์การเข้าร่วมอยู่ใน RAM

คุณมี 10 ล้านแถวคูณ 4 ไบต์สำหรับแต่ละคีย์ นั่นคือประมาณ 40M

ลองกระแทกในเซสชั่นถึง 42M (ใหญ่กว่า 40M เล็กน้อย)

SET join_buffer_size = 1024 * 1024 * 42;
UPDATE table1 a JOIN table2 b 
ON a.field1 = b.field1 
SET 
a.field2 = b.field2,
a.field3 = b.field3,
a.field4 = b.field4;

หากนี่เป็นกลอุบายให้เพิ่มส่วนนี้ไป my.cnf

[mysqld]
join_buffer_size = 42M

ไม่จำเป็นต้องทำการรีสตาร์ท mysqld สำหรับการเชื่อมต่อใหม่ เพียงแค่วิ่ง

mysql> SET GLOBAL join_buffer_size = 1024 * 1024 * 42;

ASPECT # 2: เข้าร่วมการดำเนินการ

คุณสามารถจัดการรูปแบบของการดำเนินการเข้าร่วมได้โดยการเพิ่มประสิทธิภาพของ tweeking

ตามเอกสาร MySQL เกี่ยวกับBlock Nested-Loop และ Batched Key Access Joins

เมื่อใช้ BKA ค่าของ join_buffer_size จะกำหนดจำนวนชุดของคีย์ในแต่ละคำขอไปยังเอ็นจิ้นการจัดเก็บ ยิ่งบัฟเฟอร์มีขนาดใหญ่ขึ้นการเข้าถึงที่ต่อเนื่องมากขึ้นจะไปที่ตารางด้านขวาของการดำเนินการเข้าร่วมซึ่งสามารถปรับปรุงประสิทธิภาพได้อย่างมาก

เพื่อให้ใช้ BKA ได้ต้องตั้งค่าสถานะ batched_key_access ของตัวแปรระบบ optimizer_switch BKA ใช้ MRR ดังนั้นจึงต้องเปิดแฟล็ก mrr ด้วย ปัจจุบันการประมาณราคาสำหรับ MRR นั้นมองในแง่ร้ายเกินไป ดังนั้นจึงจำเป็นสำหรับ mrr_cost_based ที่จะปิดใช้งาน BKA

หน้าเดียวกันนี้แนะนำให้ทำสิ่งนี้:

mysql> SET optimizer_switch='mrr=on,mrr_cost_based=off,batched_key_access=on';

ASPECT # 3: การเขียนการอัปเดตลงดิสก์ (ตัวเลือก)

ส่วนใหญ่ลืมที่จะเพิ่มinnodb_write_io_threadsเพื่อเขียนหน้าสกปรกออกจากบัฟเฟอร์พูลเร็วขึ้น

[mysqld]
innodb_write_io_threads = 16

คุณจะต้องเริ่ม MySQL ใหม่สำหรับการเปลี่ยนแปลงนี้

ให้มันลอง !!!


ดี! +1 สำหรับเคล็ดลับบัฟเฟอร์การเข้าร่วมที่ปรับค่าได้ หากคุณต้องเข้าร่วมเข้าร่วมในหน่วยความจำ เคล็ดลับดี!
Peter Dixon-Moses

3
  1. CREATE TABLE ที่ตรงกับ CSV
  2. LOAD DATA ลงในตารางนั้น
  3. UPDATE real_table JOIN csv_table ON ... SET ..., ..., ...;
  4. DROP TABLE csv_table;

ขั้นตอนที่ 3 จะเร็วกว่ากันมาก แต่จะยังคงล็อคแถวทั้งหมดในตารางตามระยะเวลาที่ไม่สำคัญ หากเวลาล็อคนี้สำคัญกว่าระยะเวลาที่ใช้ในกระบวนการทั้งหมด ...

หากไม่มีอะไรเขียนถึงโต๊ะอยู่ ...

  1. CREATE TABLEที่ตรงกับ CSV; ดัชนีไม่ยกเว้นสิ่งที่จำเป็นในในJOIN ถ้าไม่ซ้ำกันทำให้มันUPDATEPRIMARY KEY
  2. LOAD DATA ลงในตารางนั้น
  3. คัดลอกreal_tableไปยังnew_table( CREATE ... SELECT)
  4. UPDATE new_table JOIN csv_table ON ... SET ..., ..., ...;
  5. RENAME TABLE real_table TO old, new_table TO real_table;
  6. DROP TABLE csv_table, old;

ขั้นตอนที่ 3 เร็วกว่าการอัปเดตโดยเฉพาะอย่างยิ่งหากดัชนีที่ไม่จำเป็นถูกทิ้งไว้
ขั้นตอนที่ 5 คือ "ทันที"


สมมติว่าในตัวอย่างวินาทีหลังจากขั้นตอนที่ 3 เรากำลังทำขั้นตอนที่ 4 จากนั้นข้อมูลใหม่จะถูกแทรกใน real_table ดังนั้นเราจะพลาดข้อมูลนั้นใน new_table หรือไม่ วิธีแก้ปัญหาสำหรับสิ่งนี้คืออะไร? ขอบคุณ
AMB

ดูอะไรpt-online-schema-digest; TRIGGERมันดูแลปัญหาดังกล่าวผ่านทาง
Rick James

คุณอาจไม่จำเป็นต้องมีการจัดทำดัชนีใด ๆ LOAD DATAบนโต๊ะจาก การเพิ่มดัชนีที่ไม่จำเป็นนั้นมีค่าใช้จ่ายสูง
Rick James

จากข้อมูลล่าสุดฉันกำลังโน้มตัวไปยังไฟล์ CSV ที่กำลังโหลดลงในตาราง MyISAM ด้วยการเพียงแค่AUTO_INCREMENTแถวที่ 1K ในเวลาเดียวกันโดยอิงตาม PK แต่ฉันต้องดูข้อกำหนดทั้งหมดและสคีมาของตารางก่อนที่จะพยายามตรวจสอบรายละเอียด
Rick James

ฉันได้ตั้งค่าแฮชเป็นPRIMARY indexแล้ว แต่ในขณะที่ chunking ใน 50k โดยใช้คิวรีคำสั่งใช้เวลามากขึ้นมันจะดีกว่าไหมถ้าฉันสร้างการเพิ่มอัตโนมัติ? และตั้งเป็นPRIMARY index?
AMB

3

คุณเคยพูดว่า:

  • การอัปเดตมีผลต่อ 6-25% ของตารางของคุณ
  • คุณต้องการทำสิ่งนี้ให้เร็วที่สุด (<1 ชม.)
  • โดยไม่ต้องล็อค
  • ไม่จำเป็นต้องอยู่ในธุรกรรมเดียว
  • ยัง (ในความคิดเห็นเกี่ยวกับคำตอบของ Rick James) คุณแสดงความกังวลเกี่ยวกับสภาพการแข่งขัน

หลายข้อความเหล่านี้อาจขัดแย้งกัน ตัวอย่างเช่นการอัพเดตขนาดใหญ่ที่ไม่มีการล็อกตาราง หรือหลีกเลี่ยงสภาพการแข่งขันที่ไม่มีธุรกรรมขนาดยักษ์

นอกจากนี้เนื่องจากตารางของคุณได้รับการจัดทำดัชนีอย่างหนักทั้งส่วนแทรกและอัพเดตอาจช้า


หลีกเลี่ยงสภาพการแข่งขัน

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

วิธีนี้ทำให้คุณสามารถทำการอัปเดตทีละบรรทัด (ตามที่คุณทำอยู่ในขณะนี้) แต่ด้วยชุดการทำธุรกรรมอัตโนมัติหรือการทำธุรกรรมที่สมเหตุสมผลมากขึ้น

คุณหลีกเลี่ยงสภาพการแข่งขัน (ในขณะที่อัพเดตทีละบรรทัด) โดยทำการตรวจสอบว่าการอัพเดตในภายหลังไม่ได้เกิดขึ้น ( UPDATE ... WHERE pk = [pk] AND updated < [batchfile date])

และที่สำคัญมันช่วยให้คุณสามารถรันการอัพเดทแบบขนานได้


วิ่งเร็วที่สุด - ขนาน

ด้วยการตรวจสอบตราประทับเวลานี้อยู่ในสถานที่:

  1. แบ่งไฟล์แบตช์ของคุณออกเป็นชิ้นขนาดที่เหมาะสม (พูด 50,000 แถว / ไฟล์)
  2. ในแบบขนานให้มีสคริปต์อ่านในแต่ละไฟล์และส่งออกไฟล์ที่มีคำสั่ง 50,000 UPDATE
  3. ในแบบคู่ขนานเมื่อเสร็จสิ้น (2) ครั้งให้mysqlเรียกใช้ไฟล์ sql แต่ละไฟล์

(เช่นในการbashมองหาsplitและxargs -Pหาวิธีที่จะเรียกใช้คำสั่งได้หลายวิธีขนานกันง่าย ๆ ระดับของการขนานขึ้นอยู่กับจำนวนเธรดที่คุณต้องการอุทิศให้กับการอัปเดต )


โปรดทราบว่า "ทีละบรรทัด" น่าจะช้ากว่าการทำสิ่งต่าง ๆ เป็นแบทช์อย่างน้อย 100 เท่า
Rick James

คุณต้องทำการเปรียบเทียบในกรณีนี้เพื่อให้แน่ใจ การอัปเดตตาราง 6-25% ของตาราง (ด้วยดัชนี 8 ตัวที่เกี่ยวข้องกับคอลัมน์ที่อัปเดต) ฉันขอรับรองความเป็นไปได้ที่การบำรุงรักษาดัชนีจะกลายเป็นปัญหาคอขวด
Peter Dixon-Moses

ฉันหมายถึงในบางกรณีมันอาจจะเร็วกว่าที่จะวางดัชนีอัปเดตเป็นกลุ่มและสร้างพวกเขาใหม่หลังจาก ... แต่ OP ไม่ต้องการการหยุดทำงาน
Peter Dixon-Moses

1

การอัปเดตขนาดใหญ่นั้นถูกผูกไว้กับ I / O ฉันจะแนะนำ:

  1. สร้างตารางที่แตกต่างกันซึ่งจะจัดเก็บ 3 ฟิลด์ที่อัปเดตบ่อยๆของคุณ ลองเรียกหนึ่งตารางasset_staticที่ซึ่งคุณเก็บไว้ดีข้อมูลคงที่และasset_dynamicอื่น ๆที่จะเก็บผู้อัปโหลดเครื่องมือดาวน์โหลดและตรวจสอบความถูกต้อง
  2. หากคุณสามารถทำได้ให้ใช้เอ็นจิน MEMORY สำหรับตารางasset_dynamic (สำรองข้อมูลลงดิสก์หลังจากอัพเดตแต่ละครั้ง)
  3. อัปเดตที่มีน้ำหนักเบาและว่องไวของคุณassets_dynamicตามการปรับปรุง 4 ของคุณ (เช่น INFILE โหลด ... INTO อุณหภูมิ; UPDATE assets_dynamicเข้าร่วมอุณหภูมิ B บน a.id = b.id SET [สิ่งที่จะต้องมีการอัปเดต] นี้ควรใช้เวลาน้อยกว่า. นาที (ในระบบของเราasset_dynamicมีแถว 95M และอัปเดตส่งผลกระทบต่อแถว ~ 6M ในมากกว่า 40 วินาที)
  4. เมื่อคุณเรียกใช้ตัวทำดัชนีของสฟิงซ์ JOIN assets_staticและassets_dynamic (สมมติว่าคุณต้องการใช้หนึ่งในฟิลด์เหล่านี้เป็นแอตทริบิวต์)

0

สำหรับทาง UPDATEวิ่งเร็วคุณต้อง

INDEX(uploaders, downloaders, verified)

มันสามารถอยู่บนโต๊ะทั้งสอง ทั้งสามฟิลด์สามารถอยู่ในลำดับใดก็ได้

ที่จะอำนวยความสะดวก UPDATEสามารถจับคู่แถวระหว่างตารางทั้งสองได้อย่างรวดเร็ว

และทำให้ประเภทข้อมูลเดียวกันในสองตาราง (ทั้งสองINT SIGNEDหรือทั้งสองINT UNSIGNED)


สิ่งนี้ทำให้การอัปเดตช้าลงจริง ๆ
AMB

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