MyISAM so với InnoDB [đã đóng]


857

Tôi đang làm việc trên một dự án bao gồm rất nhiều cơ sở dữ liệu ghi, tôi nói ( 70% chèn và 30% đọc ). Tỷ lệ này cũng sẽ bao gồm các bản cập nhật mà tôi cho là một lần đọc và một lần viết. Việc đọc có thể bị bẩn (ví dụ: tôi không cần thông tin chính xác 100% tại thời điểm đọc).
Nhiệm vụ trong câu hỏi sẽ được thực hiện hơn 1 triệu giao dịch cơ sở dữ liệu một giờ.

Tôi đã đọc rất nhiều thứ trên web về sự khác biệt giữa MyISAM và InnoDB và MyISAM dường như là sự lựa chọn rõ ràng đối với tôi đối với cơ sở dữ liệu / bảng cụ thể mà tôi sẽ sử dụng cho nhiệm vụ này. Từ những gì tôi dường như đang đọc, InnoDB là tốt nếu cần giao dịch vì khóa cấp hàng được hỗ trợ.

Có ai có kinh nghiệm với loại tải này (hoặc cao hơn) không? MyISAM có phải là con đường để đi?


13
Các Hiệu suất MySQL Blog là một nguồn lực lớn cho loại điều.
ceejayoz

3
Điều này sẽ phụ thuộc một chút vào việc hệ thống của bạn là OLTP hay hướng dữ liệu nhiều hơn theo định hướng (trong đó hầu hết các ghi được tải số lượng lớn).
số

35
MyISAM không hỗ trợ khóa hàng, giao dịch, thậm chí không hỗ trợ khóa ngoại ... địa ngục, vì nó không thể cung cấp ACID , thậm chí khó có thể được coi là cơ sở dữ liệu phù hợp! Đây là lý do tại sao InnoDB là công cụ mặc định kể từ MySQL 5.5 ... nhưng, vì lý do nào, MyISAM tiếp tục là công cụ mặc định cho các bảng được tạo trong PhpMyAdmin, vì vậy rất nhiều cơ sở dữ liệu nghiệp dư kể từ khi chạy trên MyISAM.
BlueRaja - Daniel Pflughoeft


Câu trả lời:


523

Tôi đã thảo luận ngắn gọn về câu hỏi này trong một bảng để bạn có thể kết luận nên đi với InnoDB hay MyISAM .

Dưới đây là một tổng quan nhỏ về công cụ lưu trữ db mà bạn nên sử dụng trong tình huống nào:

                                                 MyISAM InnoDB
-------------------------------------------------- --------------
Yêu cầu tìm kiếm toàn văn Có 5.6.4
-------------------------------------------------- --------------
Yêu cầu giao dịch Có
-------------------------------------------------- --------------
Truy vấn chọn thường xuyên Có      
-------------------------------------------------- --------------
Thường xuyên chèn, cập nhật, xóa Có
-------------------------------------------------- --------------
Khóa hàng (đa xử lý trên một bảng) Có
-------------------------------------------------- --------------
Thiết kế cơ sở quan hệ Có

Tóm lược

  • Trong hầu hết mọi trường hợp, InnoDB là cách tốt nhất để đi
  • Nhưng, đọc thường xuyên, hầu như không viết, hãy sử dụng MyISAM
  • Tìm kiếm toàn văn bản trong MySQL <= 5.5, sử dụng MyISAM

11
InnoDB có các chỉ mục văn bản đầy đủ trong MySQL 5.6, nhưng cho đến nay, chúng chưa thực sự sẵn sàng để sử dụng sản xuất.
Bill Karwin

3
Theo 12.9. Các chức năng tìm kiếm toàn văn bản, chỉ có thể sử dụng các chỉ mục toàn văn bản với các bảng InnoDB hoặc MyISAM. Có vẻ ổn đối với MySQL> = 5.6, tuy nhiên cùng một trang cho MySQL 5.5, vẫn nói rằng chỉ mục Toàn văn bản chỉ có thể được sử dụng với các bảng MyISAM. Bảng trên có thể được cập nhật để cho biết nó khác với các phiên bản MySQL như thế nào. Thật không may, cho đến nay, MySQL 5.5 dường như là tiêu chuẩn.
Hibou57

2
Có nghĩa là gì: InnoDB - full-text: 5.6.4?? Nó hs có hay không?

2
MyISAM cũng lưu trữ số hàng trong nội bộ. Do đó, hàm Count () gần như miễn phí trong MyISAM, trong khi nó mất một lượng thời gian đáng chú ý trong InnoDB.
Hedeshy

3
bảng tốt, nhưng thêm một hàng cho chất lượng và sự ổn định, MyIsam = no, innoDB = yes sẽ làm cho nó thậm chí còn tốt hơn
pilavdzice

268

Tôi không phải là chuyên gia cơ sở dữ liệu và tôi không nói từ kinh nghiệm. Tuy nhiên:

Bảng MyISAM sử dụng khóa cấp bảng . Dựa trên ước tính lưu lượng truy cập của bạn, bạn có gần 200 ghi mỗi giây. Với MyISAM, chỉ một trong số này có thể được tiến hành bất cứ lúc nào . Bạn phải đảm bảo rằng phần cứng của bạn có thể theo kịp các giao dịch này để tránh bị tràn ngập, tức là, một truy vấn có thể mất không quá 5ms.

Điều đó gợi ý cho tôi rằng bạn sẽ cần một công cụ lưu trữ hỗ trợ khóa cấp hàng, tức là InnoDB.

Mặt khác, việc viết một vài tập lệnh đơn giản để mô phỏng tải với mỗi công cụ lưu trữ là khá đơn giản, sau đó so sánh kết quả.


12
Gần 200? Nếu giao dịch trung bình của anh ta thực hiện 2,5 truy vấn, thì đó là [(2,5 * 1M) / 3600s =] gần hơn với 700.
Ozzy

