ちょっと硬派なコンピュータフリークのBlogです。

カスタム検索

2016-09-22

MySQL 8.0.0 Development Milestone Release登場!!

先月、詳解MySQL 5.7を発刊したばかりであるが、MySQL 5.7自体は去年の10月にリリースされたバージョンである。それから約1年弱、MySQLは開発の手を緩めること無く日々改良を重ねている。

そう、MySQL 8.0の登場である。

現在はDevelopment Milestone Release(通称DMR)という状態なので、まだ正式版における機能が固まっている段階ではないという点には注意して欲しい。MySQLの開発プロセスでは、DMRをリリースするごとにその段階で成熟した機能をマージする。DMRを何度かリリースした後に、キリの良いところでリリース候補版となって正式版で追加される機能が一応確定し、その後バグ修正を経て正式版(GA版)がリリースされる予定となっている。詳しくはMySQLのマニュアルを参照して欲しい。

バージョン8.0!!

5.7の次は誰もが5.8だと思っていただろう・・・。だが、MySQLのバージョン番号は一気に8へと飛躍する!!それは、既存のMySQLから比べ、大きなアーキテクチャ変更があったからだ。それは以下で述べるデータディクショナリである。

なぜ6.0でなく8.0なのか。それはMySQLの歴史を知っている人ならよくご存知であろう。そう、MySQL 6.0というバージョンはかつて存在し、諸般の事情によりお蔵入りになってしまったのだ。いわゆる黒歴史というヤツである。ではなぜ7.0ではないのかというと、それはMySQL Clusterとかぶってしまうからという理由がある。MySQL Clusterの最新版は、7.4シリーズである。そこで、5.8の代わりにキリ良く5を取って8がメジャーバージョンになったわけである。かつてSolarisが2.6の次が7になったように、Java 1.4の次が5になったように、MySQL 5.7の次が8になるだけである。

とはいえ、バージョン番号自体はただのラベルであり、記号の列であって技術的に何ら意味はない。ガンダム風に言えば、バージョンなんてただの飾りです。偉い人にはそれがわからんのです!!というところだろうか。フルスクラッチで書き直したわけでもないので、MySQL 8.0になって全く別のものに生まれ変わったということはない。やはり、MySQLは相変わらずMySQLなのである。

データディクショナリ

Good bye .FRM!!

データディクショナリを一言で表せば、この点に尽きる。MySQLといえば、テーブルのメタデータは.FRMという拡張子を持ったファイルに、テーブルごとに格納されるのが常であった。しかし、ファイルにメタデータを格納するというアーキテクチャは様々な問題を孕んでいる。最大の問題は、データベースとファイルの同期を取ることが難しいという点である。ファイルへの更新はトランザクションによって守られていないため、不意の電源OFFなどに対して脆弱である。この点は、MySQLを運用する上で弁慶の泣き所であった。データベースサーバーをより安全に、安定して、手をかけずに運用するには、単なるファイルよりももっと安全な、つまりトランザクションによって守られた領域へメタデータを格納することが望ましい。

ではMySQL 8.0はDDLがトランザクショナルになったのか?というと、それはまだ時期尚早である。最終的にはトランザクショナルなDDLを目指すという方向に違いはないが、現時点ではまだそこまで実装が進んでおらず、メタデータをInnoDBに格納できるようになったという状態である。とはいえ、.FRMだけでなく、.par、.TRG、.TRNといったファイルも作成しなくなった。また、データディクショナリへアクセスするための内部APIが定義され、データディクショナリを前提とした実装へと構造の刷新が行われている。今後のDMRあるいはさらに次のバージョンで、データディクショナリの利点をより大きく享受できるよう、改良が続けられていくことだろう。データディクショナリへの変更の目的などについてより詳しく知りたい方は、以下のページなどを参照して欲しい。

A New Data Dictionary for MySQL | MySQL Server Blog

