このブログ記事は、Introducing JavaScript support in MySQLの翻訳版です。

MySQLは常に進化し続けているデータベースです。このたび、データベース組み込みの優れた手続き型プログラミング機能に対応しました。開発者はMySQLデータベース・サーバーにJavaScriptのストアド・プログラム(関数とプロシージャ)を作成できるようになりました。保存されたプログラムはGraalVMランタイムで実行することができます。この機能はOracle Technology Network(OTN)からダウンロードできる、MySQL Enterprise Editionのプレビューとして試していただけます。MySQL-JavaScriptは、オラクルがOCIとAWSで提供しているMySQL HeatWaveでもご利用いただけます。

※訳者注: 2025年3月27日現在、JavaScript サポートはプレビュー版ではなく GA となっており、MySQL Enterprise Edition 9.0 以降の全プラットフォームで提供されています。  

Stored Procedure in MySQL

 

JavaScriptストアド・プログラムの有用性

JavaScriptは、開発者のあいだで最も人気のあるプログラミング言語のひとつです。 比較的単純な構文と最新の言語機能のサポートに加えて、再利用可能なコード・モジュールを多く提供する優れた環境がJavaScriptの人気を支えています。

特に永続ストレージが必要な際に、JavaScript開発者の皆様には、オープンソース・データベースとして最も人気である、MySQLを選んでいただけるはずです。ストアド・プログラムでJavaScriptをサポートすることにより、開発者の皆様には使い慣れた言語でMySQLストアド・プログラムを作成し、豊富なJavaScript環境を使っていただけます。

JavaScriptストアド・プログラムのサポートは、大規模なエコシステムを活用することで開発者の生産性を向上させるだけではなく、より多くの開発者がストアド・プログラムを書くために必要なスキルを持つようになることを意味します。つまり企業や開発チームなどの組織は、より多くのエンジニアを活用する機会となり、広く利用されているJavaScriptのスキルセットをバックエンド開発のために活かすことができるという利点があります。

さらにストアド・プログラムには、データベース・サーバーとアプリケーション間のデータ移動を最小限に抑えるという重要な利点があります。バッチ処理のような大量データ転送の場合には通常、下記のような事項を考慮する必要があります。

  • 大量データ転送は時間がかかり、またネットワークに重大なオーバーヘッドを引き起こす可能性
  • アプリケーションとのやり取りが増えるとレイテンシ(遅延)の増加が顕著になる恐れ
  • 中間層またはアプリケーション層で大量データ処理をする際に、大量のメモリやストレージ、コストを消費する可能性
  • セキュリティ・リスクとデータ保護要件により、特にクラウド環境において、マシン間のデータ転送を忌避する必要性
  • データベース・サービス外に大量のデータを移す際に、エグレス・コストが発生する可能性

MySQLのストアド・プログラムはデータベース内でデータ処理を行うことで、上記のような問題を解決します。

Design Tradeoff

 

活用例ご紹介

MySQL-JavaScriptは従来トレードオフによって制約されていたアプリケーション設計において、新しい可能性を提供します。JavaScriptのストアド・プログラムを使用すると、開発者はデータ移動を抑えられるようになり、またデータベース内における高度なデータ処理ロジックの実装をシームレスかつ簡単に行なえます。下記に活用例をご紹介します。

  • データ抽出: URLの文字列のような、データベース内で一般に使われる複雑なオブジェクトから情報を抽出。
  • データのフォーマット設定: Mustacheパッケージに代表されるようなJavaScriptのテンプレート・エンジンを使用して、フォーマットを設定した文字列を生成。
  • 近似検索: テーブルから類似した文字列を取得するなど、SELECTクエリ文における類似性スコア関数の使用。
  • データ・バリデーション(検証): Validatorパッケージを使用した、複雑なバリデーション・ルールによるデータのクリーンアップ。
  • 圧縮、暗号化: MySQLには含まれてないカスタム・アルゴリズムを使用した圧縮および暗号化。
  • データ変換: 文字列の列を特徴量エンジニアリングで使用される疎行列(スパース行列)表現に変換するなどの、データ表現の変更。

上記に挙げた例は、MySQLのJavaScriptストアド・プログラムが実現するソリューションのごく一部です。複雑なデータ・パイプラインの実装や、機械学習アプリケーションのステージング環境の構築など、あらゆる用途に適用していただけます。

 

MySQL-JavaScript

JavaScriptストアド・プログラムのサポート導入により、MySQLデータベース内における高度な手続き型処理の表現が可能になります。
JavaScriptランタイムはGraalVMによって統合されており、コンパイラの最適化、性能、セキュリティ機能など全てのGraalVM Enterprise Edition(EE)の機能を追加料金無しで提供します。