12
Tôi cũng không đồng ý a single query can take no more than 5msvì bạn đã đưa ra 2 giả định không chắc chắn; A: tất cả các truy vấn cần cùng một bảng & B: chỉ có 1 kết nối khả dụng! Tôi nên thông báo cho bạn rằng thiết lập Linux & MySQL 5.5 với RAM cao có thể hỗ trợ tới 10.000 kết nối đồng thời (Xem: dev.mysql.com/doc/refman//5.5/en/too-many-connections.html )
Ozzy

152
Khi một bảng bị khóa, chỉ một truy vấn có thể chạy với nó cùng một lúc. Sẽ không có vấn đề gì nếu máy chủ hỗ trợ 10000 kết nối đồng thời, mỗi kết nối sẽ sao lưu trong khi bảng bị khóa.
Ryaner

2
Ngoài ra, có thể hữu ích khi biết rằng MyISAM hỗ trợ chỉ mục không gian trong khi InnoDB thì không. Và MyISAM dường như không sử dụng khóa ngoại mặc dù điều đó không ngăn tạo được.
kriver

4
@kriver: Bạn không thể có khóa ngoại trong bảng MyISAM. Bạn có thể bao gồm các định nghĩa FK trong các câu lệnh CREATE TABLE nhưng chúng (các định nghĩa) đơn giản bị bỏ qua.
ypercubeᵀᴹ

191

Mọi người thường nói về hiệu suất, đọc so với viết, khóa ngoại, v.v. nhưng theo tôi, có một tính năng bắt buộc khác phải có cho một công cụ lưu trữ: cập nhật nguyên tử.

Thử cái này:

  1. Phát hành CẬP NHẬT đối với bảng MyISAM của bạn mất 5 giây.
  2. Trong khi quá trình CẬP NHẬT đang diễn ra, hãy nói 2,5 giây sau, nhấn Ctrl-C để ngắt nó.
  3. Quan sát các hiệu ứng trên bàn. Có bao nhiêu hàng đã được cập nhật? Có bao nhiêu người không được cập nhật? Bảng thậm chí có thể đọc được hay đã bị hỏng khi bạn nhấn Ctrl-C?
  4. Hãy thử cùng một thử nghiệm với CẬP NHẬT đối với bảng InnoDB, làm gián đoạn quá trình truy vấn.
  5. Quan sát bảng InnoDB. Không có hàng nào được cập nhật. InnoDB đã đảm bảo bạn có các bản cập nhật nguyên tử và nếu không thể cam kết cập nhật đầy đủ, nó sẽ khôi phục toàn bộ thay đổi. Ngoài ra, bảng không bị hỏng. Điều này hoạt động ngay cả khi bạn sử dụng killall -9 mysqldđể mô phỏng một vụ tai nạn.

Hiệu suất là mong muốn tất nhiên, nhưng không mất dữ liệu nên kèn.


4
Đối với bản ghi, các đặc điểm khác của cơ sở dữ liệu ACID - Tính nhất quán, Cách ly và Độ bền - cũng không được MyISAM hỗ trợ.
Bill Karwin

Control-C không nên làm hỏng bảng - vì trong CHECK TABLE sẽ trả về thành công và tất cả các truy vấn sẽ tiếp tục mà không có lỗi. MyISAM sẽ hủy bỏ bản cập nhật mà không cập nhật tất cả các bản ghi, nhưng bảng sẽ duy trì tính toàn vẹn cấu trúc bên trong. Giết mysqld bằng SIGTERM sẽ có tác dụng tương tự. Tuy nhiên, nếu bạn cho nó SIGKILL (giết -9) hoặc một số tín hiệu bị hỏng (hoặc nó tự kiếm được khi gặp lỗi) hoặc nếu hệ điều hành bị hỏng / mất điện, thì đó là một câu chuyện khác - bạn có thể thấy Tham nhũng cấp MyISAM.
Sasha Pachev

1
InnoDB cũng có thể tham nhũng chính nó, thường là hợp lý hơn MyISAM khi nó xảy ra. Điều trớ trêu của ACID là chúng ta có khái niệm về tất cả hoặc không có gì. Vì vậy, khi InnoDB không thể cung cấp tất cả, nó không cung cấp gì cả - khẳng định nội bộ và nó từ chối chạy vì một byte trong một cấu trúc nào đó là sai - 90% thời gian có thể bị bỏ qua và hầu như chỉ ảnh hưởng đến một bảng. Các máy chủ Percona gần đây có tùy chọn để đối phó với nó - innodb_pass_corrupt_table.
Sasha Pachev

1
Tôi đã tìm kiếm loại thông tin này từ 3 ngày trước, bây giờ tôi đã nhận được thông tin này. InnoDB là tốt nhất. Cảm ơnBill Karwin
user3833682

3
@ Flow2k, Rất gần như không có, những ngày này. Ở công việc cuối cùng của chúng tôi, chúng tôi đã sử dụng MyISAM cho một bảng trên một máy chủ và lý do duy nhất là MyISAM có thể lưu trữ bảng cụ thể đó trong không gian ít hơn so với InnoDB. Chúng tôi bị hạn chế về không gian đĩa, vì vậy chúng tôi phải sử dụng MyISAM cho đến khi chúng tôi có thể di chuyển cơ sở dữ liệu sang máy chủ khác. Ở công việc mới của tôi, đã có một chính sách rằng mọi bảng phải là InnoDB.
Bill Karwin

138

Tôi đã làm việc trên một hệ thống có khối lượng lớn bằng MySQL và tôi đã thử cả MyISAM và InnoDB.

Tôi thấy rằng khóa cấp bảng trong MyISAM gây ra sự cố nghiêm trọng về hiệu suất cho khối lượng công việc của chúng tôi có vẻ giống với bạn. Thật không may, tôi cũng thấy rằng hiệu suất theo InnoDB cũng tệ hơn tôi mong đợi.

Cuối cùng, tôi đã giải quyết vấn đề tranh chấp bằng cách phân đoạn dữ liệu sao cho các phần chèn vào bảng "nóng" và chọn không bao giờ truy vấn bảng nóng.

Điều này cũng cho phép xóa (dữ liệu nhạy cảm với thời gian và chúng tôi chỉ giữ lại giá trị X ngày) xảy ra trên các bảng "cũ" mà một lần nữa không được chạm bởi các truy vấn chọn. InnoDB dường như có hiệu suất kém khi xóa hàng loạt, vì vậy nếu bạn dự định xóa dữ liệu, bạn có thể muốn cấu trúc dữ liệu theo cách mà dữ liệu cũ nằm trong một bảng cũ có thể bị bỏ thay vì chạy xóa.

Tất nhiên tôi không biết ứng dụng của bạn là gì nhưng hy vọng điều này cung cấp cho bạn cái nhìn sâu sắc về một số vấn đề với MyISAM và InnoDB.


3
'Cuối cùng, tôi đã giải quyết vấn đề tranh chấp bằng cách phân đoạn dữ liệu sao cho các phần chèn vào bảng "nóng" và chọn không bao giờ truy vấn bảng nóng. " - đó không phải là về cơ bản một nhóm đệm là gì?
BlueRaja - Danny Pflughoeft

15
Danny - Không, không thực sự. Điều chỉnh cài đặt máy chủ rất quan trọng, nhưng không có cách nào thay thế cho cấu trúc chu đáo của lược đồ của bạn. Nếu bạn có DB nhiều, lớn hơn nhiều so với RAM có sẵn và các mẫu truy cập chạm vào dữ liệu ngẫu nhiên trong toàn bộ DB thì tất cả các bộ đệm điều chỉnh trên thế giới sẽ không giúp bạn. Nếu bạn hiểu dữ liệu và các mẫu truy cập thì bạn có thể giảm bớt phần lớn nỗi đau thông qua thiết kế cẩn thận.
alanc10n

66

Một chút muộn của trò chơi ... nhưng đây là một bài viết khá toàn diện tôi đã viết vài tháng trước , kể chi tiết về sự khác biệt chính giữa MYISAM và InnoDB. Lấy một tách (và có thể là bánh quy), và thưởng thức.


Sự khác biệt chính giữa MyISAM và InnoDB là ở tính toàn vẹn tham chiếu và giao dịch. Ngoài ra còn có sự khác biệt khác như khóa, rollback và tìm kiếm toàn văn.

Tính toàn vẹn tham chiếu

Tính toàn vẹn tham chiếu đảm bảo rằng mối quan hệ giữa các bảng vẫn nhất quán. Cụ thể hơn, điều này có nghĩa là khi một bảng (ví dụ: Danh sách) có khóa ngoại (ví dụ: ID sản phẩm) trỏ đến một bảng khác (ví dụ: Sản phẩm), khi các cập nhật hoặc xóa xảy ra với bảng trỏ, các thay đổi này được xếp theo liên kết bàn. Trong ví dụ của chúng tôi, nếu một sản phẩm được đổi tên, các khóa ngoại của bảng liên kết cũng sẽ cập nhật; nếu một sản phẩm bị xóa khỏi bảng 'Sản phẩm', mọi danh sách trỏ đến mục đã xóa cũng sẽ bị xóa. Hơn nữa, bất kỳ danh sách mới nào cũng phải có khóa ngoại đó trỏ đến mục nhập hợp lệ, hiện có.

InnoDB là một DBMS quan hệ (RDBMS) và do đó có tính toàn vẹn tham chiếu, trong khi MyISAM thì không.

Giao dịch & nguyên tử

Dữ liệu trong bảng được quản lý bằng cách sử dụng các câu lệnh Ngôn ngữ thao tác dữ liệu (DML), chẳng hạn như CHỌN, CHERTN, CẬP NHẬT và XÓA. Một nhóm giao dịch hai hoặc nhiều câu lệnh DML cùng nhau thành một đơn vị công việc, do đó toàn bộ đơn vị được áp dụng hoặc không có câu lệnh nào trong số đó.

MyISAM không hỗ trợ các giao dịch trong khi InnoDB thì có.

Nếu một thao tác bị gián đoạn trong khi sử dụng bảng MyISAM, thao tác đó sẽ bị hủy ngay lập tức và các hàng (hoặc thậm chí dữ liệu trong mỗi hàng) bị ảnh hưởng vẫn bị ảnh hưởng, ngay cả khi thao tác không hoàn thành.

Nếu một hoạt động bị gián đoạn trong khi sử dụng bảng InnoDB, vì nó sử dụng các giao dịch có tính nguyên tử, bất kỳ giao dịch nào chưa hoàn thành sẽ không có hiệu lực, vì không có cam kết nào được thực hiện.

Khóa bảng vs Khóa hàng

Khi một truy vấn chạy trên bảng MyISAM, toàn bộ bảng mà nó đang truy vấn sẽ bị khóa. Điều này có nghĩa là các truy vấn tiếp theo sẽ chỉ được thực hiện sau khi kết thúc hiện tại. Nếu bạn đang đọc một bảng lớn và / hoặc có các hoạt động đọc và ghi thường xuyên, điều này có thể có nghĩa là một lượng lớn các truy vấn.

Khi một truy vấn chạy với bảng InnoDB, chỉ các hàng có liên quan bị khóa, phần còn lại của bảng vẫn có sẵn cho các hoạt động CRUD. Điều này có nghĩa là các truy vấn có thể chạy đồng thời trên cùng một bảng, miễn là chúng không sử dụng cùng một hàng.

Tính năng này trong InnoDB được gọi là đồng thời. Cũng giống như đồng thời, có một nhược điểm lớn áp dụng cho một phạm vi các bảng được chọn, trong đó có một chi phí chuyển đổi giữa các luồng nhân và bạn nên đặt giới hạn cho các luồng nhân để ngăn máy chủ dừng lại .

Giao dịch & Rollback

Khi bạn chạy một hoạt động trong MyISAM, các thay đổi được đặt; trong InnoDB, những thay đổi đó có thể được khôi phục. Các lệnh phổ biến nhất được sử dụng để kiểm soát các giao dịch là CAMIT, ROLLBACK và SAVEPOINT. 1. CAM KẾT - bạn có thể viết nhiều hoạt động DML, nhưng các thay đổi sẽ chỉ được lưu khi CAM KẾT được thực hiện 2. ROLLBACK - bạn có thể loại bỏ mọi hoạt động chưa được cam kết 3. SAVEPOINT - đặt một điểm trong danh sách các hoạt động mà hoạt động ROLLBACK có thể quay trở lại

độ tin cậy

MyISAM không cung cấp tính toàn vẹn dữ liệu - Lỗi phần cứng, tắt máy không sạch và các hoạt động bị hủy có thể khiến dữ liệu bị hỏng. Điều này sẽ yêu cầu sửa chữa đầy đủ hoặc xây dựng lại các chỉ mục và bảng.

Mặt khác, InnoDB sử dụng nhật ký giao dịch, bộ đệm ghi đôi và kiểm tra tự động và xác thực để ngăn ngừa tham nhũng. Trước khi InnoDB thực hiện bất kỳ thay đổi nào, nó sẽ ghi lại dữ liệu trước khi giao dịch vào tệp không gian bảng hệ thống có tên ibdata1. Nếu có sự cố, InnoDB sẽ tự động chuyển qua phát lại các nhật ký đó.

Lập chỉ mục FULLTEXT

InnoDB không hỗ trợ lập chỉ mục FULLTEXT cho đến khi phiên bản MySQL 5.6.4. Khi viết bài đăng này, nhiều phiên bản MySQL của nhà cung cấp dịch vụ lưu trữ chia sẻ vẫn dưới 5.6.4, điều đó có nghĩa là lập chỉ mục FULLTEXT không được hỗ trợ cho các bảng InnoDB.

Tuy nhiên, đây không phải là lý do hợp lệ để sử dụng MyISAM. Tốt nhất nên đổi sang nhà cung cấp dịch vụ lưu trữ hỗ trợ các phiên bản cập nhật của MySQL. Không phải là bảng MyISAM sử dụng lập chỉ mục FULLTEXT có thể được chuyển đổi thành bảng InnoDB.

Phần kết luận

Tóm lại, InnoDB nên là công cụ lưu trữ mặc định của bạn. Chọn MyISAM hoặc các loại dữ liệu khác khi chúng phục vụ một nhu cầu cụ thể.


Tôi đã tạo một kịch bản kiểm tra phiên php và hầu hết khóa của tôi là các chuỗi ngẫu nhiên của [az09] ... Innodb mất hơn 30ms để thực hiện INSERT ON DUPLICATE KEY UPDATEvì vậy tôi đã thử MyISAM và bây giờ nó đã giảm xuống <1ms ... Nhiều câu trả lời tôi thấy nói rằng innodb có một thời gian khó khăn để xử lý các khóa duy nhất 'không thể thay đổi' (chuỗi ngẫu nhiên) ... Bạn có bất kỳ đầu vào nào cho chúng tôi về điều đó không? Trong thực tế, tôi đã tự hỏi về tác động của nó khi sử dụng MyISAM nhưng câu trả lời tuyệt vời của bạn khiến tôi nhận ra đó là cách để giải quyết trường hợp cụ thể đó.
Louis Loudog Trottier

64

Đối với một tải có nhiều ghi và đọc hơn, bạn sẽ được hưởng lợi từ InnoDB. Vì InnoDB cung cấp khóa hàng thay vì khóa bảng, SELECTs của bạn có thể đồng thời, không chỉ với nhau mà còn với nhiều INSERTs. Tuy nhiên, trừ khi bạn có ý định sử dụng các giao dịch SQL, hãy đặt tuôn ra cam kết InnoDB thành 2 ( innodb_flush_log_at_trx_commit ). Điều này mang lại cho bạn rất nhiều hiệu năng thô mà nếu không bạn sẽ mất khi chuyển các bảng từ MyISAM sang InnoDB.

Ngoài ra, xem xét thêm nhân rộng. Điều này cung cấp cho bạn một số tỷ lệ đọc và vì bạn đã nói rằng các lần đọc của bạn không phải cập nhật, bạn có thể để bản sao bị tụt lại phía sau một chút. Chỉ cần chắc chắn rằng nó có thể đuổi kịp bất cứ thứ gì ngoại trừ lưu lượng truy cập lớn nhất hoặc nó sẽ luôn ở phía sau và sẽ không bao giờ đuổi kịp. Nếu bạn đi theo con đường này, tuy nhiên, tôi mạnh mẽ khuyên bạn nên cách ly đọc từ nô lệ và quản lý sao chép lag để xử lý cơ sở dữ liệu của bạn. Nó đơn giản hơn nhiều nếu mã ứng dụng không biết về điều này.

Cuối cùng, nhận thức được tải bảng khác nhau. Bạn sẽ không có cùng tỷ lệ đọc / ghi trên tất cả các bảng. Một số bảng nhỏ hơn với số lần đọc gần 100% có thể đủ khả năng ở lại MyISAM. Tương tự, nếu bạn có một số bảng gần 100% ghi, bạn có thể được hưởng lợi INSERT DELAYED, nhưng điều đó chỉ được hỗ trợ trong MyISAM ( DELAYEDmệnh đề được bỏ qua cho bảng InnoDB).

Nhưng điểm chuẩn để chắc chắn.


4
Là "InnoDB cam kết tuôn ra" mà bạn đề cập đến innodb_flush_log_at_trx_commit?
ceejayoz

2
Tôi thấy bài viết của bạn rất hữu ích - cảm ơn. Hiện đang đánh giá khi nào nên sử dụng MyISAM / InnoDB cho các bảng của tôi và bài đăng của bạn rất hữu ích. Chúc mừng.
starmonkey

2
dev.mysql.com/doc/refman/5.5/en/insert-delayed.html nêu rõ: Đối với các bảng MyISAM, nếu không có khối miễn phí nào ở giữa tệp dữ liệu, các câu lệnh CHỌN và INSERT đồng thời được hỗ trợ. Trong những trường hợp này, bạn rất hiếm khi cần sử dụng CHẬM TRÌ HOÃN với MyISAM.
tymtam

Bài viết rất nhiều thông tin. Tôi đã có câu hỏi tương tự như của op và tôi phải nói rằng bài đăng của bạn đã giúp tôi thoải mái về quyết định của công cụ cơ sở dữ liệu của mình. Cảm ơn! ++
Joe Majewski

Lưu ý nhanh: trì hoãn không còn được hỗ trợ trong 5.7. Thay vào đó, bạn có thể muốn kiểm tra với LOW_PRIORITY.
webmat

59

Để thêm vào sự lựa chọn rộng rãi của các câu trả lời ở đây bao gồm sự khác biệt cơ học giữa hai động cơ, tôi trình bày một nghiên cứu so sánh tốc độ theo kinh nghiệm.

Về tốc độ thuần túy, không phải lúc nào MyISAM cũng nhanh hơn InnoDB nhưng theo kinh nghiệm của tôi, nó có xu hướng nhanh hơn đối với môi trường làm việc PURE READ với hệ số khoảng 2,0-2,5 lần. Rõ ràng điều này không phù hợp với mọi môi trường - như những người khác đã viết, MyISAM thiếu những thứ như giao dịch và khóa ngoại.

Tôi đã thực hiện một chút điểm chuẩn bên dưới - Tôi đã sử dụng python để lặp và thư viện timeit để so sánh thời gian. Đối với sở thích, tôi cũng đã bao gồm công cụ bộ nhớ, điều này mang lại hiệu suất tốt nhất trên bảng mặc dù nó chỉ phù hợp với các bảng nhỏ hơn (bạn liên tục gặp phải The table 'tbl' is fullkhi vượt quá giới hạn bộ nhớ MySQL). Bốn loại lựa chọn tôi nhìn vào là:

  1. vanilla CHỌN
  2. đếm
  3. CHỌN điều kiện
  4. lựa chọn phụ được lập chỉ mục và không được lập chỉ mục

Đầu tiên, tôi đã tạo ba bảng bằng SQL sau

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

với 'MyISAM' được thay thế cho 'InnoDB' và 'bộ nhớ' trong bảng thứ hai và thứ ba.

 

1) Vanilla chọn

