MyISAM กับ InnoDB [ปิด]


857

ฉันกำลังทำงานในโครงการที่เกี่ยวข้องกับการเขียนฐานข้อมูลจำนวนมากฉันจะบอกว่า ( แทรก 70% และอ่าน 30% ) อัตราส่วนนี้จะรวมการอัปเดตซึ่งฉันคิดว่าเป็นหนึ่งการอ่านและการเขียนหนึ่งครั้ง การอ่านอาจสกปรก (เช่นฉันไม่ต้องการข้อมูลที่ถูกต้อง 100% ณ เวลาที่อ่าน)
งานที่มีปัญหาจะทำธุรกรรมฐานข้อมูลมากกว่า 1 ล้านรายการต่อชั่วโมง

ฉันได้อ่านสิ่งต่าง ๆ บนเว็บเกี่ยวกับความแตกต่างระหว่าง MyISAM และ InnoDB และ MyISAM ดูเหมือนจะเป็นทางเลือกที่ชัดเจนสำหรับฉันสำหรับฐานข้อมูล / ตารางเฉพาะที่ฉันจะใช้สำหรับงานนี้ จากสิ่งที่ฉันอ่านหนังสือ InnoDB นั้นดีถ้าต้องการธุรกรรมเนื่องจากรองรับการล็อคระดับแถว

ใครบ้างมีประสบการณ์กับโหลดประเภทนี้ (หรือสูงกว่า) หรือไม่? MyISAM เป็นวิธีที่จะไปไหม?


13
บล็อก MySQL ผลการปฏิบัติงานเป็นทรัพยากรที่ดีสำหรับประเภทของสิ่งนี้
ceejayoz

3
สิ่งนี้จะขึ้นอยู่กับว่าระบบของคุณคือ OLTP หรือมากกว่าที่มีการจัดวางคลังข้อมูล (ซึ่งการเขียนส่วนใหญ่เป็นการโหลดจำนวนมาก)
เลขที่

35
MyISAM ไม่รองรับการล็อกแถวธุรกรรมไม่สนับสนุนคีย์ต่างประเทศ ... เพราะมันไม่สามารถให้กรดได้มันจึงแทบไม่ได้รับการพิจารณาว่าเป็นฐานข้อมูลที่เหมาะสม! นี่คือสาเหตุที่ InnoDB เป็นเอ็นจิ้นเริ่มต้นตั้งแต่ MySQL 5.5 ... แต่ด้วยเหตุผลใดก็ตาม MyISAM ยังคงเป็นเอ็นจิ้นเริ่มต้นสำหรับตารางที่สร้างขึ้นภายใน PhpMyAdmin ดังนั้นฐานข้อมูลมือสมัครเล่นจำนวนมากตั้งแต่รันบน MyISAM
BlueRaja - Danny Pflughoeft


คำตอบ:


523

ฉันมีเวลาสั้น ๆกล่าวถึงคำถามนี้ในตารางเพื่อให้คุณสามารถสรุปได้ว่าจะไปกับInnoDBหรือMyISAM

นี่เป็นภาพรวมขนาดเล็กของเอ็นจิ้นการจัดเก็บ db ที่คุณควรใช้ในสถานการณ์ใด:

                                                 MyISAM InnoDB
-------------------------------------------------- --------------
การค้นหาข้อความแบบเต็มจำเป็น 5.6.4
-------------------------------------------------- --------------
ต้องการการทำธุรกรรมใช่
-------------------------------------------------- --------------
แบบสอบถามแบบใช้เลือกบ่อย      
-------------------------------------------------- --------------
การแทรกการอัพเดทและการลบบ่อยครั้ง
-------------------------------------------------- --------------
การล็อคแถว (การประมวลผลหลายรายการในตารางเดียว) ใช่
-------------------------------------------------- --------------
การออกแบบฐานสัมพันธ์

สรุป

  • ในเกือบทุกสถานการณ์InnoDBเป็นวิธีที่ดีที่สุด
  • แต่การอ่านบ่อยครั้งเกือบจะไม่มีการเขียนใช้MyISAM
  • ค้นหาข้อความแบบเต็มใน MySQL <= 5.5 ใช้MyISAM

11
InnoDB มีดัชนีข้อความแบบเต็มใน MySQL 5.6 แต่จนถึงขณะนี้พวกเขายังไม่พร้อมสำหรับการใช้งานจริง
Bill Karwin

3
สอดคล้องกับ12.9 ฟังก์ชั่นการค้นหาข้อความแบบเต็ม“ ดัชนีข้อความแบบเต็มสามารถใช้ได้กับตาราง InnoDB หรือ MyISAM เท่านั้น” ดูเหมือนว่าตกลงสำหรับ MySQL> = 5.6 แต่หน้าเดียวกันสำหรับ MySQL 5.5 ยังกล่าวว่า“ ดัชนีข้อความแบบเต็มสามารถใช้กับตาราง MyISAM เท่านั้น” ตารางด้านบนสามารถอัปเดตเพื่อบอกว่ามันแตกต่างกับเวอร์ชัน MySQL อย่างไร น่าเสียดายที่ MySQL 5.5 น่าจะเป็นมาตรฐาน
Hibou57

2
ค่าเฉลี่ยของอะไร: InnoDB - full-text: 5.6.4?? มันใช่หรือไม่?

2
MyISAM ยังเก็บการนับแถวภายใน ดังนั้นฟังก์ชั่น Count () เกือบจะฟรีใน MyISAM ในขณะที่มันใช้เวลานานใน InnoDB
Hedeshy

3
ตารางที่ดี แต่เพิ่มแถวเพื่อคุณภาพและความมั่นคง MyIsam = ไม่ innoDB = ใช่จะทำให้ดียิ่งขึ้น
pilavdzice

268

ฉันไม่ใช่ผู้เชี่ยวชาญด้านฐานข้อมูลและฉันไม่ได้พูดจากประสบการณ์ อย่างไรก็ตาม:

ตาราง MyISAM ใช้ล็อคตารางระดับ จากประมาณการการเข้าชมของคุณคุณมีเกือบ 200 เขียนต่อวินาที ด้วย MyISAM, เพียงหนึ่งในจำนวนนี้อาจจะอยู่ในความคืบหน้าในเวลาใดก็ได้ คุณต้องตรวจสอบให้แน่ใจว่าฮาร์ดแวร์ของคุณสามารถทำตามธุรกรรมเหล่านี้เพื่อหลีกเลี่ยงการถูกบุกรุกมากเกินไปเช่นการสืบค้นครั้งเดียวอาจใช้เวลาไม่เกิน 5 มิลลิวินาที

ที่แนะนำให้ฉันคุณจะต้องมีเครื่องมือจัดเก็บข้อมูลที่รองรับการล็อคระดับแถวคือ InnoDB

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


12
ใกล้ถึง 200? หากการทำธุรกรรมโดยเฉลี่ยของเขาทำการค้นหา 2.5 รายการนั่นคือ [(2.5 * 1M) / 3600s =] ใกล้ถึง 700
Ozzy