今回のリリースでサポートされるのは下記です。

  • ECMAScript 2021標準規格に基づいたJavaScript言語
  • ストアド・プロシージャ、およびストアド・関数
  • MySQLのデータ型
    (例: 整数、浮動小数点、CHAR/VARCHARなど全てのバリエーション)

ECMAScript標準ライブラリに含まれ提供される多くの基本的な操作とデータ構造は、実装を簡単かつ表現豊かにしてくれます。開発者はオンライン・パッケージ・マネージャーから入手できる何百万ものサードパーティ・パッケージ、例えば「npm」など、を再利用できます。

 

GraalVMとは何か

GraalVMとはOracleのコンパイラ・エコシステムのことを言い、JDKおよび言語実装(例: JavaScript、R、Python、Ruby、Javaなど)を含みます。さらに実行時(JIT)コンパイラ、および事前(AOT)コンパイラ・テクノロジも含み、サンドボックス機能とツール・サポートを備えたフル・マネージドVMも提供します。GraalVM Enterprise Editionは、MySQL-JavaScriptに統合されています。

 

JavaScriptストアド・プログラムの定義

※ 訳者注: 下記の前提条件を確認して下さい。

  1. LinuxがSELinuxのEnforcingモードで動作していた場合、INSTALL COMPONENTが正しく動作しないため、モードの変更をする必要があります。OS上でsudo setenforce 0を実行して、SELinuxのEnforcingモードを一時的にDisabledにします。

  2. JavaScriptコンパイラがMySQLの中で動くようにするためのコンポーネントをロードします。MySQLクライアントプログラムもしくはMySQL Shellで接続して、INSTALL COMPONENT “file://component_mle”; を実行します。

  3. グローバル関数 SET GLOBAL log_bin_trust_function_creators=ON; を実行します。これを宣言しない場合、関数の宣言時に DETERMINISTICキーワードを加える必要が生じます。詳細はこちらをご参照下さい。
  4. JavaScriptの文末は ; なので、JavaScriptのプログラムをそのまま書くとMySQLクライアントプログラム mysqlやMySQL ShellはSQL文の末尾と誤判断することになります。これを避けるため DELIMITER // を実行して、SQL側のコマンドの末尾を // に変更します。MySQLクライアントプログラム 8.2、MySQL Shell 8.3はデリミタを自動判別できるので変更の必要はありません。

MySQLにてJavaScriptストアド・プログラムを作成する際には、従来のストアド関数およびプロシージャに使用されていたSQL文の派生形を使えます。


CREATE FUNCTION gcd_js (a INT, b INT) RETURNS INT 
LANGUAGE JAVASCRIPT AS $$ 

   let [x, y] = [Math.abs(a), Math.abs(b)]; 
   while(y) [x, y] = [y, x % y]; 
   return x; 

$$;

上記の例ではJavaScriptのコードが、SQLで呼び出し可能な関数の定義に直接埋め込まれています。JavaScriptのコード内で引数名が直接参照でき、関数の呼び出しの際には、暗黙的な型変換がSQLの型とJavaScriptの型のあいだで行われます。JavaScriptストアド・プロシージャの呼び出しには、通常のSQLストアド・プロシージャに似た、CALLステートメントを使用します。ストアド・プロシージャでは、入力および出力両方のパラメータがサポートされます。

 

SQL文中でJavaScriptコードを実行する例

JavaScriptの関数は、SELECT文、WHERE句、GROUP BY句、ORDER BY句、DML文、DDL文、ビューなど、通常のSQL関数が呼び出される箇所ならどこでもSQL文で呼び出せます。このような、定義した関数を呼び出すSQL文の例は下記です。

SELECT col1, col2, gcd_js(col1,col2) 
FROM my_table 
WHERE gcd_js(col1, col2) > 1 
ORDER BY gcd_js(col1, col2);

CREATE TABLE gcd_table  
AS SELECT gcd_js(col1,col2) 
FROM my_table;

 

MySQL内でJavaScriptコードデバッグする例

デバッグはソフトウェア開発に無くてはならないものです。MySQL-JavaScript機能は、JavaScriptプログラムがMySQLデータベース内で実行されている間に、トラブルシューティングに対応する追加のSQLインターフェイスを示します。

JavaScriptで発生する 「例外」を、MySQLの「エラー」へ変換する処理は、透過的に行われます。

開発者の方はJavaScriptの標準出力だけでなく、スタック・トレースにもアクセス可能です。

CREATE PROCEDURE division (IN a INT, IN b INT, 
OUT result DOUBLE) LANGUAGE JAVASCRIPT AS $$
 function validate(num) { 
   console.log("validating input value: ", num);
    if (num === 0) throw ("Division by Zero!"); 
 } 
    validate(b);
    result = a / b; 
$$;
CALL division( 5, 0, @res);
ERROR: 6000 (HY000): MLE-JS> Division by Zero!

