ASMのきもち

DBとAnsibleが気になって仕方ない人のブログ

G検定を受けたんだってばよ

G検定受けたんだってばよロゴ


大分お久しぶりなブログです!
転職してから半年、あっと言う間の半年だったのでそれも記事に書きたいですし。
めちゃくちゃ楽しかった「マルチクラウドデータベースの教科書」の感想も書き溜めているのですが。

まずはその前にサクッと出せるアウトプットとして、最近受けた資格試験「ジェネラリスト検定」、通称「G検定」を受けたので、その話をしたいと思います。
試験を受けるためにこのブログを見た方は、「ここだけ読んで」と言う部分だけ読んでいただければOKです。

この記事で書くこと

端的に言うと「この情報、試験受けると決めた時に聞きたかったよ…」という内容をまとめています。
なのでこのブログを読んだからと言って、合格することを保証するものではございません。
以下のような方向けのブログです。ライトな気持ちで読んでください。

  • ある日会社で「受けろ」と唐突に言われて戸惑っている方
  • 普段PyTorchやTensorFlowをゴリゴリ使ったり、Jupiter Noteに嘆いたりしていない
  • 業務では触っていて、E資格ならいけるんだけど暗記もののG検定はねぇ…という方(あまりいないと思いますが)

そもそもジェネラリスト検定とは何か?

ジェネラリスト検定、通称「G検定」(以降はG検定と記載します)とは、一般社団法人 日本ディープラーニング協会が運営している検定です。
詳細は公式サイトをご確認いただければと思うのですが、ブログ記載時点の2024年9月段階では以下のように記載されています。

ディープラーニングの基礎知識を有し、適切な活用方針を決定して、事業活用する能力や知識を有しているかを検定する。

ということで、ディープラーニングの知識を問う検定です。
今後AIが当たり前のように業務やシステムで利用していく中、最低限これぐらいは知っておいてね?という内容です。

ちなみにこの検定、Di-Lite啓発プログラムという中で、取得推奨になっている資格です。
このDi-Liteとは以下のように記載されており、IPA経済産業省が協議会として名を連ねています。

デジタルを使う人材であるために、全てのビジネスパーソンが、共通して身につけるべきデジタルリテラシー範囲

この中で「この資格取ってね!」と言われている資格が以下の3つです。
この3つを見れば「あぁなるほどな」と思われるエンジニアの方もいるのではないでしょうか。

  • ITパスポート
  • G検定
  • データサイエンティスト検定

個人的には、このGっていう名前がどうも…どうも好きじゃないんですよね。Gってほら、あれを思い出し…

CochrochDBちゃん

いや、君じゃない。でも君もG…あばばばば。


試験を受ける前に知っておいてほしいこと

前提

この記事を書いた人の前提、勉強条件は以下の通りです。

  • へっぽこエンジニア。エンジニア経験は10年以上。PMとDBREやって、今はPdMもどき
  • 暗記が本当に苦手。過去ベンダ試験の暗記ものは大抵、泣きながらやってきた
  • ある日上司に「推奨資格だから合格しようね?(にこっ)」と言われ、受けないという選択肢は当然…ない
  • とはいえ優しい会社らしく、有料研修を無料で受けさせてくれた(全員ではないが)
  • 私含め、3人の同僚で受験。2人が有料研修を受けて受験、1人は本だけで受験
    • 結果、3人全員合格。3人でわちゃわちゃしながら「あれやって良かったよね」「これだめだったね」と話をした経験を記載しています

試験の情報

必ず公式を確認してください。
試験時間、問題数、受験環境などは随時変わる可能性があります。

試験の合格率

2024年9月の試験合格率は以下の通りで、これだけ見ると合格率相当高いです。
ただもちろん、落ちている方もいるので、ノー勉で受かる試験ではないと思います。
総受験者数 4,917名
合格者数  3,689名

勉強した時間

実質3日間ちょいでした。
通勤時間中に少し本を読んだりしていましたが、ガッツリ勉強できたのは3日(土日)だけでした。
実務でやっている人を除き、この短時間はあまりおすすめしません。

ここだけ読んで

前提として、この記事は2024年9月7日に受験した人の体験記です。
次回の2024年11月からシラバス(試験範囲)が変わります。
その点も踏まえ、この記事は「ここが出るよ」というような内容は一切記載していません。
勉強を始める前に。様々な本や動画、ブログを読む前に、知っておいてほしい内容を記載しています。

端的に箇条書きで記載します。

  • 暗記ものです。
    • ただ単語暗記しても受かりません。ある程度理解して回答する必要があります
  • おすすめの勉強方法は「用語集を作る」です
    • 自分用の用語集を作っていって、これなんだっけ?と用語集を検索して振り返る過程で覚えます
      • 過去問沢山やって、用語集を充実させていくのがおすすめです。過去問何回やったかが勝負です
      • 下に私の用語集のスクショ貼るので、参考になれば幸いです
    • 他人の用語集使うのは、おすすめしません。覚えない
      • 合格した人の用語集を丸暗記しても、受からないと思います
  • シラバス絶対見てください。過去の「これ読んだら受かる」「ここがよく出る」は信じない
    • AIを取り巻く技術や法令などは急速に変化しています。そのため、試験内容もどんどん変わる、増えていっています
      • 5年前に一度受けようと思ったんですが都合が悪くて受けられず、今回受けてみて範囲がものすっっっごく増えていてびっくりしました
    • 有料研修で講師の先生が「最近この範囲が試験に出ているので〜」が、一問も出なかった範囲もあります
      • これは研修や講師の方が悪いのではなく、試験内容を頻繁に変えているからではないかと思います。なので、「ここがよく出る」はあまり当てにしないで
    • どこか出るか?は、シラバスが正です
  • AIやディープラーニング以外も出ます
    • 2024年時点では、CloudNative的な内容とか、プロジェクト管理的な内容も出たりしましたが、この先は出ないかもしれないです
    • くどいですが、シラバスは見てね
  • 試験は即答しないと、時間が間に合いません
    • 2024年時点では、120分で200問解く必要があり、1問1分未満で回答しないといけないです
    • 本番前に2-3回、時間を測って模試をするのがおすすめ
  • 番役に立ったツールは「ChatGPT」
    • 解説を読んで「いやこれ、何言ってるのか分からない…」っていうことありません?そんなときはGPTに壁打ちすると理解早いです
    • 鶏卵な気がして、ちょっと変な気分にはなりますけどね
  • 本を買うなら「初版がなるべく最近のもの」を選んで
    • 少なくとも数年前の本だけでの勉強だと受からないので、なるべく最近出た本を選んで

