SQLの実行モデル
アプリケーション開発に使われるJavaやPHPなどの言語の習得者がSQLを学ぶとき、そのパラダイムの違いに気付かないとおかしなデータベース・アクセスのコードを書いてしまうことがあります。その最大の違いとはなんでしょうか。
JavaやPHPなどの「手続き的言語」は基本的に、データ構造にどのような操作を加えるかという、人がアルゴリズムを記述する言語です。一方SQLは何を記述しているのかというと、入力と出力の対応関係の集合の定義です。つまりインターフェースの仕様を記述しています。SQLにはアルゴリズムは記述されていないので、いくらSQLを眺めていてもそれがどのように実行されるかの実装はわかりません。
ではSQLで定義した集合を導出するアルゴリズムはどこにあるのかというと、DBMSが自動生成します。この生成されたアルゴリズムのことはDBMS実装によって呼び方が異なりますがOracle DatabaseではSQL実行計画(SQL Execution Plan)といいます。人がアルゴリズムを記述「しない」言語がSQLです。
一般的に、同じ入力から同じ出力を得るアルゴリズムは複数存在し得ます。DBMSは複数存在し得るアルゴリズムの中から、実行時間が最小になることを推定したアルゴリズムを探索します。
SQL実行計画のアルゴリズムはさらに複数のデータ構造とアルゴリズムに分解することができます。これらのアルゴリズムの部分実装が索引やパーティショニング、結合アルゴリズムや並列化などです。DBMSは使用可能なアルゴリズムの部分実装を組み合わせて、SQLの実行時間が最小になることを推定した全体最適化問題を探索します。
また、全体最適化問題を探索するための情報として、多くのDBMSでは表の統計情報を定期的に収集しておくことを推奨しています。これはデータの値の分布を事前に把握しておくという一種の学習です。データの値の分布によって実行時間が最小になるアルゴリズムが異なるからです。
SQLでデータベースにアクセスするアプリケーションを開発する際、データベースへのアクセスを高速化するには、SQLの記述とSQLチューニングの2段階が必要になると思っている方もいるのではないでしょうか。実際には、SQLの記述の変更やSQLチューニングを行わなくとも、アプリケーション側の実装を修正することでSQLの実行時間を短縮化することができます。なぜならSQLはAPIであり、SQLというインターフェースの定義は変更せずに実装を修正することができるからです。
トランザクション系アプリケーションではデータへのアクセス・パスは極めて単純であることが多く、SQLを見ると最適なSQL実行計画を人が想像することも容易です。ですが、集計や分析処理のように少し複雑な操作になると「最速の」アルゴリズムを想像することは容易ではありません。手続き的言語で正しい結果を出力するアルゴリズムの1つを思いついたとして、それよりも高速なアルゴリズムの探索を人力で行うと、それだけでかなり時間が取られます。SQLの実行モデルはこの探索を自動で行います。生成されたSQL実行計画を人が見て、アルゴリズムとデータ構造の実装の一部分を修正するということも可能です。しかもインターフェースであるSQLを修正することなしに、です。これがインターフェースと実装の分離の効果です。