Truy vấn: SELECT * FROM tbl WHERE index_col = xx

Kết quả: bốc thăm

So sánh các vanilla chọn bởi các công cụ cơ sở dữ liệu khác nhau

Tốc độ của tất cả đều giống nhau, và như mong đợi là tuyến tính trong số lượng cột được chọn. InnoDB có vẻ nhanh hơn MyISAM một chút nhưng điều này thực sự rất khó khăn.

Mã số:

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) Đếm

Truy vấn: SELECT count(*) FROM tbl

Kết quả: MyISAM thắng

So sánh số lượng của các công cụ cơ sở dữ liệu khác nhau

Điều này cho thấy sự khác biệt lớn giữa MyISAM và InnoDB - MyISAM (và bộ nhớ) theo dõi số lượng hồ sơ trong bảng, vì vậy giao dịch này nhanh và O (1). Lượng thời gian cần thiết để InnoDB đếm tăng siêu tuyến tính với kích thước bảng trong phạm vi tôi đã điều tra. Tôi nghi ngờ nhiều sự tăng tốc từ các truy vấn MyISAM được quan sát thấy trong thực tế là do các hiệu ứng tương tự.

Mã số:

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) Chọn điều kiện

Truy vấn: SELECT * FROM tbl WHERE value1<0.5 AND value2<0.5 AND value3<0.5 AND value4<0.5

