MySQLユーザ会会(MyNA会)2021年3月 開催しました

日本MySQLユーザ会として、「MySQLユーザ会会(MyNA会)2021年3月」を開催しました。
mysql.connpass.com


 通常、毎回4~5人くらい発表してくれるといいなぁと思っているMyNA会、今回登壇くださったのは3名とやや少なめではありましたが、そのぶん、普段聞けない立場からのお話、残念(自称)な感じながらも楽しんでいるお話(いやむしろ楽しんでいるのは周りの人かw)、MySQLの内部動作に関する深いお話など、濃厚なお話を聞かせていただける時間となりました。発表くださったみなさん、質問等で盛り上げてくださった皆さん、ありがとうございました。


 つたない進行のせいか、参加者の皆さんの声(意見や質問など)をうまく拾い上げられなかったことは少し残念でした。たぶん、皆さん、聞きたいことがもっとあったと思うんですよ。そういう皆さんの思いをイベントに拾い上げたいと考えていますので「こういうふうにしてくれたら、俺は質問をした/発言をした」というアイデアや思いがある方は、教えてください。せっかくリアルタイムで参加してくださっているのですから、後から単に動画を見るだけでは得られないことを体験できる場にしたいのです。



今回発表してくださったみなさま(数字は「MySQL 41 Speakers」の通番)。
お三方とも(たぶん)MySQLユーザ会会 には初登壇。ありがとうございます!

■2021/03/19 MyNA会
06. @kisaichi さん: 中の人が語る、MySQLマーケティング
07. @lrf141(けんつ)さん: 残念ポートフォリオ
08. @NayutaYanagisaw さん: Dive into InnoDB MVCC


当日動画:
www.youtube.com

MySQL 8.0.23で実装されたフレシェ距離関数(ST_FrechetDistance())を試す

MySQL 8.0.23で、Spatial(GIS)関連機能として、フレシェ距離を求める関数 ST_GrechetDistance() と、ハウスドルフ距離を求める関数 ST_HausdorffDistance() が追加されました。どちらも、2つのジオメトリどうしの類似度を求める関数のようですが、今ひとつよく分からないので、今日は主にフレシェ距離を中心に色々と動作を試してみて、「こういうことかな?」の理解を試みました。
 想像して、試して、結果に納得する、という作業ですので、正しくない理解を書いているかもしれません。お気づきの方は、やさしくお教えいただければ幸いです。

フレシェ距離とは

 ざっくり言うと、2つのジオメトリ(MySQL 8.0.23 ではLineStringのみ対応)がどれくらい似ているかを示す数値。2つの線があった時、片方の線上の任意の点から相手方の線の最も近いところまで、最悪でもどれくらいの距離を行けば良いかを示す数字、というざっくりとした理解をしています(この理解は、正確ではないことは実験していて分かりましたが)。
 なお、線上の任意の点と書きましたが、MySQLに実装されているのは「離散」のフレシェ距離、つまり、LineString を構成するために明示された各点のみを対象とするものです。

はじめてのFrechetDistance

 とりあえず、2つのLineStringを作って、ST_FrechetDistance()を試してみます。シンプルにこんな2つの平行線( ポイント数3)で。
f:id:sakaik:20210227171227p:plain

SET @g1=ST_GeomFromText('LINESTRING(1 1, 2 1, 4 1)');
SET @g2=ST_GeomFromText('LINESTRING(1 2, 2 2, 4 2)');
mysql> SELECT ST_FrechetDistance(@g1, @g2) d;
+------+
| d    |
+------+
|    1 |
+------+

 どの点から見ても、相手方の一番近い点は距離1のところにあるので、その中で一番大きなもの(遠いもの)も 1 となります。予想と結果は一致。

点をひとつ遠くにしてみる

青いほうの点(@g2)の真ん中の点を少しだけ遠ざけて見ます。赤い線(@g1)はそのままで。
f:id:sakaik:20210227172121p:plain

mysql> SET @g2_1=ST_GeomFromText('LINESTRING(1 2, 2 2.1, 4 2)');
mysql> SELECT ST_FrechetDistance(@g1, @g2_1) d;
+------+
| d    |
+------+
|  1.1 |
+------+

 @g1 と @g2_1 それぞれの点を比べて、真ん中の点の距離どうしが少し遠くなって 1.1 になったので、そのような結果が返ってきます。予想通り。