メタデータがInnoDBに格納されるということは、情報スキーマの性能が向上するという嬉しい副作用をもたらしてくれる。ファイルにメタデータが格納されている実装では、情報スキーマの出力を生成するには、メタデータがキャッシュ上に存在しない場合ファイルをいちいちスキャンしなければならず、極めて非効率であった。そのため、情報スキーマへアクセスするクエリは、特別な最適化を施すようになっていた。MySQL 8.0ではその点が改良され、通常のテーブルと同じようにクエリが実行可能となっている。場合によっては(テーブル数が多い場合などには)100倍以上の性能差が出るケースがあるようだ。なお、情報スキーマは厳密にいうと、データディクショナリを用いたビューとして定義されている。データディクショナリにはユーザーが直接アクセスすることはできず、DDLや情報スキーマを介してアクセスする必要がある。

データディクショナリの詳細については、マニュアルも参照して欲しい。

MySQL :: MySQL 8.0 Reference Manual :: 15 MySQL Data Dictionary

システムテーブルのInnoDB化

Good bye MyISAM!!

MySQLは従来より、ユーザーアカウントなどの情報をMyISAMテーブルに格納する仕組みになっていた。MyISAMテーブルはトランザクショナルではないため、電源断などによりデータ破壊が引き起こされる危険性と、常に隣り合わせであった。そのため、システムテーブルのInnoDB化は、MySQLにとって悲願となる実装の変更であると言える。

システムテーブルとデータディクショナリの違いは、ユーザーからアクセスが可能かどうかという点である。データディクショナリにはテーブルやストアドプロシージャなどのメタデータが、システムテーブルにはユーザーアカウントやタイムゾーン、ヘルプなどの情報が格納されている。システムテーブルはSHOW TABLESや情報スキーマによって見ることができるが、データディクショナリはそれらの出力には現れないという違いがある。

この変更により、GRANTなどがより堅牢になった。MyISAMファンにとっては嬉しくないかも知れないが、データベースサーバーを長期間安定して運用する能力が、一歩向上したことになる。MyISAMよさらば!!

ロール

ロール・ミー!!

ロール・ユー!!

