カテゴリー「mariadb」

個人でこっそりgithubで作っているMariaDBの差分検出・反映ツールである「magentadesk」に、

API機能とHTML機能を追加しました。(0.4.0からHTML機能がはいってます)

(magentadesk)

https://github.com/shigenobu/magentadesk

今まではcli版しかなったのですが、web版も追加されています。

web版でしていることは、cli版の処理を呼び出しているに過ぎないのですが、

HTML機能を使うことで、各種jsonデータをsqliteに保存しておけるようになり、ボタン一つで差分検出・反映が可能となります。

API機能は、cli版の単なるHTTPインターフェースでしかないのですが、

HTML機能で追加したrelationという設定は、テーブルの子・親関係を登録しておくことで、

差分検出時にチェックボックスが連動するというものとなります。

magantadeskでは、外部キーが設定されているものは、

反映対象外としている(これは反映順番の整合性を保つのが難しいため)のですが、

それだと、差分確認時に、親子関係がわかりくいということから、このような機能を作ってみました。

で、API・HTML機能を作るに当たり、苦労した点があったので書いておきます。


(HTTPサーバにcom.sun.net.httpserver.HttpServerを利用)

デフォルトで同胞されているHTTPサーバなのですが、これが非常にくせのあるものでした。

例外などの際、ようは最後の最後のタイミングで、ただしくHTTPレスポンスを構築してくれないので、

最後の最後で、レスポンスを構築するように工夫しました。

(HTML機能の情報を蓄積するDBとして、sqliteを利用)

READ-COMMITEDをサポートしていないので、SERIALIZABLEの分離レベルを選択。

そのうえで、ファイルのため、WRITEブロックをすることは明白なので、

とにかくsqliteに接続している時間を各処理で短くするよう調整しました。

(テンプレートエンジンとしてvelocityを利用)

え?veloctiy?と思うかもしれませんが、2.3というバージョンが出ています。

当方は、velocity-toolは使わず、

event_handler.reference_insertion.class(旧eventhandler.referenceinsertion.class)

のプロパティを設定して、独自クラスでテンプレート関数を追加しています。

テンプレート上で、NULLと空文字の判定がデフォルトではできなかったので、

独自関数で対応しました。


という具合に、地道な苦労を重ねました。

magentadeskは主にwebサービスでの本番反映を想定して、汎用化を試みたものですが、

ニーズは少なそうだなと感じています。。

今後は、国際化対応(日本語化)を入れていきたいかなと考えていますが、

JAVAではなく、jqueryでやろうかなとか考え中です。

以上

投稿日時:2021年11月25日 15:04   カテゴリー:java, mariadb   [コメントがあればどうぞ]

またMySQLのUDFをつくってみた。

https://github.com/shigenobu/mysql_ws_neologd_normalize

今回は有名なneologdの標準化アルゴリズムに、CR・LF・タブ・水平タブを削除するものを追加したUDFです。

(参考 neologdの標準化アルゴリズム)

https://github.com/neologd/mecab-ipadic-neologd/wiki/Regexp.ja

なぜこれを作ったかというと、すべては検索のためですね。

入力も、対象データも、そして辞書すらも、すべて一定のアルゴリズムで標準化されることで、

正しく検索が機能するためです。

今回のUDFは、対象データの部分に該当します。

入力の部分は、C#とPHPでも同様のアルゴリズムを実装していますが、

そこまで大したものではないので、特に公開はしてないです。

※さらにいえば、入力の部分では、対象データと同じアルゴリズムの形態素解析も必要かなと思います。

だいぶ、cgoでMySQLのUDFを作ってきた(現在5つをgithubに公開)のですが、

今後はrustとかに手を出して、redisモジュールなんかもつくってみたいかと(自分の中で需要がないが。。)。

今回のUDFは、すでに長いこと実践投入しているので、多分大丈夫だと思います。

いや、他のUDFが不具合ありって、いうわけじゃないですけど。

以上

投稿日時:2021年10月05日 23:40   カテゴリー:go, mariadb, mysql   [コメントがあればどうぞ]