試しに横方向にも動かしてみる

 先ほどは真ん中の点をy軸方向にずらしてみましたが、今度は横方向に動かしてみます。
f:id:sakaik:20210227172416p:plain

mysql> SET @g2_2=ST_GeomFromText('LINESTRING(1 2, 2.1 2, 4 2)');
mysql> SELECT ST_FrechetDistance(@g1, @g2_2) d;
+-------------------+
| d                 |
+-------------------+
| 1.004987562112089 |
+-------------------+
1 row in set (0.00 sec)

 真ん中の点どうしの距離が、1よりも少し遠くなったのだということは分かりますが、この数字が合っているかどうか、もう少し確認してみないと。この数字は、直角を挟んだ辺の長さがそれぞれ 1 と 0.1 の直角三角形の斜辺の長さですから、これもMySQLを使って計算してみます。

mysql> SELECT SQRT(1*1 + 0.1*0.1);
+---------------------+
| SQRT(1*1 + 0.1*0.1) |
+---------------------+
|   1.004987562112089 |
+---------------------+

 一致しました。想定通りのフレシェ距離が得られたことが確認できました。

少し刻んでみると・・・・

 赤いほうの線(@g1)は固定のままで、青いほうの線を少し刻んでみましょう。(3,2)と(4,2)の間に (3,2) という点を追加してみます。言うまでもなく刻もうが刻むまいが線としては同じ線をあらわしているはずですが・・・・
f:id:sakaik:20210227173511p:plain

mysql> SET @g3=ST_GeomFromText('LINESTRING(1 2, 2 2, 3 2, 4 2)');
mysql> SELECT ST_FrechetDistance(@g1, @g3) d;
+--------------------+
| d                  |
+--------------------+
| 1.4142135623730951 |
+--------------------+

 おや。この数字はルート2。追加した点から相手方の一番近い点を探した結果、x方向に1、y方向に-1行ったところにある点が一番近いと見つけたということですね、これは。 
 つまり、MySQLの(離散)フレシェ距離では、結果として同じ線をあらわしているようなLineStringどうしでも、粒度(刻み方)が異なると数字が大きくなってしまうと考えてよさそうです。

フレシェ距離は順序が大切

 ここで改めて一番最初の事例に戻ってみます。
f:id:sakaik:20210227174627p:plain
 ただしここでは、赤いほうの線を右から左へ向かって定義してみます。

SET @g2r=ST_GeomFromText('LINESTRING(4 2, 2 2, 1 2)');

 2つの線を構成するPOINT自体に何ら変更はないので、同じ結果となることを予想していたのですが・・・・

mysql> SELECT ST_FrechetDistance(@g1, @g2r) d;
+--------------------+
| d                  |
+--------------------+
| 3.1622776601683795 |
+--------------------+

 これはどうも、例えば左上の点と右下の点の距離がフレシェ距離として表示されていますね。x方向に3、y方向に1だけ隔たっていますから、

mysql> SELECT SQRT(3*3 + 1*1);
+--------------------+
| SQRT(3*3 + 1*1)    |
+--------------------+
| 3.1622776601683795 |
+--------------------+

 うん。その点どうしの距離です。
つまり、フレシェ距離は、2つのLineStringを構成する点の集合どうしを比べるものではなく、LineString を構成する点を順に比較していくものと考えられます。いや、ほんとはよくわからないので、ご存じの方、教えてください。

一方、ハウスドルフ距離は

 ハウスドルフ距離のほうは、LineString内の順序ではなく、構成する点の集合のみに着目しているように見えます。
 先ほどの2本の平行線を逆順にしたもの(@g1 と @g2r)で試すと、距離1のままとなります。

mysql> SELECT ST_HausdorffDistance(@g1, @g2r) d;
+------+
| d    |
+------+
|    1 |
+------+

 また、ST_HausdorffDistance()は引数の順序が大切(どちらのジオメトリを基準に相手方との最小距離を求めるのか)であるようです。先ほどの「刻んだ」線である @g3を例に。

mysql> SELECT ST_HausdorffDistance(@g1, @g3) d;
+------+
| d    |
+------+
|    1 |
+------+

 相手方(@g3)が幾ら刻もうが、@g1側から見て一番近い点は 距離1のところにあるので、その値が結果として返ってきます。
 一方で、@g3側から見ると、刻んだ点(3,2)から見た相手方の一番近い点、というのが最長の最短距離になるので、ルート2の値が返ってくることになります。