12
ฉันไม่เห็นด้วยa single query can take no more than 5msเพราะคุณตั้งสมมติฐาน 2 อย่างที่ไม่น่าเป็นไปได้ ตอบ: คำถามทั้งหมดต้องการตาราง & B เดียวกัน: มีการเชื่อมต่อเพียง 1 รายการเท่านั้น! ฉันควรแจ้งให้คุณทราบว่าการตั้งค่า Linux & MySQL 5.5 พร้อม RAM สูงสามารถรองรับการเชื่อมต่อได้มากถึง 10,000 ครั้ง (ดู: dev.mysql.com/doc/refman//5.5/en/too-many-connections.html )
Ozzy

152
เมื่อตารางถูกล็อคตารางแบบสอบถามเดียวเท่านั้นที่สามารถเรียกใช้กับแบบสอบถามในครั้งเดียว ไม่สำคัญว่าเซิร์ฟเวอร์รองรับการเชื่อมต่อ 10,000 รายการพร้อมกันหรือไม่แต่ละรายการจะสำรองในขณะที่ตารางถูกล็อค
Ryaner

2
นอกจากนี้อาจเป็นประโยชน์หากทราบว่า MyISAM รองรับดัชนีเชิงพื้นที่ในขณะที่ InnoDB ไม่รองรับ และ MyISAM ดูเหมือนจะไม่ใช้คีย์ต่างประเทศแม้ว่าจะไม่ได้ป้องกันการสร้างขึ้นก็ตาม
kriver

4
@kriver: คุณไม่มีคีย์ต่างประเทศในตาราง MyISAM คุณสามารถรวมคำจำกัดความของ FK ในคำสั่ง CREATE TABLE แต่คำจำกัดความ (คำจำกัดความ) นั้นจะถูกละเว้น
ypercubeᵀᴹ

191

ผู้คนมักจะพูดถึงประสิทธิภาพอ่านเทียบกับการเขียนคีย์ต่างประเทศ ฯลฯ แต่มีคุณสมบัติอื่นที่ต้องมีสำหรับเครื่องมือจัดเก็บข้อมูลในความคิดของฉัน: การปรับปรุงอะตอมมิก

ลองสิ่งนี้:

  1. ออกการอัปเดตกับตาราง MyISAM ของคุณซึ่งใช้เวลา 5 วินาที
  2. ในขณะที่ UPDATE กำลังดำเนินการอยู่ให้พูด 2.5 วินาทีกด Ctrl-C เพื่อขัดจังหวะ
  3. สังเกตผลกระทบบนโต๊ะ มีการอัพเดตกี่แถว มีการอัพเดตกี่อัน ตารางอ่านได้หรือไม่หรือเสียหายเมื่อคุณกด Ctrl-C
  4. ลองการทดสอบเดียวกันกับ UPDATE เทียบกับตาราง InnoDB ขัดจังหวะการสืบค้นที่อยู่ระหว่างดำเนินการ
  5. สังเกตตาราง InnoDB มีการอัปเดตแถวศูนย์ InnoDB มั่นใจได้ว่าคุณมีการอัปเดตอะตอมมิกและหากไม่สามารถส่งการปรับปรุงแบบเต็มได้ก็จะย้อนกลับไปสู่การเปลี่ยนแปลงทั้งหมด นอกจากนี้ตารางไม่เสียหาย วิธีนี้ใช้ได้แม้ว่าคุณkillall -9 mysqldจะใช้เพื่อจำลองข้อผิดพลาด

แน่นอนว่าประสิทธิภาพเป็นสิ่งที่น่าพึงพอใจ แต่การสูญเสียข้อมูลไม่ควรทำให้เป็นเรื่องดี


4
สำหรับเร็กคอร์ดคุณสมบัติอื่นของฐานข้อมูล ACID - ความสอดคล้องความโดดเดี่ยวและความทนทาน - MyISAM ไม่สนับสนุนเช่นกัน
Bill Karwin

Control-C ไม่ควรทำให้โต๊ะเสียหาย - เช่นเดียวกับใน CHECK TABLE จะกลับสู่ความสำเร็จและการสืบค้นทั้งหมดจะดำเนินการโดยไม่มีข้อผิดพลาด MyISAM จะยกเลิกการอัปเดตโดยไม่ต้องอัปเดตระเบียนทั้งหมด แต่ตารางจะรักษาความสมบูรณ์ของโครงสร้างภายในไว้ การฆ่า mysqld ด้วย SIGTERM จะมีผลเหมือนกัน อย่างไรก็ตามหากคุณให้ SIGKILL (kill -9) หรือสัญญาณการหยุดทำงานบางอย่าง (หรือรับได้ด้วยตนเองเมื่อมันพบจุดบกพร่อง) หรือหากระบบล่ม / พลังงานล่ม / สูญหาย OS ก็เป็นอีกเรื่องหนึ่ง - คุณสามารถเห็นได้ ความเสียหายระดับ MyISAM
Sasha Pachev

1
InnoDB สามารถสร้างความเสียหายให้กับตัวเองได้เป็นอย่างดีโดยทั่วไปมักจะมีค่ามากกว่า MyISAM ประชดของกรดคือเรามีความคิดทั้งหมดหรือไม่มีอะไร ดังนั้นเมื่อ InnoDB ไม่สามารถให้ได้ทั้งหมดจะไม่ทำอะไรเลย - ยืนยันภายในและปฏิเสธที่จะทำงานเพราะไบต์หนึ่งในโครงสร้างบางอย่างผิด - 90% ของเวลาที่มันอาจถูกเพิกเฉย เซิร์ฟเวอร์ Percona ล่าสุดมีตัวเลือกในการจัดการกับมัน - innodb_pass_corrupt_table
Sasha Pachev

1
ฉันกำลังค้นหาข้อมูลประเภทนี้จาก 3 วันล่าสุดตอนนี้ฉันได้รับแล้ว InnoDB นั้นดีที่สุด ขอบคุณBill Karwin
user3833682

3
@ flow2k แทบไม่มีเลยในวันนี้ ในงานสุดท้ายของฉันเราใช้ MyISAM สำหรับหนึ่งตารางบนเซิร์ฟเวอร์หนึ่งเครื่องและเหตุผลเดียวคือ MyISAM สามารถเก็บตารางนั้นในพื้นที่ที่น้อยกว่าที่ InnoDB จะทำได้ เรามีข้อ จำกัด เกี่ยวกับพื้นที่ดิสก์ดังนั้นเราจึงต้องใช้ MyISAM จนกว่าเราจะสามารถย้ายฐานข้อมูลไปยังเซิร์ฟเวอร์อื่น ที่งานใหม่ของฉันมีนโยบายที่ทุกโต๊ะจะต้องเป็น InnoDB
Bill Karwin

138

ฉันทำงานในระบบที่มีปริมาณมากโดยใช้ MySQL และฉันลองทั้ง MyISAM และ InnoDB

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

ในที่สุดฉันก็แก้ไขปัญหาความขัดแย้งโดยการแยกส่วนข้อมูลดังกล่าวที่แทรกเข้าไปในตาราง "ร้อน" และเลือกไม่เคยสอบถามตารางร้อน

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

แน่นอนว่าฉันไม่รู้ว่าแอปพลิเคชันของคุณคืออะไร แต่หวังว่าจะช่วยให้คุณเข้าใจถึงปัญหาบางอย่างกับ MyISAM และ InnoDB


3
'ในที่สุดฉันก็แก้ไขปัญหาความขัดแย้งโดยการแยกส่วนข้อมูลที่แทรกเข้าไปในตาราง "ร้อน" และเลือกที่ไม่เคยสอบถามตารางร้อน " - ไม่ว่าเป็นสิ่งที่บัฟเฟอร์พูลสำหรับ
BlueRaja - Danny Pflughoeft

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

66

ช้าไปนิดหน่อยกับเกม ... แต่นี่เป็นโพสต์ที่ค่อนข้างครอบคลุมฉันเขียนเมื่อไม่กี่เดือนก่อนโดยให้รายละเอียดความแตกต่างที่สำคัญระหว่าง MYISAM และ InnoDB คว้าคัปป้า (และอาจเป็นบิสกิต) และเพลิดเพลิน


ความแตกต่างที่สำคัญระหว่าง MyISAM และ InnoDB คือการอ้างอิงที่สมบูรณ์และธุรกรรม นอกจากนี้ยังมีข้อแตกต่างอื่น ๆ เช่นการล็อคการย้อนกลับและการค้นหาข้อความแบบเต็ม

Referential Integrity

Referential integrity ช่วยให้มั่นใจได้ว่าความสัมพันธ์ระหว่างตารางยังคงสอดคล้องกัน โดยเฉพาะอย่างยิ่งนี่หมายถึงเมื่อตาราง (เช่นรายชื่อ) มีคีย์ต่างประเทศ (เช่นรหัสผลิตภัณฑ์) ชี้ไปที่ตารางอื่น (เช่นผลิตภัณฑ์) เมื่อมีการอัพเดตหรือลบเกิดขึ้นกับตารางชี้ไปที่การเปลี่ยนแปลงเหล่านี้จะเรียงซ้อนกันไปยังการเชื่อมโยง โต๊ะ. ในตัวอย่างของเราหากผลิตภัณฑ์ถูกเปลี่ยนชื่อคีย์ต่างประเทศของตารางการเชื่อมโยงจะอัปเดตด้วยเช่นกัน หากผลิตภัณฑ์ถูกลบออกจากตาราง 'ผลิตภัณฑ์' รายชื่อใดที่ชี้ไปยังรายการที่ถูกลบจะถูกลบด้วย นอกจากนี้รายชื่อใหม่ใด ๆ จะต้องมีคีย์ต่างประเทศนั้นชี้ไปยังรายการที่ถูกต้องและมีอยู่

InnoDB เป็น DBMS เชิงสัมพันธ์ (RDBMS) จึงมี Referential Integrity ในขณะที่ MyISAM ไม่มี

ธุรกรรมและปรมาณู

ข้อมูลในตารางได้รับการจัดการโดยใช้คำสั่ง Data Manipulation Language (DML) เช่น SELECT, INSERT, UPDATE และ DELETE กลุ่มธุรกรรมสองหรือมากกว่างบ DML ร่วมกันในหน่วยงานเดียวดังนั้นทั้งหน่วยถูกนำไปใช้หรือไม่มีมันคือ

MyISAM ไม่รองรับการทำธุรกรรมในขณะที่ InnoDB ทำ

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

หากการดำเนินการถูกขัดจังหวะในขณะที่ใช้ตาราง InnoDB เนื่องจากเป็นการใช้ธุรกรรมซึ่งมี atomicity ธุรกรรมใด ๆ ที่ไม่ได้ดำเนินการจนเสร็จสมบูรณ์จะไม่มีผลเนื่องจากไม่มีการกระทำใด ๆ

การล็อคตารางเทียบกับการล็อคแถว

เมื่อแบบสอบถามทำงานกับตาราง MyISAM ทั้งตารางที่แบบสอบถามนั้นจะถูกล็อค ซึ่งหมายความว่าการสืบค้นที่ตามมาจะถูกดำเนินการหลังจากที่การสืบค้นปัจจุบันสิ้นสุด หากคุณกำลังอ่านตารางที่มีขนาดใหญ่และ / หรือมีการดำเนินการอ่านและเขียนบ่อยครั้งนี่อาจหมายถึงการค้างจำนวนมากของแบบสอบถาม

เมื่อแบบสอบถามทำงานกับตาราง InnoDB เฉพาะแถวที่เกี่ยวข้องเท่านั้นที่ถูกล็อคส่วนที่เหลือของตารางจะยังคงพร้อมใช้งานสำหรับการดำเนินการ CRUD ซึ่งหมายความว่าคิวรีสามารถเรียกใช้พร้อมกันในตารางเดียวกันโดยไม่ต้องใช้แถวเดียวกัน

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

การทำธุรกรรม & การย้อนกลับ

เมื่อคุณเรียกใช้การดำเนินการใน MyISAM การเปลี่ยนแปลงจะถูกตั้งค่า ใน InnoDB การเปลี่ยนแปลงเหล่านั้นสามารถย้อนกลับได้ คำสั่งที่พบบ่อยที่สุดที่ใช้ในการควบคุมการทำธุรกรรมคือ COMMIT, ROLLBACK และ SAVEPOINT 1. COMMIT - คุณสามารถเขียนการดำเนินการ DML หลายรายการได้ แต่การเปลี่ยนแปลงจะถูกบันทึกเมื่อคอมมิชชันทำ 2. ROLLBACK - คุณสามารถยกเลิกการทำงานใด ๆ ที่ยังไม่ได้ทำ 3. SAVEPOINT - กำหนดจุดในรายการ การดำเนินการที่การดำเนินการย้อนกลับสามารถย้อนกลับไป

ความเชื่อถือได้

MyISAM ไม่มีความสมบูรณ์ของข้อมูล - ความล้มเหลวของฮาร์ดแวร์การปิดระบบที่ไม่สะอาดและการดำเนินการที่ถูกยกเลิกอาจทำให้ข้อมูลเสียหายได้ นี้จะต้องมีการซ่อมแซมหรือสร้างใหม่ของดัชนีและตาราง

ในทางกลับกัน InnoDB ใช้บันทึกการทำธุรกรรมบัฟเฟอร์การเขียนซ้ำสองครั้งและการตรวจสอบอัตโนมัติและการตรวจสอบความถูกต้องเพื่อป้องกันความเสียหาย ก่อนที่ InnoDB จะทำการเปลี่ยนแปลงใด ๆ มันจะบันทึกข้อมูลก่อนการทำธุรกรรมลงในไฟล์ tablespace ของระบบที่เรียกว่า ibdata1 หากมีข้อผิดพลาด InnoDB จะทำการรีบูตอัตโนมัติผ่านการเล่นซ้ำของบันทึกเหล่านั้น

การจัดทำดัชนี FULLTEXT

InnoDB ไม่รองรับการจัดทำดัชนี FULLTEXT จนกระทั่ง MySQL เวอร์ชั่น 5.6.4 จากการเขียนโพสต์นี้ผู้ให้บริการโฮสติ้งที่ใช้ร่วมกันหลายคนของ MySQL ยังคงต่ำกว่า 5.6.4 ซึ่งหมายความว่าการจัดทำดัชนี FULLTEXT ไม่ได้รับการสนับสนุนสำหรับตาราง InnoDB

อย่างไรก็ตามนี่ไม่ใช่เหตุผลที่ถูกต้องในการใช้ MyISAM เป็นการดีที่สุดที่จะเปลี่ยนเป็นผู้ให้บริการโฮสต์ที่รองรับ MySQL รุ่นล่าสุด ไม่ใช่ว่าตาราง MyISAM ที่ใช้การทำดัชนี FULLTEXT ไม่สามารถแปลงเป็นตาราง InnoDB ได้

ข้อสรุป

โดยสรุป InnoDB ควรเป็นเครื่องมือเก็บข้อมูลเริ่มต้นที่คุณเลือก เลือก MyISAM หรือชนิดข้อมูลอื่นเมื่อตอบสนองความต้องการเฉพาะ


ฉันกำลังทำสคริปต์เช็คซัมเซสชัน php และคีย์ของฉันส่วนใหญ่เป็นสตริงแบบสุ่มของ [az09] ... Innodb ใช้เวลามากกว่า 30 วินาทีในการทำINSERT ON DUPLICATE KEY UPDATEดังนั้นฉันจึงลอง MyISAM และตอนนี้มันถึง <1ms ... คำตอบมากมายที่ฉันเห็นบอกว่า Innodb มีช่วงเวลาที่ยากลำบากในการจัดการกับคีย์เฉพาะ 'unsortable' (สตริงสุ่ม) ... คุณมีข้อมูลสำหรับเราหรือไม่? ในความเป็นจริงฉันสงสัยเกี่ยวกับผลกระทบที่จะต้องใช้ MyISAM แต่คำตอบที่ดีของคุณทำให้ฉันรู้ว่ามันเป็นวิธีที่จะไปสำหรับกรณีเฉพาะ
Louis Loudog Trottier

64

สำหรับการโหลดที่มีการเขียนและอ่านมากขึ้นคุณจะได้รับประโยชน์จาก InnoDB เพราะ InnoDB ให้แถวล็อคมากกว่าตารางล็อคของคุณSELECTs สามารถพร้อมกันไม่เพียง แต่กับแต่ละอื่น ๆ แต่ยังมีหลายINSERTs อย่างไรก็ตามถ้าคุณไม่ต้องการใช้ธุรกรรม SQL ให้ตั้งค่า InnoDB ให้ล้างข้อมูลเป็น 2 ( innodb_flush_log_at_trx_commit ) สิ่งนี้จะช่วยให้คุณได้รับประสิทธิภาพดิบที่คุณจะสูญเสียเมื่อย้ายตารางจาก MyISAM ไปยัง InnoDB

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

สุดท้ายให้ระวังการโหลดตารางที่แตกต่างกัน คุณจะไม่มีอัตราส่วนการอ่าน / เขียนเท่ากันในทุกตาราง บางตารางที่เล็กกว่าที่มีการอ่านเกือบ 100% อาจทำให้ MyISAM อยู่ได้ ในทำนองเดียวกันหากคุณมีตารางบางตัวที่ใกล้เคียงกับการเขียน 100% คุณอาจได้รับประโยชน์INSERT DELAYEDแต่ก็รองรับเฉพาะใน MyISAM (ส่วนDELAYEDคำสั่งจะถูกละเว้นสำหรับตาราง InnoDB)

แต่มาตรฐานเพื่อให้แน่ใจว่า


4
"InnoDB กระทำการชำระล้าง" ที่คุณอ้างถึงinnodb_flush_log_at_trx_commitหรือไม่
ceejayoz

2
ฉันพบว่าโพสต์ของคุณมีประโยชน์มาก - ขอบคุณ ขณะนี้ประเมินว่าจะใช้ MyISAM / InnoDB เมื่อใดสำหรับตารางของฉันและการโพสต์ของคุณมีประโยชน์ ไชโย
starmonkey

2
dev.mysql.com/doc/refman/5.5/en/insert-delayed.htmlสถานะ: สำหรับตาราง MyISAM หากไม่มีบล็อกว่างอยู่ตรงกลางของไฟล์ข้อมูลจะมีคำสั่ง SELECT และ INSERT พร้อมกัน ภายใต้สถานการณ์เหล่านี้คุณไม่ค่อยจำเป็นต้องใช้ INSERT ล่าช้ากับ MyISAM
tymtam

โพสต์ข้อมูลมาก ฉันมีคำถามเดียวกันกับ op ของและฉันต้องบอกว่าโพสต์ของคุณทำให้ฉันสบายใจเกี่ยวกับการตัดสินใจของเครื่องมือฐานข้อมูลของฉัน ขอบคุณ! ++
Joe Majewski

บันทึกด่วน: ล่าช้าไม่รองรับใน 5.7 คุณอาจต้องการทดสอบกับ LOW_PRIORITY แทน
webmat

59

เพื่อเพิ่มคำตอบมากมายที่นี่ซึ่งครอบคลุมความแตกต่างเชิงกลระหว่างเครื่องยนต์ทั้งสองฉันนำเสนอการศึกษาเปรียบเทียบความเร็วเชิงประจักษ์

ในแง่ของความเร็วบริสุทธิ์ไม่เสมอไปที่ MyISAM นั้นเร็วกว่า InnoDB แต่จากประสบการณ์ของฉันมันมักจะเร็วกว่าสำหรับสภาพแวดล้อมการทำงานของ PURE READ โดยประมาณ 2.0-2.5 เท่า เห็นได้ชัดว่านี่ไม่เหมาะสำหรับทุกสภาพแวดล้อม - ตามที่คนอื่นเขียน MyISAM ขาดสิ่งต่าง ๆ เช่นธุรกรรมและกุญแจต่างประเทศ

ฉันได้ทำการเปรียบเทียบด้านล่างแล้ว - ฉันใช้ python สำหรับการวนซ้ำและ timeit library สำหรับการเปรียบเทียบเวลา เพื่อความสนใจฉันยังได้รวมเอ็นจิ้นหน่วยความจำไว้ด้วยซึ่งจะให้ประสิทธิภาพที่ดีที่สุดทั่วกระดานแม้ว่ามันจะเหมาะสำหรับตารางที่เล็กกว่าThe table 'tbl' is fullเท่านั้น ตัวเลือกสี่ประเภทที่ฉันดูมีดังนี้:

  1. เลือกวานิลลา
  2. นับ
  3. SELECT ตามเงื่อนไข
  4. ตัวเลือกย่อยที่จัดทำดัชนีและไม่ได้จัดทำดัชนี

ประการแรกฉันสร้างสามตารางโดยใช้ SQL ต่อไปนี้

CREATE TABLE
    data_interrogation.test_table_myisam
    (
        index_col BIGINT NOT NULL AUTO_INCREMENT,
        value1 DOUBLE,
        value2 DOUBLE,
        value3 DOUBLE,
        value4 DOUBLE,
        PRIMARY KEY (index_col)
    )
    ENGINE=MyISAM DEFAULT CHARSET=utf8

ด้วย 'MyISAM' แทน 'InnoDB' และ 'memory' ในตารางที่สองและสาม

 

1) เลือกวานิลลา

