2018年8月27日月曜日

Club MySQL #3 ~ yoku0825 のつくりかた に登壇してきました(?)

去る8/20、Club MySQLの第3回「yoku0825のつくりかた」に登壇してきました。
Club MySQLなのに MySQLではなく ピンクのかわいいおとうふ のことを語ってしまって恐縮です。
主催の 坂井さん 、会場をお貸しいただいた サイボウズさん 、ご来場いただいたみなさま、どうもありがとうございました。
当日のハッシュタグまとめました(ただよう自作自演風味)


まずは坂井さんから、 “Club MySQLは日本MySQLユーザ会の一形態であり、スピンアウトじゃないよ” とクギを刺されます :D
  • 日本MySQLユーザ会 の副代表、 @sakaik さんによるスピンアウト勉強会です
    • Club MySQL は、ひとりの講演者の話をじっくりと聞こう、という趣向の、日本MySQLユーザ会の新しいイベントシリーズです だそう
( ´-`).oO(ここに訂正してお詫び申し上げます…

俺とそーだいさんの馴れ初めは多分↓これで、


その後、中国地方DB勉強会 in 東京(何を言っているのかわからねーと思うが略)で仲良くなって一緒にヤパチーでキャッキャウフフしたりYAPC::Hokkaido逝ったりともう3~4年の付き合いになるようです。
物理そーだいさん(?)から何度か「僕 弟キャラなので色んなこと教えてもらえるんですよねー」(リアル弟なのかは忘れましたが)って聞いてて、なるほど確かにそーだいさん可愛がられキャラだし聞き方も上手いよな、とか思ってたんですが、スライドの「あじぇんだ」にガリっと「利用手順」「活用事例」とか紹介されてやっぱり上手いなと思いました。
そーだいさんのLTが思いのほか面白く、本当はその5分でちゃちゃっと追加しようと思っていた第4部が未完(ただし5分作業できたとしても完成していたかどうかは定かではない)のまま、「yoku0825のつくりかた」のセッションに入ります。

前日まで何を話すか全然決まらなくて書いちゃ破き書いちゃ破き状態で、上手くまとめられなかったような気がしたんですが、楽しんでいただけたなら何よりでした!
ありがとうございました!
最後になりますが、 SH2さん 愛してますよ ;D

2018年8月22日水曜日

innodb_ft_enable_stopword が無効にできなかったはなし

TL;DR

  • innodb_ft_enable_stopword は2018/08/22現在ドキュメントの記載が “GLOBAL” のみになっているけど、実際は “GLOBAL, SESSION” で実効値はセッション側
  • このパラメーターでストップワードを判定させるか否かは CREATE TABLE または ALTER TABLE した時点の session.innodb_ft_enable_stopword に依存する

元ネタはMySQL CasualのSlackでのこの発言。
(文中の引用元リンクがたどれない方は是非とも MySQL CasualのSlackへ!
innodb_ft_enable_stopwordパラメータですが、set globalでON/OFFが切り替えられると思っていたのですが、
実際に試してみたところOFFになりません。
(コマンド自体はエラーにならない)
マニュアルには Global って書いてあるんですけど、set コマンドでは Global と Session の両方あるような雰囲気ですね…。
むむむと思って調べてみた。
まず、 innodb_ft_enable_stopwordMYSQL_THDVAR_BOOL で定義されているので、グローバルオンリーではなくてグローバルとセッションの両方持っているのはそれで合っていそう(グローバルオンリーだと MYSQL_SYSVAR_* 型)
この値(ft_enable_stopword)を唯一引きまわしているinnobase_fts_load_stopwordの中でも、 THDVAR で呼ばれているので、グローバルとセッションと両方ある時はセッション側の値が実効値、という定石の通りになっていると思われる。
innobase_fts_load_stopwordが呼ばれるのはcreate_table_info_t::create_table_update_dictとprepare_inplace_alter_table_dictの中。
というところで、ドキュメントに以下の記述を見つけた。
Specifies that a set of stopwords is associated with an InnoDB FULLTEXT index at the time the index is created.
なるほど、フルテキストインデックスが生成される時に決まるのね。

じゃあ実験。
ストップワード関連のオプションをデフォルトのままで CREATE TABLE, INSERT INTO すると、フルテキストインデックスの中味に “one” を “on”, “ne” に分割したもののうちストップワードの “on” を除いた “ne” だけが記録される。
mysql57 2> SELECT @@session.innodb_ft_enable_stopword, @@global.innodb_ft_enable_stopword;
+-------------------------------------+------------------------------------+
| @@session.innodb_ft_enable_stopword | @@global.innodb_ft_enable_stopword |
+-------------------------------------+------------------------------------+
|                                   1 |                                  1 |
+-------------------------------------+------------------------------------+
1 row in set (0.02 sec)

mysql57 2> create table t1 (val varchar(32), fulltext key (val) with parser ngram);
Query OK, 0 rows affected (0.15 sec)

mysql57 2> INSERT INTO t1 VALUES ('one');
Query OK, 1 row affected (0.23 sec)

mysql57 2> SET GLOBAL innodb_ft_aux_table = 'd1/t1';
Query OK, 0 rows affected (1.59 sec)

mysql57 2> SELECT * FROM i_s.innodb_ft_index_cache;
+------+--------------+-------------+-----------+--------+----------+
| WORD | FIRST_DOC_ID | LAST_DOC_ID | DOC_COUNT | DOC_ID | POSITION |
+------+--------------+-------------+-----------+--------+----------+
| ne   |            2 |           2 |         1 |      2 |        1 |
+------+--------------+-------------+-----------+--------+----------+
1 row in set (0.01 sec)
次、まず SET SESSION innodb_ft_enable_stopword= 0 でセッション側の設定をOFFにしてもう一度 INSERT してみる
mysql57 2> SET SESSION innodb_ft_enable_stopword= 0;
Query OK, 0 rows affected (0.00 sec)

mysql57 2> SELECT @@session.innodb_ft_enable_stopword, @@global.innodb_ft_enable_stopword;
+-------------------------------------+------------------------------------+
| @@session.innodb_ft_enable_stopword | @@global.innodb_ft_enable_stopword |
+-------------------------------------+------------------------------------+
|                                   0 |                                  1 |
+-------------------------------------+------------------------------------+
1 row in set (0.00 sec)

mysql57 2> INSERT INTO t1 VALUES ('one');
Query OK, 1 row affected (0.01 sec)

mysql57 2> SELECT * FROM i_s.innodb_ft_index_cache;
+------+--------------+-------------+-----------+--------+----------+
| WORD | FIRST_DOC_ID | LAST_DOC_ID | DOC_COUNT | DOC_ID | POSITION |
+------+--------------+-------------+-----------+--------+----------+
| ne   |            2 |           3 |         2 |      2 |        1 |
| ne   |            2 |           3 |         2 |      3 |        1 |
+------+--------------+-------------+-----------+--------+----------+
2 rows in set (0.00 sec)
セッション値を変えても INSERT した時にストップワードの “on” が取り除かれている。
じゃあグローバル値はどうかな。
mysql57 2> SET GLOBAL innodb_ft_enable_stopword= 0;
Query OK, 0 rows affected (0.00 sec)

mysql57 2> SELECT @@session.innodb_ft_enable_stopword, @@global.innodb_ft_enable_stopword;
+-------------------------------------+------------------------------------+
| @@session.innodb_ft_enable_stopword | @@global.innodb_ft_enable_stopword |
+-------------------------------------+------------------------------------+
|                                   0 |                                  0 |
+-------------------------------------+------------------------------------+
1 row in set (0.05 sec)

mysql57 2> INSERT INTO t1 VALUES ('one');
Query OK, 1 row affected (0.00 sec)

mysql57 2> SELECT * FROM i_s.innodb_ft_index_cache;
+------+--------------+-------------+-----------+--------+----------+
| WORD | FIRST_DOC_ID | LAST_DOC_ID | DOC_COUNT | DOC_ID | POSITION |
+------+--------------+-------------+-----------+--------+----------+
| ne   |            2 |           4 |         3 |      2 |        1 |
| ne   |            2 |           4 |         3 |      3 |        1 |
| ne   |            2 |           4 |         3 |      4 |        1 |
+------+--------------+-------------+-----------+--------+----------+
3 rows in set (0.00 sec)
変わらない。フルテキストインデックスが生成されるタイミングで有効なのは本当らしい。
じゃあこの状態(グローバルOFF、セッションOFF)の状態でもういっこテーブルを作ってみる。
mysql57 2> CREATE TABLE t2 (val varchar(32), FULLTEXT KEY (val) WITH PARSER ngram);
Query OK, 0 rows affected (0.08 sec)

mysql57 2> INSERT INTO t2 VALUES ('one');
Query OK, 1 row affected (0.01 sec)

mysql57 2> SET GLOBAL innodb_ft_aux_table = 'd1/t2';
Query OK, 0 rows affected (0.01 sec)

mysql57 2> SELECT * FROM i_s.innodb_ft_index_cache;
+------+--------------+-------------+-----------+--------+----------+
| WORD | FIRST_DOC_ID | LAST_DOC_ID | DOC_COUNT | DOC_ID | POSITION |
+------+--------------+-------------+-----------+--------+----------+
| ne   |            2 |           2 |         1 |      2 |        1 |
| on   |            2 |           2 |         1 |      2 |        0 |
+------+--------------+-------------+-----------+--------+----------+
2 rows in set (0.00 sec)
ストップワードが判定されなくなって “on” もフルテキストインデックスの中に入ってくるようになった。
その後、セッション値とグローバル値とパターンを変えていくつか試してみると、
  • CREATE TABLE または ALTER TABLE の時点で指定していた innodb_ft_enable_stopword のセッション値で判断される
    • innodb_optimize_fulltext_only= 1ALTER TABLE してもその時点の値が反映される
  • INSERT, SELECT の時の innodb_ft_enable_stopword は関係ない
    • SET SESSION innodb_ft_enable_stopword だけで結果が変わったらどうしようかと思っちゃった
  • ということは単にドキュメントの間違いで、本当は “GLOBAL, SESSION” である
ごちそうさまでした!

【2018/08/22 17:22】
ばぐれぽしておいた!

MySQL Bugs: #92118: innodb_ft_enable_stopword is wrongly described as "GLOBAL" scope in Docs



『』