Kết quả: MyISAM thắng

So sánh các lựa chọn có điều kiện bởi các công cụ cơ sở dữ liệu khác nhau

Ở đây, MyISAM và bộ nhớ thực hiện gần như nhau và đánh bại InnoDB khoảng 50% cho các bảng lớn hơn. Đây là loại truy vấn mà lợi ích của MyISAM dường như được tối đa hóa.

Mã số:

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) Lựa chọn phụ

Kết quả: InnoDB thắng

Đối với truy vấn này, tôi đã tạo một tập hợp các bảng bổ sung cho lựa chọn phụ. Mỗi cột chỉ đơn giản là hai cột BIGINT, một cột có chỉ mục khóa chính và một cột không có chỉ mục. Do kích thước bảng lớn, tôi đã không kiểm tra bộ nhớ. Lệnh tạo bảng SQL là

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

trong đó một lần nữa, 'MyISAM' được thay thế cho 'InnoDB' trong bảng thứ hai.

Trong truy vấn này, tôi để kích thước của bảng chọn ở mức 1000000 và thay vào đó thay đổi kích thước của các cột được chọn phụ.

So sánh các lựa chọn phụ của các công cụ cơ sở dữ liệu khác nhau

Ở đây, InnoDB thắng dễ dàng. Sau khi chúng ta có được một bảng kích thước hợp lý, cả hai động cơ đều có tỷ lệ tuyến tính với kích thước của phần chọn phụ. Chỉ mục tăng tốc lệnh MyISAM nhưng thú vị là ít ảnh hưởng đến tốc độ InnoDB. subSelect.png

Mã số:

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

Tôi nghĩ rằng thông điệp mang về nhà của tất cả những điều này là nếu bạn thực sự quan tâm đến tốc độ, bạn cần phải đánh giá các truy vấn mà bạn đang thực hiện thay vì đưa ra bất kỳ giả định nào về động cơ nào sẽ phù hợp hơn.


1
hiệu suất không phải luôn luôn là sự cân nhắc duy nhất, làm thế nào về một biểu đồ về sự ổn định? một công cụ không tốt cho bất cứ điều gì nếu nó gặp sự cố và không hỗ trợ các tính năng cơ sở dữ liệu cơ bản.
pilavdzice

1
MyISAM có thể sẽ đánh bại InnoDB hầu hết các lần nếu my.cnftệp không được tối ưu hóa cho InnoDB. Bạn đã không đề cập đến cách my.cnftệp của bạn trông như thế nào, đây thực sự là yếu tố quan trọng nhất đối với hiệu suất của InnoDB.
itoctopus

Cảm ơn itoctopus - Tôi muốn nghe thêm về bất kỳ sự tối ưu nào bạn khuyên dùng. Mã đầy đủ được sử dụng trong các thử nghiệm này ở trên, vui lòng lặp lại các thử nghiệm với các tối ưu hóa khác nhau và cho chúng tôi biết nếu bạn tìm thấy những thay đổi đáng kể trong kết quả
StackG 19/11/17

32

Hơi lạc đề, nhưng vì mục đích tài liệu và tính đầy đủ, tôi muốn thêm vào như sau.

