Advent Calendar 14日目 MySQL と PHP の間を詳しく見てみる

かじゅある! (挨拶)

本記事は、 MySQL Casual Advent Calendar 2011 (http://mysql-casual.org/2011/11/mysql-casual-advent-calendar-2011.html) 14日目です。
そして同時に do_aki Advent Calendar 2011 (http://atnd.org/events/22834) の 14日目でもあります ;-p


PHP と聞いただけで逃げ出す方も居られますでしょうが、
やはり私、PHP を使っておりまして、それ以外のネタがなかなか見つからないので、
かじゅあるに PHP ネタを投入することにしました。

MySQL を利用する手段

PHP アプリケーションから MySQL を利用する方法は結構様々です。


などなど。他にもあるかとは思いますが、ぱっと浮かんだのはこのくらい。

利用方法はググればたくさん見つかりますのでそちらをご参照あれ。(PHP の一番の*1魅力ですね!)

Doctrine は Symfony というフレームワークで標準となっている ORM で、 Zend_DB は Zend Framework の一部です。

PEAR::DB はさすがにもう使っているところは少ないと思いますが、未だに ADOdb がメンテされていることには驚きました。

MySQL利用ライブラリの実体

さて、様々なライブラリはありますが、実際にこれらの中身を追ってみると、
最終的には、先ほど列挙した中の、 PDO 拡張 (MySQL ドライバ) / mysql 拡張 / mysqli 拡張 のいずれかを呼び出していることが分かります。

  • mysql 拡張は php4 の時代から使えた古くからある拡張です。(今後新規に利用する必要性はないでしょう。)
  • mysqli 拡張は mysql 拡張を刷新する形で php5 から利用可能なモジュールです。
  • pdo 拡張は、それ自身がDB 抽象層であり、配下に多くの DBMS に対応したドライバが存在します。(その中の一つに mysql があります)


余談ですが、 PDO を使う場合は、PDO::ATTR_EMULATE_PREPARES 属性を false に設定してやらないと、 サーバサイドの Prepared Statement が利用されません。詳しくは、 PHP と MySQL と サーバサイド プリペアードステートメント - do_akiの徒然想記 を。


これらの関係を図にまとめたのが Graph.1 となります。

Graph.1 PHPMySQL の間


libmysql

さて、Graph.1 を見ていただけると分かるのですが、Application と MySQL Server の間に、先には説明していないものがあります。

  • libmysql
  • mysqlnd


の2つです。

libmysql は、MYSQL 側が用意しているライブラリで、MySQL 利用者に対して C言語レベルでの API を提供するものです。

当然ながら MySQL は、php のみならず perlpythonruby などといった主だった動的言語から利用可能なわけですが、それらの言語から MySQL を利用するに当たって、大抵はこの libmysql を呼び出しています。

libmysql のおかげで、比較的簡単にさまざまな言語から MySQL が利用可能となっています。(とはいえ関数は結構多いので、使いこなすのはなかなか大変そうですが)

mysqlnd

一方、 mysqlnd というのは、MySQL Native Driver という、PHP の拡張モジュールとして実装された、MySQL のネイティブクライアントです。

libmysql を介さないため、 MySQL サーバから受け取ったデータをそのまま PHP の変数として表現することができ、オーバヘッドが減り、メモリも節約できるそうです。

ちょっと古いですが、より詳しい内容はこの辺。
http://derickrethans.nl/talks/andrey-mysqlnd.pdf


この mysqlnd 。PHP 拡張の中でも少々特殊で、この拡張そのものは PHP スクリプトから利用可能な関数をエクスポートせず、先に挙げた mysql / mysqli / pdo-mysql のバックエンドとして動作します。
(一部、今までの関数では足りなかったのか mysqli に追加の関数が発生しています。 mysqlnd の機能をフルに使いたい場合は mysqli を使うと良いのかも)

また、 mysqlnd 自体は php 5.3 のころからありましたが、利用するためにはコンパイル時に明示的に指定してやる必要がありました。 php5.4 からはこちらが標準となるため、今後利用が進むことでしょう。(とはいえ、普通の PHP スクリプトからしたら何ら変わることはないので、気づかない人も多いかも知れません)

リファレンスとか

MySQL 側だと、 http://dev.mysql.com/downloads/connector/php-mysqlnd/ や、http://dev.mysql.com/doc/refman/5.5/en/apis-php-mysqlnd.html

PHP 側だと http://www.php.net/manual/en/book.mysqlnd.php にあります。

まぁ、書いてある内容はほぼ同じなんですが。


ちょっと気になっているのが、 mysqlnd plugin という mysqlnd にプラガプルに機能を付け足せる仕組みです。既に、 load balancer (mysqlnd_ms) や client cache (mysqlnd_qc), 各種処理をフックするユーザハンドラ (mysqlnd_uh) といったプラグインがあります。

まだ試せていないので、実力のほどは分かりませんが。

ソースとか

php にバンドルされています。

展開後の ext/mysqlnd 以下に全て含まれています。

何というか、カオスです。 C言語MySQL通信プロトコルPHP 拡張の作法、PHP Stream など、知ってないと読めない部分が満載です。

ネイティブと言うだけあって、ソケット繋いでパケット解析して……というところからやってます。
ext/mysqlnd/mysqlnd_wireprotocol.c に 解析してるっぽい部分ありますけど、これ、頭痛くなりますね。

libmysql を触ったことがある方は、ext/mysqlnd/mysqlnd_libmysql_compat.h を見ると、libmysql のAPIを模倣している関数が分かりますので、
そこから追ってみるのがいいかもしれません。 (とはいえ、その先もマクロの嵐なので読み解くのは大変ですけど。)

このコード、一体どれだけの人がメンテできるんだ……。

まとめ

  • MySQL Casual Advent Calendar なのにほとんど PHP ネタでしたごめんなさい。
  • PHP が Native Driver 書いてるんだから、 PerlRuby でも Native Driver 俺が書いてやんよっていう猛者がいたら面白いなぁ。とか。
  • mysqlnd まじカオス!


ということで、まとめもいまいちまとまってないですが、ここいらでおしまい。

かじゅある!(挨拶)


次は、[twitter:@nekokak] さん (猫神様?)です

追記

PHP 以外での Native Driver について書きました。

*1:そしてたぶん唯一の