วิธีการใช้การหน่วงเวลาการแทรกด้วยเอ็นจิน InnoDB และใช้การเชื่อมต่อน้อยลงสำหรับการแทรกคำสั่ง


10

ฉันกำลังทำงานกับแอปพลิเคชันที่เกี่ยวข้องกับการเขียนฐานข้อมูลจำนวนมากมีการแทรกประมาณ 70% และการอ่าน 30% อัตราส่วนนี้จะรวมการอัปเดตซึ่งฉันคิดว่าเป็นหนึ่งการอ่านและการเขียนหนึ่งครั้ง ผ่านคำสั่งแทรกไคลเอนต์หลายคนแทรกข้อมูลในฐานข้อมูลผ่านคำสั่งแทรกด้านล่าง:

$mysqli->prepare("INSERT INTO `track` (user, uniq_name, ad_name, ad_delay_time ) values (?, ?, ?, ?)");

คำถามคือฉันควรใช้insert_delayหรือใช้กลไกmysqli_multi_queryเพราะคำสั่งแทรกใช้ ~ 100% cpu บนเซิร์ฟเวอร์ ฉันใช้เอ็นจิ้น InnoDB บนฐานข้อมูลของฉันดังนั้นการแทรกที่ล่าช้าจึงเป็นไปไม่ได้ การแทรกบนเซิร์ฟเวอร์คือ ~ 36k / ชม. และอ่านได้ 99.89% นอกจากนี้ฉันกำลังใช้คำสั่งเลือกที่มีการดึงข้อมูลเจ็ดครั้งในแบบสอบถามเดียวแบบสอบถามนี้ใช้เวลา 150 วินาทีบนเซิร์ฟเวอร์เพื่อดำเนินการ ฉันสามารถใช้เทคนิคหรือกลไกชนิดใดสำหรับงานนี้ หน่วยความจำเซิร์ฟเวอร์ของฉันคือ 2 gb ฉันควรขยายหน่วยความจำหรือไม่ ไปดูปัญหานี้ข้อเสนอแนะใด ๆ จะขอบคุณฉัน

โครงสร้างของตาราง:

+-----------------+--------------+------+-----+-------------------+----------------+
| Field           | Type         | Null | Key | Default           | Extra          |
+-----------------+--------------+------+-----+-------------------+----------------+
| id              | int(11)      | NO   | PRI | NULL              | auto_increment |
| user            | varchar(100) | NO   |     | NULL              |                |
| uniq_name       | varchar(200) | NO   |     | NULL              |                |
| ad_name         | varchar(200) | NO   |     | NULL              |                |
| ad_delay_time   | int(11)      | NO   |     | NULL              |                |
| track_time      | timestamp    | NO   | MUL | CURRENT_TIMESTAMP |                |
+-----------------+--------------+------+-----+-------------------+----------------+

สถานะปัจจุบันของฐานข้อมูลของฉันแสดงการแทรก 41k (เขียน) ซึ่งช้ามากสำหรับฐานข้อมูลของฉัน

สถานะฐานข้อมูล


คุณสามารถให้คำจำกัดความของตารางได้หรือไม่? (คอลัมน์ทุกประเภทข้อมูลและดัชนี)
ypercubeᵀᴹ

คุณสามารถให้ตัวอย่างสั้น ๆ ของคุณSHOW FULL PROCESSLISTเมื่อมันใช้ซีพียู 100%? คุณมีการเชื่อมต่อกี่ครั้งกับจำนวนการเชื่อมต่อในช่วงเวลานี้?
Derek Downey

โปรดเรียกใช้ทั้งสองคำสั่ง: SHOW GLOBAL VARIABLES LIKE 'innodb%';และSELECT VERSION();และแสดงผลผลิตของพวกเขา
RolandoMySQLDBA

โปรดระบุจำนวนการแทรกต่อวินาทีที่คุณกำลังดำเนินการ
dabest1

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

คำตอบ:


12

เนื่องจากคุณมีการเขียนมากกว่านั้นจึงอ่านฉันอยากจะแนะนำต่อไป

การปรับแต่ง InnoDB ที่เหมาะสมจะเป็นกุญแจสำคัญ

บัฟเฟอร์พูล (ขนาดโดยinnodb_buffer_pool_size )

