gallu’s blog

エンジニアでゲーマーで講師で占い師なおいちゃんのブログです。

MySQLのmemcachedインターフェース(InnoDB Integration with memcached)を実験してみた:概要

ほぼ完全に備忘録な上に「やった手順に沿って」の内容なんで、激しく長いです(苦笑


先に結論だけ書いておくと
・格納先テーブルは任意に選べる
・keyについては…
 *charとvarcharあたりが相性がいいんだけど、intもいける
 *varbinaryが相性悪くて、故に「'A' == 'a'」「'D1' == 'd1'」が成り立つ状況がちょっと怖い
 *以外なことにintがいける
 *datetimeとかはまぁ予想通りNG
 *keyの値のうち、スペース(0x20)はアンダースコアに自動変換される。ために、元々のデータに「スペースを含むkeyの値」がある場合、取得不可能になるので注意
 *アクセス用の名前(innodb_memcache.containers.name)と値とのセパレータに.(ドット)が用いられているため、keyカラム名にはドットを入れないようにする。値に混入した場合にどうなるかは未調査
valueについては…
 *単一カラムの場合、char、varchar、varbinary、text、blob、intが利用可能。datetime系は利用不可
 *intは使えるけど、戻ってくる値がstringになってるので、微妙に注意
 *実は「複数カラム」が可能。各カラムのデータは | によって仕切られる。仕切り文字の変更が可能かどうかは不明*1。また、エスケープなどが存在するかは不明。なので、データに「 | が含まれないこと」を保証する必要がありそう
 *valueを「複数カラム」指定することも可能だが、その場合、varbinaryがまざると使えなくなる
 *日本語は問題なく使用可能
 *テーブルを「CHARACTER SET 'binary'」で作ると使用不可になるため、「CHARACTER SET 'utf8mb4'」が無難なところ


あと、未検証だけどいけそうなのが
・多分、複合キーがいけるぽい雰囲気がある


先に雑感。
PKのカラムがintまたはvarcharのテーブルにおいて、いわゆるコードテーブル(マスターテーブル)のreadであれば、利用は比較的容易かもしれない(特に引っ張ってくるべき値が単一カラムの場合)。
それ以外でも「とりあえず見たいだけ」というような、単純なread用途であれば、適宜置き換えるのは、場合によっては有益かもしれない。

おおざっぱに基本

「準備( http://d.hatena.ne.jp/gallu/20140511/p2 )」をすると、innodb_memcache っていうdatabaseが出来るです。
で、ここに
cache_policies
config_options
containers
の3つのテーブルが出来ます。
cache_policiesとconfig_optionsについては、とりあえず「用途不明」。
中を見てるとなんか出来そうなんですが、config_optionsの中身を「軽く変えた」程度だと意図する挙動にはならなかったので、ここは「眺めておく」程度が無難。


んで。
ポイントはcontainersテーブル。
いくつかよく分からんカラムもあるんだけど。
基本的には「(db_schema)にある(db_table)ってテーブルの、(key_columns)をkeyに、(value_columns)をvalueに持ってる」程度の感じ。


テーブルは、一番分かりやすいのを一つ書いておくと、こんな感じ。

create table test1 (
  `key` varchar(256),
  `val` varchar(256),
  `flags` int,
  `cas_column` bigint UNSIGNED,
  `expire_time_column` int,
  PRIMARY KEY(`key`)
);

flags、cas_column、expire_time_columnは一端「おまじない」だと思って頂けると。


このテーブルが、furu_testっていうdatabaseに入っている、と仮定すると。
まず、containersテーブルに、情報をぶちこみます。

insert into innodb_memcache.containers 
   set name='test1', db_schema='furu_test', db_table='test1', key_columns='key', value_columns='val',
       flags='flags', cas_column='cas_column', expire_time_column='expire_time_column', unique_idx_name_on_key='PRIMARY';

nameは「識別用の名前」なんで、ある程度適当に(っても使うから、ある程度は考えて)。
db_schema、db_table、key_columns、value_columnsは前述の通り。
flags、cas_column、expire_time_column、unique_idx_name_on_keyは一端「おまじない」で覚えてください。


そうすると後は

<?php
// 接続
$m = new Memcache();
$r = $m->addServer('localhost', 11211);
// データの取得
$v = $m->get('@@test1.d1');
var_dump($v);
// データの設定
$r = $m->set('@@test1.d1', (string)mt_rand(0,1000));

こんな感じで使えます。
setとかgetとかaddとかの、keyの値を「'@@' + containers.nameの値 + '.' + keyの値」にするのがコツ。

*1:innodb_memcache.config_options が怪しいが、簡単にテストした程度だと、変更は出来なかった