Nói chung, việc sử dụng InnoDB sẽ dẫn đến một ứng dụng phức tạp LESS, có lẽ cũng không có lỗi. Vì bạn có thể đặt tất cả tính toàn vẹn tham chiếu (ràng buộc khóa ngoài) vào bảng dữ liệu, nên bạn không cần bất kỳ nơi nào có nhiều mã ứng dụng như bạn cần với MyISAM.

Mỗi khi bạn chèn, xóa hoặc thay thế một bản ghi, bạn sẽ phải kiểm tra và duy trì các mối quan hệ. Ví dụ, nếu bạn xóa cha mẹ, tất cả trẻ em cũng nên bị xóa. Chẳng hạn, ngay cả trong một hệ thống viết blog đơn giản, nếu bạn xóa một bản ghi blog, bạn sẽ phải xóa các bản ghi nhận xét, lượt thích, v.v. Trong InnoDB, điều này được thực hiện tự động bởi công cụ cơ sở dữ liệu (nếu bạn đã chỉ định các điều khoản trong mô hình ) và không yêu cầu mã ứng dụng. Trong MyISAM, điều này sẽ phải được mã hóa vào ứng dụng, điều này rất khó khăn trong các máy chủ web. Về bản chất, các máy chủ web rất đồng thời / song song và vì các hành động này là nguyên tử và MyISAM không hỗ trợ các giao dịch thực tế, sử dụng MyISAM cho các máy chủ web là rủi ro / dễ bị lỗi.

Ngoài ra, trong hầu hết các trường hợp chung, InnoDB sẽ hoạt động tốt hơn nhiều, vì nhiều lý do, một trong số họ có thể sử dụng khóa mức kỷ lục thay vì khóa cấp bảng. Không chỉ trong một tình huống mà việc viết thường xuyên hơn đọc, mà còn trong các tình huống có sự tham gia phức tạp trên các bộ dữ liệu lớn. Chúng tôi nhận thấy hiệu suất tăng gấp 3 lần chỉ bằng cách sử dụng các bảng InnoDB trên các bảng MyISAM cho các phép nối rất lớn (mất vài phút).

Tôi sẽ nói rằng nói chung InnoDB (sử dụng một mô hình dữ liệu 3NF hoàn chỉnh với tính toàn vẹn tham chiếu) nên là lựa chọn mặc định khi sử dụng MySQL. MyISAM chỉ nên được sử dụng trong các trường hợp rất cụ thể. Nó rất có thể sẽ thực hiện ít hơn, dẫn đến một ứng dụng lớn hơn và nhiều lỗi hơn.

Đã nói điều này. Datamodelling là một nghệ thuật hiếm khi được tìm thấy trong số các thiết kế web / chương trình. Không xúc phạm, nhưng nó giải thích MyISAM đang được sử dụng rất nhiều.


31

InnoDB cung cấp:

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

Trong InnoDB, tất cả dữ liệu liên tiếp ngoại trừ văn bản và BLOB có thể chiếm tối đa 8.000 byte. Không có lập chỉ mục toàn văn có sẵn cho InnoDB. Trong InnoDB, các COUNT (*) (khi WHERE, GROUP BY hoặc THAM GIA không được sử dụng) thực thi chậm hơn trong MyISAM vì số lượng hàng không được lưu trữ bên trong. InnoDB lưu trữ cả dữ liệu và chỉ mục trong một tệp. InnoDB sử dụng nhóm bộ đệm để lưu trữ cả dữ liệu và chỉ mục.

MyISAM cung cấp:

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 có khóa cấp bảng, nhưng không khóa cấp hàng. Không có giao dịch. Không có phục hồi sự cố tự động, nhưng nó cung cấp chức năng sửa chữa bảng. Không có ràng buộc khóa ngoại. Các bảng MyISAM thường có kích thước nhỏ gọn hơn trên đĩa khi so sánh với các bảng InnoDB. Các bảng MyISAM có thể được giảm thêm kích thước bằng cách nén bằng myisampack nếu cần, nhưng trở thành chỉ đọc. MyISAM lưu các chỉ mục trong một tệp và dữ liệu trong một tệp khác. MyISAM sử dụng bộ đệm chính cho các chỉ mục bộ đệm và để lại việc quản lý bộ đệm dữ liệu cho hệ điều hành.

Nhìn chung, tôi muốn giới thiệu InnoDB cho hầu hết các mục đích và MyISAM cho các mục đích chuyên dụng. InnoDB hiện là công cụ mặc định trong các phiên bản MySQL mới.


2
fwiw, VARCHAR trong InnoDB cũng có thể chuyển đến các trang tràn, như BLOB và TEXT làm. Tất cả các loại dữ liệu này được lưu trữ tương tự trong nội bộ.
Bill Karwin

Thật tốt khi biết, @BillKarwin! Chúng tôi sử dụng VARCHAR rất nhiều trong ứng dụng của mình và việc VARCHAR đóng góp vào giới hạn ~ 8kB này có một chút liên quan.
rinogo


Trả lời không cập nhật annymore như công cụ innodb trong phiên bản MySQL 5.6+ hiện nay cũng hỗ trợ lập chỉ mục toàn văn bản và MySQL 5.5 + / 5.7 + hỗ trợ các loại dữ liệu không gian (5.5+)chỉ mục không gian (r-tee) (5.7+) .. Để được hỗ trợ tốt nhất, bạn ít nhất cần phải có phiên bản MySQL 5.7+
Raymond Nijland

25

Nếu bạn sử dụng MyISAM, bạn sẽ không làm gì cả giao dịch mỗi giờ, trừ khi bạn coi mỗi tuyên bố DML là một giao dịch (trong mọi trường hợp, sẽ không bền hoặc nguyên tử trong trường hợp xảy ra sự cố).

Vì vậy, tôi nghĩ rằng bạn phải sử dụng InnoDB.

300 giao dịch mỗi giây nghe có vẻ khá nhiều. Nếu bạn thực sự cần các giao dịch này để duy trì sự cố mất điện, hãy đảm bảo hệ thống con I / O của bạn có thể xử lý nhiều lần ghi này mỗi giây một cách dễ dàng. Bạn sẽ cần ít nhất một bộ điều khiển RAID với bộ nhớ cache được hỗ trợ bằng pin.

Nếu bạn có thể đạt được độ bền nhỏ, bạn có thể sử dụng InnoDB với innodb_flush_log_at_trx_commit được đặt thành 0 hoặc 2 (xem tài liệu để biết chi tiết), bạn có thể cải thiện hiệu suất.

Có một số bản vá có thể làm tăng sự tương tranh từ Google và các bản vá khác - chúng có thể được quan tâm nếu bạn vẫn không thể có đủ hiệu suất mà không có chúng.


24

Câu hỏi và hầu hết các câu trả lời đã hết hạn .

Vâng, đó là một câu chuyện của những người vợ cũ rằng MyISAM nhanh hơn InnoDB. thông báo ngày của câu hỏi: 2008; bây giờ là gần một thập kỷ sau. InnoDB đã có những bước tiến đáng kể kể từ đó.

Đồ thị đầy kịch tính đã cho một trường hợp MyISAM thắng: COUNT(*) không một WHEREkhoản. Nhưng đó có thực sự là những gì bạn dành thời gian làm?

Nếu bạn chạy thử nghiệm đồng thời , InnoDB rất có khả năng giành chiến thắng, thậm chí là chống lạiMEMORY .

Nếu bạn thực hiện bất kỳ ghi nào trong khi đo điểm chuẩn SELECTs, MyISAM và MEMORYcó khả năng bị mất do khóa cấp bảng.

Trên thực tế, Oracle rất chắc chắn rằng InnoDB tốt hơn là họ có tất cả trừ MyISAM khỏi 8.0.