เนื่องจากInnoDB ไม่รองรับ INSERT DELAYED การใช้ InnoDB Buffer Pool ขนาดใหญ่จึงเป็นสิ่งที่ใกล้เคียงที่สุดคุณจึงสามารถไปที่ INSERT DELAYED ได้ DML ทั้งหมด (INSERTs, UPDATEs และ DELETEs) จะถูกแคชใน InnoDB Buffer Pool ข้อมูลธุรกรรมสำหรับ Writes จะถูกเขียนไปยัง Redo Logs ทันที (ib_logfile0, ib_logfile1) การเขียนที่โพสต์ใน Buffer Pool จะถูกฟลัชจากหน่วยความจำไปยังดิสก์เป็นระยะ ๆ โดยใช้ ibdata1 (InsertBuffer สำหรับดัชนีรอง, Double Write Buffer) ยิ่งบัฟเฟอร์พูลมีขนาดใหญ่เท่าใดปริมาณของ INSERTs ที่สามารถแคชได้มากขึ้น ในระบบที่มี RAM 8GB หรือมากกว่าให้ใช้ 75-80% ของ RAM เป็น innodb_buffer_pool_size ในระบบที่มี RAM น้อยมาก 25% (เพื่อรองรับระบบปฏิบัติการ)

ถ้ำ: คุณสามารถตั้งinnodb_doublewriteเป็น 0 เพื่อเพิ่มความเร็วในการเขียนได้มากขึ้น แต่มีความเสี่ยงต่อความถูกต้องของข้อมูล นอกจากนี้คุณยังสามารถเร่งความเร็วด้วยการตั้งค่าinnodb_flush_methodเป็น O_DIRECT เพื่อป้องกันการแคช InnoDB ไปเป็นระบบปฏิบัติการ

ทำซ้ำบันทึก (ขนาดโดยinnodb_log_file_size )

โดยดีฟอลต์บันทึกการทำซ้ำจะมีชื่อว่า ib_logfile0 และ ib_logfile1 และจะเป็น 5MB ต่อไฟล์ ขนาดควรเป็น 25% ของ innodb_buffer_pool_size หากทำซ้ำบันทึกอยู่แล้วเพิ่มการตั้งค่าใหม่ใน my.cnf ปิด MySQL, ลบพวกเขาและเริ่มต้นใหม่ MySQL

Log Buffer (ขนาดโดยinnodb_log_buffer_size )

บัฟเฟอร์การบันทึกจะทำการเปลี่ยนแปลง RAM ก่อนที่จะลบทิ้งในบันทึกการทำซ้ำ ค่าเริ่มต้นคือ 8M ยิ่งบัฟเฟอร์การบันทึกมีขนาดใหญ่เท่าใดดิสก์ I / O ก็จะยิ่งน้อยลง ระมัดระวังธุรกรรมที่มีขนาดใหญ่มากเนื่องจากอาจทำให้ COMMIT ลดลงเป็นมิลลิวินาที

การเข้าถึงหลาย CPU

MySQL 5.5 และปลั๊กอิน MySQL 5.1 InnoDB มีการตั้งค่าเพื่อให้ InnoDB Storage Engine เข้าถึงซีพียูหลายตัว นี่คือตัวเลือกที่คุณต้องตั้งค่า:

  • innodb_thread_concurrencyตั้งค่าขอบเขตบนของจำนวนเธรดที่เกิดขึ้นพร้อมกันที่ InnoDB สามารถเปิดค้างไว้ ขอแนะนำให้ตั้งค่านี้โดยปกติคือ (2 X จำนวน CPU) + จำนวนดิสก์ เมื่อปีที่แล้วฉันได้เรียนรู้โดยตรงจากการประชุม Percona NYC ว่าคุณควรตั้งค่านี้เป็น 0 เพื่อแจ้งเตือน InnoDB Storage Engine เพื่อค้นหาจำนวนเธรดที่ดีที่สุดสำหรับสภาพแวดล้อมที่ทำงานอยู่
  • innodb_concurrency_ticketsตั้งค่าจำนวนเธรดที่สามารถข้ามการตรวจสอบพร้อมกันด้วยการไม่ต้องรับโทษ หลังจากถึงขีด จำกัด นั้นการตรวจสอบการทำงานพร้อมกันของเธรดจะกลายเป็นบรรทัดฐานอีกครั้ง
  • innodb_commit_concurrencyตั้งค่าจำนวนธุรกรรมที่เกิดขึ้นพร้อมกันที่สามารถยืนยันได้ เนื่องจากค่าเริ่มต้นคือ 0 การตั้งค่านี้ไม่อนุญาตให้มีจำนวนการทำธุรกรรมใด ๆ พร้อมกัน
  • innodb_thread_sleep_delayตั้งค่าจำนวนมิลลิวินาทีที่เธรด InnoDB สามารถหยุดทำงานก่อนที่จะป้อนคิว InnoDB อีกครั้ง ค่าเริ่มต้นคือ 10000 (10 วินาที)
  • innodb_read_io_threads (ตั้งค่านี้เป็น 3000) และinnodb_write_io_threads (ตั้งค่านี้เป็น 7000) (ทั้งคู่ตั้งแต่ MySQL 5.1.38) จัดสรรจำนวนเธรดที่ระบุสำหรับการอ่านและเขียน ค่าเริ่มต้นคือ 4 และสูงสุดคือ 64 ตั้งค่าเหล่านี้เป็น 64 และตั้งค่าinnodb_io_capacityเป็น 10,000