mysql> SELECT ST_HausdorffDistance(@g3, @g1) d;
+--------------------+
| d                  |
+--------------------+
| 1.4142135623730951 |
+--------------------+

おわりに

 と、フレシェ距離、ハウスドルフ距離を試してみたのですが、今に至ってもこれらの関数がどのようなシーンで便利になるのか、今ひとつ分かっていません。。どなたか現実世界での使いどころをご存じでしたら、教えてください。
 また、冒頭でもお断りしたとおり、このエントリーは「よくわからない中で、とりあえずどんな動きをするのかを試してみた」というものですので、不正確な点、勘違いしている点等あるかと思います。ご承知おきください。
 なお、今回はデカルト座標で試してみましたが、これらの関数はもちろん各測地系にも対応しています。

MySQL Cafe #11「MySQL 8.0日本語ドキュメント」登壇しました

ラクルさん主催の MySQL Technology Cafe #11 にて、登壇させていただきました。今回のテーマは「MySQL 8.0 日本語ドキュメント」。お声がけをいただいたときに、ちょうど、ドキュメントについて語りたい内容を持っていたため、発表枠のお時間を頂戴してお話をさせていただきました。

oracle-code-tokyo-dev.connpass.com


今回の私の発表は、内容三本立て
(1)MySQL 8.0 の日本語マニュアル嬉しいよ嬉しいよ超嬉しいよ!!!!
(2)過去バージョンの日本語マニュアルのおもいで
(3)最近のマニュアルの更新差分を眺めてるけど、面白いよ!
発表資料(スライド)は、本エントリ末尾にあります。

「スライド」って書いて思いだしたんだけど(関係ない話)、最近は、発表の時に「次のスライドおねがいします」って台詞を吐いたことのない人も、たぶん増えてきていますよね。

MySQL 8.0 日本語マニュアル嬉しい!!!

 
 英語圏で開発され、公用語が「下手な英語」であるMySQL界において、英語以外の言語でマニュアルが公式に用意されるというのは、極めて異例のことです。恵まれているんです。世界中見回しても、英語以外は日本語だけなんです。 オラクル社社内でものすごいネゴシエーションをして、日本語マニュアルを作るプロジェクトを通して、完成させてくれている人がいることに感謝するとともに、我々一般技術者も、「日本語マニュアル、作るのはコストかかるけど、それに見合うリターンもあるな」と開発元に思ってもらえるよう、経済的な力はもちろん、日本でのMySQLを盛り上げていくために、みんなで少しずつ力を出し合えたらいいなと思っています。

 さて、そのMySQL。ご存じの通りOSSオープンソースソフト)です。オープンソースですが、かなり複雑化、巨大化して、少なくとも私のようなレベルの人では、もはや「オープンソースの開発に、ソースコードで貢献」というのは、かなり難しくなってきました。そんな中で、私たちでも貢献できるのが「翻訳内容の修正」です。今回、現時点で公開されているMySQL8.0日本語マニュアルは暫定版なので、みなさんからの修正提案を募集しているとのことです。提案して採用されるかどうかはオラクル社次第ですが、普通に意味がおかしい部分を報告してリジェクトされることはたぶんないでしょう。MySQLというオープンソースの(ドキュメントはGPLではありませんが)活動に貢献できるチャンスです。あなたの提案がMySQLの公式マニュアルに残るのです。なんか嬉しいじゃないですか。
 個人的には、1つずつ報告するのもナニなので、幾つかまとめて報告してみていたのですが、どうも、ひとつずつポロポロ報告している人もいるようなので、それでいいみたいです(笑)。ぜひみなさんも、MySQL日本語マニュアルに記念パピコをしてみてはいかがでしょうか。なお、報告された修正提案は3月中下旬にまとめて反映するとのことです。


 報告されている修正レポートの一覧(bugs.mysql.com):
https://bugs.mysql.com/search.php?search_for=&status=Active&severity=&limit=50&order_by=id&cmd=display&direction=DESC&bug_type%5B%5D=Server%3A+Docs+JP&os=0&phpver=8.0&bug_age=0


暫定公開の MySQL 8.0 日本語マニュアルは以下(4月以降は本公開となりURLが変わります):
https://dev.mysql.com/doc/translation-refman/8.0/ja/

マニュアルの思い出

 詳細は発表資料をご覧ください。