Mysql/MariaDBのsubstring関数は、マルチバイトセーフと書いてあります。

しかしながら、日本語の長文を扱っている際、JDBCおよびADO.NETからsubstringするとなぜか、

Incorrect string value:

のエラーが出てしまいました。

文字コードや各接続はutf8mb4で統一しており、どうもおかしいと思い、原因は不明なままでしたが、

例によってcgoで作ってみました。

https://github.com/shigenobu/mysql_ws_substring

この関数を通すことで、上記エラーは発生しなくなりました。

あまりに長文だったのですが、utf8の不正なバイトシーケンスが入っていたのでは?と思っていますが、

さすがに根気がなくなり調査断念しました。(それに急ぎだったので)

まあ、なんでこんな関数つくったのかというと、mroongaを使っていた際、

mecab_sparse_tostr() failed len=xxxxx err=too long sentence

のエラーが出てしまい、自作のwordwrap関数でもこの問題は解決せず、

「あれ、ひょっとして文書が長過ぎる?」と思い、データを見てみたところ、

どうも256KiBを超えたあたりが怪しい感じがしました。

というわけで、10万文字でsubstringしてINSERTできればOKじゃね?と思い、

この関数を作ってみました。

結果として、10万文字に収めたところ、上記エラーはでなくなりました。

mroongaの公式サイトには、

GRN_MECAB_CHUNKED_TOKENIZE_ENABLED=yes

の環境変数を利用することで、解決するかもと書いてあって試してみたものの、

当該カラムの文書量が多いせいか、2時間以上たっても、FULL TEXT インデックスが構築完了しませんでした。

※文書が少ないカラムはこちらの環境変数を設定していても即座にインデックスの構築は完了しました。

一度でも登録したらエラーとなっているので、今回の関数でいかざるを得なかった感じです。

時間があったら、mecabのソースなどを調査してみようと思います。

以上

投稿日時:2021年10月01日 00:28   カテゴリー:go, mariadb, mysql   [コメントがあればどうぞ]

PHPのwordwrap関数のマルチバイト対応版をMySQLのUDFとしてつくりました。

いつものようにcgoで作ってます。

https://github.com/shigenobu/mysql_ws_wordwrap

PHPのwordwrap関数は以下のリンクとなります。

(PHPのwordwrap)

https://www.php.net/manual/ja/function.wordwrap.php

今回作ったUDFのポイントは、なるべくPHPの関数の第4引数(cut_long_words)をtrueの状態にしたものとなります。

で、このPHPのwordwrap関数の特徴として、何度やっても同じになる(微妙な表現ですが)になるってことなのかと思います。

php > $input = 'aa<br>abbbccc<br>dddee<br>e';
php > $dst1 = wordwrap($input, 3, '<br>', true);
php > echo $dst1;
aa<br>abb<br>bcc<br>c<br>ddd<br>ee<br>e
php > $dst2 = wordwrap($dst1, 3, '<br>', true);
php > echo $dst2;
aa<br>abb<br>bcc<br>c<br>ddd<br>ee<br>e
php > echo (int) $dst1 == $dst2;
1

つまり、breakワードが分割位置に含まれていたら、そこで分割せずに、breakワードを残しつつ、次以降の文字列の評価を行うものなのかと。

※なんていうアルゴリズムなのかわからなかったので、正解ではないかもしれません。

作り始めた当初は、breakワードを一旦消してから、指定文字数でbreakワードいれればいける?と思っていたのですが、

もとの文章にbreakワードが入っている場合、それを消してしまうことになるので、それはちょっと違うかなと思い、

breakワードの位置を探しつつ、構築する形にしてみました。

なんでこんな関数を作ったのかというと、mroongaを使っていた際、

mecab_sparse_tostr() failed len=xxxxx err=too long sentence

というエラーがでたので、これってmecabのストップワードがないから?と思ってしまい、

それなら強制的にwordwrapさせればいける?と思い、作りました。

実際には、文書自体が長過ぎるとエラーになるようで、この関数では解決しなかったんですが。。