ค้นหา: SELECT * FROM tbl WHERE index_col = xx

ผล: วาด

การเปรียบเทียบวานิลลาเลือกโดยเอนจิ้นฐานข้อมูลที่แตกต่างกัน

ความเร็วของสิ่งเหล่านี้ล้วนกว้างเหมือนกันและตามที่คาดไว้จะเป็นเชิงเส้นในจำนวนคอลัมน์ที่จะเลือก InnoDB ดูเหมือนจะเร็วกว่า MyISAM เล็กน้อยแต่นี่ก็เป็นเพียงเล็กน้อยเท่านั้น

รหัส:

import timeit
import MySQLdb
import MySQLdb.cursors
import random
from random import randint

db = MySQLdb.connect(host="...", user="...", passwd="...", db="...", cursorclass=MySQLdb.cursors.DictCursor)
cur = db.cursor()

lengthOfTable = 100000

# Fill up the tables with random data
for x in xrange(lengthOfTable):
    rand1 = random.random()
    rand2 = random.random()
    rand3 = random.random()
    rand4 = random.random()

    insertString = "INSERT INTO test_table_innodb (value1,value2,value3,value4) VALUES (" + str(rand1) + "," + str(rand2) + "," + str(rand3) + "," + str(rand4) + ")"
    insertString2 = "INSERT INTO test_table_myisam (value1,value2,value3,value4) VALUES (" + str(rand1) + "," + str(rand2) + "," + str(rand3) + "," + str(rand4) + ")"
    insertString3 = "INSERT INTO test_table_memory (value1,value2,value3,value4) VALUES (" + str(rand1) + "," + str(rand2) + "," + str(rand3) + "," + str(rand4) + ")"

    cur.execute(insertString)
    cur.execute(insertString2)
    cur.execute(insertString3)