この記事書いた人の成功失敗談

  • やってよかった
    • 同僚達と情報交換しながら勉強した
      • 用語集作る感じで勉強するのがいいよね、という同僚のアドバイスを早めにもらったのが、本当助かりました
      • 辛みを分かち合いながらやれるのも、救いになりました
    • 有料研修の模試がすごく助かった
      • 初めてやったとき、全然時間が足りなくて正答率が低く、絶望したのが幸いしました。これはまずいぞ、と
    • GPTに課金
      • ごめん、分からん。が多くて、GPTに相当お世話になりました
  • 失敗したなぁ
    • いつも思うんだけど、勉強開始するのが遅いんですよtomoさん
      • 30回は「これ先週時点でやっておけば〜〜〜〜〜〜〜〜」という後悔を叫びながらやってました。学ばない
      • 3日間ぐらいの勉強時間しかなかったので、最後の方、脳内メモリリークしてました。いや、オーバーフローか。メモリ少ないのに勘弁してほしい
    • 買った本が古かった
      • 有料研修が動画メインだったので、移動中に気軽に読めるように本を買って読んでいたのですが、初版が4年前と少し古く、模試をやったら全然本に書いてない内容が出てきて「??!」となりました

G検定受かったらE資格も受かるか

受かりません。E資格に必要なのは、統計学とプログラミングです
全然別物です。もちろん、E試験を受ける前提知識としては必要かなとは思います

作った用語集

こんなのをスプシで作りました。ツールはお好みで
GPTの回答貼り付けてあったり、模試の解答メモしたりしたので、自分しかわからない、ぐちゃぐちゃな感じを分かって貰えれば

用語集。スプシ最高

ChatGPTとのやりとり

こんな感じで、まず聞きたいことを聞いて、そこから深堀りしたり、じゃあこれは?なんて聞いたり

GPTさんとのやり取り例

最後に感想

受けてよかったか?と聞かれると、もちろん良かったです。
仕組みを知っていて使うのとそうでないのだと、見方が変わりました。
それにAIに何ができて何が苦手で、どう使うのがいいのかとか、こうゆう使い方は良くない(倫理的にも含め)をきちんと学ぶというのは、良い機会だったと思います。
ただ、普段使っていない技術に関する勉強はやはり、ハードル高いなぁとしみじみ。

一緒に受けた同僚達と、今度お祝い飲み会をします。
題して「おれたちジェネラリストになったんだ会」。
なんかジェネラリストって響きがいいですよねぇ

自分探しの旅 2nd

はい!ということで、転職することになりました!!(どーん!)

面接が大の大の苦手な私が、まさか2度も転職することになるとは…人生何があるかわかりませんね、本当。



前回転職した理由を振り返ってみよう

↓前回の転職ブログ
tomomo1015.hatenablog.com

「所属会社」という肩書きが無い貴方に、何ができるかを考えてみなさい。

端的に、これを探す旅に出ました。
詳細は↑のブログに書いてあるので割愛しますが、私が自分探しの旅に出ていました。

月に多くて、1回。
これは、前職の私の、TerraTermの起動回数です。
その中でもSQLを打つなんて言うのは、年に数回。
私がSQL打つなんていうのは、チームメンバーの仕事を奪ったに近かった。
検証作業なんてメンバーに任せて、一つでも案件を生み出すプレゼンを、見積もりを。
そんな私が、「エンジニア」なんて肩書を持っていることが嫌いでした。

何もできないじゃない。人に指示するばっかりで。
結局私には何も、なんにもできないじゃない。

何もできない私は、実質それまで築いたPMの経歴をすべて捨てて、DBエンジニアの道を選びました。
どれほどPMとしての成果を評価されても、嬉しくなかった。
「所属会社」という肩書きも、それまでの経歴も無くした私が、何が出来るのか知りたかったからです。



1回目の転職してみて

オンプレしか触ったことがない人が、AWSのイベントに出るまで

オンプレしか触ったことがない私を、上司と同僚達は、驚くほど丁寧にオンボーディングしてくれました。2on1も頻繁に実施してくれ、コロナ禍で直接話すことはなくとも、多くの方と接点を持ってくれました。
入社直後に発生したトラブル対応もさせて頂き、あれほど憧れていたSQL実行を頻繁にできるようになりました。
特にAWSに関しては2度も登壇の機会を頂きました。AWSさん、声かけて頂きありがとうございました!
でも登壇するっていうのは私の希望じゃなくて、某上司がかっ…イヤナンデモナイデス

aws innovate

1つ目のオンプレからAmazon RDS for OracleDBへの移行は、AWS触って初めて実施したプロジェクトでした。本格的に触って、約半年程度でしょうか。
もちろんオンプレ時代の経験も生きたとは思いますが、上司と同僚達オンボーディングと、関係各社の支援無しにこれは、決して成し得られませんでした。
AWS Summitに出ろと言われた時は、信じられなくて3回ぐらいSlackを再起動させました。(事実)

2つ目のElastiCacheを使った事例は、転職後初の、PM兼DBエンジニアの仕事でした。
これも、当時のテックリードの多大な支援を頂いて成し得た成果ですが、このプロジェクトに過去携わってきた全て皆さんの挑戦無しには、この成果は生まれなかったと思います。誰一人、欠けてはできませんでした。今でも胸を張ってそう言えます。


憧れのDBRE

前職SIer時代、当時あわっちさんが書かれたDBREについて書かれたブログを拝見して、衝撃を受けました。

engineering.visional.inc

いつもインフラと開発の板挟み、問題出た時だけしか呼ばれないDBA。
DBREの、特にデータストア教育者でありメンターでありプラットフォーマーであるという点に、非常に魅力を感じました。
当時チーム内でこのブログを展開し、いつかDBREやってみたいね。なんて話をしていたんです。

そんな私が…DBREのSlackを立ち上げ、DBRE Summitというイベントに参加させていただく事ができました。

この写真とてもお気に入り


speakerdeck.com


私が出て大丈夫なのこれ?!と、当日まで半泣きになっていたのですが、無事死亡話はできました。
ちょっと風変わりなコストの話をしてみましたが、いつかは技術メインの話をしてみたいな。