本来ならストップワードを指定して分割する形も考えたのですが、急ぎで対応する必要があったので、

今後ヒマがあったら考えみようかと思います。

以上

投稿日時:2021年10月01日 00:02   カテゴリー:go, mariadb, mysql   [コメントがあればどうぞ]

MariaDB 10.6が7月にGAになっていました。

https://mariadb.com/kb/en/changes-improvements-in-mariadb-106/

ざっくり変更点。(ざっくりだよ)

  • Atomic DDL が入った模様
  • SKIP LOCKEDが入った模様(MySQL8に追従ですね)
  • ignored index(MySQLでいうとinvisbile index)
  • json_table関数(ここもMySQL8に追従ですね)
  • sysスキーマ
  • utf8mb3の導入
  • innodbのパラメータが結構削除

と言った形で、利用者向けには、MySQL8への追従が結構ある感じです。(Oracleの関数対応もありますが)

管理者向けには、innodb関係のパラメータ削除(10.4でdeprecatedになっていたが)は気をつけるべきかと。

まだ全然試せていませんが、utf8がなくなっている(DDLではutf8でOKだが、information_schemaではutf8mb3になっている)ので、

ちょっと注意が必要。(わたしがつくっているmagentadeskも10.6には対応済み)

そのほか、気になっているのが、10.5.9くらい(10.4系の新しいのも)で、log_write_up_toの改修が入ったようなのですが、

10.6系も引き続き入っており、このあたりがどうなっているかはちょっとテストしてみないとわからん感じです。

以上

投稿日時:2021年08月05日 21:34   カテゴリー:mariadb   [コメントがあればどうぞ]

10.2からバイナリログを逆さにするflashbackという機能が追加されたのですが、中々実践でためす機会もなかったので、改めて動きを確認してみます。

確認したバージョンは、10.5.5です。


(前提)

以下のようなテーブルを作成し、データと投入します。

MariaDB [test]> show create table fb;
+-------+-----------------------------------------------------------------------------------------------------------------------------------+
| Table | Create Table |
+-------+-----------------------------------------------------------------------------------------------------------------------------------+
| fb | CREATE TABLE fb (
no int(11) NOT NULL,
name text NOT NULL,
PRIMARY KEY (no)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 |
+-------+-----------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.000 sec)

MariaDB [test]> insert into fb value (1, 'あああ');
Query OK, 1 row affected (0.003 sec)

MariaDB [test]> select * from fb;
+----+-----------+
| no | name |
+----+-----------+
| 1 | あああ |
+----+-----------+
1 row in set (0.001 sec)

GTIDとバイナリログを確認します。

MariaDB [test]> show variables like 'gtid_binlog_pos';
+-------------------------+------------+
| Variable_name | Value |
+-------------------------+------------+
| gtid_binlog_pos | 0-1-284795 |
+-------------------------+------------+
1 rows in set (0.001 sec)

MariaDB [test]> show binary logs;
+------------------+-----------+
| Log_name | File_size |
+------------------+-----------+
| mysql-bin.000066 | 54405979 |
| mysql-bin.000067 | 9650 |
| mysql-bin.000068 | 2667 |
+------------------+-----------+
3 rows in set (0.000 sec)

わかりやすくするために、一度バイナリログをflushします。

MariaDB [test]> flush binary logs;
Query OK, 0 rows affected (0.005 sec)

MariaDB [test]> show binary logs;
+------------------+-----------+
| Log_name | File_size |
+------------------+-----------+
| mysql-bin.000066 | 54405979 |
| mysql-bin.000067 | 9650 |
| mysql-bin.000068 | 2714 |
| mysql-bin.000069 | 385 |
+------------------+-----------+
4 rows in set (0.000 sec)

一応、GTID確認します。

MariaDB [test]> show variables like 'gtid_binlog_pos';
+-------------------------+------------+
| Variable_name | Value |
+-------------------------+------------+
| gtid_binlog_pos | 0-1-284795 |
+-------------------------+------------+
1 rows in set (0.001 sec)