db.commit()

# Define a function to pull a certain number of records from these tables
def selectRandomRecords(testTable,numberOfRecords):

    for x in xrange(numberOfRecords):
        rand1 = randint(0,lengthOfTable)

        selectString = "SELECT * FROM " + testTable + " WHERE index_col = " + str(rand1)
        cur.execute(selectString)

setupString = "from __main__ import selectRandomRecords"

# Test time taken using timeit
myisam_times = []
innodb_times = []
memory_times = []

for theLength in [3,10,30,100,300,1000,3000,10000]:

    innodb_times.append( timeit.timeit('selectRandomRecords("test_table_innodb",' + str(theLength) + ')', number=100, setup=setupString) )
    myisam_times.append( timeit.timeit('selectRandomRecords("test_table_myisam",' + str(theLength) + ')', number=100, setup=setupString) )
    memory_times.append( timeit.timeit('selectRandomRecords("test_table_memory",' + str(theLength) + ')', number=100, setup=setupString) )

 

2) การนับ

ค้นหา: SELECT count(*) FROM tbl

ผลลัพธ์: MyISAM ชนะ

การเปรียบเทียบจำนวนด้วยเอนจิ้นฐานข้อมูลที่แตกต่างกัน

อันนี้แสดงให้เห็นถึงความแตกต่างอย่างมากระหว่าง MyISAM และ InnoDB - MyISAM (และหน่วยความจำ) ติดตามจำนวนเร็กคอร์ดในตารางดังนั้นธุรกรรมนี้จึงรวดเร็วและ O (1) จำนวนเวลาที่ต้องใช้ในการนับ InnoDB จะเพิ่มขึ้นเป็นเส้นตรงด้วยขนาดของตารางในช่วงที่ฉันตรวจสอบ ฉันสงสัยว่าการเพิ่มความเร็วจากแบบสอบถาม MyISAM จำนวนมากที่พบในทางปฏิบัตินั้นเกิดจากผลกระทบที่คล้ายกัน

รหัส:

myisam_times = []
innodb_times = []
memory_times = []

# Define a function to count the records
def countRecords(testTable):

    selectString = "SELECT count(*) FROM " + testTable
    cur.execute(selectString)

setupString = "from __main__ import countRecords"

# Truncate the tables and re-fill with a set amount of data
for theLength in [3,10,30,100,300,1000,3000,10000,30000,100000]:

    truncateString = "TRUNCATE test_table_innodb"
    truncateString2 = "TRUNCATE test_table_myisam"
    truncateString3 = "TRUNCATE test_table_memory"

    cur.execute(truncateString)
    cur.execute(truncateString2)
    cur.execute(truncateString3)

    for x in xrange(theLength):
        rand1 = random.random()
        rand2 = random.random()
        rand3 = random.random()
        rand4 = random.random()

        insertString = "INSERT INTO test_table_innodb (value1,value2,value3,value4) VALUES (" + str(rand1) + "," + str(rand2) + "," + str(rand3) + "," + str(rand4) + ")"
        insertString2 = "INSERT INTO test_table_myisam (value1,value2,value3,value4) VALUES (" + str(rand1) + "," + str(rand2) + "," + str(rand3) + "," + str(rand4) + ")"
        insertString3 = "INSERT INTO test_table_memory (value1,value2,value3,value4) VALUES (" + str(rand1) + "," + str(rand2) + "," + str(rand3) + "," + str(rand4) + ")"

        cur.execute(insertString)
        cur.execute(insertString2)
        cur.execute(insertString3)

    db.commit()

    # Count and time the query
    innodb_times.append( timeit.timeit('countRecords("test_table_innodb")', number=100, setup=setupString) )
    myisam_times.append( timeit.timeit('countRecords("test_table_myisam")', number=100, setup=setupString) )
    memory_times.append( timeit.timeit('countRecords("test_table_memory")', number=100, setup=setupString) )

 

3) การเลือกแบบมีเงื่อนไข

ค้นหา: SELECT * FROM tbl WHERE value1<0.5 AND value2<0.5 AND value3<0.5 AND value4<0.5

ผลลัพธ์: MyISAM ชนะ

การเปรียบเทียบเงื่อนไขที่เลือกโดยเอ็นจินฐานข้อมูลที่แตกต่างกัน

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

รหัส:

myisam_times = []
innodb_times = []
memory_times = []

# Define a function to perform conditional selects
def conditionalSelect(testTable):
    selectString = "SELECT * FROM " + testTable + " WHERE value1 < 0.5 AND value2 < 0.5 AND value3 < 0.5 AND value4 < 0.5"
    cur.execute(selectString)

setupString = "from __main__ import conditionalSelect"

# Truncate the tables and re-fill with a set amount of data
for theLength in [3,10,30,100,300,1000,3000,10000,30000,100000]:

    truncateString = "TRUNCATE test_table_innodb"
    truncateString2 = "TRUNCATE test_table_myisam"
    truncateString3 = "TRUNCATE test_table_memory"

    cur.execute(truncateString)
    cur.execute(truncateString2)
    cur.execute(truncateString3)

    for x in xrange(theLength):
        rand1 = random.random()
        rand2 = random.random()
        rand3 = random.random()
        rand4 = random.random()

        insertString = "INSERT INTO test_table_innodb (value1,value2,value3,value4) VALUES (" + str(rand1) + "," + str(rand2) + "," + str(rand3) + "," + str(rand4) + ")"
        insertString2 = "INSERT INTO test_table_myisam (value1,value2,value3,value4) VALUES (" + str(rand1) + "," + str(rand2) + "," + str(rand3) + "," + str(rand4) + ")"
        insertString3 = "INSERT INTO test_table_memory (value1,value2,value3,value4) VALUES (" + str(rand1) + "," + str(rand2) + "," + str(rand3) + "," + str(rand4) + ")"

        cur.execute(insertString)
        cur.execute(insertString2)
        cur.execute(insertString3)

    db.commit()

    # Count and time the query
    innodb_times.append( timeit.timeit('conditionalSelect("test_table_innodb")', number=100, setup=setupString) )
    myisam_times.append( timeit.timeit('conditionalSelect("test_table_myisam")', number=100, setup=setupString) )
    memory_times.append( timeit.timeit('conditionalSelect("test_table_memory")', number=100, setup=setupString) )

 

4) การเลือกย่อย

ผลลัพธ์: InnoDB เป็นผู้ชนะ

สำหรับแบบสอบถามนี้ฉันสร้างชุดตารางเพิ่มเติมสำหรับตัวเลือกย่อย แต่ละคอลัมน์เป็นเพียงสองคอลัมน์ของ BIGINT โดยคอลัมน์หนึ่งมีดัชนีคีย์หลักและคอลัมน์หนึ่งไม่มีดัชนีใด ๆ เนื่องจากตารางขนาดใหญ่ฉันจึงไม่ได้ทดสอบเอนจิ้นหน่วยความจำ คำสั่งการสร้างตาราง SQL คือ

CREATE TABLE
    subselect_myisam
    (
        index_col bigint NOT NULL,
        non_index_col bigint,
        PRIMARY KEY (index_col)
    )
    ENGINE=MyISAM DEFAULT CHARSET=utf8;

โดยที่ 'MyISAM' ถูกแทนที่ด้วย 'InnoDB' ในตารางที่สอง

ในแบบสอบถามนี้ฉันเว้นขนาดตารางการเลือกไว้ที่ 1000000 และจะเปลี่ยนขนาดของคอลัมน์ย่อยที่เลือกแทน

การเปรียบเทียบการเลือกย่อยโดยเอนจิ้นฐานข้อมูลที่แตกต่างกัน