何より、あの私が。
DBエンジニアの前で、DBの話ができた。これが何より、嬉しかったです。
私、DBREみたいなこと、少しはできたかな?



結論

もうsqlplus打つの飽きたわ!と笑って言っていた時、私が涙目になっていたことを、多分同僚達は知らないでしょう。
それほど、嬉しかった。あの頃ずっと憧れていたSQLを打つということ、DBエンジニアとしての仕事ができたんです。
もちろん現実は泥臭すぎて笑っちゃいますが、それを笑えるほど楽しかった。

私の選択は、間違っていなかった。ここに来てよかった。
今もそう思います。

何一つ無駄な時間なんてなかった。
苦労したこと、失敗したこと、つまらなかったことも、何一つ無駄なことなんてなかったんです。





では何故、転職するのか?

それでも私は、マネジメントをする人間なんだなと気付いたから

誤解されないように、少し丁寧に書きます。
DBエンジニアとして転職しましたが、徐々にマネジメントの仕事を求められるようになりました。
前職で散々PMをしていた私からすると、PMまたはPLなんていうのは苦でもなんでもなく、仕事においては息をするようなものです。
誰もやらないなら喜んで、と手を上げました。
当時の上司は、私がPMから転身していたことを知っていたので、渋々、ごめんねという言葉を添えてくれていました。

ところがその上司が変わり、新しい上司が来ました。それは別段よくあることです。
新しい上司も非常にできる方で、私の特性をすぐ見抜きました。そして、DBよりマネジメントを主軸にしてほしいと言われました。

ここまで言うと、DBエンジニアの仕事ができないから辞める、と思われそうですが、違います。
だからこそ、PMとして転職することにしました。

結局のところ、私はPMの仕事も好きだったんです。
自分が調整することで、エンジニアが生き生きと仕事をしているのを見るのが、好きです。
彼らのパフォーマンスを最大に出させ、プロジェクトの目的を達成させることが、好きです。
そして彼らが目標を達成した、と喜んでいる姿を見るのが、大好きなんです。

過去の私には、技術という点での自信がゼロでした。
でも今は違う。小さいながらも、自分が得意な技術で、事例紹介できるような実績に携わることができました。
だからもう、自信のない以前の私じゃない。
揉めたら一番面倒なデータベース、それを鎮める事ができるPMがいてもいい。

DBエンジニア辞めるなんて、言ってないですよ?
だってDBは、どこにでもいるもの。
次に会うDBがどんな子か、楽しみにしてるね。



転職しなくてもできるけど、あえて転職という選択を選んだ理由

とはいえ現職でマネジメント(組織とプロジェクトどちらも)を求められたわけですから、転職しなくてもできます。
そこで、再度自分のキャリアプランを考え直しました。よくある、3年後5年後、自分がどうありたいのか。
もやもやしながら考えていた時、当時同僚だったある方に、こんなニュアンスのことを言われました。

「事業会社のエンジニアって、その事業がよほど好きか興味がないと、続かないよね。他でも大体同じことが出来るしね。」

それが、答えでした。
もちろん興味があって入りました。その点では嘘ではないです。
ただ、自分がこれまで携わった業界の中で、一番興味があるかと言われたら、NOでした。
だから、自分の一番興味のある業界に行く。そこで3年後こんなことをして、5年後にはこんなことしよう。
そんなキャリアプランを書いてみたら、すぐ書けました。くどいですがそれが、答えでした。

あとはこの判断軸です↓

私が転職するかどうか考える判断軸

ありがたいことに、過去携わった業界の中で一番興味があった業界の会社に、拾っていただくことができました。
実は今でも半信半疑で、未だ実感ゼロです。え、私、転職するんだよね?



子育てと年齢という壁

最後に。少し現実的なことを書きます。

子育てが少し山を超えたという点です。
転職時子供が3歳、まだまだ手のかかる年齢でした。今は小学生になり、一人で朝登校できるようになったり、自分でできることが増えてきたことで、子育てが少し落ち着いてきたという点があります。その為、仕事のセーフを少し外すことにしました。
いやまぁ、別の苦労増えましたけど…宿題とか、習い事とか(以下略)

次に、年齢です。
数えるといい年齢になってしまったんですよ、私。つい最近まで新人扱いだったのなぁ(落ち着け)
転職するかもしれない、と考えた時、どうしても年齢という壁を意識する必要がありました。
もう転職できない、とは考えていません。ですが自分が選考者だった時、後何年働いてくれるかなと言うのはどうしても考える訳で、逆の立場でそれを考えると、これがラストチャンスなのかなと考えたのです。


所属会社の肩書のない自分に、何が出来るのか

こうしてPMとして転職することができたのは、新卒入社したSIer時代の経験のおかげです。
あの頃苦労したこと、不安だったこと、辛かったこと。全部全部、今の私に繋がっています。

所属会社の肩書のない自分に、何が出来るのか。
結論、自分では何もできないです。助けてくれる人がいるから、私は何かを成し得ることが出来るだけです。
それが、私の答えです。

その「助けてくれる人」で一番助けてくれる人に、過去の自分がいます。
過去のキャリアは何一つ無駄にならない、未来を作ってくれるものなんだよ。
どうか自信を持って。大丈夫、ちゃんとDBエンジニアできたよ。


自分探しの旅、次の道に行きます

突然なんですけど、私、スレイヤーズってアニメが好きなんですよ。
特にNEXTの主題歌「Give a reason」って曲が大好きで。
あの歌は躓いた時に大抵聞くんですが、こんなフレーズがあります。

ゴールに もたれたりしない
たとえ辿り着いたって
新しい夢がきっと
私の背中押すから

3年前に目指したゴール、 100点ではなかったけど辿り着いたので。
次の新しい夢に背中をバシバシ押してもらいながら…

自分探しの旅に、また行ってきます!!!

Amazon RDS for OracleでインストールされているRDS固有のプロシージャリストを調べる

完全にメモです。
Amazon RDS for Oracleには、標準OracleDBには無いrdsadmin系のプログラムが導入されています。
これ、想定外のタイミングで増えたりするので調べる方法ないかなーと思ったら、なんとこれでわかるそうです。


desc rdsadmin.rdsadmin_util;

これで調べられます。
出力例(内容載せると怒られそうなので、XXXXしています)