MySQLでは、すべてのメジャーバージョンについて日本語マニュアルがあるわけではなく、結果としてひとつおきくらいに作られていました。 MySQL 5.1 の日本語化の時には、海外の翻訳会社に依頼した結果を、コミュニティの有志(希望者)で、svnのファイルをゴリゴリ更新していったという思い出があります。翻訳会社も章ごとに担当者がいたようで、特に意味の通じないひどい章があったりしたのも、楽しかったなぁ(笑)。
 あと、発表資料中では MySQL 4.1 には日本語マニュアルがない、と書いてしまったのですが、その後、手元のPCのフォルダを漁ってみたら、謎の「refman-4.1-ja.a4.pdf」というファイル(MySQL 4.1 日本語マニュアル)が出てきました。日本語マニュアル、あったみたいです。

マニュアルの差分を見てみて

 どれくらいの頻度で、どんな内容が更新されているのだろうと興味を持って、昨年末(2020年12月)から、簡単な仕組みを作って、差分を眺めています。diffを取って、目視で面白そうなものがないかを眺めているという程度ですが、いち早く最新情報をキャッチアップできたり(でも、その新機能を試せるのは半年後だったりするのですが)、言い回しの変更を見ながらドキュメントチームのこだわりに接して楽しんでいます。
 html化されたマニュアル(MySQLマニュアルは、XML形式の原簿から PDFやHTML形式へと変換されています)には、変換時につけられるIDのようなものがHTMLタグ中に多く含まれているため、そのまま、昨日のマニュアルと今日のマニュアルのdiffを取ってしまうと、実際には内容の変更ではない部分で、大量の差分が出てしまいます。また、HTMLファイルでは、1行が長くなる事も多く、差分を確認するには、ちょっと見にくい面もあり、そのあたりに対する工夫なども紹介しました(詳細は発表資料を参照ください)。

 現時点では、公開するための仕組みを作っていないので、自分でニマニマしながら眺めているだけですが、差分に興味を持ってくださった方もいるようなので、とりあえず手元にある差分ファイル群をお見せできる形にしてサンプルページを作ってみました(雑に手作業で作ったものなので、更新はしません)。ちょっと apache の設定がうまくいっていないみたいで、ブラウザによっては charset を正しく認識できずに文字化けしているところがあるかもしれません。そのときは UTF-8 にして見てみてください。

MySQL refman diff sample.

その他

 発表の機会のドサクサに紛れてちょっぴり営業活動しちゃおうかな、なんて少し思ったのですが、発表内容の分量も結構あったので、そんなことよりも1分でも内容の話に時間を割きたくなり、あんまりちゃんと語りませんでしたので、改めてここで。
 コロナの影響で、私のお仕事面、実は結構時間にアキがある状態になっています。「坂井がいるとなんかよくなる」という仕事をしているので、仕事内容を説明するのにいつも苦労するのですが、、、データベースそのものの技術だけではなく「データの流れ」を全体俯瞰することで、お客さんが本当は何をやりたいのか(要件)、それはどのように格納・出し入れしたらいいのか(RDBMS設計)、発生しうるリスクにはどのようなものがあり、どの程度対応しておくべきなのか(リスク管理)的な事について助言したり、必要に応じて実際に手を動かしたりなどを提供しています。チームに入り込んで一緒に考えたり助言したりというやり方ですので、貴チームでこのあたりのノウハウにお困り・お悩みでしたら、ぜひ一度ご相談ください。 

 というお話を、あの場でやるのは時間勿体ないですもんねー(笑)。(そもそもたぶん怒られるw)



最後に

 あらためて、MySQLのドキュメントチームに感謝! 日本語版作成に尽力くださった皆さんに感謝! そして、きっとこのマニュアルの修正提案をしてよりよいものにしてくれるみんなにも感謝!!!





発表資料:

www.slideshare.net

「MySQL8.0.23リリースノートでわいわい言う勉強会」開催しました

MySQL 8.0.23 のリリースノートを見ながらわいわい言う勉強会を開催しました。

mysql.connpass.com