バッ!バッ!
(出典:えの素

というわけで、MySQLにもROLEがやってきた。MySQL 5.7でもプロキシーユーザーを使えば擬似ROLEのようなことができたが、ひとつのユーザーに複数のプロキシーユーザーを割り当てることができず、運用上の限界があったことは否めない。

MySQL 8.0で追加されたROLEにはそのような制限はない。ROLEを作成し、ROLEに権限を付与し、ROLEごとユーザーに付与することができる。

mysql> create database me;
Query OK, 1 row affected (0.01 sec)

mysql> create database you;
Query OK, 1 row affected (0.01 sec)

mysql> create role 'roll-me';
Query OK, 0 rows affected (0.00 sec)

mysql> create role 'roll-you';
Query OK, 0 rows affected (0.02 sec)

mysql> grant all on me.* to 'roll-me';
Query OK, 0 rows affected (0.00 sec)

mysql> grant all on you.* to 'roll-you';
Query OK, 0 rows affected (0.01 sec)

mysql> create user roller@localhost identified by 'ropper';
Query OK, 0 rows affected (0.02 sec)

mysql> grant 'roll-me', 'roll-you' to roller@localhost;
Query OK, 0 rows affected (0.01 sec)

ROLEを有効化するには、SET ROLEコマンドを使う。以下の例では、'roll-me'というROLEはyouというデータベースに対するアクセス権が無いのでエラーになっている。SET ROLE 'roll-you'をすればyouにアクセス可能となる。'

mysql> set role 'roll-me';
Query OK, 0 rows affected (0.00 sec)

mysql> SELECT current_role();
+----------------+
| current_role() |
+----------------+
| `roll-me`@`%`  |
+----------------+
1 row in set (0.00 sec)

mysql> use me
Database changed
mysql> use you
ERROR 1044 (42000): Access denied for user 'roller'@'localhost' to database 'you'

ROLEに別のROLEをsub-ROLEとして付与することも可能だ。

mysql> create role 'rolling-all';
Query OK, 0 rows affected (0.01 sec)

mysql> grant 'roll-me', 'roll-you' to 'rolling-all';
Query OK, 0 rows affected (0.01 sec)

mysql> create user rolling@localhost identified by 'bopper';
Query OK, 0 rows affected (0.01 sec)

mysql> grant 'rolling-all' to rolling@localhost;
Query OK, 0 rows affected (0.02 sec)

SET ROLE 'rolling-all'をすると、meとyouの両方のデータベースに対する権限が付与される。

ROLEの詳細については、マニュアルを参照して欲しい。

MySQL :: MySQL 8.0 Reference Manual :: 7.3.4 Using Roles

また、yokuさんの投稿もぜひ読んでいただきたい。

日々の覚書: MySQL 8.0.0で追加されたROLEの仕組み

AUTO_INCREMENTの問題を解消

InnoDBがまたひとつ便利になった。

MySQL 5.7までのInnoDBの実装では、AUTO_INCREMENTの値は、MySQLサーバーを再起動すると、そのテーブルに格納されているAUTO_INCREMENTカラムの最大値へとリセットされてしまう。これは何が困るのかというと、AUTO_INCREMENTカラムの値を更新する変更を行ったのにロールバックしてしまったトランザクションがあると、再起動を経て同じAUTO_INCREMENT値が割り当てられてしまう可能性があるのだ。

MySQL 8.0ではこの問題が解消された。一度割り当てたAUTO_INCREMENTの値は、REDOログに書き込まれる。そのため、少なくともクリーンシャットダウンによる再起動であれば、例えロールバックしたトランザクションがあったとしても、AUTO_INCREMENTの値が重複して割り当てられることはない。

InnoDBの性能向上

MySQL 8.0でもInnoDBの性能が引き続き強化されている。

Mutexを分割することでCPUスケーラビリティを向上させたり、複数のパージスレッドが同じテーブルに対するパージを行わないようにしてロックの競合を防ぐといった改良が加えられている。

また、BLOB(TEXT、JSON含む)に対して、部分的に読み書きをする機能の追加といった改良も加えられている。これにより、無駄なデータアクセスが減り、全体的なスループットの改善が期待される。特にJSONは使う機会が多いと思うので、この改良による影響は大きいはずだ。

非常にベーシックな部分としては、範囲検索をする際のバッファサイズを調整することで、範囲検索の性能が5〜20%ほどの改善を見せている。範囲検索は極めて高い頻度で実行される処理なので、この改良による影響は小さくないものとなるだろう。

インビジブル・インデックス

存在しているけどオプティマイザからは認識されない。そんなインデックスが追加された。

オプティマイザからインデックスを見えないようにすることで、そのインデックスを削除したときのインパクトをシミュレートすることが可能となる。それにより、「要らないように見えるけど、実際どうなんだろう・・・。削除してもいいのかどうか・・・」という迷いを、ズバッ!!と断ち切ることができるようになるのである。インデックスは見えないだけでそこに存在するので、悪影響があると分かったら、また元に戻せばいいだけなのだ。

インデックスはSELECTを高速化してくれる一方、インデックスは更新のオーバヘッドとデータ領域が犠牲になる。なので無駄なインデックスは極力存在させたくない。しかしインデックスの追加と削除はコストの高い処理である。というわけで、お試しでインデックスを無効化するという機能が役に立つわけだ。

インデックスをインビジブル(不可視)にするには、次のようにクエリを実行すれば良い。

mysql>  ALTER TABLE table_name ALTER INDEX index_name INVISIBLE;

可視にするには、INVISIBLEの代わりにVISIBLEを指定しよう。

MySQL :: MySQL 8.0 Reference Manual :: 9.3.10 Invisible Indexes

パフォーマンス・スキーマの改良

パフォーマンス・スキーマがますます便利に進化を遂げた。

一つ目の改良は、パフォーマンス・スキーマの各テーブルにインデックスが追加されたというものである。インデックスと言ってもHASHインデックスのようなもので、範囲検索には使えない。だがインデックスが追加されたことで、パフォーマンス・スキーマを用いたJOIN系のクエリが速くなるだろう。それにより、sysスキーマによる、パフォーマンス・スキーマへのアクセスが高速化されるだろう。

もうひとつの改良点は、エラーに関する集計が行われるようになったということだ。クライアントへどれだけエラーが返っているかということを知るのに大変便利である。

MySQL :: MySQL 8.0 Reference Manual :: 23.9.15.11 Performance Schema Error Summary Tables

情報スキーマの改良

情報スキーマが根本的に刷新された。

すでにデータディクショナリのところで述べたように、情報スキーマはデータディクショナリに対するビューになっている。これにより、情報スキーマに対するアクセスが、格段に効率化した。

以下はTABLES情報スキーマの例である。

mysql> show create table tables\G
*************************** 1. row ***************************
                View: TABLES
         Create View: CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `TABLES` AS select `cat`.`name` AS `TABLE_CATALOG`,`sch`.`name` AS `TABLE_SCHEMA`,`tbl`.`name` AS `TABLE_NAME`,`tbl`.`type` AS `TABLE_TYPE`,if((`tbl`.`type` = 'BASE TABLE'),`tbl`.`engine`,NULL) AS `ENGINE`,if((`tbl`.`type` = 'VIEW'),NULL,10) AS `VERSION`,`tbl`.`row_format` AS `ROW_FORMAT`,`stat`.`table_rows` AS `TABLE_ROWS`,`stat`.`avg_row_length` AS `AVG_ROW_LENGTH`,`stat`.`data_length` AS `DATA_LENGTH`,`stat`.`max_data_length` AS `MAX_DATA_LENGTH`,`stat`.`index_length` AS `INDEX_LENGTH`,`stat`.`data_free` AS `DATA_FREE`,`stat`.`auto_increment` AS `AUTO_INCREMENT`,`tbl`.`created` AS `CREATE_TIME`,`stat`.`update_time` AS `UPDATE_TIME`,`stat`.`check_time` AS `CHECK_TIME`,`col`.`name` AS `TABLE_COLLATION`,`stat`.`checksum` AS `CHECKSUM`,if((`tbl`.`type` = 'VIEW'),NULL,get_dd_create_options(`tbl`.`options`,if((ifnull(`tbl`.`partition_expression`,'NOT_PART_TBL') = 'NOT_PART_TBL'),0,1))) AS `CREATE_OPTIONS`,internal_get_comment_or_error(`sch`.`name`,`tbl`.`name`,`tbl`.`type`,`tbl`.`options`,`tbl`.`comment`) AS `TABLE_COMMENT` from ((((`mysql`.`tables` `tbl` join `mysql`.`schemata` `sch` on((`tbl`.`schema_id` = `sch`.`id`))) join `mysql`.`catalogs` `cat` on((`cat`.`id` = `sch`.`catalog_id`))) left join `mysql`.`collations` `col` on((`tbl`.`collation_id` = `col`.`id`))) left join `mysql`.`table_stats` `stat` on(((`tbl`.`name` = `stat`.`table_name`) and (`sch`.`name` = `stat`.`schema_name`)))) where (can_access_table(`sch`.`name`,`tbl`.`name`) and (not(`tbl`.`hidden`)))
character_set_client: latin1
collation_connection: latin1_swedish_ci
1 row in set (0.00 sec)

情報スキーマのベーステーブルであるデータディクショナリは、内部的にはInnoDBなので、MVCCによるノンロッキングリードが可能である。つまり、他のDDLなどによって、情報スキーマへのアクセスがブロックされないという特性が得られるのだ!

SET PERSIST:設定の永続化

コマンドで設定を永続化できるようになった。

MySQLサーバーは動的に設定の変更をすることが可能であり、SET GLOBALによってそれを行うのが常であった。しかし、SET GLOBALは動作中のインスタンスへの変更を行うものの、再起動によって設定が失われてしまう。再起動後も設定を残しておくには、my.cnfを書き換える必要があった。これは少し面倒である。

そこで、MySQL 8.0では、SET PERSISTというコマンドによって、設定を永続化できるようになった。SET PERSISTを実行すると、mysqld-auto.cnfというデータディレクトリにあるファイルに、設定が書き込まれるようになっている。再起動時にはこのファイルが読み込まれるわけだ。

このように設定ファイルが分散してしまうと、それぞれの値がどこから反映されたものかを把握するのが難しくなってしまう。そこで、MySQL 8.0では、パフォーマンス・スキーマにvariables_infoというテーブルが追加され、それぞれの設定がどこから来たものかを知ることが可能となった。

パーサーとオプティマイザの改良

MySQL 8.0では、データベースサーバーの心臓部とも言える、パーサーとオプティマイザについても改良が加えられている。

パーサーはリファクタリングが進められ、SELECTの定義が文脈ごとに無駄に重複していた7箇所が一本化されるなどの改良が入っている。リファクタリングの結果、単一の式だけを構文解析するといった機能も追加された。これは、パーティションキーを管理する際などに便利である。

オプティマイザも様々な改良が加えられている。コストモデルが改良され、インデックスやデータのキャッシュされている割合が、実行計画に影響を及ぼすようになったり、オプティマイザヒントによってFROM句のサブクエリが実体化するかどうかを調整できるようになったりしている。また、まだオプティマイザによって使用するまでには至ってはいないが、ヒストグラムの実装が進められている。ヒストグラムがあれば、データの分布が実行計画に影響を与えるようになり、より効率的な実行計画が選択される可能性が高くなる。

ラボ版にてCTE到来

MySQLにもCTEが到来か?

まだラボ版(=プレビュー版)というステータスではあるものの、CTE(Common Table Expression)を追加したバージョンが配布されている。CTEは平たく言えばWITH句によってテーブルを定義する構文である。詳細については、以下のブログ記事を見て欲しい。

MySQL 8.0 Labs: [Recursive] Common Table Expressions in MySQL (CTEs) | MySQL Server Blog

ラボ版は以下のページよりダウンロード可能となっている。もちろんライセンスはGPLv2だ。

MySQL :: MySQL Labs

まとめ

MySQL 5.7では、数多くの新機能が追加された。いわば機能の充実を目指したバージョンであると言える。

一方、MySQL 8.0は、その新機能を紐解くと、大胆なリファクタリングが行われた形跡が伺えるだろう。将来も継続して機能を進化させるには、古くなって都合が悪い構造を刷新するリファクタリングが欠かせない。従来の機能を保ったままリファクタリングすることが、非常に難しい作業であることは言うまでもない。だが、それは必要な作業であり、その労力を掛ける価値があるものなのだ。

現在はDMRというステータスなので、正式版のリリースまで、まだまだ期間が空くことだろう。だが、いち早く次のバージョンのMySQLの機能をキャッチアップしたいという人は、ぜひダウンロードして評価して欲しいと思う。MySQL 8.0のダウンロードは、以下のページより、「Development Release」のタブをクリックすることで可能となっている。

MySQL :: Download MySQL Community Server

また、MySQL 8.0の新機能についてさらに詳しく知りたい人は、以下のページを参照して欲しい。

The MySQL 8.0.0 Milestone Release is available | MySQL Server Blog

MySQL :: MySQL 8.0 Reference Manual :: 1.4 What Is New in MySQL 8.0

MySQL :: MySQL 8.0 Release Notes :: Changes in MySQL 8.0.0 (2016-09-12, Development Milestone Release)

これからのMySQLの進化にも、乞うご期待!!である。

0 コメント:

コメントを投稿