Các câu hỏi được viết sớm trong ngày 5.1. Kể từ đó, các phiên bản chính này được đánh dấu là "Tính khả dụng chung":

  • 2010: 5.5 (.8 vào tháng 12)
  • 2013: 5.6 (.10 vào tháng 2)
  • 2015: 5.7 (.9 vào tháng 10)
  • 2018: 8.0 (.11 vào tháng 4)

Điểm mấu chốt: Đừng sử dụng MyISAM


2
Công nghệ cơ sở dữ liệu MySQL tiến bộ. Và câu hỏi và câu trả lời của StackOverflow vẫn bị sa lầy trong quá khứ. Sự khác biệt chính giữa MyISAM và InnoDB là ít hơn về "tải" trên máy chủ và nhiều hơn về hỗ trợ cho tính toàn vẹngiao dịch tham chiếu , cũng như khả năng đồng thờikhả năng phục hồi (+10)
spencer7593

12

Ngoài ra, hãy kiểm tra một số thay thế thả xuống cho chính MySQL:

MariaDB

http://mariadb.org/

MariaDB là một máy chủ cơ sở dữ liệu cung cấp chức năng thay thế thả xuống cho MySQL. MariaDB được xây dựng bởi một số tác giả gốc của MySQL, với sự hỗ trợ từ cộng đồng các nhà phát triển phần mềm nguồn mở và miễn phí rộng lớn hơn. Ngoài chức năng cốt lõi của MySQL, MariaDB cung cấp một bộ cải tiến tính năng phong phú bao gồm các công cụ lưu trữ thay thế, tối ưu hóa máy chủ và các bản vá.

Máy chủ Percona

https://launchpad.net/percona-server

Một sự thay thế thả xuống nâng cao cho MySQL, với hiệu suất tốt hơn, chẩn đoán được cải thiện và các tính năng được thêm vào.


1
Tôi đang sử dụng cả hai (Percona trong sản xuất, Maria trên cửa sổ phát triển). họ ar nhanh hơn và làm việc một cách hoàn hảo.
Moshe L

4
Điều này không trả lời câu hỏi. MariaDB và Percona là nhánh của MySQL và cũng sử dụng các công cụ InnoDB và MyISAM.
dr_

12

Xin lưu ý rằng giáo dục và kinh nghiệm chính thức của tôi là với Oracle, trong khi công việc của tôi với MySQL hoàn toàn mang tính cá nhân và theo thời gian của riêng tôi, vì vậy nếu tôi nói những điều đúng với Oracle nhưng không đúng với MySQL, tôi xin lỗi. Trong khi hai hệ thống chia sẻ rất nhiều, lý thuyết / đại số quan hệ là như nhau và cơ sở dữ liệu quan hệ vẫn là cơ sở dữ liệu quan hệ, vẫn còn nhiều khác biệt !!

Tôi đặc biệt thích (cũng như khóa cấp hàng) rằng InnoDB dựa trên giao dịch, nghĩa là bạn có thể đang cập nhật / chèn / tạo / thay đổi / thả / v.v nhiều lần cho một "thao tác" của ứng dụng web của mình. Vấn đề phát sinh là nếu chỉ một số trong những thay đổi / hoạt động đó được cam kết, nhưng một số khác thì không, hầu hết các lần (tùy thuộc vào thiết kế cụ thể của cơ sở dữ liệu) sẽ kết thúc với cơ sở dữ liệu có cấu trúc / dữ liệu xung đột.

Lưu ý: Với Oracle, các câu lệnh tạo / thay đổi / thả được gọi là câu lệnh "DDL" (Định nghĩa dữ liệu) và ngầm kích hoạt một cam kết. Các câu lệnh chèn / cập nhật / xóa, được gọi là "DML" (Thao tác dữ liệu), không được cam kết tự động, nhưng chỉ khi DDL, cam kết hoặc thoát / thoát được thực hiện (hoặc nếu bạn đặt phiên của mình thành "tự động cam kết" hoặc nếu khách hàng của bạn tự động cam kết). Cần phải nhận thức được điều đó khi làm việc với Oracle, nhưng tôi không chắc chắn cách MySQL xử lý hai loại câu lệnh này. Vì điều này, tôi muốn làm rõ rằng tôi không chắc về điều này khi nói đến MySQL; chỉ với Oracle.

Một ví dụ về khi công cụ dựa trên giao dịch vượt trội:

Giả sử tôi hoặc bạn đang ở trên một trang web để đăng ký tham dự một sự kiện miễn phí và một trong những mục đích chính của hệ thống là chỉ cho phép tối đa 100 người đăng ký, vì đó là giới hạn của chỗ ngồi dành cho sự kiện. Khi đạt được 100 lần đăng ký, hệ thống sẽ vô hiệu hóa các lần đăng ký tiếp theo, ít nhất là cho đến khi những người khác hủy bỏ.

Trong trường hợp này, có thể có một bảng cho khách (tên, điện thoại, email, v.v.) và một bảng thứ hai theo dõi số lượng khách đã đăng ký. Do đó, chúng tôi có hai hoạt động cho một "giao dịch". Bây giờ, giả sử rằng sau khi thông tin khách được thêm vào bảng GUESTS, có lỗi mất kết nối hoặc lỗi có cùng tác động. Bảng GUESTS đã được cập nhật (chèn vào), nhưng kết nối bị mất trước khi "chỗ ngồi có sẵn" có thể được cập nhật.

Bây giờ chúng tôi có một khách được thêm vào bảng khách, nhưng số lượng ghế có sẵn hiện không chính xác (ví dụ: giá trị là 85 khi thực sự là 84).

Tất nhiên, có nhiều cách để xử lý việc này, chẳng hạn như theo dõi số ghế có sẵn với "100 trừ số lượng hàng trong bảng khách" hoặc một số mã kiểm tra xem thông tin có nhất quán không, v.v .... Nhưng với cơ sở dữ liệu dựa trên giao dịch công cụ như InnoDB, hoặc TẤT CẢ các hoạt động được cam kết hoặc KHÔNG phải là hoạt động. Điều này có thể hữu ích trong nhiều trường hợp, nhưng như tôi đã nói, đó không phải là cách CHỈ để an toàn, không (một cách hay, tuy nhiên, được xử lý bởi cơ sở dữ liệu, không phải lập trình viên / người viết kịch bản).

Đó là tất cả "dựa trên giao dịch" về cơ bản có nghĩa là trong bối cảnh này, trừ khi tôi thiếu một cái gì đó - rằng toàn bộ giao dịch thành công như mong muốn hoặc không có gì thay đổi, vì chỉ thực hiện một số thay đổi có thể tạo ra sự thay đổi nhỏ của SEVERE cơ sở dữ liệu, thậm chí có thể làm hỏng nó ...

Nhưng tôi sẽ nói thêm một lần nữa, đó không phải là cách duy nhất để tránh gây rối. Nhưng đó là một trong những phương thức mà công cụ tự xử lý, khiến bạn phải viết mã / tập lệnh mà chỉ cần lo lắng về việc "giao dịch có thành công hay không và tôi phải làm gì nếu không (chẳng hạn như thử lại)", thay vì thủ công viết mã để kiểm tra "thủ công" từ bên ngoài cơ sở dữ liệu và thực hiện nhiều công việc hơn cho các sự kiện đó.

Cuối cùng, một lưu ý về khóa bảng so với khóa hàng:

TUYÊN BỐ TỪ CHỐI: Tôi có thể sai trong tất cả các vấn đề liên quan đến MySQL và các tình huống giả định / ví dụ là những điều cần xem xét, nhưng tôi có thể sai về những gì chính xác có thể gây ra tham nhũng với MySQL. Tuy nhiên, các ví dụ rất thực tế trong lập trình nói chung, ngay cả khi MySQL có nhiều cơ chế hơn để tránh những điều như vậy ...