「リリースノートでわいわい言う勉強会」略称リノベも、今回で4回目の開催になりました。MySQLのリリースはおよそ3ヶ月に1度なので、つまり、ちょうど一年分、開催を続けることができたということになります。いつも参加してくださっている皆さん、そして、余りなじみのない会でちょっと怖いけど勇気を持って飛び込んでくださってた参加者のみなさん、ありがとうございます。

 ずっと以前よりこういう勉強会をやりたいと思っていたものが、勉強会のオンライン化により実現しやすくなりました。90分限定という尺は、個人的にはちょうど良く感じていますが、リアル会場に集まっての会だと、(場所によりますが)わざわざ足を運ぶには、やや短く感じます。移動の時間が勿体なく感じるんですよね。
 オンライン化で、自宅から、あるいは聞くだけなら電車の中でもおふとんの中でも参加できるので、尺の短い勉強会もやりやすくなった面はあるのかな、と感じています。


 開催を重ねる中で、随分と私の中での考え方も変わりました。
当初は、やっぱりイベント主催者として、公開された動画もある程度はコンテンツとして成立するようにということを意識していて、会の進行もそれぞれの時間に「お題」が付けることができるような進行をイメージしていました。今何の話題をしているかを明確にする、という方針です。
 でも、なんか「わいわい」ってそういうのじゃないんですよね。「そういえばさ」と言って、元の話題がどっかに行ってしまっても、それもライブ会合の面白さ。そういうのを殺してしまっているなぁと感じ、特に4回目の今回はあとで動画を見る人のことは、あまり気にしないことにしました。わいわいやっている雰囲気を、後から見て楽しんだり、その中から役に立つ情報を拾ってもらったり、それでいいのかな、と。

 更に言えば、動画公開のための作業も少しは手間がかかっている上に、それほど再生数があるわけでもなく、反応も皆無に近いので、もう動画公開はやめてしまってもいいのかなとも思い始めたりもしています。 誰も見てないでしょ?(笑)。 動画を見た感想とか得たものとかを書いてくれるブログが毎回5個くらいあるなら、もちろん公開を続けるんですけどね。


 えっと、内容のことを書いていなかった。
個人的には、今回の MySQL 8.0.23 では、Spatial(GIS)の機能として、フレシェ距離とハウスドルフ距離を求める関数が追加されたのが大きなトピックでした。でも正直なところ、使いどころがよくわからない。その辺りを調べてからこの会合で紹介できれば良かったのですが、(会が終わって2週間くらい経っている、これを書いている)今でさえよくわかりません。

 今回は全体として、おとなしめの「メンテナンスリリース」だったこともあって、大きく膨らむ話題もあまりなく、少し早めの散会となりました。
 もうちょっと運営の力量で盛り上げることはできたかな、という思いはあり、その点、力不足ですいません。今後も工夫は続けていきますので、今後ともぜひご参加ください&おつきあいください。

当日の模様の動画は以下でご覧いただけます。
www.youtube.com

MySQL 8.0.24で予定されているCAST()の拡張はGIS機能を大きく進化させる

 最近、MySQLのリファレンスマニュアルの差分を追いかけているのですが、本日の更新で、Spatial(GIS)機能に注目している人には非常に大きな機能に関する記述が追加されました。CAST() 関数と CONVERT() 関数の spatial への拡張です。

MySQL :: MySQL 8.0 Reference Manual :: 12.11 Cast Functions and Operators

 あくまでも CAST() 関数ですので、複数行のデータを1つにまとめたり、1つの(たとえばLINESTRINGの)データを複数の(例えばPOINT)データにするものではないと考えられますが、CAST() 関数の 8.0.24で予定されている拡張によって、Spatialの各型どうしの変換がやりやすくなることは間違いないでしょう。強調しておきますが、数日前にリリースされた MySQL 8.0.23 ではなく、(通常どおりなら)2021年4月中旬にリリースされる予定の MySQL 8.0.24 でのお話です。

 今回のマニュアルへの追加記述によると、変換できるのは以下のもののようです。

singleな型からの変換:
f:id:sakaik:20210123171904p:plain

MULTIな型からの変換:
f:id:sakaik:20210123171933p:plain

一枚の図にあらわしたもの:
f:id:sakaik:20210123171943p:plain


当然、変換可能なもののみの動作するものと思いますが(たとえば MULTIPOINT から POINT への変換は「MULTI POINT型の中にただひとつの点だけがある場合」などの条件)、色々とドキュメントにも細かい事項が書かれているようですので、後ほどここに追記したいと思います。

続・MySQL 8.0.23 の INVISIBLE COLUMN :その用途

昨日の日記で、MySQL 8.0.23 で開放された INVISIBLE COLUMN(不可視列)について書きました。
sakaik.hateblo.jp