ที่นี่ InnoDB เป็นผู้ชนะได้อย่างง่ายดาย หลังจากเราไปที่ตารางขนาดที่เหมาะสมทั้งสองเครื่องยนต์จะขยายขนาดเชิงเส้นด้วยขนาดของตัวเลือกย่อย ดัชนีจะเร่งความเร็วคำสั่ง MyISAM แต่น่าสนใจมีผลกระทบเล็กน้อยต่อความเร็ว InnoDB subSelect.png

รหัส:

myisam_times = []
innodb_times = []
myisam_times_2 = []
innodb_times_2 = []

def subSelectRecordsIndexed(testTable,testSubSelect):
    selectString = "SELECT * FROM " + testTable + " WHERE index_col in ( SELECT index_col FROM " + testSubSelect + " )"
    cur.execute(selectString)

setupString = "from __main__ import subSelectRecordsIndexed"

def subSelectRecordsNotIndexed(testTable,testSubSelect):
    selectString = "SELECT * FROM " + testTable + " WHERE index_col in ( SELECT non_index_col FROM " + testSubSelect + " )"
    cur.execute(selectString)

setupString2 = "from __main__ import subSelectRecordsNotIndexed"

# Truncate the old tables, and re-fill with 1000000 records
truncateString = "TRUNCATE test_table_innodb"
truncateString2 = "TRUNCATE test_table_myisam"

cur.execute(truncateString)
cur.execute(truncateString2)

lengthOfTable = 1000000

# Fill up the tables with random data
for x in xrange(lengthOfTable):
    rand1 = random.random()
    rand2 = random.random()
    rand3 = random.random()
    rand4 = random.random()

    insertString = "INSERT INTO test_table_innodb (value1,value2,value3,value4) VALUES (" + str(rand1) + "," + str(rand2) + "," + str(rand3) + "," + str(rand4) + ")"
    insertString2 = "INSERT INTO test_table_myisam (value1,value2,value3,value4) VALUES (" + str(rand1) + "," + str(rand2) + "," + str(rand3) + "," + str(rand4) + ")"

    cur.execute(insertString)
    cur.execute(insertString2)

for theLength in [3,10,30,100,300,1000,3000,10000,30000,100000]:

    truncateString = "TRUNCATE subselect_innodb"
    truncateString2 = "TRUNCATE subselect_myisam"

    cur.execute(truncateString)
    cur.execute(truncateString2)

    # For each length, empty the table and re-fill it with random data
    rand_sample = sorted(random.sample(xrange(lengthOfTable), theLength))
    rand_sample_2 = random.sample(xrange(lengthOfTable), theLength)

    for (the_value_1,the_value_2) in zip(rand_sample,rand_sample_2):
        insertString = "INSERT INTO subselect_innodb (index_col,non_index_col) VALUES (" + str(the_value_1) + "," + str(the_value_2) + ")"
        insertString2 = "INSERT INTO subselect_myisam (index_col,non_index_col) VALUES (" + str(the_value_1) + "," + str(the_value_2) + ")"

        cur.execute(insertString)
        cur.execute(insertString2)

    db.commit()

    # Finally, time the queries
    innodb_times.append( timeit.timeit('subSelectRecordsIndexed("test_table_innodb","subselect_innodb")', number=100, setup=setupString) )
    myisam_times.append( timeit.timeit('subSelectRecordsIndexed("test_table_myisam","subselect_myisam")', number=100, setup=setupString) )

    innodb_times_2.append( timeit.timeit('subSelectRecordsNotIndexed("test_table_innodb","subselect_innodb")', number=100, setup=setupString2) )
    myisam_times_2.append( timeit.timeit('subSelectRecordsNotIndexed("test_table_myisam","subselect_myisam")', number=100, setup=setupString2) )

ฉันคิดว่าข้อความนำกลับบ้านของทั้งหมดนี้คือถ้าคุณเป็น กังวลเกี่ยวกับความเร็วจริง ๆคุณต้องเปรียบเทียบข้อความค้นหาที่คุณกำลังทำแทนที่จะทำการตั้งสมมติฐานว่าเครื่องยนต์ใดจะเหมาะสมกว่า


1
ประสิทธิภาพไม่ได้เป็นเพียงข้อพิจารณาเดียวเท่านั้นแล้วกราฟเกี่ยวกับความเสถียรล่ะ? เอ็นจิ้นไม่ดีสำหรับอะไรเลยถ้ามันล้มเหลวและไม่รองรับคุณสมบัติฐานข้อมูลพื้นฐาน
pilavdzice

1
MyISAM อาจชนะ InnoDB เกือบทุกครั้งหากmy.cnfไฟล์ไม่ได้รับการปรับให้เหมาะสมกับ InnoDB คุณไม่ได้พูดถึงว่าmy.cnfไฟล์ของคุณมีลักษณะอย่างไรซึ่งเป็นปัจจัยที่สำคัญที่สุดสำหรับประสิทธิภาพของ InnoDB
itoctopus

ขอบคุณ itoctopus - ฉันชอบที่จะได้ยินมากขึ้นเกี่ยวกับการเพิ่มประสิทธิภาพใด ๆ ที่คุณแนะนำ รหัสเต็มรูปแบบที่ใช้ในการทดสอบเหล่านี้อยู่ด้านบนอย่าลังเลที่จะทำการทดสอบซ้ำด้วยการเพิ่มประสิทธิภาพต่างๆและแจ้งให้เราทราบหากคุณพบการเปลี่ยนแปลงที่สำคัญในผลลัพธ์
StackG

32

ปิดหัวข้อเล็กน้อย แต่เพื่อวัตถุประสงค์ด้านเอกสารและความสมบูรณ์ฉันต้องการเพิ่มสิ่งต่อไปนี้

โดยทั่วไปแล้วการใช้ InnoDB จะส่งผลให้แอปพลิเคชั่นมีความซับซ้อนน้อยมากซึ่งอาจไม่มีข้อผิดพลาดมากขึ้น เนื่องจากคุณสามารถใส่ Referential Integrity ทั้งหมด (Foreign Key-constraints) ลงใน datamodel ได้คุณจึงไม่จำเป็นต้องใช้แอพพลิเคชั่นใด ๆ ใกล้เคียงกับ MyISAM

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

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

ฉันจะบอกว่าโดยทั่วไป InnoDB (การใช้ดาต้าโมเดล 3NF พร้อมด้วย Referential Integrity) ควรเป็นตัวเลือกเริ่มต้นเมื่อใช้ MySQL MyISAM ควรใช้ในกรณีที่เฉพาะเจาะจงเท่านั้น มันน่าจะทำงานได้น้อยลงส่งผลให้แอปพลิเคชันมีขนาดใหญ่ขึ้นและมากขึ้น

ต้องพูดแบบนี้ Datamodelling เป็นศิลปะที่ไม่ค่อยพบในหมู่นักออกแบบเว็บ / - โปรแกรม ไม่มีความผิดใด ๆ แต่อธิบายถึงการใช้ MyISAM ได้มาก


31

ข้อเสนอ InnoDB:

ACID transactions
row-level locking
foreign key constraints
automatic crash recovery
table compression (read/write)
spatial data types (no spatial indexes)

ใน InnoDB ข้อมูลทั้งหมดในแถวยกเว้น TEXT และ BLOB สามารถใช้งานได้สูงสุด 8,000 ไบต์ ไม่มีการจัดทำดัชนีข้อความแบบเต็มสำหรับ InnoDB ใน InnoDB นั้น COUNT (*) s (เมื่อไม่ใช้ WHERE, GROUP BY หรือ JOIN) ทำงานช้ากว่าใน MyISAM เพราะจำนวนแถวจะไม่ถูกเก็บไว้ภายใน InnoDB เก็บข้อมูลและดัชนีไว้ในไฟล์เดียว InnoDB ใช้บัฟเฟอร์พูลเพื่อแคชข้อมูลและดัชนี

ข้อเสนอ MyISAM:

fast COUNT(*)s (when WHERE, GROUP BY, or JOIN is not used)
full text indexing
smaller disk footprint
very high table compression (read only)
spatial data types and indexes (R-tree)

MyISAM มีการล็อคระดับตาราง แต่ไม่มีการล็อคระดับแถว ไม่มีการทำธุรกรรม ไม่มีการกู้คืนความผิดพลาดโดยอัตโนมัติ แต่มีฟังก์ชั่นการซ่อมแซมตาราง ไม่มีข้อ จำกัด ของรหัสต่างประเทศ โดยทั่วไปแล้วตาราง MyISAM จะมีขนาดกะทัดรัดกว่าบนดิสก์มากกว่าเมื่อเปรียบเทียบกับตาราง InnoDB ตาราง MyISAM สามารถลดขนาดได้อีกมากโดยการบีบอัดด้วย myisampack หากจำเป็น แต่กลายเป็นแบบอ่านอย่างเดียว MyISAM เก็บดัชนีในไฟล์เดียวและข้อมูลในอีกไฟล์หนึ่ง MyISAM ใช้บัฟเฟอร์หลักสำหรับดัชนีการแคชและปล่อยให้การจัดการแคชข้อมูลอยู่ในระบบปฏิบัติการ

โดยรวมแล้วฉันจะแนะนำ InnoDB สำหรับวัตถุประสงค์ส่วนใหญ่และ MyISAM สำหรับการใช้งานเฉพาะเท่านั้น InnoDB เป็นเครื่องมือเริ่มต้นในรุ่น MySQL ใหม่


2
fwiw, VARCHAR ใน InnoDB สามารถไปที่หน้าล้นได้เช่น BLOB และ TEXT ชนิดข้อมูลเหล่านี้ทั้งหมดจะถูกเก็บไว้ในทำนองเดียวกัน
Bill Karwin

