What’s New in MySQL 8.0? (Generally Available)
を日本語訳しました。yakstに載せる勇気がないチキンだったので、場末のブログでひっそりと。(自分用ともいう)
正直なところ、英語もさることながら技術的に追いついていないところが多々あるので、解釈が誤っているところがあるかもしれません。極力間違いが無いように心がけてはいますが、万一誤りがあっても責任は負えませんのでご了承ください。誤りを指摘して頂ければ喜んで修正します。
訳してみて、1つ言えることがあります。
「MySQL 8.0は本当に多くの機能追加とパフォーマンス改善があった。訳してみればわかる。」
それではさっそく。
MySQL 8.0(GA)の新しい点
2018/4/19, Geir Hoydalsvik
MySQL 8.0のGAをお知らせできることをうれしく思います。是非ダウンロードしてください!MySQL 8.0は、世界で最もポピュラーなオープンソースデータベースを全面的に改善した、とてもエキサイティングなバージョンです。
重要な改善点:
- SQL
Window関数、Common Table Expressions(CTE, 共通テーブル式)、NOWAIT/SKIP LOCKED句、Descending Indexes(降順インデックス)、GROUPING、正規表現、キャラクタセット、コストモデル、ヒストグラム。 - JSON
拡張した構文、新しい関数、ソートの向上、部分アップデート。JSONテーブル関数を使用することで、JSONデータに対してSQLを使用することができます。 - GIS
Geographyのサポート。Spatial Reference Systems(SRS)、SRS対応のspatialデータタイプ、spatialインデックス、spatial関数。 - 信頼性
InnoDBにより、DDLがアトミックでクラッシュセーフになり、メタデータは単一のトランザクショナルなデータディクショナリに格納されます。 - 観察性
Performance Schema、Information Schema、システム変数、エラーロギングへの重要な改善。 - 管理性
リモート管理、UNDO表領域管理、新しいインスタントDDL。 - セキュリティ
OpenSSLの改善、新しいデフォルト認証方式、ロール、SUPER権限の分割、パスワード強度、など。 - パフォーマンス
InnoDBは、読み書きのワークロード、IOバウンドなワークロード、集中度の高い「ホットスポット」ワークロードで改善されています。追加されたリソースグループ機能は、特定のワークロードやハードウェアに対する最適化のオプションを提供します。
これらはハイライトの一部であり、一連のマイルストーンとなるブログ ― 8.0.0, 8.0.1, 8.0.2, 8.0.3, 8.0.4 ― をドリルダウンすることをお勧めします。さらには、個々のワークログで特徴や向上の詳細をドリルダウンすることもお勧めします。または、単にgithub.com/mysqlでソースコードを見る方が良いかもしれません。
開発者向け機能
MySQL開発者の新しい機能要望を受け、MySQL 8.0は新しい多くの機能を、SQL、JSON、正規表現、GISなどの分野で提供します。また、絵文字を格納できるようにして欲しいという要望を受け、MySQL 8.0ではUTF8MB4が新しいデフォルトキャラクタセットとなりました。最後に、データ型について、BINARYデータ型へのビット演算、IPv6、UUID関数に改善があります。
SQL
Window関数
Window関数が導入されました。グループ化された集計関数と同じく、Window関数はCOUNTやSUMのように、行のセットに対して計算を実行します。しかし、集計関数は行のセットを1行にすることに対し、Window関数は結果セットの中の各行に対して集計を行います。Window関数には2つの種類があります。Window関数として使用される集計関数と、専用のWindow関数です。
以下がMySQLでWindowningをサポートする集計関数です。
COUNT, SUM, AVG, MIN, MAX, BIT_OR, BIT_AND, BIT_XOR, STDDEV_POP (と、そのシノニムSTD, STDDEV), STDDEV_SAMP, VAR_POP (と、そのシノニムVARIANCE), VAR_SAMP
専用のWindow関数は以下です。
RANK, DENSE_RANK, PERCENT_RANK, CUME_DIST, NTILE, ROW_NUMBER, FIRST_VALUE, LAST_VALUE, NTH_VALUE, LEAD, LAG
Window関数(別名、分析関数)のサポートはユーザーの要望が多かった機能です。Window関数は長らくSQL標準(SQL2003)の一部でした。こちらのDag Wanvikのブログ記事や、こちらのGuilhem Bichotのブログ記事をご覧ください。
共通テーブル式(CTE)
再帰的CTEが導入されました。非CTEは、改善された導出表(DERIVED TABLE)である、と説明できます。なぜなら、非CTEは導出表に複数回参照されることを許すからです。再帰的CTEは反復的に作られた行セットです。最初の行セットから、新しい行を導出するプロセスによりで行が拡大し、その行がまたこのプロセスの元となって更なる行を生成され続け、このプロセスが新たな行を作成しなくなるまで実行される、といった具合です。CTEはよく要望される機能で、例えば機能リクエスト16244, 32174をご覧ください。こちら、こちら、こちら、こちらにある、Guilhem Bichotのブログ記事もご覧ください。
NOWAITとSKIP LOCKED
SQLのロック節(clause)で、NOWAITとSKIP LOCKEDの選択肢が導入されました。通常、UPDATEやSELECT…FOR UPDATEなどにより行がロックされていた場合、他のトランザクションはその行にアクセスするまで待つことになります。あるユースケースでは、行がロックされていた時に即座に戻ってきてほしい、あるいはロックされた行を無視してほしい、というニーズがあります。NOWAITを使用したLOCK節では、行ロック獲得のための待機を一切行いません。代わりに、クエリはエラーとなります。SKIP LOCKEDを使用したロック節では、リストされたテーブルへのロック獲得のための待機を一切行いません。代わりに、ロックされた行はスキップされ、全く読まれません。NOWAITとSKIP LOCKEDは要望の多かった機能です。例えば機能リクエスト49763をご覧ください。Kyle Oppenheimさん、コードの貢献ありがとうございます!こちらのMartin Hanssonのブログ記事もご覧ください。
Descending Index(降順インデックス)
降順のインデックスがサポートされます。このインデックスの値は降順になり、前に向かってスキャンされます。8.0以前では、ユーザーが降順インデックスを作成した時には昇順インデックスを作成し、後ろ向きにスキャンしていました。メリットの1つは、前向きのインデックススキャンは後ろ向きのインデックススキャンよりも早い点です。もう1つのメリットは、「本当の」降順インデックスにより、ASC/DESCが混在したORDER BY節に対するファイルソートの代わりにインデックスを使用できるようになる点です。Descending Indexは要望の多かった機能です。例えば、機能リクエスト13375をご覧ください。こちらのChaithra Gopalareddyのブログ記事もご覧ください。
GROUPING
GROUPING関数(SQL FEATURE:T433)が導入されました。GROUPING()関数は超集約行を通常のグループ化された行と区別します。GROUP BYの拡張(ROLLUPプロシージャのような)は、全ての値がNULLで表現される超集約行を生成します。GROUPING関数を使用することで、全ての値がNULLである超集約行と、通常の行のNULLとを区別することができます。GROUPINGは要望の多かった機能です。機能リクエスト3156、46053をご覧ください。Zoe Dongさん、Shane Adamsさん、機能リクエスト46053でのコードの貢献ありがとうございます!こちらのChaithra Gopalareddyのブログ記事もご覧ください。
オプティマイザヒント
MySQL 5.7で、私たちはオプティマイザヒントのための新しいHINT構文を紹介しました。この新しい構文により、ヒントはSELECT、INSERT、REPLACE、UPDATE、DELETEキーワードの後に、/*+ +/形式のコメントで囲むことで、直接記述できるようになりました。(こちらのSergey Glukhovの5.7ブログ記事をご覧ください。)MySQL 8.0では、以下の新しい形式によりその全体像を完成させました。
- INDEX_MERGE、NO_INDEX_MERGEのヒントを追加しました。これはoptimizer switchを変更することなく、個々のクエリのインデックスマージの制御を可能にします。
- JOIN_FIXED_ORDER、JOIN_ORDER、JOIN_PREFIX、JOIN_SUFFIXのヒントを追加しました。これはJOIN実行のテーブルの順番をコントロール可能にします。
- SET_VARというヒントを追加しました。SET_VARヒントは、次のステートメントに限り、与えられたシステム変数をセットします。このため、ステートメントが完了すると、値はもとの値にリセットされます。こちらのSergey Glukhovのブログ記事をご覧ください。
私たちは、かつてのHINT形式とoptimizer_switchのセットと同じように、新しいオプティマイザヒントの形式が気に入っています。
SQLが混じらない形になったことで、新しいヒントはクエリの様々な場所に挿入できるようになりました。
ヒントになることにより、クエリはより意味が分かりやすくなりました(ディレクティブであることと比べて)。
JSON
新しいJSON関数を加え、JSONの値のソートやグルーピングのパフォーマンスを向上しました。
JSONパス表現の範囲の拡張文法
JSONパス表現での範囲に関する文法を拡張しました。例えば、SELECT JSON_EXTRACT(‘[1, 2, 3, 4, 5]’, ‘$[1 to 3]’);は、[2, 3, 4]となります。この新しい構文は、SQL標準2016の9.39、SQL/JSONパス言語:文法とセマンティクスで規定された、SQL標準文法のサブセットです。Roland Boumanに報告された、Bug #79052もご覧ください。
JSONテーブル関数
JSONデータにSQLが使用できるよう、JSONテーブル関数が導入されました。JSON_TABLE()関数はJSONデータのリレーショナルなビューを生成します。これは、JSONデータを評価した結果をリレーショナルな行・列にマッピングします。この関数によって返された結果に対して、あたかも通常のリレーショナルなテーブルのように、JOIN、PROJECT、AGGREGATEのようなクエリを実行することができます。
JSON集計関数
JSON配列を生成するJSON_ARRAYAGG()関数と、JSONオブジェクトを生成するJSON_OBJECTAGG()関数が導入されました。これにより、複数行にまたがったJSONドキュメントを、1つのJSON配列やJSONオブジェクトに統合することができるようになりました。こちらのCatalin Besleagaのブログ記事をご覧ください。
JSONマージ関数
JSON_MERGE_PATCH()関数により、RFC7396で規定されたJavaスクリプト(と、他のスクリプト言語)のセマンティクスが実装されました。すなわち、2つ目のドキュメントを優先することで、重複を排除します。例えば、JSON_MERGE(‘{“a”:1,”b”:2 }’,'{“a”:3,”c”:4 }’);は{“a”:3,”b”:2,”c”:4}を返します。
JSON_MERGE_PRESERVE()関数は、MySQL 5.7で実装されていた、すべての値を保持するJSON_MERGE()関数と同じセマンティクスを持ちます。例えば、
JSON_MERGE(‘{“a”: 1,”b”:2}’,'{“a”:3,”c”:4}’);は{“a”:[1,3],”b”:2,”c”:4}を返します。
既存のJSON_MERGE()関数は、マージ操作のあいまいさを排除するため、MySQL 8.0では非推奨となりました。Bug #81283での提案と、こちらのMorgan Tockerのブログ記事をご覧ください。
JSON pretty関数
JSON_PRETTY()関数が追加されました。この関数は、JSONネイティブなデータ型、あるいはJSONの文字表現を受けて、JSONフォーマット済みの文字列を人間が読める形に改行・インデントして返します。
JSONサイズ関数
渡されたJSONオブジェクトのスペース利用状況に関する関数が追加されました。JSON_STORAGE_SIZE()関数は、JSONデータタイプの実際のサイズをバイトで返します。JSON_STORAGE_FREE()関数は、JSONバイナリタイプのフリースペースをバイトで返します(フラグメンテーションや、インプレースアップグレードのために持たれているパディングも含みます)。
JSONのソート性能向上
可変長のソートキーを使うことで、JSON値のソート、グルーピングにおいてパフォーマンスが改善しました。予備的なベンチマークでは、ソートにおいて、ユースケースに依存して1.2から18倍の向上が見られました。
JSON部分アップデート
JSON_REMOVE()関数、JSON_SET()関数、JSON_REPLACE()関数での部分アップデートを追加しました。JSONドキュメントの一部のみがアップデートされた時、ストレージエンジンとレプリケーションが全ドキュメントを書かずとも済むようにするためには、ハンドラに何が変更されたのか、という情報を渡す必要があります。レプリケーション環境では、マスターとスレーブでJSONドキュメントのレイアウトが完全に同じであることが保証されないため、
行ベースレプリケーションにおいて、物理的な差異はネットワークI/Oの縮小に使用できません。そこで、MySQL 8.0では、行ベースレプリケーションでもスレーブで再適用できるように、論理的な差異を渡します。こちらのKnut Anders Hatlenのブログ記事をご覧ください。
GIS
geography機能がサポートされます。これは、SRS(Spatial Reference System)対応のデータ型、インデックス、関数だけではなく、SRSのメタデータサポートも含みます。端的に言えば、MySQL 8.0は地球表面上の緯度と経度を理解し、約5000のサポートされるSRSで、地球の表面上にある任意の2点間の距離を正確に計算することができます。
Spatial Reference System(SRS:空間参照系)
information schema中のST_SPATIAL_REFERENCE_SYSTEMSビューは、利用可能な空間データのSRSについての情報を提供します。このビューはSQL/MM(ISO/IEC 13249-3)標準に基づいています。各SRSはSRID番号によって識別されます。MySQL 8.0ではEPSG Geodetic Parameter Datasetから約5000のSRIDを搭載し、位置のリファレンス付けがなされた楕円対2Dのプロジェクション(フル2DのSRSのような)をカバーしています。
SRID対応の空間データ型
空間データ型はSRSの定義に依存すると考えることができます。例えば、SRID4326番ならこうです。CREATE TABLE t1 (g GEOMETRY SRID 4326);ここでのSRIDはGEOMETRYデータ型に対するSQL型修飾子であり、SRIDプロパティを持った列に挿入される値はこのSRIDを持たなければならず、異なるSRIDを持った値を挿入しようとすると例外が発生します。SRIDの指定のない型のように、修飾がない型では、以前同様、すべてのSRIDを許容します。
MySQL 8.0では、SQL/MM Part3, Sect.19.2で規定されている、INFORMATION_SCHEMA.ST_GEOMETRY_COLUMNSビューが追加されました。このビューは、MySQLインスタンスに含まれる全てのGEOMETRYカラムをリストし、各カラムに対して、標準のSRS_NAME、SRS_ID、GEOMETRY_TYPE_NAMEをリストします。
SRID対応の空間インデックス
空間データ型に対しては空間インデックスを張ることができます。空間インデックス内のカラムでは、NOT NULLが宣言されていなければなりません。
例:CREATE TABLE t1 (g GEOMETRY SRID 4326 NOT NULL, SPATIAL INDEX(g));
オプティマイザがインデックスを使うためには、空間インデックスを含むカラムでSRID型修飾子を持たなければなりません。SRID型修飾子を持たないカラムに対して空間インデックスが作成された場合、warningが出力されます。
SRID対応の空間関数
ST_Distance()とST_Length()のような空間関数に対して、そのパラメータが地理的(楕円体)SRSであるかを識別するため、また、楕円体上の距離を計算するため、拡張を行いました。現状では、ST_Distanceや、ST_Within、ST_Intersects、ST_Contains、ST_Crossesなどのような空間関係については、地理的計算(原文:geographic computations)をサポートします。これらのST関数の振る舞いは、SQL/MM Part3 Spatialで定義されています。
キャラクタセット
UTF8MB4がデフォルトのキャラクタセットになりました。SQLのパフォーマンス(UTF8MB4文字列のソートなど)は、5.7と比べて20倍に向上しました。UTF8MB4はWEB上でよく使われているキャラクタセットですので、ほとんどのMySQLユーザーにとっては朗報でしょう。
- デフォルトキャラクタセットがlatin1からutf8mb4に変更となり、照合順序はlatin1_swedish_ciからutf8mb4_800_ci_aiに変更となりました。
- このデフォルト変更はサーバー本体だけでなく、libmysqlやサーバーコマンドツールでも同様です。
- この変更はMTRテストにも反映されており、新しいキャラクタセットで実行されています。
- 照合順序の重みづけや大文字小文字のマッピングは、2016年6月21日にUnicode委員会が発表したUnicode 9.0.0に基づいています。
- latin1(過去のMySQLのもの)で21個あった、言語特有のケースインセンシティブな照合順序は、utf8mb4の照合順序として実装されました。例えば、チェコ語の照合順序はutf8mb4_cs_800_ai_ciとなります。完全なリストについては、WL#9108をご覧ください。こちらのXing Zhangのブログ記事もご覧ください。
- ケース/アクセントセンシティブな照合順序へのサポートが追加されました。MySQL 8.0ではDUCET(Default Unicode Collation Entry Table)で定義された
照合順序重みづけレベルの3つすべてをサポートします。こちらのXing Zhangのブログ記事をご覧ください。 - レベル3重みづけで文字をソートする、日本語のutf8mb4_ja_0900_as_cs照合順序(utf8mb4用)。これは、日本語の正しいソート順を提供します。こちらのXing Zhangのブログ記事をご覧ください。
- 日本語のかなセンシティブな追加機能、utf8mb4_ja_0900_as_cs_ks(ksはKana Sensitiveの意)。こちらのXing Zhangのブログ記事をご覧ください。
- Unicode 9.0.0以降では、新しい照合順序はPAD文字列がなくなり、NO PADとなりました。つまり、他の文字と同じくスペースを文字列の終端とみなします。これは、一貫性とパフォーマンスを向上するために行われました。古い照合順序はそのままです。
こちら、こちら、こちらの、Bernt Marius Johnsenのブログ記事もご覧ください。
データ型
バイナリデータ型へのビット単位の操作
ビット演算(ビット単位のANDなど)が[VAR]BINARY/[TINY|MEDIUM|LONG]BLOBでも動くように拡張しました。8.0以前では、ビット演算は整数型に対してのみサポートされており、バイナリに対するビット演算を行う場合、操作前に引数は暗黙的にBIGINT(64ビット)にキャストされるため、ビットを失う可能性がありました。8.0からは、ビット演算は全てのBINARY、BLOBデータ型で機能し、これらのビットへの引数のキャストは失われることはありません。
IPV6の取り扱い
BINARYデータ型へのビット演算をサポートすることで、IPv6の取り扱いがしやすくなりました。MySQL 5.6で、我々は’fe80::226:b9ff:fe77:eb17′ から VARBINARY(16)のように、IPv6アドレスからテキストに変換するINET6_ATON()関数、INET6_NTOA()関数を導入しましたが、これまでこれらのIPv6関数をビット演算に使用することはできませんでした。誤って出力がBIGINTに変換されてしまったためです。例えば、IPv6アドレスがあったとして、これをネットワークマスクに対してテストしたい場合、INET6_ATON(address) & INET6_ATON(network)とすればよくなりました(INET6_ATON()が正しくVARBINARY(16)を返すようになったため)。こちらのCatalin Besleagaのブログ記事もご覧ください。
UUIDの取り扱い
3つの新しいSQL関数(UUID_TO_BIN()、BIN_TO_UUID()、IS_UUID())を導入することで、UUIDの取り扱いがしやすくなりました。UUID_TO_BINはUUIDフォーマットのテキストをVARBINARY(16)に変換し、BIN_TO_UUIDはVARBINARY(16)をUUIDフォーマットのテキストに変換し、IS_UUIDはUUIDフォーマットのバリデーションを行います。VARBINARY(16)で格納されているUUIDにはファンクショナルインデックスを張ることができます。UUID_TO_BINとUUID_TO_BIN(原文ママ)は時間に紐づいたビットを先頭に持ってくることで、インデックスフレンドリーにしてBツリーへのランダムINSERTを避け、INSERTの時間を短縮します。このような機能の欠落については、UUID使用時の欠点の1つとして触れられてきました。こちらのCatalin Besleagaのブログ記事をご覧ください。
コストモデル
クエリオプティマイザがデータバッファリングを計算に入れるようになった
データがメモリ上にあるかディスク上にあるかに基づいて実行計画を立てるようになりました。これは自動で使用されますので、ユーザから見ると何も設定することはありません。以前よりMySQLのコストモデルでは、データは回転するディスク上にあると仮定していました。ですが今は、メモリ上のデータとディスク上のデータでは、参照についてのコストは異なり、これによりオプティマイザは、データのある場所に応じてより良いアクセス手段を選択できるようになります。こちらのOystein Grovlenのブログ記事をご覧ください。
オプティマイザヒストグラム
オプティマイザヒストグラムを実装しました。これにより、典型的にはインデックスのないカラムに対して、データの分散についての統計を取得することができ、オプティマイザが最適な実行計画を探すのに使用するようになります。一番のユースケースとしては、「カラム名 演算子 定数」という述語での選択性(フィルタリング効果)を計算することです。
ヒストグラムは、拡張されたANALYZE TABLE句で生成することができます。ANALYZE TABLEは、UPDATE HISTOGRAM ON column [, column] [WITH n BUCKETS]とDROP HISTOGRAM ON column [, column]の2つの句を受け付けるようになっています。bucketの数は任意で、デフォルトは100です。ヒストグラム統計はcolumn_statisticsディクショナリテーブルに格納され、information_schema.column_statisticsビューを通して確認できます。ヒストグラムは、JSONデータ型の柔軟性を活かしてJSONオブジェクトとして格納されます。ANALYZE TABLEは自動でテーブルサイズに基づいて、ベーステーブルをサンプリングするかどうか決定します。また、データの分散度合いとbucketの数から、singletonかequi-height、どちらのヒストグラムを生成するかも決定します。こちらのErik Frosethのブログ記事をご覧ください。
正規表現
UTF8MB4の正規表現や、REGEXP_INSTR(), REGEXP_LIKE(), REGEXP_REPLACE(), REGEXP_SUBSTR()のような新しい関数をサポートするようになりました。regexp_stack_limitシステム変数(デフォルト8000000バイト)と、regexp_time_limitシステム変数(デフォルト32ステップ)が、実行のコントロールのために追加されました。REGEXP_REPLACE()関数はMySQLコミュニティから最も要望の多かった機能の1つです。例として、Hans Ginzelによる機能リクエストBUG #27389をご覧ください。また、こちらのMartin Hanssonのブログ記事、こちらのBernt Marius Johnsenのブログ記事もご覧ください。
Dev Ops向け機能
Dev Opsは、データベースのオペレーションについての側面、典型的には信頼性、可用性、パフォーマンス、セキュリティ、観察性、管理性に関心があります。MySQL InnoDB ClusterとMySQL Group Replicationによる高可用性については別のブログ記事にてカバーすることとし、ここでは他のカテゴリについて、MySQL 8.0が何をもたらすか見ていきます。
信頼性
全体的に信頼性が向上しました。理由は以下です。
- トランザクショナルなストレージエンジンであるInnoDBにメタデータを格納している
- 潜在的な非一貫性を排除した
5.7やそれ以前のバージョンでは、元来2つのデータディクショナリがありました。1つはサーバーレイヤー、もう1つはInnoDBレイヤーです。そしてこれらは特定のクラッシュシナリオにおいて同期がズレ得るものでした。MySQL 8.0では、データディクショナリはただ1つです。 - アトミックでクラッシュセーフなDDLを保証する
これにより、DDLは完全に実行されたか、全く実行されないか、どちらかに必ずなります。このことは特にレプリケーション環境において重要であり、これがないとマスターとスレーブの同期が崩れ、データ乖離の原因となります。
この作業は新しいトランザクショナルなデータディクショナリという背景の元、行われました。こちら、こちらのStaale Deraasのブログ記事をご覧ください。
観察性
Information Schema(スピードアップ)
Information Schemaを再構成しました。新しいInformation Schemaテーブルは、シンプルにInnoDBに格納されたデータディクショナリテーブルのビューです。かつての実装と比べると圧倒的に効率が良く、最大100倍にまでスピードアップしました。これにより、Information Schemaは外部ツールからも実践的に使用できるようになりました。こちら、こちらのGopal Shankarによるブログ記事、こちらのStale Deraasによるブログ記事をご覧ください。
Performance Schema(スピードアップ)
100を超えるインデックスをテーブルに追加することで、performance schemaへのクエリをスピードアップしました。performance schemaへのインデックスは事前に定義されており、削除・追加・変更はできません。performance schemaのインデックスは、分割されたデータ構造の走査というより、既存のテーブルデータに対するフィルタリングしたスキャンです。Bツリーやハッシュテーブルの構築・更新・管理はありません。performance schemaのインデックスはハッシュインデックスのようにふるまい、a. すばやく目的の行を読み出し、b. 行順がなく必要であればサーバーに結果のソートを任せ、ます。しかしクエリによっては、インデックスはフルテーブルスキャンを防止し、かなり小さな結果を返すことになります。performance schemaインデックスはSHOW INDEXESで確認することができ、インデックスが付いたカラムを参照するクエリのEXPLAINの結果でも表れます。Simon Muddのコメントをご覧ください。こちらのMarc Alffのブログ記事をご覧ください。
システム変数
システム変数について有用な情報を追加しました。例えば、変数名、最小/最大値、どこで現在の値が設定されたのか、だれがいつ変更したのか、などです。これらの情報は、新しいpeformance schemaテーブルであるvariables_infoで確認できます。こちらのSatish Bharathyのブログ記事をご覧下さい。
クライアントのエラーレポート(メッセージ数カウント)
サーバでレポートされた、クライアントのエラーメッセージの数を集計できるようになりました。統計は以下の5つのテーブルから確認できます。Global count、summary per thread、summary per user、summary per host、summary per accountです。ユーザーは各エラーメッセージについて、何回そのエラーが起こったか、SQL例外ハンドラに何回捕捉されたか、最初・最後に現れた日時のタイムスタンプを確認できます。適切な権限を付与すれば、これらのテーブルをSELECTすることも、統計をリセットするためにTRUNCATEすることもできます。こちらのMayank Prasadのブログ記事をご覧下さい。
ステートメントレイテンシヒストグラム
クエリのレスポンスタイムの可視化のため、ステートメントレイテンシについてのperformance schemaヒストグラムを提供します。これは、取得したヒストグラムから、P95、P99、P999のパーセンタイル値を計算します。この値はサービスの質の指標として利用できます。こちらのFrederic Descampsのブログ記事をご覧下さい。
データロック依存関係グラフ
データロックについて、performance schemaに実装しました。トランザクションAが行Rをロックし、トランザクションBが正に同じ行を待っている場合、BはAにブロックされています。今回実装された機能では、どのデータがRで、誰がロックAを持ち、誰がデータを待っているBなのかがわかります。こちらのFrederic Descampsのブログ記事をご覧ください。
クエリダイジェストサンプル
events_statements_summary_by_digestというperformance schemaテーブルに対して、クエリサンプルの完全なクエリ例と重要な情報を得られるよう、変更が行われました。ユーザーが実際のクエリにEXPLAINを実行して実行計画を得られるようにするため、クエリサンプルを格納するQUERY_SAMPLE_TEXT列が追加されました。QUERY_SAMPLE_SEEN列が、クエリサンプルのタイムスタンプを確認するために追加されました。QUERY_SAMPLE_TIMER_WAIT列が、クエリサンプルの実行所要時間を確認するために追加されました。FIRST_SEEN列とLAST_SEEN列が、秒の小数部分を表示するよう変更されました。こちらのFrederic Descampsのブログ記事をご覧ください。
ツールのメタデータ
プロパティや変動性、ドキュメントなどのメタデータを、setup_instrumentsというperformance schemaテーブルに追加しました。この読み取り専用のメタデータは、ユーザやツールが参照できる、ツールのオンラインドキュメントとして機能します。こちらのFrederic Descampsのブログ記事をご覧ください。
エラーロギング
エラーログの総点検を行いました。アーキテクチャ全体の観点からは、エラーログは新たなサービスインフラストラクチャー内のコンポーネントとなりました。これは、レベルの高いユーザなら独自のエラーログを実装できることを意味します。ほとんどのユーザは独自のログを書くことは望みませんが、何をどこに出力するかについての柔軟性を求める声は一定数存在します。このため、MySQL 8.0ではsinks(どこに)、filters(何を)を追加するためのファシリティを追加しました。フィルタリングサービス(API)と、デフォルトのフィルタリングサービス(コンポーネント)です。ここでのフィルタリングは、あるログメッセージの抑制(選択)や、ログメッセージ内のフィールドの抑制(射影)という意味です。MySQL 8.0ではログライターサービス(API)とデフォルトのログライターサービス(コンポーネント)を実装します。ログライターはログイベントを受けてこれをログに出力します。このログとは、従来のファイル、シスログ、イベントログ、新たなJSONログです。
デフォルトでは、多くの革新的なエラーログの改善がなされています。
- エラーナンバリング
「MY-10001」のように、「MY-」の後に10000番台の数字が続くフォーマットとなります。エラーナンバーはGAリリースでは固定ですが、それに関連するエラーテキストはメンテナンスリリースで変更される(改善される)可能性があります。 - システムメッセージ
システムメッセージはエラーログに、[Error]、[Warning]、[Note]の代わりに[System]と出力されます。[System]と[Error]メッセージは詳細度(verbosity)にかかわらず出力され、止めることはできません。[System]メッセージは、主にサーバーの起動停止などの大きな状態遷移に関連した、少数のケースでしか使用されません。 - 詳細度(verbosity)の縮小
log_error_verbosityのデフォルト値が3(Notes)から2(Warning)に変更となりました。これにより、デフォルトでMySQL 8.0のエラーログは粗くなります。 - 出力元コンポーネント
各メッセージは、どのサブシステムからメッセージが出力されたのかわかるように、[Server]、[InnoDB]、[Replic]という3つの値の注釈が付きます。
以下がMySQL 8.0 GAの起動後にエラーログに出力されるものです。
2018-03-08T10:14:29.289863Z 0 [System] [MY-010116] [Server] /usr/sbin/mysqld (mysqld 8.0.5) starting as process 8063 2018-03-08T10:14:29.745356Z 0 [Warning] [MY-010068] [Server] CA certificate ca.pem is self signed. 2018-03-08T10:14:29.765159Z 0 [System] [MY-010931] [Server] /usr/sbin/mysqld: ready for connections. Version: '8.0.5' socket: '/tmp/mysql.sock' port: 3306 Source distribution. 2018-03-08T10:16:51.343979Z 0 [System] [MY-010910] [Server] /usr/sbin/mysqld: Shutdown complete (mysqld 8.0.5) Source distribution.
エラーナンバリングの導入により、MySQLではエラーナンバー(ID)を変えることなく、メンテナンスリリースで(必要なら)エラーテキストを向上させることができるようになりました。エラーナンバーは、フィルタリングや出力の抑制、グローバリゼーションやローカリゼーションの基礎ともなります。
管理性
INVISIBLEインデックス
インデックスが見えるか見えないか、状態を変更できるようになりました。INVISIBLEインデックスは、オプティマイザが実行計画を立てる時には考慮されません。しかし、インデックスはバックグラウンドで依然メンテナンスされており、再度見えるようにするのは簡単です。この目的は、DBAやDevOpにインデックスを削除できるかできないか判断できるようにすることです。もしインデックスが利用されていないのではないか、と思った場合、まずINVISIBLEにし、クエリのパフォーマンスをモニタリングし、クエリのスローダウンがなければ最終的にインデックスを削除します。この機能はBug#70299などで、多くのユーザによって希望されたものです。こちらのMartin Hanssonのブログ記事をご覧ください。
柔軟なUNDO表領域管理
ユーザーにUNDO表領域のフルコントロールを提供します。すなわち、いくつ表領域を作るか、どこに配置するか、ロールバックセグメントをいくつもたせるか、です。
- システム表領域にUNDOログをもたない
UNDOログはアップグレード中に、システム表領域からUNDO表領域に移動されます。これにより、システム表領域をUNDOログに使用している、MySQL 5.7からのアップグレードパスを提供します。 - UNDO表領域はシステム表領域と分離して管理できる
例えば、UNDO表領域を高速なストレージに配置することができます。 - 突発的な巨大トランザクションによって確保されたスペースを回収する(オンラインで)
表領域のTRUNCATEができるようにするため、最小2つのUNDO表領域が作成されます。これにより、片方のUNDO表領域がTRUNCATEされている間にもう片方がアクティブでいられるため、InnoDBはUNDO表領域を縮小することができます。 - 多くのロールバックセグメントによりアクセスの集中を低減する
ユーザーは、最大127のUNDO表領域を作成でき、さらに各表領域は128のロールバックセグメントを持つことができます。多くのロールバックセグメントを持つということは、並列のトランザクションが、それぞれのUNDOログに別々のロールバックセグメントを使う可能性が高くなり、結果として同一リソースへのアクセスの集中を低減できます。
こちらのKevin Lewisのブログ記事をご覧ください。
グローバル変数へのSET PERSIST
グローバルに動的なサーバ変数を永続化できるようになりました。多くのサーバ変数はGLOBALかつDYNAMICであり、サーバ起動中に変更ができます。
例:SET GLOBAL sql_mode=’STRICT_TRANS_TABLES’;
しかし、このような設定はサーバ再起動後は失われます。
この変更により、SET PERSIST sql_mode=’STRICT_TRANS_TABLES’;という記述が可能になります。この効果は、サーバ再起動後も設定が残る、ということです。この機能には多くの利用方法が考えられますが、最も重要なのは、設定ファイルの修正が不便であったり選択肢外である場合、例えば、ファイルシステムアクセスができず、サーバーに接続することしかできないような環境などでも、サーバ設定を管理できるようになる、という点です。SET GLOBALには、SET PERSISTのためのSUPER権限が必要です。
また、RESET PERSISTコマンドも存在します。RESET PERSISTコマンドは永続化設定からシステム変数を除去する意味があり、SET GLOBALとよく似た挙動をします。
SET PERSISTは、ほとんどの読み取り専用変数に対しての設定にも利用できますが、新しい値は次のサーバー再起動後に反映されます。一部の読み取り専用変数については、意図的に設定できないようになっている点にご注意ください。こちらのSatish Bharathyのブログ記事をご覧ください。
リモートマネジメント
RESTARTコマンドが実装されました。この目的は、SQL接続でのMySQLのリモートマネジメントができるようにすることであり、例えば動的でないシステム変数をSET PERSISTで変更し、RESTARTする、ということができます。Frederic Descampsによる、MySQL 8.0: changing configuration easily and cloud friendly !のブログ記事をご覧ください。
DDLによる表領域のリネーム
ALTER TABLESPACE s1 RENAME TO s2;が導入されました。SharedまたはGeneralの表領域は、ユーザーから見えるエンティティであり、CREATE、ALTER、DROPすることができます。Bug#26949、Bug#32497、Bug#58006もご覧ください。
DDLによる列のリネーム
ALTER TABLE … RENAME COLUMN old_name TO new_name;が導入されました。これは、既存の文法ALTER TABLE CHANGE …でカラムの全ての属性を再度記述しなければならなかった点の改善です。既存の文法では、リネームしようとするアプリケーションから、全ての情報が見えるわけではない可能性がある、という欠点があります。また、データ損失につながる、意図せぬデータ型の変更のリスクもあります。
セキュリティ機能
新しいデフォルト認証プラグイン
デフォルトの認証プラグインが、mysql_native_passwordからcaching_sha2_passwordになりました。関連して、libmysqlclientもデフォルトの認証機構としてcaching_sha2_passwordを使用するようになりました。新しいcaching_sha2_passwordは、より強固なセキュリティ(SHA2アルゴリズム)と高パフォーマンス(キャッシング)を併せ持ちます。一般的に我々はネットワークコミュニケーションにTLS/SSLを使用するよう推奨しています。こちらのHarin Vdodariaのブログ記事をご覧ください。
コミュニティエディションのデフォルトにOpenSSLが使用される
Enterprise EditionとCommunity Editionで、デフォルトのTLS/SSLライブラリとしてOpenSSLを使用するよう統一されました。以前Community EditionではYaSSLを使用していました。Community EditionでのOpenSSLのサポートは、最も要望の多かった機能の1つです。こちらのFrederic Descampsのブログ記事をご覧ください。
OpenSSLが動的にリンクされた
OpenSSLに動的リンクされるようになりました。MySQLレポジトリのユーザからみると、MySQLパッケージはその時のLinuxに提供されるOpenSSLファイルに依存します。動的リンクすることで、MySQLをアップグレードしたりパッチ当てしたりせずに、OpenSSLのアップデートを即座に利用できるようになります。
こちらのFrederic Descampsのブログ記事をご覧ください。
UNDO、REDOログの暗号化
UNDOログ、REDOログの蓄積したデータ暗号化を実装しました。MySQL 5.7で、我々はfile per table表領域に格納されたInnoDBテーブルの表領域暗号化をご紹介しました。この機能は物理的な表領域データファイルの暗号化を提供するものでした。MySQL 8.0ではこれをUNDOログ、REDOログにも拡張しました。
こちらのドキュメントをご覧ください。
ロール
ロールを実装しました。ロールは、権限の集合に名前を付けたもので、目的はユーザアクセス権限管理を単純化することです。ロールをユーザに付与したり、権限をロールに付与したり、ロールを作成/削除したり、セッションでどのロールが使用できるか決めたりできます。こちらのFrederic Descampsのブログ記事をご覧ください。
PUBLICへのGRANT/REVOKEができるようになった
新しいユーザが作成された時にデフォルトで付与するロールを決めることができる、mandatory-rolesシステム変数を導入しました。
例:role1@%,role2,role3,role4@localhost
記述されたロールは、常にすべてのユーザに付与され、REVOKEできません。これらのロールはデフォルトのロールでない場合はアクティベーションを必要とします。新しいシステム変数activate-all-roles-on-loginがONにセットされると、全てのロールはユーザ認証後、常にアクティベートされた状態になります。
SUPER権限の分解
以前SUPER権限が持っていた様々な種類の権限を、より細かいセットに定義しました。目的は、ユーザに与える権限を、あるジョブを実行するのに必要十分な範囲に絞ることです。例えば、BINLOG_ADMIN、CONNECTION_ADMIN、ROLE_ADMINなどです。
XAトランザクション管理の認証モデル
XA RECOVERステートメントを実行権限をコントロールできる、XA_RECOVER_ADMINシステム権限を導入しました。XA_RECOVER_ADMIN権限を持たないユーザがXA RECOVERを実行しようとしてもエラーとなります。
パスワードローテーションポリシー
パスワードの再利用制限を導入しました。この制限は、グローバルレベルでも個々のユーザレベルでも設定できます。パスワード変更時、個々のユーザの習慣やパターンについての手がかりを与えるため、パスワード履歴は安全に保たれます。パスワードローテーションポリシーは他にも適用され、既存のメカニズムであるパスワード期限切れポリシーや使用できるパスワードのポリシーにも適用されます。Password Managementをご覧ください。
ユーザパスワードへのブルートフォース攻撃を低速化する
ログインに連続して失敗した時、認証プロセスを遅らせるようになりました。目的は、ユーザパスワードへのブルートフォース攻撃を低速化することです。認証遅延が始まるまでのログイン失敗回数と、最大遅延量は設定可能です。
skip-grant-tablesの廃止
サーバーが–skip-grant-tablesオプションで起動した場合、リモート接続を拒否するようになりました。Omar Bourjaに報告されたBug#79027もご覧ください。
mysqld_safeの機能をサーバーに追加した
現在mysqld_safeで提供しているロジックをサーバ内部に実装しました。これは、–daemonize起動オプション使用時などのケースでサーバの利便性を向上します。また、mysqld_safeスクリプトへの依存性を下げることができます。(我々はmysqld_safeは将来廃止したいと考えています)また、Peter Laursenに報告された、Bug#75343の修正ともなります。
パフォーマンス
R/W、I/Oバウンド、ホットスポットのある(集中度の高い)ワークロードでより良いパフォーマンスを発揮するようになりました。加えて、新たなリソースグループ機能により、ユーザスレッドをCPUにマッピングすることで特定のワークロード、ハードウェアへの最適化ができるようになりました。
Read/Writeワークロードのスケール
RWやWriteの多いワークロードで良くスケールするようになりました。意図的な高RWワークロード、4並列ユーザで、MySQL 5.7と比べて2倍以上のパフォーマンスを確認しています。MySQL 5.7ではRead Onlyワークロードのスケーラビリティを向上させましたが、MySQL 8.0ではRead Writeワークロードのスケーラビリティが向上した、といえます。効果としては、MySQLが一般的なサーバー用HW(2CPUソケットのような)でのHW利用効率を向上した、ということになります。この向上の理由は、InnoDBがREDOログを書く方法が再デザインされたことにあります。各ユーザースレッドがデータ変更のために常に争っていたこれまでの実装と異なり、新しいREDOログではユーザースレッドはロックがなく、REDOログ書き込みとフラッシュは専用のバックグラウンドスレッドが行い、REDOログのプロセスはイベントドリブンとなりました。こちらのDimitri Kravtchukのブログ記事をご覧ください。
I/Oキャパシティの活用(高速ストレージ)
ストレージデバイスのパワーを限界まで使うことができるようになりました。例えば、インテルのOptaneフラッシュデバイスでは、I/Oバウンドなワークロード(データがバッファ上になく、二次ストレージから取ってこなくてはならない状態)下で、1Mを超える単一行SELECTのQPSを得ました。これは、fil_system_mutexグローバルロックを取り除いたことに因ります。
高集中度のワークロード(hot row)でのパフォーマンス向上
高集中度のワークロード下でのパフォーマンスが向上しました。高集中度のワークロードは、複数のトランザクションがテーブル内の同じ行のロックを待っている時に発生し、待機するトランザクションのキューイングの原因となります。多くの現実のワークロードでは、ある日のワークロードは安定しておらず、特定の時刻にバーストする可能性があります(パレート分布)。MySQL 8.0では、このようなバーストをTPS(Transactions Per Second)、平均レイテンシ、95パーセンタイルレイテンシの観点でより良く対処できます。エンドユーザにとってのメリットは、システムが余分なキャパシティを持たずにより高付加な状態で稼働できることにより、より良いHW利用効率が得られるという点です。オリジナルのパッチはJiamin Huang(Bug#84266)により提供されました。Contention-Aware Transaction Scheduling(CATS)アルゴリズムについて学習し、こちらのJiamin HuangとSunny BainsによるMySQLブログ記事をご覧ください。
リソースグループ
グローバルリソースグループが導入されました。リソースグループによって、DevOpsやDBAはユーザー/システムスレッドとCPUのマッピングを管理できるようになります。これはCPUをまたがるワークロードを分割するのに使用でき、ユースケースによっては、より良い効率・パフォーマンスを得ることができます。
このように、リソースグループはDBAの道具箱に新たな道具を加えます。そのツールとは、DBAがHW使用率やクエリの安定性を向上させるのを助けるものです。
例として、Intel(R) Xeon (R) CPU E7-4860 2.27 GHz 40 cores-HTでのSysbenchのRWワークロードでは、書き込み負荷を10コアに絞ることで全体としてのスループットを倍にすることができました。リソースグループはかなり高度なツールであり、効果が負荷のタイプやHWによって変わることから、使いこなすには力のあるDevOps/DBAが必要です。
その他の機能
より良いデフォルト値
MySQLチームでは、デフォルトの設定によく注意を払っており、ユーザーに可能な限り最高の体験をして頂くことを目指しています。MySQL 8.0では、30以上のデフォルト値を我々がより良いと考える値に変更しました。New Defaults in MySQL 8.0のブログ記事をご覧ください。この動きの動機について、こちらのブログ記事でMogan Tockerが概略を記しています。
プロトコル
結果セットへのメタデータの生成・送信をしないことができるようになりました。結果セットの組み立て、構文解析、送受信は、サーバ、クライアント、ネットワークのリソースを消費します。場合によっては、メタデータのサイズは実際の結果セットサイズよりも大きくなることがあり、しかもそのメタデータは不要なケースがあります。これらのデータの生成と蓄積を無効化することで、クエリの結果セットの送信をスピードアップすることができます。クライアントは、もし結果セットにメタデータを返してほしくない場合、CLIENT_OPTIONAL_RESULTSET_METADATAフラグをセットしてください。
CクライアントAPI
パケットストリームとしてサーバーからレプリケーションイベントを得る安定したインターフェースを、libmysqlのC APIに追加しました。目的は、MySQL Applier for Hadoopのようなバイナリログベースのプログラムを実装するために、ドキュメントに書かれていないAPIをコールしたり、内部ヘッダーファイルをパッケージングしたりすることを避けることです。
Memcached
InnoDB Memcachedの機能を、multiple getオペレーションとrange queryのサポートにより強化しました。multiple getオペレーションは、更なる読み取りパフォーマンスの向上のために追加しました。すなわち、ユーザーは複数のキーバリューの組み合わせを1つのmemcachedクエリでフェッチできます。range queryへのサポートは、FacebookのYoshinoriにリクエストされていました。range queryにより、ユーザーは特定の範囲を記述し、その範囲の該当する値を全てフェッチできます。これらの機能により、クライアント/サーバー間のラウンドトリップ数を低減することができます。
AUTOINCカウンターの永続化
AUTOINCカウンターをREDOログに書くことで永続化しました。これははるか昔のBug#199の修正です。MySQLのリカバリプロセスではREDOログを再生するため、AUTOINCカウンターの正しい値を保証します。AUTOINCカウンターのロールバックは一切ありません。これは、データベースのクラッシュ後、カウンターの最後の値を再発行することを意味し、AUTOINCカウンターは同じ値を2度とることがないことを保証します。カウンターは単調増加しますが、ギャップ(使用されない値)が発生し得る点に注意してください。AUTOINC永続性の欠落は、以前から問題となっていました。例えば、2006年にStephen Deweyに報告されたBug#21641か、このブログ記事をご覧ください。
まとめ
これまで見てきたように、MySQL 8.0は多くの新機能を搭載し、パフォーマンスを向上しました。dev.mysql.comからダウンロードして使ってみてください!
また、既存のMySQL 5.7からアップグレードすることもできます。その過程で、新しいMySQL Shell(mysqlsh)のUpgrade Checkerを使用してみたくなるかもしれません。このユーティリティは既存のMySQL 5.7サーバーを解析し、MySQL 8.0と非互換な点を教えてくれます。他のリソースとしては、Frederic Descampsのブログ記事、Migrating to MySQL 8.0 without breaking old applicationがあります。
このブログ記事ではサーバーの機能についてカバーしましたが、他にもまだまだたくさんあります!
我々は他の機能、例えばレプリケーション、グループレプリケーション、InnoDB Cluster、ドキュメントストア、MySQL Shell、DevAPI、
DevAPIベースコネクタ(Connector/Node.js、Connector/Python、PHP、Connector/NET, Connector/ODBC, Connector/C++、Connector/J)
についてもブログ記事を書いています。
今回はここまでです。
MySQLをご利用ありがとうございます!