しがないエンジニアのブログ

技術的な内容をメモ代わりにつらつら

mysqlのストレージエンジンの種類について

mysqlのengineってなんだろうと思ったのでまとめてみた。
現在使っているのはInnoDBというものだが、実はいろいろ種類があるらしい。

mysql> show engines;
+--------------------+---------+----------------------------------------------------------------+--------------+------+------------+
| Engine             | Support | Comment                                                        | Transactions | XA   | Savepoints |
+--------------------+---------+----------------------------------------------------------------+--------------+------+------------+
| PERFORMANCE_SCHEMA | YES     | Performance Schema                                             | NO           | NO   | NO         |
| CSV                | YES     | CSV storage engine                                             | NO           | NO   | NO         |
| MEMORY             | YES     | Hash based, stored in memory, useful for temporary tables      | NO           | NO   | NO         |
| BLACKHOLE          | YES     | /dev/null storage engine (anything you write to it disappears) | NO           | NO   | NO         |
| MRG_MYISAM         | YES     | Collection of identical MyISAM tables                          | NO           | NO   | NO         |
| MyISAM             | YES     | MyISAM storage engine                                          | NO           | NO   | NO         |
| ARCHIVE            | YES     | Archive storage engine                                         | NO           | NO   | NO         |
| FEDERATED          | NO      | Federated MySQL storage engine                                 | NULL         | NULL | NULL       |
| InnoDB             | DEFAULT | Supports transactions, row-level locking, and foreign keys     | YES          | YES  | YES        |
+--------------------+---------+----------------------------------------------------------------+--------------+------+------------+

公式リファレンスはこちら
MySQL :: MySQL 5.6 リファレンスマニュアル :: 15 代替ストレージエンジン

それらを1つずつざっくりと説明する。

InnoDB

mysql5.5以降はデフォルトでこれが指定される。
とりあえずこちらを利用しておけばいいと思う。
以下のような特徴がある。

MyISAM

InnoDBと比較されるもう一つのストレージエンジン。
InnoDBを使う理由がない場合はMyISAMを使う。
以下のような特徴がある。

  • テーブルロック
  • アクセスが早い
  • トランザクション機能がない
  • InnoDBよりテーブルサイズが小さい

参考

MEMORY

名前の通り、データをメモリ上に展開して保存する。
そのため、mysqlを再起動するとデータが消えてしまう。
メモリ上にあるため、アクセスが非常に高速。
インデックスの種類として、b treeとhashの2種類が存在する(基本的にはb tree)

参考

CSV

sqlのデータをcsvファイルとして扱うことができる。
my.cnfに設定したdatadir以下に、.frmの他に、.CSM.CSVの計3種類のファイルが作られる。
その中のcsvファイルを変更することで、DBのデータも一緒に変更することができる。
変更したあとはFLUSH TABLE;を忘れずに。

参考

ARCHIVE

データの登録、参照のみ可能で、変更ができない。
つまり、SELECT, INSERTのみの操作しけ受け付けず、UPDATE, DELETE, REPLACEなどは利用できない。
データは圧縮して保存されているため、容量が小さく済む。
また、インデックスを付与することができない。(AUTO INCREMENTのカラムは除く)

参考

BLACKHOLE

SELECTINSERTなどのSQLを発行しても、すべてemptyが返ってくるような形式。
主に試運転時や、マスター-スレーブ構成のときに使うらしい(よくわかってないです)。
これについては参考サイトを確認してください。

参考

MERGE

複数のテーブルを結合し、あたかも1つのテーブルで処理しているかのようにできる。
INSERTUPDATE,DELETEをした場合、merge元とmerge先のテーブルの両方のデータが更新される。
merge先のテーブルがインデックスをもつ場合、merge元のテーブルも必ず同じインデックスを有している必要がある。
merge先のテーブルにINSERTする場合、INSERT_METHODオプションでどのテーブルに挿入するかを決定する。

CREATE TABLE t1 (
  a INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
  message CHAR(20)) ENGINE=MyISAM;

CREATE TABLE t2 (
  a INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
  message CHAR(20)) ENGINE=MyISAM;

INSERT INTO t1 (message) VALUES ('Testing'),('table'),('t1');
INSERT INTO t2 (message) VALUES ('Testing'),('table'),('t2');

CREATE TABLE total (
  a INT NOT NULL AUTO_INCREMENT,
  message CHAR(20), INDEX(a))
  ENGINE=MERGE UNION=(t1,t2) INSERT_METHOD=LAST;

参考

FEDERATED

別のネットワークのMySQLデータにアクセスし、あたかもローカルがDBを持っているかのように振る舞うことができる。
これによって、簡易的なマスター-スレーブ構成が作れる。

参考

EXAMPLE