用途がよくわからない、といいつつ、最後に、「PKを不可視列にすれば、ちょっとだけINSERTが便利!」ということを発見したのですが、偶然ながらも、当たらずとも唐辛子といったところだったようです。

 lefred さんのブログに説明がありました。

lefred.be

 INVISIBLE COLUMN の話について書くと、「今まで、PKがなかったテーブルにAUTO_INCREMENT なPK列を追加する際に使うといいよ」ということでした。

 PKのないテーブルが存在すること自体、あまり褒められたものではありませんが、まぁ色々事情はあるのでしょう。このテーブルに id列(integer primary key)を追加する場合、通常は先頭に列を追加したいでしょうから、そのテーブルの列位置が変わってしまいます。まぁこれで影響が出ちゃうクエリもあまり褒められたものじゃないとは思うのですが、理想より現実。とにかく問題が起きたら困るので、列位置が変わらない方法があるなら、それに超したことはありません。
 こんな時に、追加する id列を不可視にすれば、影響なしなし無問題。

ALTER TABLE t1 
  ADD COLUMN id INT UNSIGNED 
        AUTO_INCREMENT PRIMARY KEY INVISIBLE FIRST;

 べつに、このid列を使ってデータアクセスしたいわけではないので、不可視でいいのです。


 lefredさんのブログには、明示的なPKが必要な理由や、PKがAUTO_INCREMENT であることをお勧めする理由が書かれていますので、興味ある方は読んでみるといいと思います。
 私の理解の範囲で簡単にまとめると:

  • PK がないテーブルは、MySQLが勝手に6バイトの内部的なPK列を作る
  • しかし内部的なPK列は、触れないし見えない、つまりコントローラブルじゃない
  • 内部的なPK列は全テーブル通しての連番(?)になるので、イケてない
  • ランダムな文字列をPKにするのはお勧めしない。INSERTのたびに内部の配置換えが起こるから(クラスタド・インデックスなので)
  • UUID() を UUID_TO_BIN してPKとして使うアイデアも、↑と同じ
  • つまりは、intやbigintのAUTO_INCREMENT 最高!

 私の勘違いや読み間違いをしている点があったら教えてください。


 PKがないテーブルに対して、内部で勝手につけるPKが現在の仕様ではなく、INVISIBLE なAUTO_INCREMENT になってくれれば、それで良い気もしますが、今回はそこへ向けての伏線なのかもしれませんね。

MySQL 8.0.23 の INVISIBLE COLUMN を試してみる

 MySQL 8.0.23 では、INVISIBLE COLUMN の仕組みが解放されました。
ドキュメントによると「カラムを追加しても、SELECT * の動作に影響を与えないところがいいんだよねー」と書いてあるのですが、うーん、それって何処の人のニーズなの?という感じで、もにょもにょします。(そんなニーズないだろう、という思いと、もしあるとしたら私の思いもつかない使い方なので、話を聞いて感動してみたい思いとが共存している感じです)

MySQL :: MySQL 8.0 Reference Manual :: 13.1.20.10 Invisible Columns


 ということで、試すのも簡単そうなので、実際に動かしてみました。
だらだらと、やります。

テーブルの作成と確認

 himitu カラムを INVISIBLE として、テーブルt1を作ってみます。

CREATE TABLE t1 (
  id         integer,
  name       varchar(10),
  himitu     varchar(10) INVISIBLE,
  created_at datetime);

 作れたので、descと show create table それぞれで確認してみます。

desc:

mysql> desc t1;
+------------+-------------+------+-----+---------+-----------+
| Field      | Type        | Null | Key | Default | Extra     |
+------------+-------------+------+-----+---------+-----------+
| id         | int         | YES  |     | NULL    |           |
| name       | varchar(10) | YES  |     | NULL    |           |
| himitu     | varchar(10) | YES  |     | NULL    | INVISIBLE |
| created_at | datetime    | YES  |     | NULL    |           |
+------------+-------------+------+-----+---------+-----------+
4 rows in set (0.01 sec)

 出力を見ると、普通に4カラムのテーブルが作成されて、付加情報として「INVISIBLE」という属性がついている、というイメージですね。


show create table:

mysql> SHOW CREATE TABLE t1\G
*************************** 1. row ***************************
       Table: t1