Dù sao, tôi khá tự tin trong việc đồng ý với những người đã lập luận rằng có bao nhiêu kết nối được phép tại một thời điểm nào không làm việc xung quanh một bảng khóa. Trong thực tế, nhiều kết nối là toàn bộ điểm khóa bảng !! Vì vậy, các quy trình / người dùng / ứng dụng khác không thể làm hỏng cơ sở dữ liệu bằng cách thay đổi cùng một lúc.

Làm thế nào hai hoặc nhiều kết nối làm việc trên cùng một hàng sẽ tạo ra một NGÀY THỰC SỰ THỰC cho bạn ?? Giả sử có hai quy trình cả hai muốn / cần cập nhật cùng một giá trị trong cùng một hàng, giả sử vì hàng đó là bản ghi của chuyến tham quan bằng xe buýt và mỗi hai quy trình đồng thời muốn cập nhật "người đi xe" hoặc "có sẵn" trường là "giá trị hiện tại cộng với 1."

Hãy làm điều này theo giả thuyết, từng bước một:

  1. Quá trình một người đọc giá trị hiện tại, giả sử nó trống, do đó '0' cho đến nay.
  2. Quá trình hai cũng đọc giá trị hiện tại, vẫn là 0.
  3. Quá trình một ghi (hiện tại + 1) là 1.
  4. Quá trình hai nên viết 2, nhưng vì nó đọc giá trị hiện tại trước khi tiến trình một ghi giá trị mới, nó cũng ghi 1 vào bảng.

Tôi không chắc chắn rằng hai kết nối có thể xen kẽ như vậy, cả hai đều đọc trước khi kết nối đầu tiên viết ... Nhưng nếu không, thì tôi vẫn sẽ gặp vấn đề với:

  1. Quá trình một đọc giá trị hiện tại, là 0.
  2. Quá trình một ghi (hiện tại + 1), đó là 1.
  3. Quá trình hai đọc giá trị hiện tại bây giờ. Nhưng trong khi xử lý một lần ghi DID (cập nhật), nó không cam kết dữ liệu, do đó, chỉ có quá trình đó mới có thể đọc giá trị mới mà nó cập nhật, trong khi tất cả những người khác nhìn thấy giá trị cũ hơn, cho đến khi có một cam kết.

Ngoài ra, ít nhất là với cơ sở dữ liệu của Oracle, có các mức cô lập mà tôi sẽ không lãng phí thời gian để cố gắng diễn giải. Đây là một bài viết hay về chủ đề đó, và mỗi cấp độ cách ly đều có ưu và nhược điểm, sẽ đi cùng với việc các công cụ dựa trên giao dịch quan trọng có thể như thế nào trong cơ sở dữ liệu ...

Cuối cùng, có thể có các biện pháp bảo vệ khác nhau được áp dụng trong MyISAM, thay vì các khóa ngoại và tương tác dựa trên giao dịch. Chà, đối với một người, có một thực tế là toàn bộ một bảng bị khóa, điều đó làm cho ít có khả năng các giao dịch / FK là cần thiết .

Và than ôi, nếu bạn nhận thức được các vấn đề tương tranh này, vâng, bạn có thể chơi nó ít an toàn hơn và chỉ cần viết các ứng dụng của bạn, thiết lập hệ thống của bạn để không xảy ra lỗi đó (mã của bạn chịu trách nhiệm, thay vì cơ sở dữ liệu). Tuy nhiên, theo tôi, tôi sẽ nói rằng tốt nhất là luôn sử dụng càng nhiều biện pháp bảo vệ càng tốt, lập trình phòng thủ và luôn ý thức được rằng lỗi của con người là không thể tránh khỏi hoàn toàn. Điều đó xảy ra với tất cả mọi người và bất cứ ai nói rằng họ miễn dịch với điều đó đều phải nói dối hoặc không làm gì hơn là viết một ứng dụng / kịch bản "Hello World". ;-)

Tôi hy vọng rằng MỘT SỐ điều đó hữu ích với một số người, và thậm chí hơn thế nữa, tôi hy vọng rằng tôi không chỉ là thủ phạm của các giả định và là một con người có lỗi !! Tôi xin lỗi nếu có, nhưng các ví dụ rất tốt để suy nghĩ, nghiên cứu rủi ro, v.v., ngay cả khi chúng không có tiềm năng trong bối cảnh cụ thể này.

Hãy sửa tôi, chỉnh sửa "câu trả lời" này, thậm chí bỏ phiếu xuống. Chỉ cần cố gắng cải thiện, thay vì sửa chữa một giả định xấu của tôi với người khác. ;-)

Đây là phản hồi đầu tiên của tôi, vì vậy xin vui lòng tha thứ cho độ dài do tất cả các từ chối, v.v ... Tôi chỉ không muốn tỏ ra kiêu ngạo khi tôi không chắc chắn lắm!



5

Theo kinh nghiệm của tôi, MyISAM là một lựa chọn tốt hơn miễn là bạn không thực hiện XÓA, CẬP NHẬT, toàn bộ rất nhiều CHỨNG CHỈ, giao dịch và lập chỉ mục toàn văn. BTW, KIỂM TRA BẢNG thật kinh khủng. Khi bảng cũ hơn về số lượng hàng, bạn không biết khi nào nó sẽ kết thúc.


2
Lập chỉ mục toàn văn chỉ có thể với MyISAM, không phải với InnoDB.
Pixel Voi

2
@PixelElephant, điều đó bắt đầu thay đổi trong MySQL 5.6. InnoDB có loại chỉ mục toàn văn bản, nhưng cho đến nay loại này chưa sẵn sàng để sử dụng IMHO.
Bill Karwin

1
Chỉ có thể lập chỉ mục toàn văn bản với MyISAM, không phải với InnoDB, không còn đúng vì MySQL> = 5.6. Xem dev.mysql.com/doc/refman/5.6/en/fulltext-search.html .
Hibou57

5

Tôi đã nhận ra rằng mặc dù Myisam có sự tranh chấp về khóa, nhưng nó vẫn nhanh hơn InnoDb trong hầu hết các kịch bản vì kế hoạch mua lại khóa nhanh mà nó sử dụng. Tôi đã thử vài lần Innodb và luôn quay trở lại MyIsam vì lý do này hay lý do khác. Ngoài ra InnoDB có thể rất tốn CPU trong tải ghi lớn.


4

Mỗi ứng dụng có hồ sơ hiệu suất riêng để sử dụng cơ sở dữ liệu và rất có thể nó sẽ thay đổi theo thời gian.

Điều tốt nhất bạn có thể làm là kiểm tra các lựa chọn của bạn. Chuyển đổi giữa MyISAM và InnoDB là không đáng kể, vì vậy hãy tải một số dữ liệu thử nghiệm và lửa kế vào trang web của bạn và xem điều gì sẽ xảy ra.


4

Tôi đã cố chạy chèn dữ liệu ngẫu nhiên vào các bảng MyISAM và InnoDB. Kết quả khá sốc. MyISAM cần ít hơn vài giây để chèn 1 triệu hàng so với InnoDB chỉ với 10 nghìn!


2
Bạn sẽ nhận được hiệu suất tương tự, nếu bạn sử dụng giao dịch và tắt tự động tự động cho công cụ InnoDB.
stanleyxu2005

IDK nếu cùng hiệu suất, nhưng đó là những gì tôi làm trong các ứng dụng phức tạp hơn và nó tăng tốc nó.
dùng965748

1
Bạn không thể cung cấp chi tiết chính xác về thử nghiệm của mình - cài đặt cấu hình nào? Những gì đã có trong bảng trước? Những loại dữ liệu? và có lẽ quan trọng nhất - đã có chèn liên tiếp? Song song, tương đông? Thời gian của họ là gì? Có bao nhiêu lõi CPU? Chủ đề? v.v.
einpoklum

