MySQL の RAND 関数の引数

MySQL の RAND 関数の引数の意味がよくわからなかったので色々試してみました。
MySQL :: MySQL 5.1 リファレンスマニュアル :: 11.4.2 数学関数


引数に定数を与えて複数回呼び出すと毎回同じ値が返されます。同じシードで初期化していることになるので当然です。

mysql> SELECT RAND(1);
  -> 0.40540353712197724

mysql> SELECT RAND(1);
  -> 0.40540353712197724

mysql> SELECT RAND(1);
  ->  0.40540353712197724


引数に定数を与えて呼び出した後、引数なしで呼び出すと・・・引数無しの呼び出しは反復しません。

mysql> SELECT RAND(1);
  -> 0.40540353712197724

mysql> SELECT RAND();
  -> 0.7938656181039899

mysql> SELECT RAND();
  -> 0.7477519910295978

mysql> SELECT RAND(1);
  -> 0.40540353712197724

mysql> SELECT RAND();
  -> 0.3571631315696641

mysql> SELECT RAND();
  -> 0.5425597154931722


MySQLのリファレンスをよく読むと・・・

定数イニシャライザを使用すれば、シードは実行の前の、ステートメントがコンパイルされる際に一度初期化されます。

とあるので、次のように実行してみました(userは数件のレコードを持つテーブル)。

mysql> SELECT RAND(1) FROM user;
  -> 0.40540353712197724
  -> 0.8716141803857071
  -> 0.1418603212962489
  -> 0.09445909605776807
  -> 0.04671454713373868
  -> 0.9501954782290342
  -> 0.6108337804776
  -> 0.2035824984345422
  -> 0.18541118147355615

つまり RAND(N) を含む SQL を実行するときは、SQL をコンパイル(prepare)したときだけシートが初期化され、実際に RAND が SELECT で実行されるときにはコンパイル時に初期化された乱数生成器が使用される、ということなのだと思います。


RANDがSQLの中に複数現れる場合は次のようになります。

mysql> SELECT RAND(1), RAND(2) FROM user;
  -> 0.40540353712197724  0.6555866465490187
  -> 0.8716141803857071   0.12234661925802624
  -> 0.1418603212962489   0.64497318737672
  -> 0.09445909605776807  0.8578261098431667
  -> 0.04671454713373868  0.354211017819318
  -> 0.9501954782290342   0.19757679030073508
  -> 0.6108337804776      0.9252509287793663
  -> 0.2035824984345422   0.03352430372827156
  -> 0.18541118147355615  0.3918687630369037

この場合はコンパイル時に初期化された RAND(1) と RAND(2) がそれぞれ反復可能な乱数を生成しているようです。


所謂普通のプログラミング言語擬似乱数関数では考えにくい動作なので、理解に少し時間がかかりました。