GTIDは「0-1-284795」のままですね。

(データ追加)

データを追加し、GTIDを確認します。

MariaDB [test]> insert into fb value (2, 'いいい');
Query OK, 1 row affected (0.003 sec)

MariaDB [test]> select * from fb;
+----+-----------+
| no | name |
+----+-----------+
| 1 | あああ |
| 2 | いいい |
+----+-----------+
2 rows in set (0.000 sec)

MariaDB [test]> show variables like 'gtid_binlog_pos';
+-------------------------+------------+
| Variable_name | Value |
+-------------------------+------------+
| gtid_binlog_pos | 0-1-284796 |
+-------------------------+------------+
1 rows in set (0.001 sec)

GTIDが「0-1-284796」に変わりました。ここで、バイナリログを見てみます。長いので、一部だけにします。

# mysqlbinlog --no-defaults -vvv /var/lib/mysql/mysql-bin.000069
:
:
# at 256
#210224 11:08:36 server id 1  end_log_pos 299 CRC32 0xacff8998 	Gtid list [0-1-284795]
# at 299
#210224 11:08:36 server id 1  end_log_pos 342 CRC32 0x8bf7cf8a 	Binlog checkpoint mysql-bin.000068
# at 342
#210224 11:08:36 server id 1  end_log_pos 385 CRC32 0x187e7066 	Binlog checkpoint mysql-bin.000069
# at 385
#210224 11:09:30 server id 1  end_log_pos 427 CRC32 0x5386bf8e 	GTID 0-1-284796 trans
/*!100101 SET @@session.skip_parallel_replication=0*//*!*/;
/*!100001 SET @@session.gtid_domain_id=0*//*!*/;
/*!100001 SET @@session.server_id=1*//*!*/;
/*!100001 SET @@session.gtid_seq_no=284796*//*!*/;
START TRANSACTION
/*!*/;
# at 427
# at 487
#210224 11:09:30 server id 1  end_log_pos 487 CRC32 0x685176b0 	Annotate_rows:
#Q> insert into fb value (2, 'いいい')
#210224 11:09:30 server id 1  end_log_pos 534 CRC32 0x02e81a93 	Table_map: `test`.`fb` mapped to number 64
# at 534
#210224 11:09:30 server id 1  end_log_pos 583 CRC32 0x9a15a3b4 	Write_rows: table id 64 flags: STMT_END_F

BINLOG '
WrU1YBMBAAAALwAAABYCAAAAAEAAAAAAAAEABHRlc3QAAmZiAAID/AECAJMa6AI=
WrU1YBcBAAAAMQAAAEcCAAAAAEAAAAAAAAEAAv/8AgAAAAkA44GE44GE44GEtKMVmg==
'/*!*/;
### INSERT INTO `test`.`fb`
### SET
###   @1=2 /* INT meta=0 nullable=0 is_null=0 */
###   @2='いいい' /* BLOB/TEXT meta=2 nullable=0 is_null=0 */
# Number of rows: 1
# at 583
#210224 11:09:30 server id 1  end_log_pos 614 CRC32 0x2ae1c8a4 	Xid = 4087358
COMMIT/*!*/;
DELIMITER ;
:
:

まずは、「# at 256」を見てみます。

# at 256
#210224 11:08:36 server id 1  end_log_pos 299 CRC32 0xacff8998 	Gtid list [0-1-284795]

listされたGTIDが「0-1-284795」になっているので、ここが直前のGTIDであり、

insert into fb value (1, 'あああ');

の直後となっています。

念の為、確認します。

MariaDB [test]> select binlog_gtid_pos('mysql-bin.000069', 256);
+------------------------------------------+
| binlog_gtid_pos('mysql-bin.000069', 256) |
+------------------------------------------+
| 0-1-284795 |
+------------------------------------------+
1 row in set (0.001 sec)

次に、「# at 385」を見てみます。

# at 385
#210224 11:09:30 server id 1 end_log_pos 427 CRC32 0x5386bf8e GTID 0-1-284796 trans