SQL> desc rdsadmin.rdsadmin_util;
PROCEDURE ADD_INST_STORE_TEMPFILE
 引数名                         タイプ                  In/Out Default?
 ------------------------------ ----------------------- ------ --------
 XXXXXXXX		VARCHAR2		IN
PROCEDURE XXXXXXXXX

あくまで2023年12月時点の情報なので、今後なくなるかも知れないです。
その場合怒っちゃだめ。マネージドですからね。

どこぞの統計アドバイザ止めたいとか、SYSでやりたいことはRDSの場合はこれらプロシージャを利用して実行するわけですが。
偶にバージョンによって導入されていなかったりしますので、その場合はこちらのコマンドで調べて、サポートの方に相談してみてください。

メモ書きでした!

MySQLの勉強をリファレンスを読みながらやってみることにした話

この記事はMySQL Advent Calendar 2023 12日目の記事です。
昨日は山崎さんの 2023年にMySQL Shellのデータダンプユーティリティにwhereオプションが追加されました+α でしたね。
MySQL Shell 8.0.32からdumpに様々な機能が搭載されたとのことですが、それが山崎さんのリクエストで実現した!というのが胸熱でした…!
機能がない場合は、ナイナイと文句言う前にコミュニティに声を上げることが大切ですね。しみじみ。

さて今日は、技術的な話でなくてポエムです。
タイトルの通り、MySQLの勉強をリファレンスを読みながらやってみた」という話です。

MySQLの勉強をしようと思った背景

そもそも私がMySQLを触ったのは、とあるシステムで相談を受けた際だったと思います。
当時は100% OracleDBでした。そんな人間が、MySQLでの問題を相談を受けてた訳ですが。
MySQL固有の問題ではなくRDBMSの一般的な問題だったのもあって、「なんとなくこうかな?」という回答で解決できました。
ディスクとかCPUとかそうゆう類だと思ってください

そんな感じで「なんとなく対応した」が「MySQLも出来るよねあの人」になっていってしまったのです。

はっきり言いますが、いま現時点でも私のMySQLレベルは非常に低いです。
2-3年MySQLを使って開発されてる若手の方の方が、よっぽど知っていると思います。
ところが俄な知識で ちょっとInnoDB Clusterの案件 とかやってみたせいで、なんかMySQLできます体になってる。
まぁOracleDBも全然わからないんですけどね?

まずい。これはまずいぞ私!!

ということでMySQLの勉強を、いちからちゃんとしようと思ったのが、今年のきっかけです。

何故マニュアルを?

ここで普通、本を買います。ええ、本は持っております。そしてこの本、めちゃくちゃ良いですおすすめです。

ただ、あえてのリファレンスを読むことにしました。その理由が以下です。

  • 網羅性:リファレンスが全てである。網羅性においてはリファレンスこそが最もカバー範囲が広い内容である
  • 正当性:(ドキュメントBugもあるが)基本的に書かれている内容は正しい
  • 汎用性:オンラインでどこでも読める。「これ、あそこに書いてあったよね?」がわかるだけでも、MySQL力は上がる
  • 読解力:マニュアルを読める力も、エンジニアにとっては必要

一つずつ、私の考えを書いていきます。

網羅性

これに関しては説明不要かと。リファレンスは開発者が記載しているドキュメントであり、製品が具備している機能が記載されています。
もちろん本にも様々な機能が書かれていますが、あくまで「よく使われる」機能であって、網羅性はリファレンスの方が当然広いですよね。
今回、MySQLのもつ機能を広く知りたいという想いもあって、この網羅性からリファレンスを読み始めることにしました。

正当性

ドキュメントBugがあるのはわかっていますが、それでもこのドキュメントは開発者が記載しているドキュメントです。
「こうゆう機能を作ったよ!」という情報を学ぶ際、最も正しく学べると考えました。

汎用性

ちょっと別の話になりますが、皆さんOracle Master Plutinumという怖い試験をご存知ですか。
OracleDBの実機試験ですね。指示通りに構築やセットアップを行っていかなければならないのですが、参考できる文献はリファレンスのみです。
あの試験で大事なポイントに「リファレンスのどこに何の機能、コマンド、制限事項が書いてあるか知っておくこと」という点があります。
問題発生時、障害発生時。あれ、ここどうゆう仕様だっけ?を、すぐリファレンスマニュアル見て調べられる。
こうゆうことがしたいんだけど、できないよねー…に対して、そういえばこんな機能あったよね?を思い出して、リファレンスみて調べられる。
それだけで結構、片付く課題が増えると考えています。まぁ今は、AIに探してもらうほうが早そうですけどね。

読解力

リファレンスの日本語難しいんですよ助けて←
ということで、リファレンスの日本語読解力をあげようと思いました。解釈間違えると、誤ったパラメータ値を設定してしまうこととかあるんです。私はあります。ごめんなさい。
解釈が難しくて、時々慣れない英語版見ます…それもまた、勉強…

何故ブログに書いた?

そう考え始めたマニュアル読む会ですが、何かしらアウトプット出さないとだめな人間なので、自分のメモ用にブログに書き始めました。
今日はここ読む、こんな機能あるんだ、これなんだろー?という、完全に独り言ですね。
気軽に書けるように、本当に独り言形式、メモにしました。
内容は誰かに見せる用ではないので、読みやすさゼロです。というか、誰も読まないよねと思って書いてました。

やってみて、どうだった?

まさかの、読んでくださる方がいらっしゃるんですよ!!神ですか!優しさの神様がいるんですか!!
間違っている点を指摘していただいたり(土下座)、ここわからないって呟いたのを教えてくださったり(感謝感激で半泣きになって拝見していました)
個人的に この投稿の イテレータエグゼキューター について、論文や紹介されているブログを教えてくださったりして、非常に学びになりました。

また、実行計画について書かれていたので「Oracleと比較してみようかな?」と思いやってみたところ、はてぶさんの注目ブログに載せて頂いたりしまして(感謝)
tomomo1015.hatenablog.com

当初考えていた学びの3倍以上の学び、経験をさせていただきました。
見ていただいた方々、そしてコメント頂いた皆様に心から感謝を。ありがとうございます!!

これから?

最近私事が理由で書けていないのですが、そろそろ落ち着いてきたので、ゆるっと再開したいなと考えています。
マニュアル読むの、楽しいですよ。アウトプットすると、誰かが見てくれたりするのも、すごく楽しいですよ!

