运行以下查询时:
SELECT productid
FROM product
WHERE productid=ROUND(RAND()*(SELECT MAX(productid) FROM product));
结果应该是0或1个结果(0表示由于数据缺口,如果找到记录则为1),但是它会导致多次结果很多次(很容易重现,90%的查询超过1结果)。
示例输出:
+-----------+
| productid |
+-----------+
| 11701 |
| 20602 |
| 22029 |
| 24994 |
+-----------+
(DB中的记录数约为30k)。
运行单个SELECT RAND()
始终会产生一个结果。
说明:
explain SELECT productid FROM product WHERE productid=ROUND(RAND()*(SELECT MAX(productid) FROM product));
+----+-------------+---------+------------+-------+---------------+--------------+---------+------+-------+----------+------------------------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+---------+------------+-------+---------------+--------------+---------+------+-------+----------+------------------------------+
| 1 | PRIMARY | product | NULL | index | NULL | idx_prod_url | 2003 | NULL | 31197 | 10.00 | Using where; Using index |
| 2 | SUBQUERY | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL | Select tables optimized away |
+----+-------------+---------+------------+-------+---------------+--------------+---------+------+-------+----------+------------------------------+
谁可以解释这种行为?
跟进: 按照Martin的评论重写了以下内容:
SELECT productid FROM product
WHERE productid=(SELECT ROUND(RAND()*(SELECT MAX(productid) FROM product)));
说明:
explain SELECT productid FROM product WHERE productid=(SELECT ROUND(RAND()*(SELECT MAX(productid) FROM product)));
+----+----------------------+---------+------------+-------+---------------+--------------+---------+------+-------+----------+------------------------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+----------------------+---------+------------+-------+---------------+--------------+---------+------+-------+----------+------------------------------+
| 1 | PRIMARY | product | NULL | index | NULL | idx_prod_url | 2003 | NULL | 31197 | 100.00 | Using where; Using index |
| 2 | UNCACHEABLE SUBQUERY | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL | No tables used |
| 3 | SUBQUERY | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL | Select tables optimized away |
+----+----------------------+---------+------------+-------+---------------+--------------+---------+------+-------+----------+------------------------------+
然而,尽管计划已经改变,但行为保持不变。
跟进2 :
使用INNER JOIN
,行为消失:
SELECT a.productid FROM product a
INNER JOIN (SELECT ROUND(RAND()*(SELECT MAX(productid))) as productid
FROM product) b ON a.productid=b.productid;
说明:
explain SELECT a.productid FROM product a INNER JOIN (SELECT ROUND(RAND()*(SELECT MAX(productid))) as productid FROM product) b ON a.productid=b.productid;
+----+--------------------+------------+------------+--------+---------------+--------------+---------+-------+-------+----------+----------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+--------------------+------------+------------+--------+---------------+--------------+---------+-------+-------+----------+----------------+
| 1 | PRIMARY | <derived2> | NULL | system | NULL | NULL | NULL | NULL | 1 | 100.00 | NULL |
| 1 | PRIMARY | a | NULL | const | PRIMARY | PRIMARY | 4 | const | 1 | 100.00 | Using index |
| 2 | DERIVED | product | NULL | index | NULL | idx_prod_url | 2003 | NULL | 31197 | 100.00 | Using index |
| 3 | DEPENDENT SUBQUERY | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL | No tables used |
+----+--------------------+------------+------------+--------+---------------+--------------+---------+-------+-------+----------+----------------+
答案 0 :(得分:0)
试试这个:
SELECT productid
FROM product
ORDER BY rand() LIMIT 1;
有关其他随机选择选项,请参阅MySQL Select Random Records。
答案 1 :(得分:0)
说明:
执行原始帖子中的查询时,Maria说:“我需要查看表,产品中的数据,所以让我从第一行开始。然后,“让我检查WHERE子句以查看是否应使用此行。”那时,Maria计算一个随机数,然后将其乘以最大乘积,然后将其舍入为整数。她检查该整数是否等于第一行中的productid。如果不是,那么她会忘记该行。如果是这样,那么她从该行中选择productid并保留它。无论哪种方式,她都将继续前进到第二行。她计算了一个(新的)随机数,将其乘以最大的产品编号,然后检查它是否等于第二行中的产品编号。如果没有,她继续前进。如果是这样,她会将该产品ID添加到她的选定值列表中。她在第三行上做同样的事情,等等。然后,最终输出是一个零到MAX(productid)个productid值的列表,每个值都以1 / MAX(productid)的概率独立选择。
执行来自后续2的查询时,联接的左侧只是一个表。对于连接的右侧,Maria表示:“我需要查看产品表中的数据。由于没有WHERE子句,因此我将查看整个表。哦,我有一个聚合函数MAX( productid),在SELECT子句中。那给了我整个表中的一个值。”她计算一个随机数并将其乘以该值,从而创建一个表b,该表b由单列productid和一行组成。然后,将该表与表product进行内部连接,以查找具有匹配productid的每一行,该行恰好是一行,然后选择该行中的productid。
请注意,如果您要查找的只是productid,而您不需要选定行中的任何其他数据,那么联接的右侧就是您所需要的。
SELECT ROUND(RAND()*(SELECT MAX(productid))) as productid from product;
还请注意,ROUND可能不是您要尝试执行的正确功能。这可能就是您真正想要的:
SELECT FLOOR(1+RAND()*(SELECT MAX(productid))) as productid from product;