385からが、次のGTIDの開始点となります。そこから直近のCOMMITまでを追っていくと、

# at 583
#210224 11:09:30 server id 1  end_log_pos 614 CRC32 0x2ae1c8a4 	Xid = 4087358
COMMIT/*!*/;

583に辿り着きます。583のGTIDを確認します。

MariaDB [test]> select binlog_gtid_pos('mysql-bin.000069', 583);
+------------------------------------------+
| binlog_gtid_pos('mysql-bin.000069', 583) |
+------------------------------------------+
| 0-1-284796 |
+------------------------------------------+
1 row in set (0.001 sec)

ここまでを整理すると、

GTID:「0-1-284795」(ポジション:「256」)は「(1, ‘あああ’)」の直後、

GTID:「0-1-284796」(ポジション:「583」)は「(2, ‘いいい’)」の直後、

となります。

※正確には、256を示すend_log_posのatが、1つ前のポジションです。

(操作取消)

では、GTID:「0-1-284796」の操作を取り消します。

# mysqlbinlog --no-defaults -vvv /var/lib/mysql/mysql-bin.000069 --start-position=256 --stop-position=583 --flashback 
/*!50530 SET @@SESSION.PSEUDO_SLAVE_MODE=1*/;
/*!40019 SET @@session.max_insert_delayed_threads=0*/;
/*!50003 SET @OLD_COMPLETION_TYPE=@@COMPLETION_TYPE,COMPLETION_TYPE=0*/;
DELIMITER /*!*/;
#210224 11:08:36 server id 1  end_log_pos 256 CRC32 0x9b36958f 	Start: binlog v 4, server v 10.5.5-MariaDB-log created 210224 11:08:36
# Warning: this binlog is either in use or was not closed properly.
BINLOG '
JLU1YA8BAAAA/AAAAAABAAABAAQAMTAuNS41LU1hcmlhREItbG9nAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAEzgNAAgAEgAEBAQEEgAA5AAEGggAAAAICAgCAAAACgoKAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAEEwQADQgICAoKCgGPlTab
'/*!*/;
#210224 11:08:36 server id 1  end_log_pos 299 CRC32 0xacff8998 	Gtid list [0-1-284795]
#210224 11:08:36 server id 1  end_log_pos 342 CRC32 0x8bf7cf8a 	Binlog checkpoint mysql-bin.000068
#210224 11:08:36 server id 1  end_log_pos 385 CRC32 0x187e7066 	Binlog checkpoint mysql-bin.000069
#210224 11:09:30 server id 1  end_log_pos 487 CRC32 0x685176b0 	Annotate_rows:
#Q> insert into fb value (2, 'いいい')
#210224 11:09:30 server id 1  end_log_pos 534 CRC32 0x02e81a93 	Table_map: `test`.`fb` mapped to number 64
# Number of rows: 1
#210224 11:09:30 server id 1  end_log_pos 583 CRC32 0x9a15a3b4 	Delete_rows: table id 64 flags: STMT_END_F

BINLOG '
WrU1YBMBAAAALwAAABYCAAAAAEAAAAAAAAEABHRlc3QAAmZiAAID/AECAJMa6AI=
WrU1YBkBAAAAMQAAAEcCAAAAAEAAAAAAAAEAAv/8AgAAAAkA44GE44GE44GEtKMVmg==
'/*!*/;
### DELETE FROM `test`.`fb`
### WHERE
###   @1=2 /* INT meta=0 nullable=0 is_null=0 */
###   @2='いいい' /* BLOB/TEXT meta=2 nullable=0 is_null=0 */
COMMIT
/*!*/;
COMMIT
/*!*/;
DELIMITER ;
# End of log file
ROLLBACK /* added by mysqlbinlog */;
/*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/;
/*!50530 SET @@SESSION.PSEUDO_SLAVE_MODE=0*/;

これをファイルに落として、実行することで、「(2, ‘いいい’)」のINSERTが取り消されます。ただし、バイナリログには、別途GTIDが切り出されます。

長くなりましたが、

start-positionの部分には、”戻したい場所”にしましょう。

