41から始めました

文字通り41歳から始めたブログです。DB(MySQL)を使ってお仕事してるので、DB周りの話を中心に最近始めたこととかをTwitterのノリで書いています。なお、本サイトにおいて示されている見解は私個人の見解であり、所属団体や組織を代表するものではありません。

MySQLの全文検索インデックスでハマったこと(主にストップワードテーブル)

以下ハマったことを羅列

  1. innodb_ft_enable_stopwordパラメータが、公式にはグローバルのみと書いてあるのに、グローバルをOFFにしてもパラメータがOFFにならない。
  2. alter table spec_bukken_view Engine = InnoDB;を使えばインデックスの張り直しは不要だが、レプリケーション環境にはクエリが飛ばない。
  3. 再起動しないとスレーブ側ではinnodb_ft_enable_stopwordが古いまま(インデックスの張り直しが無意味)
  4. 複数全文検索インデックスを貼ってあると、張り直す場合、一度全ての全文検索インデックスを削除してからでなければ張り直しが効かない。

あ、ちなみに環境はMySQL5.7、InnoDBの話です。

1について

1についてはinnodb_ft_enable_stopwordパラメータにはセッションもあるのに、公式がグローバルと書いてあったのが原因。

SET GLOBAL innodb_ft_enable_stopword = OFF;

Query OK, 0 rows affected (0.00 sec)

# ONのまま
mysql> show variables like 'innodb_ft_enable_stopword';
+---------------------------+-------+
| Variable_name             | Value |
+---------------------------+-------+
| innodb_ft_enable_stopword | ON    |
+---------------------------+-------+
1 row in set (0.00 sec)

# 理由はセッションパラメータ側が変わってないから
mysql> select @@innodb_ft_enable_stopword, @@global.innodb_ft_enable_stopword;
+-----------------------------+------------------------------------+
| @@innodb_ft_enable_stopword | @@global.innodb_ft_enable_stopword |
+-----------------------------+------------------------------------+
|                           1 |                                  0 |
+-----------------------------+------------------------------------+
1 row in set (0.00 sec)

# セッション側も変える
mysql> SET innodb_ft_enable_stopword = OFF;
Query OK, 0 rows affected (0.00 sec)

# OK
mysql> select @@innodb_ft_enable_stopword, @@global.innodb_ft_enable_stopword;
+-----------------------------+------------------------------------+
| @@innodb_ft_enable_stopword | @@global.innodb_ft_enable_stopword |
+-----------------------------+------------------------------------+
|                           0 |                                  0 |
+-----------------------------+------------------------------------+
1 row in set (0.00 sec)

# OK
mysql> show variables like 'innodb_ft_enable_stopword';
+---------------------------+-------+
| Variable_name             | Value |
+---------------------------+-------+
| innodb_ft_enable_stopword | OFF    |
+---------------------------+-------+
1 row in set (0.00 sec)

2について

2についてはインデックスの張り直しは時間かかりそうだなー、と思ってたらとあるMySQLマスターがおススメしてくれた。

お!その手があったか! と飛びついたが、よく考えたら今回のテーブル、インデックスがバカみたいに貼ってあるので全インデックスの見直しが走ってしまい余計つらかった。(これはうちの環境の問題)

というわけで、おとなしく対象インデックスの張り直しにする。

3について

これが結構きつかった。でも、気づいたらまあそうかという感じ。

公式では

FULLTEXT インデックスの定義は、テーブルの作成時に CREATE TABLE ステートメントで指定することも、あとで ALTER TABLE または CREATE INDEX を使用して追加することもできます。

とあることから、①パラメータを設定しておき、②インデックスを再作成 すれば全文検索がうまくいくはずである。

ところが、レプリケーションしているスレーブ側では、あらかじめパラメータを変更してレプリケーションでインデックスの再作成を行ってもパラメータの変更が読み込まれていない。

これはレプリケーションのセッションが初期接続時のパラメータを見ており、innodb_ft_enable_stopwordパラメータはグローバルを変えてもセッションが変更されないためであった。

レプリケーションをSTOP SLAVE START SLAVEしたら大丈夫かな?と思ったが駄目だった。

そのため、スレーブ側のパラメータ変更後再起動して、そのあとマスターからインデックスを貼りなおすことで対応した。

4について

1本ずつインデックスを張りなおすのでは駄目で、一回全ての全文検索インデックスを消した上で無いとinnodb_ft_enable_stopwordパラメータの値が読み込まれてないのが検証で分かった。

まあ、このパラメータの性質上部分的に残すことは無いし、それでいいと思うけど1本ずつDROP →CREATE(ALTER TABLE ADD FULLTEXT INDEXでもいい)じゃうまくいかないってのはイケてないなあ、と個人的には思うところ。