明日は @hmatsu47 さんの「MySQL HeatWave on AWS でインバウンドレプリケーションを試してみた」です。
わーいHeatWave!楽しみ!!

MySQLのリファレンスを読む 1章の続き その⑨

まいえすきゅーえりたい ぽすぐれない おらくるってる(狂ってる)tomoです。

やるぞやるぞ詐欺を経て、ようやく戻ってまいりました!
あぁMySQL、寂しかったよMySQL
ちょっと登壇したり、社内のごにょごにょしたり、Oraくるってました。
speakerdeck.com


もうMySQLばっかりで、ええんやで←

今日もこれの続き。
tomomo1015.hatenablog.com


今日読んだもの
1.3 MySQL 8.0 の新機能
ここの「SQL 標準の明示的なテーブル句およびテーブル値コンストラクタ」から。

  • SQL 標準に従って、テーブル値コンストラクタや明示的なテーブル句が追加されました、と。
    • 例のこれが私的にわかりやすかった。SQL標準だとこんな感じで「TABLE t2」だけでまとめられるのかぁ。便利
    • これは 各ステートメントのリファレンスちゃんと読んだ方が良さそう
    • 論点ずれますが、DBによってSQL方言って結構あるんだなぁとしみじみ
--- 以下2つは同じSQL文
SELECT a FROM t1 WHERE b > ANY (TABLE t2) ;
SELECT a FROM t1 WHERE b > ANY (SELECT * FROM t2) ;
  • インデックスレベルのオプティマイザヒント!ほぼ毎月どこかでやってる「このINDEX使ってねー」というオプティマイズヒント句
    • 注意すべきは「これらのオプティマイザヒントは、将来の MySQL リリースで非推奨になり、その後 MySQL から削除する予定の FORCE INDEX および IGNORE INDEX を置き換えることを目的としています。」とあるので、FORCE INDEXはGROUP_INDEXに、 IGNORE INDEX はNO_GROUP_INDEXに変えていってね、というこでいいかな。
--- (i_a, i_b, i_c) にはインデックスマージが使用されるパターン
SELECT /*+ INDEX_MERGE(t1 i_a, i_b, i_c)*/ * FROM t1
  WHERE b = 1 AND c = 2 AND d = 3;
  • JSON_VALUE() 関数が増えたよ。これはJSON カラムのインデックス付けを簡略化するためのもの…ほうほう?
    • これ、マニュアルに書いてあるSQLをそのまま流してみたんだけど…あれ?8.1だから??
    • このあたり正直不慣れすぎるので、ちょうどいいつまり方したかも。
mysql> SELECT version();
+-----------+
| version() |
+-----------+
| 8.1.0     |
+-----------+
1 row in set (0.00 sec)

mysql>

mysql> CREATE TABLE t1(
    ->     j JSON,
    ->     INDEX i1 ( (JSON_VALUE(j, '$.id' RETURNING UNSIGNED)) )
    -> );
Query OK, 0 rows affected (0.03 sec)

mysql> INSERT INTO t1 VALUES ROW('{"id": "123", "name": "shoes", "price": "49.95"}');
Query OK, 1 row affected (0.01 sec)

mysql> SELECT name, price FROM t1
    ->     WHERE JSON_VALUE(j, '$.id' RETURNING UNSIGNED) = 123;
ERROR 1054 (42S22): Unknown column 'name' in 'field list'

mysql> select * from t1;
+--------------------------------------------------+
| j                                                |
+--------------------------------------------------+
| {"id": "123", "name": "shoes", "price": "49.95"} |
+--------------------------------------------------+
1 row in set (0.00 sec)

mysql>

という、ここで詰まって今日はタイムアウト。明日このエラーの原因調べようと思います…!

MySQLとOracleの実行計画を比較してみた

まいえすきゅーえりたい ぽすぐれない おらくるってる(狂ってる)tomoです。


今日はいつものMySQLリファレンスを読むではなく、夏休みの宿題にしていたこれをやってみます。

MySQLとOracleDBの実行計画を比較してみた

さて同じようなテーブルで同じデータを載せて。
実行計画を取ってみた時、どのくらい情報量が違うのか簡単に違いを見てみましょう。


前提として、以下をご認識ください。

  • 一方はOSSのDBエンジン、もう一方はガチガチ商用DBエンジンです。情報量が違うのは当たり前であって、良し悪しを比較したいのではありません。そして製品比較をしたいのではありません。いつも商用DBメインで使っているエンジニアが、OSSのDBにこうゆう情報も出してほしいな!というのをお願いしたいと思っていて、それを考える元ネタメモだと思ってください。
    • OSSでこれだけの情報出せるMySQLや、今回紹介しませんがPostgreSQL等、OSSのDBは本当すごいです。OSSに関わるすべての皆様に対する賛辞を最初にお伝えしたいです。あのワンコマンドでこれだけの情報出すだなんて、すごすぎるかっこよすぎる!最高ですね!!
  • 性能検証が目的ではありません
    • HWスペックが違いますし、そもそも性能検証結果を出すのはNGです

検証対象DB

MySQLはコミュニティ、バージョンはできたてほやほやの8.1.0です。
8.1おめでとう!待ってたよー!!

mysql> SELECT version();
+-----------+
| version() |
+-----------+
| 8.1.0     |
+-----------+
1 row in set (0.00 sec)

OracleDBのバージョンはエンジンがEnterprise、現時点で long support version の19シリーズの19.9です。
私の相棒ちゃんです←

TOMO@oracle > select banner_full  from v$version;

BANNER_FULL
------------------------------
Oracle Database 19c Enterprise Edition Release 19.0.0.0.0 -ProductionVersion 19.9.0.0.0

経過: 00:00:00.01

DDLと投入データ

作ったTABLEはこんな感じ。意味のないカラムとかありますけど、見なかったことにしてください…

データはこんなの入れました。
MySQLでもOracleDBでも同じSQLで入れられます。
(このデータに「ん?」と思った皆さんは、握手)

--- m_custにデータを入れる
insert into m_cust(cust_id,cust_flag) values('test-01', 1);
insert into m_cust(cust_id,cust_flag) values('test-02', 1);
insert into m_cust(cust_id,cust_flag) values('test-03', 1);
insert into m_cust(cust_id,cust_flag) values('test-04', 0);
insert into m_cust(cust_id,cust_flag) values('test-05', 0);
insert into m_cust(cust_id,cust_flag) values('test-06', 0);