SELECT mle_session_state("stdout");
+-----------------------------+
| mle_session_state("stdout") |
+-----------------------------+
| validating input value:  0
 |
+-----------------------------+
1 row in set (0.0003 sec)

SELECT mle_session_state("stack_trace");
+------------------------------------------------------------------------------------------------------------+
| mle_session_state("stack_trace")                                                                           |
+------------------------------------------------------------------------------------------------------------+
| <js> validate(division:9:195-222)
<js> division(division:11:230-240)
<js> :anonymous(division:15:264-273)
 |
+------------------------------------------------------------------------------------------------------------+
1 row in set (0.0003 sec)

 

セキュリティ

MySQLのJavaScriptサポートは、最高レベルのセキュリティ、分離、データ保護を提供します。 MySQL上でのJavaScriptは業界で実証済みであるOracleのGraalVMのセキュリティ保証に依存しています。

VMのサンド・ボックスは、悪意のあるコードがMySQLサーバーの他のモジュールに不正アクセスできないようにします。またすべてのストアド・プログラムは、独自のコンテキストで解析され、実行されます。

この分離ポリシーでは、あるストアド・プログラムが他のストアド・プログラムのデータやコードに対し、読み取りや変更を行うことは許可されていません。JavaScriptのユーザー・コードからスレッドの生成および操作を行うことは禁止されており、またJavaScriptのユーザー・コードはネットワーク通信やファイル・システムにもアクセスできません。

JavaScriptストアド・プログラムは標準のMySQL権限モデルに基づいて構築されていて、ストアド・プログラムを作成できるのは権限を持つユーザに限られます。ストアド・プログラムへのアクセスは権限によって制御でき、また他のユーザが実行できるストアド・プログラムの定義もできます。

 

互換性

JavaScriptストアド・プログラムは、従来のSQLストアド・プログラムとシームレスに動作します。この機能は特定のストレージ・エンジンに依存することなく、データは透過的にInnoDBや LakehouseおよびHeatWaveからアクセス可能です.

オラクルがOCIとAWSで提供しているMySQL HeatWaveでは、予めインストールされて構成されたJavaScriptが利用可能です。一方、MySQL Enterprise Editionでは手動によるインストールと構成が必要です(※訳者注: 先述の INSTALL COMPONENT "file://component_mle"; を参照して下さい)。

 

 

性能

MySQLとJavaScriptの統合では、特定の用途に合わせてカスタム構成されたVMが使用され、優れたエンド・ツー・エンド性能を発揮します。このカスタマイズは、高速処理のために言語実装がネイティブ・バイナリ表現にコンパイルされる、GraalVMの事前(AOT)コンパイラに基づいています。


GraalVMは、ECMAScript 2021標準規格に基づいた独自のJavaScript実装を持ちます。同ーVM内における複数のプログラミング言語のサポートに重点を置いたGraalVMのPolyglotフレームワークを使用して実装されているにも関わらず、この言語実装は性能に優れています


このMySQL-JavaScript機能は、積極的なインライン化や、部分的エスケープ分析を含むコンパイラの最適化など、GraalVM Enterprise Editionに由来する様々な先進的・最適化技術の恩恵を受けています。これはインタプリタ・プログラムとネイティブ・コンパイラを実行時に切り替える、プロファイル・ガイド付き実行時(JIT)コンパイラを含みます。

 

まとめ

MySQL-JavaScriptを活用すると、開発者は複雑なプログラミング・ロジックをMySQLサーバー内で直接表現できるようになり、またアプリケーションのデータ集約部分をデータの近くに配置することで、データの移動コストの削減ができるようになります。ECMAScript 2021標準規格に基づいたJavaScriptを使用することで、システムが特定のベンダーに依存するようなベンダー・ロックインの懸念が払拭され、開発者の皆様には追加料金無しで、GraalVM Enterprise Editionの全ての利益を享受していただくことができます。

Oracle Technology Network(OTN)からMySQL Enterprise Editionをダウンロードしていただくと、MySQL-JavaScriptの無料トライアルを体験していただけます。MySQL-JavaScript は、オラクルがOCIとAWSで提供しているMySQL HeatWaveとシームレスに統合されているので、皆様のすぐお手元でこれらの最新イノベーションを体感していただけます。

MySQLのJavaScriptサポートを、OCIとAWSで提供しているMySQL HeatWaveにてご利用になりたいお客様は、下記にお問い合わせ下さい(平日 9:00-12:00 | 13:00-17:00、祝日および年末年始休業日を除く)。

  • 電話: 0120-06-5556
  • Eメール: mysql-sales_jp_grp@oracle.com

 

参考資料

ユーザーマニュアル(英語): User Manual (JavaScript Stored-Programs Section 25.3)

 

デモ映像