ดีใจที่ได้ทราบ @BillKarwin! เราใช้ VARCHAR เป็นจำนวนมากในแอปของเราและการมี VARCHAR นั้นมีส่วนช่วยให้ขีด จำกัด ~ 8kB นั้นเกี่ยวกับ
rinogo

ดูmysqlperformanceblog.com/2010/02/09/blob-storage-in-innodbสำหรับรายละเอียดเพิ่มเติม
Bill Karwin

คำตอบไม่ได้อีกต่อไปเป็นเครื่องมือ Innodb ในรุ่น MySQL 5.6+ ปัจจุบันยังรองรับการจัดทำดัชนีข้อความแบบเต็มและ MySQL 5.5 + / 5.7 + รองรับประเภทข้อมูลเชิงพื้นที่ (5.5+)และดัชนีเชิงพื้นที่ (r-tee) (5.7+) .. สำหรับการสนับสนุนที่ดีที่สุดคุณจะต้องมีรุ่น MySQL 5.7+ ขึ้นไป
Raymond Nijland

25

หากคุณใช้ MyISAM คุณจะไม่ทำธุรกรรมใด ๆต่อชั่วโมงยกเว้นว่าคุณพิจารณาว่าคำสั่ง DML แต่ละรายการเป็นธุรกรรม

ดังนั้นฉันคิดว่าคุณต้องใช้ InnoDB

300 ธุรกรรมต่อวินาทีฟังดูค่อนข้างเยอะ หากคุณต้องการให้ธุรกรรมเหล่านี้มีความทนทานต่อความล้มเหลวของระบบไฟฟ้าตรวจสอบให้แน่ใจว่าระบบย่อย I / O ของคุณสามารถรองรับการเขียนจำนวนมากต่อวินาทีได้อย่างง่ายดาย อย่างน้อยคุณจะต้องมีตัวควบคุม RAID พร้อมแคชแบตเตอรี่สำรอง

หากคุณมีความทนทานน้อยคุณสามารถใช้ InnoDB กับ innodb_flush_log_at_trx_commit ตั้งค่าเป็น 0 หรือ 2 (ดูเอกสารสำหรับรายละเอียด) คุณสามารถปรับปรุงประสิทธิภาพได้

มีแพตช์จำนวนมากที่สามารถเพิ่มการทำงานพร้อมกันจาก Google และอื่น ๆ - สิ่งเหล่านี้อาจเป็นที่สนใจหากคุณยังคงมีประสิทธิภาพไม่เพียงพอหากไม่มีพวกเขา


24

คำถามและคำตอบส่วนใหญ่ล้าสมัยแล้ว

ใช่มันเป็นนิทานเก่าแก่ที่ MyISAM เร็วกว่า InnoDB สังเกตวันที่ของคำถาม: 2008; ตอนนี้เกือบหนึ่งทศวรรษต่อมา InnoDB ได้เพิ่มความก้าวหน้าด้านประสิทธิภาพอย่างมากตั้งแต่นั้นมา

กราฟแสดงละครเป็นกรณีหนึ่งที่ MyISAM ชนะ: COUNT(*) โดยไม่ต้องWHEREข้อ แต่นั่นคือสิ่งที่คุณใช้เวลาทำ?

หากคุณทดสอบการใช้งานพร้อมกันนั้น InnoDB มีโอกาสชนะได้MEMORYสูงมาก

หากคุณทำการเขียนใด ๆ ในขณะทำการเปรียบเทียบSELECTsMyISAM และMEMORYมีแนวโน้มที่จะสูญเสียเนื่องจากการล็อกระดับตาราง

ในความเป็นจริง Oracle มั่นใจว่า InnoDB ดีกว่าที่มีทั้งหมดยกเว้น MyISAM ที่ลบออกจาก 8.0

คำถามที่ถูกเขียนขึ้นในช่วงต้นของวัน 5.1 ตั้งแต่นั้นมาเวอร์ชันหลักเหล่านี้ถูกทำเครื่องหมาย "ความพร้อมใช้งานทั่วไป":

  • 2010: 5.5 (.8 ในเดือนธันวาคม)
  • 2013: 5.6 (.10 ในเดือนกุมภาพันธ์)
  • 2558: 5.7 (.9 ในเดือนตุลาคม)
  • 2018: 8.0 (.11 ในเดือนเมษายน)

บรรทัดล่างสุด: อย่าใช้ MyISAM


2
เทคโนโลยีฐานข้อมูล MySQL ก้าวหน้า และ StackOverflow คำถามและคำตอบยังคงติดหล่มในอดีต หลักความแตกต่างระหว่าง MyISAM และ InnoDB มีน้อยเกี่ยวกับ "ภาระ" บนเซิร์ฟเวอร์และอื่น ๆ อีกมากมายเกี่ยวกับการสนับสนุนสำหรับการอ้างอิงและการทำธุรกรรมเช่นเดียวกับการเห็นพ้องและคืน (10)
spencer7593

12

นอกจากนี้ตรวจสอบการแทนที่แบบหล่นในสำหรับ MySQL เอง:

MariaDB

http://mariadb.org/

MariaDB เป็นเซิร์ฟเวอร์ฐานข้อมูลที่มีฟังก์ชั่นการแทนที่แบบหล่นในสำหรับ MySQL MariaDB สร้างขึ้นโดยผู้เขียนต้นฉบับของ MySQL ด้วยความช่วยเหลือจากชุมชนในวงกว้างของผู้พัฒนาซอฟต์แวร์โอเพนซอร์ซและโอเพนซอร์ส นอกเหนือจากฟังก์ชั่นหลักของ MySQL แล้ว MariaDB ยังมีชุดการปรับปรุงคุณสมบัติมากมายรวมถึงเอ็นจิ้นการจัดเก็บข้อมูลสำรองการปรับแต่งเซิร์ฟเวอร์และแพทช์

เซิร์ฟเวอร์ Percona

https://launchpad.net/percona-server

การแทนที่แบบเลื่อนขั้นที่เพิ่มขึ้นสำหรับ MySQL ด้วยประสิทธิภาพที่ดีขึ้นการวินิจฉัยที่ดีขึ้นและคุณสมบัติที่เพิ่มขึ้น


1
ฉันใช้ทั้งคู่ (Percona ในการผลิต, Maria กับการพัฒนา windows) มันทำงานได้เร็วขึ้นและทำงานอย่างผิดปกติ
Moshe L

4
สิ่งนี้ไม่ตอบคำถาม MariaDB และ Percona เป็นส้อมของ MySQL และใช้เครื่องมือ InnoDB และ MyISAM เช่นกัน
dr_

12

โปรดทราบว่าการศึกษาอย่างเป็นทางการและประสบการณ์ของฉันอยู่กับ Oracle ในขณะที่การทำงานกับ MySQL นั้นเป็นส่วนตัวอย่างสมบูรณ์และตามเวลาของตัวเองดังนั้นถ้าฉันพูดในสิ่งที่เป็นจริงสำหรับ Oracle แต่ไม่เป็นความจริงสำหรับ MySQL ฉันขอโทษ แม้ว่าทั้งสองระบบจะแบ่งปันกันมาก แต่ทฤษฎี / พีชคณิตเชิงสัมพันธ์ก็เหมือนกันและฐานข้อมูลเชิงสัมพันธ์ยังคงเป็นฐานข้อมูลเชิงสัมพันธ์ แต่ก็ยังมีความแตกต่างมากมาย !!

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

หมายเหตุ:สำหรับ Oracle คำสั่งสร้าง / แก้ไข / วางจะเรียกว่าคำสั่ง "DDL" (Data Definition) และเรียกการกระทำโดยปริยาย แทรก / อัปเดต / ลบคำสั่งที่เรียกว่า "DML" (Data Manipulation) จะไม่ถูกส่งโดยอัตโนมัติ แต่จะดำเนินการเมื่อดำเนินการ DDL, commit, exit หรือ exit (หรือหากคุณตั้งค่าเซสชันเป็น "auto-commit" หรือ หากลูกค้าของคุณทำสัญญาอัตโนมัติ) จำเป็นต้องทราบว่าเมื่อทำงานกับ Oracle แต่ฉันไม่แน่ใจว่า MySQL จัดการกับข้อความทั้งสองประเภทได้อย่างไร ด้วยเหตุนี้ฉันต้องการทำให้ชัดเจนว่าฉันไม่แน่ใจเมื่อพูดถึง MySQL; เฉพาะกับ Oracle

ตัวอย่างของเมื่อเอ็นจินที่อิงธุรกรรม

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

ในกรณีนี้อาจมีตารางสำหรับแขก (ชื่อ, โทรศัพท์, อีเมล, ฯลฯ ) และตารางที่สองซึ่งติดตามจำนวนของแขกที่ลงทะเบียน เราจึงมีสองการดำเนินงานสำหรับ "ธุรกรรม" หนึ่งรายการ ตอนนี้สมมติว่าหลังจากเพิ่มข้อมูลผู้เยี่ยมชมในตาราง GUESTS แล้วการเชื่อมต่อขาดหายหรือข้อผิดพลาดที่มีผลกระทบเหมือนกัน ตาราง GUESTS ได้รับการอัปเดต (แทรกเข้าไป) แต่การเชื่อมต่อขาดหายไปก่อนที่จะมีการอัปเดต "ที่นั่งว่าง"