--- m_cust_flagにデータを入れる
insert into m_cust_flag(cust_flag, cust_gender,cust_country) values(1, 0, 'Hyrule');
insert into m_cust_flag(cust_flag, cust_gender,cust_country) values(1, 1, 'Hyrule');
insert into m_cust_flag(cust_flag, cust_gender,cust_country) values(0, 0, 'past-Hyrule');
insert into m_cust_flag(cust_flag, cust_gender,cust_country) values(0, 1, 'past-Hyrule');

--- m_cust_infoにデータを入れる
insert into m_cust_info(cust_id, first_name,last_name, cust_gender) values('test-01', 'Swordsman', 'Rink', 1);
insert into m_cust_info(cust_id, first_name,last_name, cust_gender) values('test-02', 'PhD', 'Purua', 0);
insert into m_cust_info(cust_id, first_name,last_name, cust_gender) values('test-03', 'PhD', 'Robely', 1);
insert into m_cust_info(cust_id, first_name,last_name, cust_gender) values('test-04', 'Zonai', 'Raule', 1);
insert into m_cust_info(cust_id, first_name,last_name, cust_gender) values('test-05', 'Princess', 'Zelda', 0);

SELECT文

検索は以下のSELECT文にしてみました。
もうちょっと凝ったことがしたかったんですが、left joinとcase入れたから多少なにかエンジン側で工夫してくれたらいいな。
これもMySQLとOracleDB、同じSQL文で通ります。

select distinct c.cust_country as country, b.last_name as name,
  case b.cust_gender
    when 0 then 'female'
    when 1 then 'male'
    else 'seacret' end as gender
  from m_cust a
  left join m_cust_info b on a.cust_id = b.cust_id
  left join m_cust_flag c on a.cust_flag = c.cust_flag
  order by country;

MySQLの実行計画

さて、大好きな実行計画タイムです。
まずは普通のEXPLAINをしてみる。

mysql> EXPLAIN select distinct c.cust_country as country, b.last_name as name,
    ->   case b.cust_gender
    ->     when 0 then 'female'
    ->     when 1 then 'male'
    ->     else 'seacret' end as gender
    ->   from m_cust a
    ->   left join m_cust_info b on a.cust_id = b.cust_id
    ->   left join m_cust_flag c on a.cust_flag = c.cust_flag
    ->   order by country;
+----+-------------+-------+------------+------+---------------+---------+---------+----------------+------+----------+--------------------------------------------+
| id | select_type | table | partitions | type | possible_keys | key     | key_len | ref            | rows | filtered | Extra                                      |
+----+-------------+-------+------------+------+---------------+---------+---------+----------------+------+----------+--------------------------------------------+
|  1 | SIMPLE      | a     | NULL       | ALL  | NULL          | NULL    | NULL    | NULL           |    5 |   100.00 | Using temporary; Using filesort            |
|  1 | SIMPLE      | b     | NULL       | ref  | cust_id       | cust_id | 42      | tomo.a.cust_id |    1 |   100.00 | NULL                                       |
|  1 | SIMPLE      | c     | NULL       | ALL  | NULL          | NULL    | NULL    | NULL           |    4 |   100.00 | Using where; Using join buffer (hash join) |
+----+-------------+-------+------------+------+---------------+---------+---------+----------------+------+----------+--------------------------------------------+
3 rows in set, 1 warning (0.00 sec)

mysql>

個人的な意見です

  • 好きなところ
    • 転記すると見辛いですが、すごく見やすい。特にどのTABLEを使っていて、どのKEYを使ったのかというのは本当にわかりやすい
      • 余談ですが、私はMySQLのSELECT等の「アウトプットの見やすさ」が何より好きです
    • 各「select_type」に対して何をしたのかというアクションがわかりやすい
      • 例えばaテーブルに対しては一時テーブル使って、Fileソートしたんだな、とか
      • partitionsじゃないよ、typeは何したよ、Index何使ったよ等などが明瞭ですよね
  • 苦手なところ
    • SQL流れが、一見分かりづらい
      • それぞれに対して何をしたのか分かるけど、どんな流れでSQL文処理したのか?はわからない(ボトルネックになる箇所はわかるので必要ないのかもしれないですが)
      • 後述するANALYZEだと分かるんですが、実はNested loopしてるんですよね。そこの動きが見れなくて「ここのNested loopのところが遅いの直したいな」とか、わからないのでは?


では、ANALYZEしてみよう。

mysql> EXPLAIN ANALYZE select distinct c.cust_country as country, b.last_name as name,
    ->   case b.cust_gender
    ->     when 0 then 'female'
    ->     when 1 then 'male'
    ->     else 'seacret' end as gender
    ->   from m_cust a
    ->   left join m_cust_info b on a.cust_id = b.cust_id
    ->   left join m_cust_flag c on a.cust_flag = c.cust_flag
    ->   order by country;
+------------------+
| EXPLAIN                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           |
+------------------+
| -> Sort: c.cust_country  (actual time=0.12..0.12 rows=5 loops=1)
    -> Table scan on <temporary>  (cost=4.52..7.13 rows=20) (actual time=0.108..0.109 rows=5 loops=1)
        -> Temporary table with deduplication  (cost=4.38..4.38 rows=20) (actual time=0.106..0.106 rows=5 loops=1)
            -> Left hash join (c.cust_flag = a.cust_flag)  (cost=2.38 rows=20) (actual time=0.0575..0.0833 rows=10 loops=1)
                -> Nested loop left join  (cost=2.5 rows=5) (actual time=0.021..0.0437 rows=5 loops=1)
                    -> Table scan on a  (cost=0.75 rows=5) (actual time=0.00607..0.00799 rows=5 loops=1)
                    -> Index lookup on b using cust_id (cust_id=a.cust_id)  (cost=0.27 rows=1) (actual time=0.00568..0.00674 rows=1 loops=5)
                -> Hash
                    -> Table scan on c  (cost=0.13 rows=4) (actual time=0.019..0.0245 rows=4 loops=1)
 |
+------------------+
1 row in set (0.01 sec)