Create Table: CREATE TABLE `t1` (
  `id` int DEFAULT NULL,
  `name` varchar(10) DEFAULT NULL,
  `himitu` varchar(10) DEFAULT NULL /*!80023 INVISIBLE */,
  `created_at` datetime DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
1 row in set (0.00 sec)

 8.0.23 以降の場合のみに「INVISIBLE」がつくようになっています。つまり 8.0.23 で作成/ダンプしたテーブルを、それ以前の(たとえばお隣のサーバの)MySQL に入れると、INVISIBLE なカラムはVISIBLE になるということでもあり、この機能のウリである「SELECT * の結果が変わらない」という観点からは、異なる動作が発生すると言えます。まぁそもそも、個人的には SELECT * の使用はお勧めしていないので、このことで問題になってしまうようなシステムは私の周りにはないと思うのですが、、

データを入れる

 INSERT文でカラム明示しない場合は、ないものとして扱われる(以下の例では3カラムの値のみを与えている)。INVISIBLE カラムに値を入れたい場合は INSERT文でカラムを明示する必要がある。

INSERT INTO t1 VALUES (1, "watashi", now());
INSERT INTO t1 (id, name, himitu, created_at) VALUES (2, "oreore", "naisyo", now());


内容確認。SELECT * には出てこない。

mysql> SELECT * FROM t1;
+------+---------+---------------------+
| id   | name    | created_at          |
+------+---------+---------------------+
|    1 | watashi | 2021-01-21 14:47:02 |
|    2 | oreore  | 2021-01-21 14:47:41 |
+------+---------+---------------------+
2 rows in set (0.00 sec)

 カラム明示をすれば、もちろん確認可能。

mysql> SELECT id, name, himitu, created_at FROM t1;
+------+---------+--------+---------------------+
| id   | name    | himitu | created_at          |
+------+---------+--------+---------------------+
|    1 | watashi | NULL   | 2021-01-21 14:47:02 |
|    2 | oreore  | naisyo | 2021-01-21 14:47:41 |
+------+---------+--------+---------------------+
2 rows in set (0.00 sec)

INVISIBLEをVISIBLEに

 秘密カラムを隠す必要がなくなったので(というシナリオで) VISIBLE 化してみる。

mysql> ALTER TABLE t1 MODIFY COLUMN himitu VARCHAR(10) VISIBLE;
Query OK, 0 rows affected (0.01 sec)
Records: 0  Duplicates: 0  Warnings: 0


 desc で見ても、Extraのところにあった「INVISIBLE」の表示はなくなっているし、Oracleみたいに、VISIBLE化した時に一番最後のカラムに移動したりはしない。

mysql> desc t1;
+------------+-------------+------+-----+---------+-------+
| Field      | Type        | Null | Key | Default | Extra |
+------------+-------------+------+-----+---------+-------+
| id         | int         | YES  |     | NULL    |       |
| name       | varchar(10) | YES  |     | NULL    |       |
| himitu     | varchar(10) | YES  |     | NULL    |       |
| created_at | datetime    | YES  |     | NULL    |       |
+------------+-------------+------+-----+---------+-------+
4 rows in set (0.00 sec)


SELECT * でももちろん表示されるようになった。

mysql> SELECT * FROM t1;
+------+---------+--------+---------------------+
| id   | name    | himitu | created_at          |
+------+---------+--------+---------------------+
|    1 | watashi | NULL   | 2021-01-21 14:47:02 |
|    2 | oreore  | naisyo | 2021-01-21 14:47:41 |
+------+---------+--------+---------------------+
2 rows in set (0.00 sec)
mysql> show create table t1;
+-------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Table | Create Table                                                                                                                                                                                                                 |
+-------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| t1    | CREATE TABLE `t1` (
  `id` int DEFAULT NULL,
  `name` varchar(10) DEFAULT NULL,
  `himitu` varchar(10) DEFAULT NULL,
  `created_at` datetime DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci |

ぜんぶ隠しちゃうことはできない

すべてのカラムを秘密にしてみようと思ったのだけど、許してもらえなかった。

mysql> CREATE TABLE t2 (
    ->   id         integer     INVISIBLE,
    ->   name       varchar(10) INVISIBLE,
    ->   himitu     varchar(10) INVISIBLE,
    ->   created_at datetime    INVISIBLE);
ERROR 4028 (HY000): A table must have at least one visible column.


 ということで、とりあえず1つだけVISIBLEなカラムを作った状態で、

CREATE TABLE t2 (
  id         integer     INVISIBLE,
  name       varchar(10) ,
  himitu     varchar(10) INVISIBLE,
  created_at datetime    INVISIBLE);


そのカラムを INVISIBLE にしてみようとしたが、、、

mysql> ALTER TABLE t2 MODIFY COLUMN name VARCHAR(10) INVISIBLE;
ERROR 4028 (HY000): A table must have at least one visible column.

 やはり同じエラー。最終的に1つもVISIBLEなカラムが存在しな状態が許されないことが確認できました。
これ、今回の機能のために新たに付け加えられたエラーメッセージなんですよね。お会いできて、なんだか嬉しい。

INVISIBLEなカラムに値必須オプションを付けると面倒

 id 列を PRIMARY KEY にして INVISIBLE にしてみます。なんと、これ、テーブル作成できます。
(ここまでのテーブルを元にしたので himituという名前の列がありますが、もはや秘密ではありません)

mysql> CREATE TABLE t3 (
    ->   id         integer     PRIMARY KEY INVISIBLE,
    ->   name       varchar(10) ,
    ->   himitu     varchar(10) ,
    ->   created_at datetime    );
Query OK, 0 rows affected (0.01 sec)

でも、列の明示なしでのINSERTを試みると、エラー。id列の値を指定していないのだから当然ですね。

mysql> INSERT INTO t3 VALUES ("watashi", "naisyo", now());
ERROR 1364 (HY000): Field 'id' doesn't have a default value

INVISIBLE カラムの使い方を見つけた!!!

 先ほど INVISIBLE にした PRIMARY KEY の id列に、AUTO_INCREMENTを付けてみます。

 CREATE TABLE t4 (
   id         integer     AUTO_INCREMENT PRIMARY KEY INVISIBLE,
   name       varchar(10) ,
   himitu     varchar(10) ,
   created_at datetime    );


ここに3件のデータを入れて、内容確認してみます。

INSERT INTO t4 VALUES ("watashi", "naisyo", now());
INSERT INTO t4 VALUES ("oreore", "nainai", now());
INSERT INTO t4 VALUES ("kare", "syosyo", now());
mysql> SELECT id, name, himitu, created_at FROM t4;
+----+---------+--------+---------------------+
| id | name    | himitu | created_at          |
+----+---------+--------+---------------------+
|  1 | watashi | naisyo | 2021-01-21 14:58:35 |
|  2 | oreore  | nainai | 2021-01-21 14:59:04 |
|  3 | kare    | syosyo | 2021-01-21 14:59:04 |
+----+---------+--------+---------------------+
3 rows in set (0.01 sec)

 うん!!これだ!!!
INSERT時に、AUTO_INCREMENT やデフォルト値に任せて、普段は値を明示しないような場合、ちょっとだけ便利だぞ、これ!
今までは、AUTO_INCREMENT を持つテーブルに手作業で値を入れる場合に、id列を除いた列名を羅列するか、あるいは 値として*1NULLを明示していたのが、これで不要になるのです。きっと便利だ!

 ということで本日時点の結論。

  • INVISIBLE カラムは、AUTO_INCREMENT の列に指定すると INSERTがちょっとラク

(笑)

追記:秘密カラムの追加

 いちばん本筋であった「カラムを追加しても SELECT * の結果が変わらないのがいいんだよー」というシナリオを書いていませんでした。

 以下のようにして、追加できます。

mysql> ALTER TABLE t4 ADD COLUMN himi2 varchar(5) INVISIBLE;
Query OK, 0 rows affected (0.03 sec)
Records: 0  Duplicates: 0  Warnings: 0

 descで確認すると、ちゃんと追加されています。

mysql> desc t4;
+------------+-------------+------+-----+---------+--------------------------+
| Field      | Type        | Null | Key | Default | Extra                    |
+------------+-------------+------+-----+---------+--------------------------+
| id         | int         | NO   | PRI | NULL    | auto_increment INVISIBLE |
| name       | varchar(10) | YES  |     | NULL    |                          |
| himitu     | varchar(10) | YES  |     | NULL    |                          |
| created_at | datetime    | YES  |     | NULL    |                          |
| himi2      | varchar(5)  | YES  |     | NULL    | INVISIBLE                |
+------------+-------------+------+-----+---------+--------------------------+
5 rows in set (0.00 sec)

*1:本当は「値」ではないのだけど便宜上