読者です 読者をやめる 読者になる 読者になる

uokadaの見逃し三振は嫌いです

ここで述べられていることは私の個人的な意見に基づくものであり、私が所属する組織には一切の関係はありません。

MySQLのHandler構文でハマったメモ

MySQLにはHANDLER構文というものがあります。 (Handler Socketとはまた別の話。)
MySQL :: MySQL 5.1 リファレンスマニュアル (オンラインヘルプ) :: 8.2.4 HANDLER 構文

この構文がサポートしているのはMyISAM,InnoDBだけなので使う際は注意が必要です。

CREATE TABLE IF NOT EXISTS tweet (
    tid  INT(10)       AUTO_INCREMENT,
    body VARCHAR(255),
    PRIMARY KEY (tid)
)Engine=InnoDB;
INSERT INTO tweet (body) VALUES ('hoge');
INSERT INTO tweet (body) VALUES ('foo');
INSERT INTO tweet (body) VALUES ('bar');
INSERT INTO tweet (body) VALUES ('ham');
INSERT INTO tweet (body) VALUES ('spam');
INSERT INTO tweet (body) VALUES ('egg');
% mysql  -uroot -Dfoo < tweet.sql 
% mysql  -uroot -Dfoo < sample_data.sql 

こんな感じでテーブルとサンプルデータを投入してちょっと動かしてみましょう。

# まず、テーブルをオープン
mysql> HANDLER tweet open;
Query OK, 0 rows affected (0.00 sec)

# データを取得します。 デフォルトではPKでソートされた順番に取得します。
mysql> HANDLER tweet READ NEXT;
+-----+------+
| tid | body |
+-----+------+
|   1 | hoge |
+-----+------+
1 row in set (0.00 sec)

# LIMIT句で取得する件数を指定もできます。
mysql> HANDLER tweet READ NEXT LIMIT 3;
+-----+------+
| tid | body |
+-----+------+
|   2 | foo  |
|   3 | bar  |
|   4 | ham  |
+-----+------+
3 rows in set (0.00 sec)

mysql> HANDLER tweet READ NEXT LIMIT 5;
+-----+------+
| tid | body |
+-----+------+
|   5 | spam |
|   6 | egg  |
+-----+------+
2 rows in set (0.00 sec)

# 最後までいくと Emptyを返します。
mysql> HANDLER tweet READ NEXT;
Empty set (0.00 sec)

# テーブルをクローズ
mysql> HANDLER tweet CLOSE;
Query OK, 0 rows affected (0.00 sec)

ただし、HANDLER構文はSELECT文のように取得するカラムは選べません。

さて、なんでハマったかという本題からずれているので戻します。
こんなテーブルを作ってみました。

CREATE TABLE IF NOT EXISTS tweet (
    tid  INT(10)       AUTO_INCREMENT,
    body VARCHAR(255),
    PRIMARY KEY (tid)
)Engine=InnoDB;
ALTER TABLE tweet PARTITION BY KEY(tid) PARTITIONS 4;

すると、こんなエラーが・・・。

mysql> HANDLER tweet open;
ERROR 1031 (HY000): Table storage engine for 'tweet' doesn't have this option

なんでかなって考えたら、テーブルファイルの構造がパーティションによって変更を受けるのが原因のような気がしている。

パーティションしてない場合のデータファイルはこう。

% sudo ls -lh  /var/lib/mysql/foo

-rw-rw---- 1 mysql mysql   65  9月 24 09:58 2012 db.opt
-rw-rw---- 1 mysql mysql 8.4K  9月 30 17:31 2012 tweet.frm

パーティションしている場合のデータファイルはこう。

% sudo ls -lh  /var/lib/mysql/foo
-rw-rw---- 1 mysql mysql   65  9月 24 09:58 2012 db.opt
-rw-rw---- 1 mysql mysql 8.4K  9月 30 17:24 2012 tweet.frm
-rw-rw---- 1 mysql mysql   32  9月 30 17:24 2012 tweet.par

テーブル名.parが増えているのでその辺が悪いのかなって思ってる。


まとめ、テーブルパーティションする可能性がある場合はHANDLER構文を使ってはダメです。
SELECT構文で簡単に書き直せるので使っている場合は今からでも書き直しましょう。