2026-11-03,
I’m reposting something I wrote on my old blog. (Original post)
The RAND() function in MySQL returns a floating-point value greater than or equal to 0 and less than 1.0 when no seed is specified. Under no circumstances does it generate a random value greater than or equal to 1.0.
Internally, MySQL uses a maximum value of 1073741823 when generating random numbers. The seed value is subjected to a modulo operation using this maximum value. If the seed exceeds 32 bits, an additional modulo operation with 2^32 is performed. Therefore, regardless of how large the seed value is, the RAND() function is ultimately constrained by the maximum value used in the random number generation process.
Let’s take a closer look at how random numbers are calculated, distinguishing between cases where a seed is provided and where no seed is specified.
Although the following explanation focuses primarily on the code involved in the random number generation process, it should not be difficult to understand if you read through it carefully.
When a Seed Value Is Provided
The seed value passed as an argument to the RAND() function is calculated and managed using a random number structure(rand structure).
SELECT RAND(123.11)
When a seed value of 123.11 is passed as shown above, the random value generated by the RAND() function is calculated through the following steps.
1) item_func.cc:Item_func_rand::seed_random
void Item_func_rand::seed_random(Item *arg) {
/*
TODO: do not do reinit 'rand' for every execute of PS/SP if
args[0] is a constant.
*/
const uint32 tmp = (uint32)arg->val_int();
randominit(m_rand, (uint32)(tmp * 0x10001L + 55555555L),
(uint32)(tmp * 0x10000001L));
}
Line 6
- tmp: 123(Converted to an unsigned positive integer and assigned to the
tmpvariable.)
Line 7
- m_rand: A pointer to the
rand_structtype(Memory is allocated inItem_func.cc:Item_func_rand::fix_fields. Refer toitem_func.hfor the structure definition.) - (uint32)(tmp * 0x10001L + 55555555L): 63616606 → First seed value(Multiplying the seed value
123by0x10001and adding55555555appears to be part of the random number generation algorithm.) - (uint32)(tmp * 0x10000001L): 2952790139 → Second seed value
- randominit: Random number generator initialization
-> The seed value 123.11 is converted to a 32-bit unsigned integer. Two seed values are then calculated using different formulas and passed to the random number generator initialization function. If the provided seed value exceeds the maximum value representable by a 64-bit integer, it is capped at the maximum 64-bit value (silent overflow).
2) password.cc:randominit
void randominit(struct rand_struct *rand_st, ulong seed1,
ulong seed2) { /* For mysql 3.21.# */
rand_st->max_value = 0x3FFFFFFFL;
rand_st->max_value_dbl = (double)rand_st->max_value;
rand_st->seed1 = seed1 % rand_st->max_value;
rand_st->seed2 = seed2 % rand_st->max_value;
}
Line 1
- rand_st: Initializes the random number structure pointed to by
m_randthroughrand_st.
Line 3
- rand_st->max_value: 1073741823 (2^30 – 1)(Sets the maximum value limit for the random number structure.)
Line 4
- rand_st->max_value_dbl: 1073741823(Converts the maximum random number value to the
doubletype and stores it.)
Lines 5 and 6
- rand_st->seed1: 63616606 % 1073741823 = 63616606
- rand_st->seed2: 2952790139 % 1073741823 = 805306493
-> The seed values and the maximum value used for random number generation are initialized in the random number structure. These initialized values are subsequently used during the actual random number generation process.
3) item_func.cc:Item_func_rand::var_real
double Item_func_rand::val_real() {
assert(fixed);
rand_struct *rand;
if (arg_count > 0) {
if (!args[0]->const_for_execution())
seed_random(args[0]);
else if (first_eval) {
/*
Constantness of args[0] may be set during JOIN::optimize(), if arg[0]
is a field item of "constant" table. Thus, we have to evaluate
seed_random() for constant arg there but not at the fix_fields method.
*/
first_eval = false;
seed_random(args[0]);
}
rand = m_rand;
} else {
/*
Save the seed only the first time RAND() is used in the query
Once events are forwarded rather than recreated,
the following can be skipped if inside the slave thread
*/
THD *const thd = current_thd;
if (!thd->rand_used) {
thd->rand_used = true;
thd->rand_saved_seed1 = thd->rand.seed1;
thd->rand_saved_seed2 = thd->rand.seed2;
}
rand = &thd->rand;
}
return my_rnd(rand);
}
Line 16
- rand: Assigns the random number structure pointed to by
m_randto therandstructure pointer declared on Line 3.
Line 31
- my_rnd(rand): Passes the
randpointer as an argument to themy_rndfunction.
-> Calls the my_rnd function to generate a random number.
4) my_rnd.cc:my_rnd
double my_rnd(struct rand_struct *rand_st) {
rand_st->seed1 = (rand_st->seed1 * 3 + rand_st->seed2) % rand_st->max_value;
rand_st->seed2 = (rand_st->seed1 + rand_st->seed2 + 33) % rand_st->max_value;
return (((double)rand_st->seed1) / rand_st->max_value_dbl);
}
Line 2, 3
- rand_st->seed1: (63616606 * 3 + 805306493) % 1073741823 = 996156311
- rand_st->seed2: (996156311 + 805306493 + 33) % 1073741823 = 727721014
Line 4
- return: 996156311 / 1073741823 = 0.92774286114400517 ≒ 0.9277428611440052
mysql> SELECT RAND(123.11);
+--------------------+
| RAND(123) |
+--------------------+
| 0.9277428611440052 |
+--------------------+
→ The first and second seed values are used to generate a single final random number. Since the result of a modulo operation cannot be greater than or equal to the divisor, the seed1 and seed2 values used in random number generation must always be smaller than the maximum random number value. Furthermore, because the seed value is divided by the maximum random number value (i.e., a smaller value is divided by a larger value), the result can never be greater than or equal to 1.
Therefore, the generated random number always falls within the range 0 ≤ a < 1.
When No Seed Value Is Provided
The process is similar when no seed value is provided, but there are some minor differences.
SELECT RAND();
< On the First Execution >
1) sql_class.cc:randominit
auto_inc_intervals_forced.clear();
{
ulong tmp;
tmp = sql_rnd_with_mutex();
randominit(&rand,
tmp + static_cast<ulong>(reinterpret_cast<uintptr_t>(&rand)),
tmp + (ulong)::atomic_global_query_id);
}
Line 1
- auto_inc_intervals_forced.clear(): When a query is executed, the THD object is initialized through
THD::init. During this process, therandstructure member variable within the object is initialized.
Line 4
- tmp: 47641308128(A random number is generated by the
sql_rnd_with_mutexfunction inmysqld.ccand assigned to thetmpvariable.)
ulong sql_rnd_with_mutex() {
mysql_mutex_lock(&LOCK_sql_rand);
ulong tmp =
(ulong)(my_rnd(&sql_rand) * 0xffffffff); /* make all bits random */
mysql_mutex_unlock(&LOCK_sql_rand);
return tmp;
}
Lines 5, 6, and 7
- tmp + static_cast<ulong>(reinterpret_cast<uintptr_t>(&rand)): 663490581(Converts the memory address of the
randstructure pointer to an integer, adds it to thetmpvariable, and generates the first seed value used for random number generation.) - tmp + (ulong)::atomic_global_query_id: 266834210(Adds the globally unique query ID to the
tmpvariable to generate the second seed value used for random number generation.)
(lldb) p rand
(rand_struct) $346 = (seed1 = 663490581, seed2 = 266834210, max_value = 1073741823, max_value_dbl = 1073741823)
2) mysql_rnd.cc:my_rnd
double my_rnd(struct rand_struct *rand_st) {
rand_st->seed1 = (rand_st->seed1 * 3 + rand_st->seed2) % rand_st->max_value;
rand_st->seed2 = (rand_st->seed1 + rand_st->seed2 + 33) % rand_st->max_value;
return (((double)rand_st->seed1) / rand_st->max_value_dbl);
}
Line 1, 2
- rand_st->seed1: (663490581 * 3 + 266834210) % 1073741823 = 109822307
- rand_st->seed2: (109822307 + 266834210 + 33) % 1073741823 = 376656550
Line 3
- return: (109822307 / 1073741823) = 0.10227999380070715
mysql> SELECT RAND();
+---------------------+
| rand() |
+---------------------+
| 0.10227999380070715 |
+---------------------+
(lldb) p thd->rand
(rand_struct) $368 = (seed1 = 109822307, seed2 = 376656550, max_value = 1073741823, max_value_dbl = 1073741823)
→ When no seed value is provided, the randominit function in sql_class.cc is called only once during initialization. The two seed values used for random number generation are stored in the thread’s rand member variable and used as the initial seed values for the next call to the RAND() function. The seed values are updated and stored each time the RAND() function is called, as long as the server connection remains active.
< On the Second Execution >
SELECT RAND();
1) item_func.cc:Item_func_rand::fix_fields
bool Item_func_rand::fix_fields(THD *thd, Item **ref) {
if (Item_real_func::fix_fields(thd, ref)) return true;
if (arg_count > 0) { // Only use argument once in query
/*
Allocate rand structure once: we must use thd->stmt_arena
to create rand in proper mem_root if it's a prepared statement or
stored procedure.
No need to send a Rand log event if seed was given eg: RAND(seed),
as it will be replicated in the query as such.
*/
assert(m_rand == nullptr);
m_rand = pointer_cast<rand_struct *>(thd->alloc(sizeof(*m_rand)));
if (m_rand == nullptr) return true;
} else {
/*
Save the seed only the first time RAND() is used in the query
Once events are forwarded rather than recreated,
the following can be skipped if inside the slave thread
*/
if (!thd->rand_used) {
thd->rand_used = true;
thd->rand_saved_seed1 = thd->rand.seed1;
thd->rand_saved_seed2 = thd->rand.seed2;
}
}
return false;
}
Lines 22 and 23
- By dereferencing the object pointed to by the
thdpointer, we can confirm that theseed1andseed2values are stored in therandmember variable.
(lldb) frame variable thd->rand
(rand_struct) thd->rand = (seed1 = 109822307, seed2 = 376656550, max_value = 1073741823, max_value_dbl = 1073741823)
- thd->rand_saved_seed1: 109822307
- thd->rand_saved_seed2: 376656550
→ The thread’s seed value stored in the previous step is assigned to the thread’s saved seed variable (rand_saved_seed1).
2) item_func.cc:Item_func_rand::val_real
double Item_func_rand::val_real() {
assert(fixed);
rand_struct *rand;
if (arg_count > 0) {
if (!args[0]->const_for_execution())
seed_random(args[0]);
else if (first_eval) {
/*
Constantness of args[0] may be set during JOIN::optimize(), if arg[0]
is a field item of "constant" table. Thus, we have to evaluate
seed_random() for constant arg there but not at the fix_fields method.
*/
first_eval = false;
seed_random(args[0]);
}
rand = m_rand;
} else {
/*
Save the seed only the first time RAND() is used in the query
Once events are forwarded rather than recreated,
the following can be skipped if inside the slave thread
*/
THD *const thd = current_thd;
if (!thd->rand_used) {
thd->rand_used = true;
thd->rand_saved_seed1 = thd->rand.seed1;
thd->rand_saved_seed2 = thd->rand.seed2;
}
rand = &thd->rand;
}
return my_rnd(rand);
}
Line 24
- thd->rand_used: Since this variable was set to
trueinItem_func_rand::fix_fields, theifstatement is skipped.
Line 29
- rand: Assigns the memory address of the
randmember variable pointed to bythdto therandstructure pointer.(Therand->seed1andrand->seed2values are updated.)
Line 31
- my_rnd(rand): rand->seed1: 109822307, rand->seed2: 376656550(Passes the
randpointer as an argument to themy_rndfunction.)
-> The memory address is assigned so that the rand structure pointer of type rand_struct points to thd->rand, and the pointer is then passed as an argument to the my_rnd function.
3) my_rnd.cc:my_rnd
double my_rnd(struct rand_struct *rand_st) {
rand_st->seed1 = (rand_st->seed1 * 3 + rand_st->seed2) % rand_st->max_value;
rand_st->seed2 = (rand_st->seed1 + rand_st->seed2 + 33) % rand_st->max_value;
return (((double)rand_st->seed1) / rand_st->max_value_dbl);
}
Line 2, 3
- rand_st->seed1: (109822307 * 3 + 376656550) % 1073741823 = 706123471
- rand_st->seed2: (706123471 + 376656550 + 33) % 1073741823 = 9038231
Line 4
- return: 706123471 / 1073741823 = 0.6576287296206027
mysql> SELECT RAND();
+--------------------+
| rand() |
+--------------------+
| 0.6576287296206027 |
+--------------------+
→ When no seed value is provided, random numbers are generated through two distinct stages, as described above: the initial execution and subsequent executions.
Conclusion
Regardless of whether a seed value is provided to the RAND() function, the two internally calculated seed values are subjected to modulo operations using the maximum random number value. The resulting values are then divided by the same maximum value. Consequently, the generated random number can never be greater than or equal to 1.
When a seed value is provided, the random number generation process involves no unpredictable factors other than the specified seed value. Therefore, the same seed value always produces the same random number.
When no seed value is provided, the initial execution generates a random number using thread-specific seed values. On subsequent executions, random numbers are generated using the seed values from the previous operation (the values used in the preceding RAND() calculation). As a result, the seed values are not fixed, and different random numbers are generated on successive calls.

답글 남기기