mysql>
  • 好きなところ
    • 「a=cのJOINはhashで、Nested loopして突き合わせさせたんだな」という「DBがどうやってTABLEを検索しに行ったのか」の流れがわかりやすい
      • SQL作成時に脳内で描く「こうやって検索して〜」という流れとDBが実際内部で実施した流れが同じなのか、違うのかがわかる
      • 遅い時って大抵「あれここなんでこの順序でやった?」ということが多い
    • costやactual time、loop等でどの処理で時間かかったのかわかりやすい
      • 既存のEXPLAINでも分かるんですが、「ここのhash join異様に時間かかっているな。ということはこのjoinの箇所が問題だな」という問題箇所の特定がより明確
  • 苦手なところ
    • 既存の「EXPLAIN」と比較すると、情報がごちゃごちゃして読み辛い
      • もちろんちゃんと読めるですが、元々が表形式で見やすかっただけに、余計見辛い感じがする


さて、TREEにした場合どうなるかというと

mysql> EXPLAIN FORMAT=TREE select distinct c.cust_country as country, b.last_name as name,
    ->   case b.cust_gender
    ->     when 0 then 'female'
    ->     when 1 then 'male'
    ->     else 'seacret' end as gender
    ->   from m_cust a
    ->   left join m_cust_info b on a.cust_id = b.cust_id
    ->   left join m_cust_flag c on a.cust_flag = c.cust_flag
    ->   order by country;
+------------------+
| EXPLAIN                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               |
+------------------+
| -> Sort: c.cust_country
    -> Table scan on <temporary>  (cost=4.52..7.13 rows=20)
        -> Temporary table with deduplication  (cost=4.38..4.38 rows=20)
            -> Left hash join (c.cust_flag = a.cust_flag)  (cost=2.38 rows=20)
                -> Nested loop left join  (cost=2.5 rows=5)
                    -> Table scan on a  (cost=0.75 rows=5)
                    -> Index lookup on b using cust_id (cust_id=a.cust_id)  (cost=0.27 rows=1)
                -> Hash
                    -> Table scan on c  (cost=0.13 rows=4)
 |
+------------------+
1 row in set (0.00 sec)

mysql>

ちょっと情報がコンパクトになりましたね?
ざっと動きを見るならTREEの方が見やすそうですが、actual time、loop等が抜けているのでリリース前に実行計画見るのであればTREEでない方がいいかも。


OracleDBの実行計画

さて、同じようなTABLEで同じデータが入ったOracleDBで、実行計画を取ってみます。

TOMO@oracle > select distinct c.cust_country as country, b.last_name as name,
  case b.cust_gender
    when 0 then 'female'
    when 1 then 'male'
    else 'seacret' end as gender
  from m_cust a
  left join m_cust_info b on a.cust_id = b.cust_id
  left join m_cust_flag c on a.cust_flag = c.cust_flag
  order by country;

実行計画
----------------------------------------------------------
Plan hash value: 3044041168

--------------------------------------------------------------------------------------
| Id  | Operation	       | Name	     | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT       |	     |	2040 |	 173K|	  10  (20)| 00:00:01 |
|   1 |  SORT UNIQUE	       |	     |	2040 |	 173K|	   9  (12)| 00:00:01 |
|*  2 |   HASH JOIN RIGHT OUTER|	     |	2040 |	 173K|	   8   (0)| 00:00:01 |
|   3 |    TABLE ACCESS FULL   | M_CUST_FLAG |	 409 | 12270 |	   3   (0)| 00:00:01 |
|*  4 |    HASH JOIN OUTER     |	     |	 409 | 23313 |	   5   (0)| 00:00:01 |
|   5 |     TABLE ACCESS FULL  | M_CUST      |	  82 |	1640 |	   2   (0)| 00:00:01 |
|   6 |     TABLE ACCESS FULL  | M_CUST_INFO |	 409 | 15133 |	   3   (0)| 00:00:01 |
--------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   2 - access("A"."CUST_FLAG"="C"."CUST_FLAG"(+))
   4 - access("A"."CUST_ID"="B"."CUST_ID"(+))


統計
----------------------------------------------------------
	 49  recursive calls
	  0  db block gets
	117  consistent gets
	  1  physical reads
	  0  redo size
	853  bytes sent via SQL*Net to client
	676  bytes received via SQL*Net from client
	  2  SQL*Net roundtrips to/from client
	 11  sorts (memory)
	  0  sorts (disk)
	  5  rows processed

前半の「統計」までを、MySQLには無いなと思うところ見ていきましょう。
くどいですが、これは有償DBです。情報量が多いのは当たり前なので、良し悪しを言いたいのではありません。

MySQLを見た後にみると、「MySQLのEXPLAINとEXPLAIN ANALYZEのいいとこ取り」をしているように思います。

  • 実行計画に対し一意性(hash value値)がある
    • これは私にとって重要です
      • 今朝までXXXXXXXXだったのに、今見たらYYYYYYYYYYになってる!オプティマイザ変えたな実行計画…!とすぐ分かる
      • Oracleでは、SQLに対するIDとこの実行計画のhash valueを紐づけて、DB側で「このSQLはこの実行計画で絶対動いてねー」という設定ができるのですが、その時このhash valueを使います
  • Name欄に「どのTABLEに対して」「どうやって処理をして」「どの順に」が明確である
    • ここはMySQLの既存のEXPLAINの好きなところと、EXPLAIN ANALYZEの好きなところが両方入ってる
  • hash joinの箇所等に「どのTABLEのどのカラムを、どうやって結合したよ」を*をつけて「Predicate Information」で欄外で詳細を記載してくれているので読みやすい
    • 「"A"."CUST_FLAG"="C"."CUST_FLAG"(+)」 は、a.cust_falgに対し、c.cust_flagをjoinしたんだよ、という意味です。ちゃんとleft joinしたのね偉いこ
      • 長文SQLだとこの「Predicate Information」は大量に出るので、注釈してくれていると読みやすいのです
    • 「HASH JOIN RIGHT OUTER」は外部ハッシュ結合したよってことです。おや、DISK読み込みしたのかしら?とここで思ったりします
  • Timeはミリ秒までなのでMySQLの「actual time」よりは精度は低い
    • 個人的な意見ですが、これは軽量で処理することを求められるMySQLならではのいいところだと思います。OracleDBが遅いとは言わないですが、バックグラウンドプロセス等考えると、シンプルかつ高速がMySQLのいいところなので