今回では、

Gtid list [0-1-284795]

の箇所が直前のGTID払い出し位置となるので、ここに戻すようにしています。

MariaDBだと、GTIDで状態を確認することが多いので、flashbackでもGTIDの状態をみるように注意して対応してみました。

以上

投稿日時:2021年02月24日 13:50   カテゴリー:mariadb   [コメントがあればどうぞ]

MariaDB10.5がリリースされたのは、2020年6月でそれから大分たってしまいました。。

当ブログも10.5に移行完了済みなので、10.5での変更点などをのせておきます。

(公式)

https://mariadb.com/kb/en/changes-improvements-in-mariadb-105/

個人的に気になったは、

  • innodb_buffer_pool_instances
  • innodb_log_files_in_group

がDeprecatedになったということでしょうか。

…なぜこのような変更になったのか、暫く調査していたのですが、ちょっとはっきりとした理由が不明な状態です。。

これは誰か教えてほしい。。

その他、レプリケーション系での権限が細分化されており、「slave」ではなく「replica」に変更になっていたり(※「slave」という表現は10.5では廃止されたわけではないのですが、将来的にはなくなるかと)、といったところでしょうか。

以上

投稿日時:2021年02月24日 12:34   カテゴリー:mariadb   [コメントがあればどうぞ]

またしてもcgoで作りました。

https://github.com/shigenobu/mysql_ws_split

前回作成した、ws_parse_url関数との違いは、

引数が2つあることですが、意外とこれがはまりました。

MySQLって、splitする関数がなくて(まあ、あったとしてもどうするんだという話)、

splitして、JSON配列に展開しちゃえば、そこから加工しやすくなるだろうという算段です。

以上

投稿日時:2020年05月28日 18:26   カテゴリー:go, mariadb, mysql   [コメントがあればどうぞ]

PHPのparse_url関数のような動作をするMySQLのUDFをcgoで作成しました。

https://github.com/shigenobu/mysql_ws_parse_url

(参考)PHPのparse_url関数

https://www.php.net/manual/ja/function.parse-url.php

この関数のポイントは、クエリー形式のパラメータをキー名でとれるところです。

最近はアクセスログをDBに保存して、そのまま分析に使うなどをすることもあり、MySQL側で一気に加工できれば楽だなと思いつくりました。

これ以外にも作成したものがいくつかあるので、そのうち公開しようと思います。

なお、動作確認したのはMariaDB10.4のみなので、もしお使いになる場合は自身の環境での動作確認をお願いします。

以上

投稿日時:2020年05月13日 22:45   カテゴリー:go, mariadb, mysql   [コメントがあればどうぞ]

MariaDB10.4.7から、text/blobについても、桁数を指定しないでINDEXが作成できるようになった。

以下のリンクの下のほうに書いてあった。

https://jira.mariadb.org/browse/MDEV-20918

しかし、UNIQUE KEYの場合、これによる弊害が現時点では発生する。

10.3まではエラーで抑止してくれたものの、10.4からはスルーして、HASHインデックスとして作成しまうのだ。

つまり、InnoDBにおいては、現状有効でないHASHインデックスが形だけ定義されるということである。

実際に例を挙げてみます。

MariaDB [test]> create table dummy (
    ->   c_tinytext tinytext,
    ->   c_text text,
    ->   c_mediumtext mediumtext,
    ->   c_longtext longtext,
    ->   cu_tinytext tinytext,
    ->   cu_text text,
    ->   cu_mediumtext mediumtext,
    ->   cu_longtext longtext,
    ->   key k1 (c_tinytext),
    ->   key k2 (c_text),
    ->   key k3 (c_mediumtext),
    ->   key k4 (c_longtext),
    ->   unique key u1 (cu_tinytext),
    ->   unique key u2 (cu_text),
    ->   unique key u3 (cu_mediumtext),
    ->   unique key u4 (cu_longtext)
    -> ) Engine=InnoDB;
Query OK, 0 rows affected, 3 warnings (0.016 sec)

waringがあるものの、問題なくテーブルが作成できてしまった。