ขณะนี้เรามีแขกที่เพิ่มลงในตารางผู้เยี่ยมชม แต่จำนวนที่นั่งที่มีอยู่ไม่ถูกต้อง (ตัวอย่างเช่นค่าคือ 85 เมื่อเป็นจริง 84)

แน่นอนว่ามีหลายวิธีในการจัดการสิ่งนี้เช่นการติดตามที่นั่งที่มีอยู่ด้วย "100 ลบจำนวนแถวในตารางแขก" หรือรหัสบางอย่างที่ตรวจสอบว่าข้อมูลสอดคล้องกัน ฯลฯ .... แต่มีฐานข้อมูลตามธุรกรรม เครื่องยนต์เช่น InnoDB ทั้งทั้งหมดของการดำเนินงานมีความมุ่งมั่นหรือไม่มีของพวกเขา สิ่งนี้มีประโยชน์ในหลาย ๆ กรณี แต่อย่างที่ฉันบอกว่ามันไม่ใช่วิธีเดียวที่จะปลอดภัยไม่ใช่ (เป็นวิธีที่ดี แต่จัดการโดยฐานข้อมูลไม่ใช่โปรแกรมเมอร์ / ผู้เขียนสคริปต์)

นั่นคือทั้งหมด "การทำธุรกรรมตาม" เป็นหลักหมายถึงในบริบทนี้เว้นแต่ฉันจะหายไปบางสิ่งบางอย่าง - ว่าการทำธุรกรรมทั้งหมดประสบความสำเร็จตามที่ควรหรือไม่มีอะไรเปลี่ยนแปลงเนื่องจากการเปลี่ยนแปลงเพียงบางส่วนเท่านั้นที่สามารถทำให้ระเบียบของ ฐานข้อมูลอาจทำให้เสียหายได้ ...

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

สุดท้ายข้อควรทราบเกี่ยวกับการล็อคตารางเทียบกับการล็อกแถว:

หมายเหตุ: ผมอาจจะผิดในทุกที่ตามในเรื่องการ MySQL และสมมุติ / สถานการณ์เช่นนี้เป็นสิ่งที่จะมองเข้าไป แต่ผมอาจจะผิดในสิ่งที่ว่าเป็นไปได้ที่จะทำให้เกิดความเสียหายกับ MySQL ตัวอย่างมีความเป็นจริงมากในการเขียนโปรแกรมทั่วไปแม้ว่า MySQL จะมีกลไกมากกว่าในการหลีกเลี่ยงสิ่งต่าง ๆ ...

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

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

ลองทำอย่างนี้ตามขั้นตอน:

  1. กระบวนการหนึ่งอ่านค่าปัจจุบันสมมติว่ามันว่างเปล่าดังนั้น '0' จนถึงตอนนี้
  2. กระบวนการที่สองอ่านค่าปัจจุบันเช่นกันซึ่งยังคงเป็น 0
  3. กระบวนการหนึ่งเขียน (+1 ปัจจุบัน) ซึ่งเป็น 1
  4. กระบวนการที่สองควรจะเขียน 2 แต่เนื่องจากมันอ่านค่าปัจจุบันก่อนที่กระบวนการหนึ่งจะเขียนค่าใหม่มันก็จะเขียน 1 ไปยังตาราง

ฉันไม่แน่ใจว่าการเชื่อมต่อสองจุดสามารถเชื่อมโยงกันเช่นนั้นทั้งการอ่านก่อนที่จะเขียนครั้งแรก ... แต่ถ้าไม่เช่นนั้นฉันก็จะยังคงพบปัญหากับ

  1. กระบวนการหนึ่งอ่านค่าปัจจุบันซึ่งเป็น 0
  2. กระบวนการหนึ่งเขียน (ปัจจุบัน + 1) ซึ่งก็คือ 1
  3. กระบวนการที่สองอ่านค่าปัจจุบันทันที แต่ในขณะที่ประมวลผลหนึ่ง DID เขียน (อัพเดต) มันไม่ได้คอมมิตข้อมูลดังนั้นกระบวนการเดียวกันเท่านั้นที่สามารถอ่านค่าใหม่ที่อัปเดตในขณะที่คนอื่น ๆ ทั้งหมดเห็นค่าที่เก่ากว่าจนกว่าจะมีการคอมมิชชัน

นอกจากนี้อย่างน้อยกับฐานข้อมูล Oracle มีระดับการแยกซึ่งฉันจะไม่เสียเวลาของเราพยายามที่จะถอดความ นี่คือบทความที่ดีเกี่ยวกับเรื่องนั้นและแต่ละระดับการแยกมีข้อดีและข้อเสียซึ่งจะไปพร้อมกับเครื่องมือการทำธุรกรรมตามความสำคัญอาจอยู่ในฐานข้อมูล ...

ท้ายที่สุดอาจมีการป้องกันที่แตกต่างกันใน MyISAM แทนที่จะเป็นคีย์ต่างประเทศและการโต้ตอบตามธุรกรรม ดีสำหรับหนึ่งมีความจริงที่ว่าทั้งตารางถูกล็อคซึ่งทำให้มันมีโอกาสน้อยว่าการทำธุรกรรม / FKs จะจำเป็น

และถ้าคุณตระหนักถึงปัญหาการเกิดพร้อมกันใช่คุณสามารถเล่นได้อย่างปลอดภัยน้อยลงและเพียงแค่เขียนแอปพลิเคชันของคุณตั้งค่าระบบของคุณเพื่อให้ข้อผิดพลาดดังกล่าวเป็นไปไม่ได้ (รหัสของคุณรับผิดชอบมากกว่าฐานข้อมูลเอง) อย่างไรก็ตามในความคิดของฉันฉันจะบอกว่ามันเป็นการดีที่สุดที่จะใช้เป็นจำนวนมากที่สุดเท่าที่จะทำได้ป้องกันการเขียนโปรแกรมป้องกันและตระหนักว่าข้อผิดพลาดของมนุษย์เป็นไปไม่ได้ที่จะหลีกเลี่ยงอย่างสมบูรณ์ มันเกิดขึ้นกับทุกคนและทุกคนที่บอกว่าพวกเขามีภูมิคุ้มกันต่อมันจะต้องโกหกหรือยังไม่ได้ทำมากกว่าเขียนแอปพลิเคชัน / สคริปต์ "Hello World" ;-)

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

อย่าลังเลที่จะแก้ไขฉันแก้ไข "คำตอบ" นี้แม้แต่ลงคะแนน เพียงแค่พยายามปรับปรุงให้ดีขึ้นแทนที่จะแก้ไขข้อสันนิษฐานที่ผิดพลาดของฉันกับสิ่งอื่น ;-)

นี่เป็นคำตอบแรกของฉันดังนั้นโปรดให้อภัยความยาวเนื่องจากข้อจำกัดความรับผิดชอบทั้งหมดและอื่น ๆ ... ฉันไม่ต้องการที่จะฟังดูหยิ่งเมื่อฉันไม่แน่ใจ!



5

จากประสบการณ์ของฉัน MyISAM เป็นตัวเลือกที่ดีกว่าตราบใดที่คุณไม่ลบ DELETE อัปเดต INSERT รายการธุรกรรมและการทำดัชนีข้อความแบบเต็มจำนวนมาก BTW ตารางตรวจสอบที่น่ากลัว เมื่อตารางโตขึ้นในแง่ของจำนวนแถวคุณไม่รู้ว่าจะสิ้นสุดเมื่อใด


2
การจัดทำดัชนีข้อความแบบเต็มสามารถทำได้กับ MyISAM เท่านั้นไม่ใช่กับ InnoDB
Pixel Elephant

2
@PixelElephant ที่เริ่มเปลี่ยนแปลงใน MySQL 5.6 InnoDB มีดัชนีแบบ fulltext แต่จนถึงขณะนี้ยังไม่พร้อมสำหรับการใช้งาน IMHO
Bill Karwin

1
“ การจัดทำดัชนีข้อความแบบเต็มสามารถทำได้กับ MyISAM เท่านั้นไม่ใช่กับ InnoDB”: ไม่เป็นความจริงอีกต่อไปตั้งแต่ MySQL> = 5.6 ดูdev.mysql.com/doc/refman/5.6/en/fulltext-search.html
Hibou57

5

ฉันเข้าใจแล้วว่าถึงแม้ Myisam จะล็อคการโต้แย้ง แต่ก็ยังเร็วกว่า InnoDb ในสถานการณ์ส่วนใหญ่เนื่องจากรูปแบบการล็อคอย่างรวดเร็วที่ใช้ ฉันพยายาม Innodb หลายครั้งและมักจะกลับไปที่ MyIsam ด้วยเหตุผลใดข้อหนึ่ง นอกจากนี้ InnoDB ยังสามารถใช้งาน CPU ได้อย่างเข้มข้นในการเขียนจำนวนมาก


4

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

สิ่งที่ดีที่สุดที่คุณสามารถทำได้คือทดสอบตัวเลือกของคุณ การสลับระหว่าง MyISAM และ InnoDB นั้นไม่สำคัญดังนั้นให้โหลดข้อมูลทดสอบและยิง jmeter ไปยังไซต์ของคุณและดูว่าเกิดอะไรขึ้น


4

ฉันพยายามเรียกใช้การแทรกข้อมูลแบบสุ่มลงในตาราง MyISAM และ InnoDB ผลลัพธ์ที่ได้ค่อนข้างน่าตกใจ MyISAM ต้องการเวลาน้อยกว่าสองสามวินาทีในการแทรก 1 ล้านแถวจาก InnoDB เพียง 10,000 เท่านั้น!