自作のストレージエンジンを作成するための例として存在する。
クエリを発行できるが、SELECTINSERTはできない。

参考

XMLHttpRequestと後継のfetch APIについて

XMLHttpRequest

XMLHttpRequestは、urlを指定してリクエストを送信することができる機能である。
基本的な使い方は以下の様になっている

const xhr = new XMLHttpRequest();
xhr.open('GET', 'http://~~~');
xhr.send();
xhr.onload = () => {
  console.log(xhr.response);
});
xhr.onerror = () => {
  console.log('error');
}

open()で対象urlを指定する。このとき、POSTとGETの2種類から選択する
send()が実際に実行する部分
onloadは、実行が完了したあとに処理される部分

ただし、この処理のあとに、onloadした結果を使いたいとなった場合、その処理が完了するのを待たなくてはいけない
なにも考えずに使うとonloadの処理中に次にいってしまうため扱いづらい

fetch API

fetch APIは、よりシンプルに記述できるようになったもの
IEでは使えなさそう(Edgeは使えそう)
https://caniuse.com/#search=fetch

使い方は以下の様になる

fetch('http://~~~').then((response) => {
  console.log(response.status);
}).catch(() => {
  console.log('error');

});

メソッドチェーンを作って記述できるので、確実に処理の流れをつかんで記述できる
メソッドチェーンを作らずに async/awaitを使うことで、よりきれいに書くことができる

(async() => {
  try {
    const response = await fetch('http://~~~');
    console.log(response.status);
  } catch (e) {
    console.log(e);
  }
})();

外部から関数化して呼び出す場合は以下のようにする

const func = async() => {
  try {
    const response = await fetch('http://~~~');
    console.log(response.status);
  } catch (e) {
    console.log(e);
  }
}

async/awaitを使うことで、よりスマートに書くことができる


参考文献

XMLHttpRequest

fetch API

fetch API + async/await

javascriptのPromiseやasync/awaitについて

Promise

Promiseはjs側で用意されている非同期処理である。

Promise.resolve().then(() => {
  console.log('1');
  return '1';
}).then((result) => {
  console.log('2');
  return result + '2';
}).then((result) => {
  console.log('3');
  return result + '3';
}).then((result) => {
  console.log('4');
  return result + '4';
}).then((result) => {
  console.log('5');
  return result + '5';
}).then((result) => {
  console.log(result);
});

/* => output
1
2
3
4
5
12345
*/

メソッドチェーンによって、段階的に処理を記述できる

jQuery.Deferred

DeferredはjQuery側のPromiseである。
例として、以下のサンプルを示す

const deferred = new $.Deferred();

setTimeout(() => {
  console.log('timeout 1000');
  deferred.resolve('resolved');
}, 1000);

deferred.promise().then((result) => {
  console.log(result);
});

/* => output
timeout 1000
promise
*/

となる。

deferred.resolve()で処理が終了したことを知らせて、
deferred.promise()で終了したデータを取得する。
resolve()に引数を渡すことで、promise()側でそのデータを利用できる

async/await

今風の一番いい書き方がこれ
async/awaitを使うことで、非同期をシーケンスに書くことができるようになる。
asyncを定義した関数内で、awaitを使用することができる。
awaitは、Promiseの結果を受け取る。awaitの指定した関数が終了するまで、処理が一時停止する。

IEではサポートされていないなど、ブラウザに制限がある(2019.3現在)
確認はこちらから

以下に例を示す

async function func(){
  const res1 = await afunc1();
  const res2 = await afunc2();
  const res3 = await afunc3();

  console.log('sum: ' + (res1 + res2 + res3));
}

// そのまま結果を返す(resolveされる)
function afunc1() {
  console.log(100);
  return 100;
}

// Promiseを宣言し、内部でresolveする
function afunc2() {
  return new Promise((resolve) => {
    setTimeout(() => {
      console.log(200);
      resolve(200);
    }, 1000);
  });
}

// asyncを組み合わせてresolveする
async function afunc3() {
  await new Promise((resolve) => setTimeout(resolve, 2000));
  console.log(300);
  return 300;
}

func();

/* => output
100
200
300
sum: 600
*/

ちなみに、Promise.allというものを利用すれば、複数の処理を並列に行うことができる

async function func() {
  let promises = [];
  promises.push(subfunc('promise1', 1000));
  promises.push(subfunc('promise2', 2000));
  promises.push(subfunc('promise3', 500));

  const result = await Promise.all(promises);
}

function subfunc(name, ms) {
  console.log(name + ' start');
  return new Promise((resolve) => {
    setTimeout(() => {
      console.log(name + ' resolve');
      resolve(name);
    }, ms);
  });
}

/* => output
promise1 start
promise2 start
promise3 start
promise3 resolve
promise1 resolve
promise2 resolve
*/


参考文献

Promise

Deferred

async/await