3

myisam là một NOGO cho loại khối lượng công việc đó (ghi đồng thời cao), tôi không có nhiều kinh nghiệm với innodb (đã thử nghiệm 3 lần và tìm thấy trong mỗi trường hợp hiệu suất bị giảm, nhưng đó là một thời gian kể từ lần thử nghiệm cuối cùng) nếu bạn 'Không bị buộc phải chạy mysql, hãy xem xét thử lại các postgres vì ​​nó xử lý việc viết đồng thời NHIỀU tốt hơn


3

Nói tóm lại, InnoDB là tốt nếu bạn đang làm việc trên một cái gì đó cần một cơ sở dữ liệu đáng tin cậy có thể xử lý rất nhiều hướng dẫn INSERT và UPDATE.

và, MyISAM là tốt nếu bạn cần một cơ sở dữ liệu chủ yếu sẽ thực hiện nhiều hướng dẫn đọc (CHỌN) thay vì viết (CHERTN và CẬP NHẬT), xem xét nhược điểm của nó đối với khóa bảng.

bạn có thể muốn kiểm tra;
Ưu và nhược điểm của InnoDB
Ưu và nhược điểm của MyISAM


2

Tôi biết điều này sẽ không phổ biến nhưng ở đây đi:

myISAM thiếu hỗ trợ cho các yếu tố cần thiết của cơ sở dữ liệu như giao dịch và tính toàn vẹn tham chiếu thường dẫn đến các ứng dụng bị lỗi / lỗi. Bạn không thể học các nguyên tắc thiết kế cơ sở dữ liệu phù hợp nếu chúng thậm chí không được hỗ trợ bởi công cụ db của bạn.

Không sử dụng tính toàn vẹn tham chiếu hoặc giao dịch trong thế giới cơ sở dữ liệu cũng giống như không sử dụng lập trình hướng đối tượng trong thế giới phần mềm.

InnoDB tồn tại ngay bây giờ, sử dụng thay thế! Ngay cả các nhà phát triển MySQL cuối cùng cũng đã thừa nhận thay đổi điều này thành công cụ mặc định trong các phiên bản mới hơn, mặc dù myISAM là công cụ ban đầu là mặc định trong tất cả các hệ thống cũ.

Không, không quan trọng bạn đang đọc hay viết hay bạn đang cân nhắc hiệu năng gì, sử dụng myISAM có thể dẫn đến nhiều vấn đề khác nhau, chẳng hạn như vấn đề này tôi vừa gặp phải: Tôi đang thực hiện đồng bộ hóa cơ sở dữ liệu và cùng lúc với người khác đã truy cập một ứng dụng đã truy cập một bảng được đặt vào myISAM. Do thiếu hỗ trợ giao dịch và độ tin cậy kém của công cụ này, điều này đã làm hỏng toàn bộ cơ sở dữ liệu và tôi phải tự khởi động lại mysql!

Trong 15 năm phát triển, tôi đã sử dụng nhiều cơ sở dữ liệu và động cơ. myISAM đã đánh sập tôi khoảng một chục lần trong giai đoạn này, các cơ sở dữ liệu khác, chỉ một lần! Và đó là cơ sở dữ liệu SQL microsoft nơi một số nhà phát triển đã viết mã CLR bị lỗi (thời gian chạy ngôn ngữ chung - về cơ bản là mã C # thực thi bên trong cơ sở dữ liệu), đó không phải là lỗi chính xác của cơ sở dữ liệu.

Tôi đồng ý với các câu trả lời khác ở đây nói rằng các ứng dụng hiệu suất cao, hiệu suất cao không nên sử dụng myISAM vì nó không hoạt động, nó không đủ mạnh hoặc ổn định để mang lại trải nghiệm không bị thất vọng. Xem câu trả lời của Bill Karwin để biết thêm chi tiết.

PS Gotta thích nó khi fanboy của tôi downvote nhưng không thể cho bạn biết phần nào của câu trả lời này là không chính xác.


5
Tôi đã không downvote, nhưng nếu tôi đã làm nó sẽ được khuyên không bao giờ sử dụng. từ không bao giờ nên bị đánh vần trong từ vựng của nhà phát triển ... hãy cẩn thận là "không bao giờ nói không bao giờ".
hubson bropa

1

Đối với tỷ lệ đọc / ghi đó, tôi đoán InnoDB sẽ hoạt động tốt hơn. Vì bạn ổn với việc đọc bẩn, bạn có thể (nếu bạn đủ khả năng) sao chép thành nô lệ và để tất cả các lần đọc của bạn chuyển sang nô lệ. Ngoài ra, hãy xem xét chèn hàng loạt, thay vì một bản ghi tại một thời điểm.


1

Hầu như mỗi khi tôi bắt đầu một dự án mới, tôi sẽ Google cùng một câu hỏi để xem liệu tôi có đưa ra bất kỳ câu trả lời mới nào không.

Cuối cùng nó cũng sôi lên - Tôi lấy phiên bản mới nhất của MySQL và chạy thử nghiệm.

Tôi có các bảng nơi tôi muốn thực hiện tra cứu khóa / giá trị ... và đó là tất cả. Tôi cần lấy giá trị (0-512 byte) cho khóa băm. Không có nhiều giao dịch trên DB này. Bảng thỉnh thoảng được cập nhật (toàn bộ), nhưng 0 giao dịch.

Vì vậy, chúng ta không nói về một hệ thống phức tạp ở đây, chúng ta đang nói về một tra cứu đơn giản, .. và làm thế nào (ngoài việc làm cho cư dân RAM bảng) chúng ta có thể tối ưu hóa hiệu suất.

Tôi cũng thực hiện các thử nghiệm trên các cơ sở dữ liệu khác (ví dụ NoQuery) để xem liệu có nơi nào tôi có thể nhận được lợi thế không. Ưu điểm lớn nhất mà tôi đã tìm thấy là trong ánh xạ chính, nhưng theo như tìm kiếm, MyISAM hiện đang đứng đầu tất cả.

Mặc dù, tôi sẽ không thực hiện các giao dịch tài chính với các bảng MyISAM nhưng để tìm kiếm đơn giản, bạn nên kiểm tra nó .. thường là gấp 2 đến 5 lần các truy vấn / giây.

Kiểm tra nó, tôi hoan nghênh tranh luận.


1

Nếu nó được chèn 70% và đọc 30% thì nó giống như ở phía InnoDB hơn.


0

điểm mấu chốt: nếu bạn đang làm việc ngoại tuyến với các lựa chọn trên khối dữ liệu lớn, MyISAM có thể sẽ cung cấp cho bạn tốc độ tốt hơn (tốt hơn nhiều).

có một số tình huống khi MyISAM hiệu quả hơn nhiều so với InnoDB: khi thao tác các bãi dữ liệu lớn ngoại tuyến (vì khóa bảng).

ví dụ: Tôi đã chuyển đổi tệp csv (bản ghi 15 triệu) từ NOAA sử dụng các trường VARCHAR làm khóa. InnoDB đã dùng mãi mãi, ngay cả với khối lượng lớn bộ nhớ có sẵn.

đây là một ví dụ về csv (trường thứ nhất và thứ ba là khóa).

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,

vì những gì tôi cần làm là chạy một bản cập nhật ngoại tuyến hàng loạt các hiện tượng thời tiết quan sát được, tôi sử dụng bảng MyISAM để nhận dữ liệu và chạy THAM GIA trên các phím để tôi có thể xóa tệp đến và thay thế các trường VARCHAR bằng các khóa INT (có liên quan đến các bảng bên ngoài nơi lưu trữ các giá trị VARCHAR gốc).

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.