2
คุณจะได้รับประสิทธิภาพเดียวกันหากคุณใช้ทรานแซคชันและปิดการเติมข้อความอัตโนมัติสำหรับเอ็นจิ้น InnoDB
stanleyxu2005

IDK ถ้าประสิทธิภาพเดียวกัน แต่นั่นคือสิ่งที่ฉันทำในแอพพลิเคชั่นที่ซับซ้อนกว่าและเร็วขึ้น
user965748

1
คุณไม่สามารถให้รายละเอียดที่แน่นอนเกี่ยวกับการทดสอบของคุณ - การตั้งค่าการกำหนดค่าแบบใด ก่อนหน้านี้มีอะไรในตาราง ข้อมูลประเภทใด และที่สำคัญที่สุด - มีการแทรกลำดับหรือไม่ ขนาน? เวลาของพวกเขาคืออะไร? มีแกน CPU กี่ตัว? หัวข้อ? ฯลฯ
einpoklum

3

myisam เป็น NOGO สำหรับประเภทของงานนั้น (เขียนพร้อมกันสูง) ฉันไม่ได้มีประสบการณ์มากกับ Innodb (ทดสอบ 3 ครั้งและพบว่าในแต่ละกรณีที่ประสิทธิภาพการดูด แต่เป็นเวลานานแล้วตั้งแต่การทดสอบครั้งสุดท้าย) ถ้าคุณ ไม่ได้บังคับให้เรียกใช้ mysql ลองพิจารณา postgres แล้วลองจัดการกับการเขียนพร้อมกันได้ดีกว่า


3

กล่าวโดยย่อคือ InnoDB นั้นดีถ้าคุณกำลังทำงานกับบางสิ่งที่ต้องการฐานข้อมูลที่เชื่อถือได้ซึ่งสามารถจัดการคำสั่ง INSERT และ UPDATE ได้จำนวนมาก

และ MyISAM นั้นดีถ้าคุณต้องการฐานข้อมูลที่ส่วนใหญ่จะใช้คำสั่ง read (SELECT) เป็นจำนวนมากแทนที่จะเขียน (INSERT และ UPDATES) โดยพิจารณาข้อเสียของมันในเรื่องของการล็อคตาราง

คุณอาจต้องการตรวจสอบ;
ข้อดีข้อเสียของ InnoDB
ข้อดีข้อเสียของ MyISAM


2

ฉันรู้ว่านี่จะไม่เป็นที่นิยม แต่ที่นี่จะไป:

myISAM ขาดการสนับสนุนข้อมูลสำคัญเกี่ยวกับฐานข้อมูลเช่นธุรกรรมและความสมบูรณ์ของการอ้างอิงซึ่งมักส่งผลให้เกิดแอปพลิเคชันที่บกพร่อง / บั๊ก คุณไม่สามารถเรียนรู้พื้นฐานการออกแบบฐานข้อมูลที่เหมาะสมหากไม่ได้รับการสนับสนุนจากโปรแกรมฐานข้อมูลของคุณ

การไม่ใช้ Referential Integrity หรือทรานแซคชันในโลกของฐานข้อมูลนั้นไม่เหมือนกับการใช้โปรแกรมเชิงวัตถุในโลกซอฟต์แวร์

มีอยู่ InnoDB ตอนนี้ใช้มันแทน! แม้แต่นักพัฒนา MySQL ก็ยอมรับที่จะเปลี่ยนสิ่งนี้เป็นเอ็นจิ้นเริ่มต้นในเวอร์ชันที่ใหม่กว่าแม้ว่า myISAM จะเป็นเอ็นจิ้นดั้งเดิมที่เป็นค่าเริ่มต้นในระบบเดิมทั้งหมด

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

ในช่วง 15 ปีที่ผ่านมาของการพัฒนาฉันได้ใช้ฐานข้อมูลและเครื่องมือมากมาย myISAM ชนกับฉันประมาณสิบครั้งในช่วงเวลานี้ฐานข้อมูลอื่นเพียงครั้งเดียว! และนั่นคือฐานข้อมูลไมโครซอฟต์ SQL ซึ่งนักพัฒนาบางคนเขียนรหัส CLR ที่ผิดพลาด (รันไทม์ภาษาทั่วไป - โดยทั่วไปคือรหัส C # ที่เรียกใช้ภายในฐานข้อมูล) โดยวิธีการนั้นมันไม่ใช่ความผิดของเอ็นจิ้นฐานข้อมูลอย่างแน่นอน

ฉันเห็นด้วยกับคำตอบอื่น ๆ ที่นี่ที่บอกว่าแอปพลิเคชันคุณภาพสูงที่มีความพร้อมใช้งานสูงและมีประสิทธิภาพสูงไม่ควรใช้ myISAM เพราะมันจะไม่ทำงาน แต่ก็ไม่ได้แข็งแกร่งหรือมั่นคงพอที่จะทำให้เกิดประสบการณ์ที่ไม่หงุดหงิด ดูคำตอบของ Bill Karwin สำหรับรายละเอียดเพิ่มเติม

PS ต้องรักเมื่อ myISAM fanboys downvote แต่ไม่สามารถบอกคุณได้ว่าคำตอบส่วนใดไม่ถูกต้อง


5
ฉันไม่ได้ลงคะแนน แต่ถ้าฉันทำมันจะเป็นการให้คำปรึกษาไม่เคยใช้ คำที่ไม่ควรจะตกอยู่ในคำศัพท์ของนักพัฒนา ... การเป็น caveat 'ไม่พูดไม่เคย'
hubson bropa

1

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


1

เกือบทุกครั้งที่ฉันเริ่มโครงการใหม่ฉัน Google คำถามเดียวกันนี้เพื่อดูว่าฉันได้คำตอบใหม่ ๆ หรือไม่

ในที่สุดมันก็เดือดร้อนลงไป - ฉันใช้ MySQL เวอร์ชันล่าสุดและทำการทดสอบ

ฉันมีตารางที่ฉันต้องการค้นหาคีย์ / ค่าการค้นหา ... และนั่นคือทั้งหมด ฉันต้องการรับค่า (0-512 ไบต์) สำหรับคีย์แฮช ไม่มีธุรกรรมจำนวนมากในฐานข้อมูลนี้ ตารางได้รับการอัปเดตเป็นครั้งคราว (โดยสมบูรณ์) แต่เป็นธุรกรรม 0 รายการ

ดังนั้นเราไม่ได้พูดถึงระบบที่ซับซ้อนที่นี่เรากำลังพูดถึงการค้นหาง่าย ๆ .. และอย่างไร (นอกเหนือจากการทำให้ผู้อยู่อาศัยในตาราง RAM) เราสามารถเพิ่มประสิทธิภาพ

ฉันยังทำการทดสอบกับฐานข้อมูลอื่น ๆ (เช่น NoSQL) เพื่อดูว่ามีทุกที่ที่ฉันจะได้รับประโยชน์หรือไม่ ข้อได้เปรียบที่ใหญ่ที่สุดที่ฉันพบคือการทำแผนที่สำคัญ แต่เท่าที่การค้นหาดำเนินไป MyISAM กำลังเติมเต็มทุกสิ่ง

แม้ว่าฉันจะไม่ทำธุรกรรมทางการเงินกับตาราง MyISAM แต่สำหรับการค้นหาง่าย ๆ คุณควรทดสอบมัน .. โดยทั่วไปแล้ว 2x ถึง 5x แบบสอบถาม / วินาที

ทดสอบฉันยินดีต้อนรับการอภิปราย


1

ถ้าเป็นเม็ดมีด 70% และอ่าน 30% จะเป็นเช่นนั้นมากกว่าในด้าน InnoDB


0

bottomline: หากคุณทำงานออฟไลน์ด้วยการเลือกข้อมูลจำนวนมาก MyISAM อาจให้ความเร็วที่ดีขึ้น (ดีกว่า) มากขึ้น

มีบางสถานการณ์ที่ MyISAM มีประสิทธิภาพมากกว่า InnoDB อย่างไร้ขีด จำกัด : เมื่อจัดการกับการทิ้งข้อมูลขนาดใหญ่แบบออฟไลน์ (เนื่องจากการล็อกตาราง)

ตัวอย่าง: ฉันกำลังแปลงไฟล์ csv (บันทึก 15M) จาก NOAA ซึ่งใช้ฟิลด์ VARCHAR เป็นคีย์ InnoDB ใช้เวลาตลอดไปแม้จะมีหน่วยความจำขนาดใหญ่ว่าง

นี่เป็นตัวอย่างของ csv (ฟิลด์แรกและฟิลด์ที่สามคือคีย์)

USC00178998,20130101,TMAX,-22,,,7,0700
USC00178998,20130101,TMIN,-117,,,7,0700
USC00178998,20130101,TOBS,-28,,,7,0700
USC00178998,20130101,PRCP,0,T,,7,0700
USC00178998,20130101,SNOW,0,T,,7,

เนื่องจากสิ่งที่ฉันต้องทำคือรันการอัพเดตแบบออฟไลน์ของปรากฏการณ์สภาพอากาศที่สังเกตฉันใช้ตาราง MyISAM เพื่อรับข้อมูลและรัน JOINS บนปุ่มเพื่อให้ฉันสามารถล้างไฟล์ขาเข้าและแทนที่ฟิลด์ VARCHAR ด้วยปุ่ม INT (ซึ่งเกี่ยวข้องกับ ตารางภายนอกที่เก็บค่า VARCHAR ดั้งเดิม)

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