อัปเกรดเป็น MySQL 5.5

หากคุณมี MySQL 5.0 ให้อัพเกรดเป็น MySQL 5.5 หากคุณมี MySQL 5.1.37 หรือก่อนหน้าให้อัปเกรดเป็น MySQL 5.5 หากคุณมี MySQL 5.1.38 หรือสูงกว่าและต้องการอยู่ใน MySQL 5.1 ให้ติดตั้งปลั๊กอิน InnoDB ด้วยวิธีนี้คุณสามารถใช้ประโยชน์จาก CPU ทั้งหมดสำหรับ InnoDB


หน่วยความจำเซิร์ฟเวอร์ของฉันคือ 2GB ดังนั้นตามหน่วยความจำฉันตั้งค่าพูลบัฟเฟอร์ innodb เป็น 500M และล็อกไฟล์ 25% เป็นพูลตั้งค่า log buffer เป็น 64M แต่เซิร์ฟเวอร์ยังคงยุ่งมาก ฉันควรอัพเกรดหน่วยความจำหรือไม่ เซิร์ฟเวอร์ของฉันอยู่บน Ubuntu 32 บิตดังนั้นสูงสุดฉันสามารถตั้งหน่วยความจำได้ถึง 4 GB
Shashank

หากเซิร์ฟเวอร์นั้นใช้สำหรับ MySQL (ไม่มี apache, ไม่มี PHP) ดังนั้น innodb_buffer_pool_size สามารถเพิ่มขึ้น 75% ของ 2GB ซึ่งก็คือ 1536M หากคุณอัพเกรดเป็น 4GB, innodb_buffer_pool_size สามารถเป็น 3G ได้ ไฟล์บันทึกควรเป็น 25% ของบัฟเฟอร์พูลตามที่คุณระบุ
RolandoMySQLDBA

เซิร์ฟเวอร์ใช้ apache2, mysql และ php, ฉันควรจะไปอัพเกรดหน่วยความจำในสถานการณ์นี้หรือมีทางออกที่ดีที่สุดยกเว้น innodb buffer pool?
Shashank

ผู้ชายคนนี้ไม่เห็นด้วยกับคุณ: percona.com/blog/2008/11/21/… ยากที่จะโต้แย้งกับ Percona
Zenexer

Rolando - แนะนำให้คุณเพิ่มคำตอบด้วยการอัปเดตสำหรับ 5.6 และ 5.7 ค่าเริ่มต้นมีการเปลี่ยนแปลง การตั้งค่าอื่น ๆ ที่มีอยู่; ฯลฯ อาจรวมถึง Percona และ MariaDB และเคล็ดลับ 8.0
Rick James

2

INT (2) ยังคงใช้ 4 ไบต์ - บางทีคุณอาจหมายถึง TINYINT UNSIGNED?

มีค่าแตกต่างกันใน setno ถ้ามันมีขนาดเล็ก KEY (setno) จะไม่ถูกใช้งาน INSERTing ต้องอัปเดตดัชนีนั้น การลบคีย์จะเพิ่มความเร็วใน INSERT บ้าง

CHAR (10) - flagยาว 10 อักขระเสมอหรือไม่ และใน utf8 บางทีคุณอาจใช้ flag VARCHAR (10) CHARACTER SET ascii

Batch ของคุณแทรก - 100 ต่อครั้งจะทำงาน 10 ครั้งเร็ว (เกิน 100 จะเข้าสู่ 'ผลตอบแทนลดลง')

ค่าของ autocommit คืออะไร คุณใส่ INSERT แต่ละรายการใน BEGIN ... COMMIT ไหม innodb_flush_log_at_trx_commit คืออะไร


ฉันจะแทรกในชุดได้อย่างไรถ้าข้อมูลถูกแทรกผ่านแหล่งภายนอกเช่นไคลเอนต์ที่แตกต่างกันด้วยค่าที่แตกต่างกัน .... มันน่าเชื่อถือถ้าฉันใช้: codeแทรกลงใน t_name (col1, col2, col3) ค่า (val1, val2, val3) (val1, val2, val3), (val1, val2, val3), (val1, val2, val3), (val1, val2, val3); code
Shashank

1

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

ฉันได้เห็นแล้วว่าการผสมเม็ดมีด 10,000 ครั้งเป็นวิธีที่เร็วที่สุดดังนั้นคุณจะต้องทดสอบเพื่อหาจุดที่น่าสนใจ

คุณสามารถสร้างระบบคิวอย่างง่ายของคุณเองหรือใช้ระบบที่มีอยู่ นี่คือตัวอย่างบางส่วน: HornetQและไฟล์ :: คิว นี่คือโพสต์ใน SE รายชื่อบางตัวเลือกที่ดีอื่น ๆ : คิวข้อความใน Perl,


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