尝试从表中选择一个随机行,基于没有孔的自动增量主键。
表架构:
CREATE TABLE IF NOT EXISTS `testTable` (
`id` int(9) NOT NULL AUTO_INCREMENT,
`data` varchar(100) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=0 ;
INSERT INTO `testTable` (`id`, `data`) VALUES
(1, 'hello'),
(2, 'world'),
(3, 'new'),
(4, 'data'),
(5, 'more and more'),
(6, 'data '),
(7, 'more rows here'),
(8, 'most rows here'),
(9, 'testing'),
(10,'last');
查询:
1 / explain select * from testTable where id = ceil(Rand()*10) limit 1 ;
http://sqlfiddle.com/#!2/6e2b1/1
结果:
| ID | SELECT_TYPE | TABLE | TYPE | POSSIBLE_KEYS | KEY | KEY_LEN | REF | ROWS | EXTRA |
--------------------------------------------------------------------------------------------------------
| 1 | SIMPLE | testTable | ALL | (null) | (null) | (null) | (null) | 10 | Using where |
2 / explain select * from testTable where id = 7 limit 1 ;
http://sqlfiddle.com/#!2/6e2b1/2
结果:
| ID | SELECT_TYPE | TABLE | TYPE | POSSIBLE_KEYS | KEY | KEY_LEN | REF | ROWS | EXTRA |
---------------------------------------------------------------------------------------------------
| 1 | SIMPLE | testTable | const | PRIMARY | PRIMARY | 4 | const | 1 | |
为什么查询#1不使用索引,ceil(rand()*10)
理想情况下应该评估为一个常数,然后可以与主键进行比较?优化器不应该这样工作吗?或者我错过了一些明显的东西。
答案 0 :(得分:6)
密钥不能与该查询一起使用,因为每行调用RAND()
并且每次都返回不同的值。
您可以尝试使用此代码:
SET @rand_value := CEIL(RAND()*10);
EXPLAIN SELECT * FROM testTable WHERE id = @rand_value;
首先计算随机值并将其分配给变量,然后在查询中使用它
正如aneroid所指出的,LIMIT 1
是无用的:因为条件适用于主键,所以查询永远不会返回多行。
使用此查询,输出为:
| ID | SELECT_TYPE | TABLE | TYPE | POSSIBLE_KEYS | KEY | KEY_LEN | REF | ROWS | EXTRA |
---------------------------------------------------------------------------------------------------
| 1 | SIMPLE | testTable | const | PRIMARY | PRIMARY | 4 | const | 1 | |
答案 1 :(得分:3)
来自MySQL documentation for RAND()
:
每次RAND()
时,WHERE
子句中的WHERE
会重新评估执行。
所以它不是将主键与常量进行比较,它每次都是一个变化的值(在这种情况下,对于每一行)。如果您删除查询中的LIMIT 1
,您会看到更多的行与不同的PK匹配 - 显示“每次重新评估”行为。
编辑:请参阅Jocelyn的示例,首先生成随机数,然后获得匹配PK id
的行(不需要LIMIT 1
,btw)。同样在Najzero的评论中说明。