念のためwarningを見てみる。

MariaDB [test]> show warnings;
+-------+------+----------------------------------------------------------+
| Level | Code | Message                                                  |
+-------+------+----------------------------------------------------------+
| Note  | 1071 | Specified key was too long; max key length is 3072 bytes |
| Note  | 1071 | Specified key was too long; max key length is 3072 bytes |
| Note  | 1071 | Specified key was too long; max key length is 3072 bytes |
+-------+------+----------------------------------------------------------+
3 rows in set (0.000 sec)

3つしかない。次にshow create tableを見てみる。

MariaDB [test]> show create table dummy;
+-------+-----------------------------------------+
| Table | Create Table                            |
+-------+-----------------------------------------+
| dummy | CREATE TABLE dummy (
  c_tinytext tinytext DEFAULT NULL,
  c_text text DEFAULT NULL,
  c_mediumtext mediumtext DEFAULT NULL,
  c_longtext longtext DEFAULT NULL,
  cu_tinytext tinytext DEFAULT NULL,
  cu_text text DEFAULT NULL,
  cu_mediumtext mediumtext DEFAULT NULL,
  cu_longtext longtext DEFAULT NULL,
  UNIQUE KEY u1 (cu_tinytext) USING HASH,
  UNIQUE KEY u2 (cu_text) USING HASH,
  UNIQUE KEY u3 (cu_mediumtext) USING HASH,
  UNIQUE KEY u4 (cu_longtext) USING HASH,
  KEY k1 (c_tinytext(255)),
  KEY k2 (c_text(768)),
  KEY k3 (c_mediumtext(768)),
  KEY k4 (c_longtext(768))
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 |
+-------+-----------------------------------------+
1 row in set (0.001 sec)

なんと、UNIQUE KEYが、自動的にHASH INDEXに変更されてしまった。

念のため、INDEXの状態を見てみる。

MariaDB [test]> show index from dummy;
+-------+------------+----------+--------------+---------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name   | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+-------+------------+----------+--------------+---------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| dummy |          0 | u1       |            1 | cu_tinytext   | A         |        NULL |     NULL | NULL   | YES  | HASH       |         |               |
| dummy |          0 | u2       |            1 | cu_text       | A         |        NULL |     NULL | NULL   | YES  | HASH       |         |               |
| dummy |          0 | u3       |            1 | cu_mediumtext | A         |        NULL |     NULL | NULL   | YES  | HASH       |         |               |
| dummy |          0 | u4       |            1 | cu_longtext   | A         |        NULL |     NULL | NULL   | YES  | HASH       |         |               |
| dummy |          1 | k1       |            1 | c_tinytext    | A         |           0 |      255 | NULL   | YES  | BTREE      |         |               |
| dummy |          1 | k2       |            1 | c_text        | A         |           0 |      768 | NULL   | YES  | BTREE      |         |               |
| dummy |          1 | k3       |            1 | c_mediumtext  | A         |           0 |      768 | NULL   | YES  | BTREE      |         |               |
| dummy |          1 | k4       |            1 | c_longtext    | A         |           0 |      768 | NULL   | YES  | BTREE      |         |               |
+-------+------------+----------+--------------+---------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
8 rows in set (0.002 sec)

やはり、UNIQUE KEYだけHASH INDEXになっている。

この状態において、残念ながらUNIQUE KEYの検索時のインデックスは効きません。HASH INDEXだから等価なら効くのかと思いきや、InnDBなんで、フルスキャンになってしまいます。ご注意ください。

これ、見落とすと思う。少なくとも今までMySQLに触ってきた人なら。

ポジティブに考えるなら、InnoDBでもHASH INDEXを近いうちにサポートするということなのだろうか?とも考えられなくはない。10.5で導入されるのだろうか?

UNIQUE制約を張る以上、等価検索が往々にして行われるので、InnoDBのHASH INDEXサポートは個人的には歓迎かなと。

以上

投稿日時:2020年03月08日 01:08   カテゴリー:mariadb   [コメントがあればどうぞ]