MySQLに無いのは「統計」の箇所ですね

  • このSQLでどのくらいDISK読み込みしたか(physical reads)、DMLの場合はREDOにどのくらいログだすか(redo size)とか、データどのくらいこねくり回したか(consistent gets)、ソートどのくらいしたか(sorts (memory/disk))等などのインフラリソースへの影響がまとまっている点です
    • オンライン系のSQLであればphysical readsやconsistent gets等、バッチであればredo size等など、それぞれのSQLに応じて気になる点を確認しています

MySQLの実行計画(EXPLAIN ANALYZE)に欲しい情報

ということで単純比較してみました。
個人的な意見としては、

  • 既存「EXPLAIN」は、流れは分かりづらいけれど、読みやすい
  • 「EXPLAIN ANALYZE」は流れは分かるけど、読みづらい

なので、個人的に欲しいなとおもうのは

  • 実行計画に一意性をもたせる値がほしい
    • hash valueでなくてもいいので「あれこれ前回と変わったな」がわかるようにして欲しいような。MySQL開発のみなさんはどうしてるんだろう?
      • Oracle屋さんは、SQLレポートで見てますが、あそこまでやろうとすると機能が複雑になるので不要だと思ってます
  • 「EXPLAIN ANALYZE」はOracleDBみたいに、元の「EXPLAIN」みたいに表形式にできないか
    • 箇条書きみたいしているのが、分かるようで分かりづらい
  • OracleDBにある「統計」みたいなのが出せないか
    • 個人的にphysical readsとconsistent gets、sorts等はほしいなぁ

余談:OracleDBで更に詳細なSQLのコスト情報を出す

ここは余談ですが、こんなことすると「このSQLがCPUどのくらい使ったか」が詳細にとれます。

TOMO@oracle > select name,value from v$mystat my inner join v$statname snon my.STATISTIC# = sn.STATISTIC# where sn.name in ('parse time cpu','parse time elapsed','DB time','CPU used by this session') order by name;

NAME			  VALUE
-------------------- ----------
CPU used by this ses	     52
sion

DB time 		    207
parse time cpu		     20
parse time elapsed	     61

DB Time(DB CPUと待機時間の合計)が取れるのもいいですよね。
DB Timeは「津島博士のパフォーマンス講座  第17回 チューニングについて」に詳しく書かれているのでこちらをぜひ。
また、parseをどのくらいしているのかも分かるので、思ったより多かったりすると「あれおかしいな、なんでこんなにしてるの?」と疑ったりしてます。

MySQLのリファレンスを読む 1章の続き その⑧

まいえすきゅーえりたい ぽすぐれない おらくるってる(狂ってる)tomoです。

まずはこのブログ、拝見頂いてありがとうございます!
レスおっっそいかもですが、頂いたコメントに対してお返事したい所存ですので、是非気軽に「ここまちがってるでー」と指摘いただけると幸いです。

そして前回更新から、少し間があきました><
夏休み第一弾をしてきました!

某避暑地に行ったのですが、全然涼しくなかった…今年の日本の暑さは本当異常ですね。
みなさま、ご自愛くださいませ。

で。でででで。
明後日から一週間、別の所に旅に行ってきますので、またまたしばしお休みになります。
ということで、今日も読んでいこー!!

今日もこれの続き。
tomomo1015.hatenablog.com


今日読んだもの
1.3 MySQL 8.0 の新機能
ここのEXPLAIN ANALYZE ステートメントから。

  • これはEXPLAIN ANALYZE による情報の取得をちゃんと読んだほうがいい
    • オプティマイザの期待が実際の実行とどのように一致したかに関する EXPLAIN 出力を生成します」ってすごくないですか?
    • リファレンスの例をみて「うぉぉおぉおこれすごいいいい!!」と一人大興奮してる人です。知らなかった!こんなに詳細に出してくれるの?!MySQLすごい!これ絶対使おうそうしよう。loopsまで出してくれるなんて、あなたイイコ過ぎませんかMySQLさん…
    • しかも「EXPLAIN FORMAT=TREE 」とか「EXPLAIN FORMAT=JSON」にすると、それぞれの形式で出してくれるんだ…しゅごい。個人的にはTREEが好き
mysql> EXPLAIN ANALYZE SELECT * FROM t1 JOIN t2 ON (t1.c1 = t2.c2)\G
*************************** 1. row ***************************
EXPLAIN: -> Inner hash join (t2.c2 = t1.c1)  (cost=4.70 rows=6)
(actual time=0.032..0.035 rows=6 loops=1)
    -> Table scan on t2  (cost=0.06 rows=6)
(actual time=0.003..0.005 rows=6 loops=1)
    -> Hash
        -> Table scan on t1  (cost=0.85 rows=6)
(actual time=0.018..0.022 rows=6 loops=1)
  • クエリーキャストは、暗黙的型変換のことであっているかな?
    • ↑に書いたEXPLAIN ANALYZE使うと、CASTしているところはcastと出る。わかりやすい。
mysql> EXPLAIN FORMAT=TREE SELECT * from d JOIN n ON d.dt = n.i\G
*************************** 1. row ***************************
EXPLAIN: -> Inner hash join (cast(d.dt as double) = cast(n.i as double))
(cost=0.70 rows=1)
    -> Table scan on n  (cost=0.35 rows=1)
    -> Hash
        -> Table scan on d  (cost=0.35 rows=1)
  • TIMESTAMP および DATETIME のタイムゾーンサポートの箇所は「タイムゾーンオフセットを受け入れます」と書かれていて、ナンノコッチャーと思ったのですが例がちゃんと書いてあって。'2023-08-01 13:00:30+09:00' とかの「+09:00」のことなんですね。
  • JSON_SCHEMA_VALID() について
    • リファレンスの例がまたわかりやすいのだけど、エラーになった時「SHOW WARNINGS」で見れば理由をちゃんと教えてくれる。
    • これ他でもあるよね?多分使えば出てくる所で使っていないかも。これも普段利用するようにしよう
  • ON DUPLICATE KEY UPDATE について
    • duplicateと聞くと、RMAN思い出しちゃいますね
    • エイリアスを使用してINSERTとか参照できるのは長文SQL書くときに便利そう


短いですが、今日はここまで!
明日は「SQL 標準の明示的なテーブル句およびテーブル値コンストラクタ」から読みますよー!