Programming log - Shindo200

イベント参加記録とプログラミング系の雑記

MySQLの「InnoDB」と「MyISAM」についての易しめな違い

今回はMySQLのストレージエンジンという重箱の隅をつつくようなネタをメモしておきます。
私はMySQLについてはよちよちレベルなので、込み入った内容には触れられません。初心者でも理解しやすい部分での違いを中心にまとめていこうと思います。

【復習】ストレージエンジンとは

MySQLなどのデータベース管理システムが、データベースにデータを書き込んだり、読み込んだりするときに使われる基盤を「ストレージエンジン」と呼びます。初心者同士の会話の中で「MySQLを使ってデータを保存する」と表現することがありますが、実際にデータの保存処理を行っているのが、このストレージエンジンになります。MySQLの論理構造を図で載せます。

f:id:Shindo_Masaya:20150401154842p:plain:w500

MySQLは「データベース管理システム」ですので、データベースを管理するために必要である様々な機能が搭載されています。その中の「データの読み書き」という部分を担当しているのがストレージエンジンになります。

MySQLには様々なストレージエンジンが最初から組み込まれています。その中でも特に有名なのがInnoDBMyISAMです。どちらも「データの読み書き」というストレージエンジンに必須である機能は搭載されていますが、細かい機能に違いがあります。初心者はどちらを使えばいいのか迷うと思います。さて、どちらを使えばいいのでしょうか。

MyISAMInnoDBの違いの中で、初心者が理解しやすいところ

いよいよ本題に入ります。MySQLのバージョン5.5以降では、InnoDBというストレージエンジンがデフォルトとなっています。InnoDBの特徴を調べて紹介することは私には難し過ぎますので、InnoDBMyISAMの違いの中で、わりと理解しやすいものを2つだけを紹介します。

ロックの粒度

1つ目はロックの粒度です。ロックとは何でしょうか。例えば、複数のクライアントから同時に「このレコードを更新してください」という内容のリクエストが来たとします。ストレージエンジンが1つ目のリクエストの内容に沿って、更新処理を始めました。その最中に2つ目のリクエストの更新処理も始めてしまいました。こうなると、1つ目のリクエストと2つ目のリクエストが混ざり合って、誰も意図していなかった内容で更新されてしまうかもしれません。このようなことを防ぐために、ストレージエンジンは更新対象のテーブルやレコードに対して書き込みや読み込みを一時的に止めるように命令を出します。これを「ロック」と呼びます。InnoDBは対象のレコードに対してロックを行いますが、MyISAMは対象のテーブルに対してロックを行います。InnoDBは同じテーブルであっても異なるレコードであれば同時にリクエストを処理することができますが、MyISAMはそうはいきません。InnoDBのがロックの粒度が低いので、MyISAMより処理が早くなると考えられているようです。ただし、マシンへの負担はMyISAMのが小さいようですので、複数のクライアントから同時に更新などのリクエストを受けることが少ないアプリであれば、MyISAMのが良いという意見もあるようです。

トランザクション

2つ目はトランザクションの有無についてです。トランザクションを一言で説明すると複数SQLクエリを1つの作業としてまとめたもの」です。例えば、Aさんが自分の銀行口座からBさんの銀行口座に10,000円を振り込むとします。これをプラグラムに処理させる場合、手順はこのようになります。

1. Aさんの銀行口座の残高が10,000円以上であることを確認する。

2. Aさんの銀行口座の残高から10,000円を引く。

3. Bさんの銀行口座の残高に10,000円を足す。

この一連の手順が正常に終われば、振り込みは完了です。しかし、途中でトラブルが発生し、処理が中断されることがあるかもしれません。いずれかのステップで失敗した場合は、ロールバックしたいですね。そこで登場するのがトランザクションです。上記の一連の手順をトランザクションとしてまとめておくと、いずれかのステップで失敗した場合にロールバックを行ってくれます。InnoDBではトランザクション機能をサポートしていますが、MyISAMではサポートしていません。トランザクション機能を使いたいならば、InnoDB(もしくは、他のトランザクション機能があるストレージエンジン)を選ばないといけません。

トランザクションの実験

念のために、トランザクション機能の有無をRailsを使って確認してみます。InnoDBのテーブルを用意し、適当なコントローラーに下記のメソッドを追加して、このメソッドを呼び出してみます。

def test_transaction
  ActiveRecord::Base.transaction do
    User.create(name: 'hoge')
    fail
  end
end

メソッド呼び出し後に、Userの総数を見てみます。

# InnoDBのとき
User.count
=> 0

0件です。途中で処理が失敗していますので、ロールバックされています。同じ処理をMyISAMでも行ってみます。

# MyISAMのとき
User.count
=> 1

データが1件残っています。トランザクションが機能していませんね。やはりMyISAMにはトランザクション機能がないようです。

InnoDBMyISAMの使い分け

今回は2つの機能面による違いでInnoDBMyISAMを見てきましたが、どちらを使うのがよいのでしょうか。書き込みが多いアプリケーションの場合はInnoDBのが有利そうな感じがしますね。では、書き込みが多いアプリケーションの場合はMyISAMのが良いのでしょうか。いろいろと調べてみると、答えはノーらしいです。MyISAMはサーバーがクラッシュしたときの対応策が少ないようです。今回は初心者向けの記事ですので、これ以上の内容には触れませんが、より詳しく知りたい方は『実践ハイパフォーマンスMySQL』の第1章で説明されていますので、そちらをご一読ください。

まとめ

  • データの読み書きを行う基盤のことを「ストレージエンジン」と呼ぶ
  • ストレージエンジンには「InnoDB」や「MyISAM」など様々な種類がある
  • MySQL5.5以降でのデフォルトのストレージエンジンはInnoDB
  • InnoDBは対象のレコードだけをロックする(行ロック)
  • MyISAMは対象のテーブル自体をロックする(テーブルロック)
  • InnoDBにはトランザクション機能がある
  • MyISAMにはトランザクション機能がない
  • 更新処理が多いアプリケーションの場合はInnoDBを選ぶと良さそう。そうではない場合もInnoDBのが色々と楽かも?