MySQL:为什么将主键与随机生成的数字进行比较时不使用索引?

MySQL:为什么将主键与随机生成的数字进行比较时不使用索引?,mysql,Mysql,尝试根据无孔的自动递增主键从表中选择随机行 表架构: 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` (`

尝试根据无孔的自动递增主键从表中选择随机行

表架构:

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/解释从测试表中选择*,其中id=CEILR和*10限制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/解释从测试表中选择*,其中id=7限制1

结果:

| ID | SELECT_TYPE |     TABLE |  TYPE | POSSIBLE_KEYS |     KEY | KEY_LEN |   REF | ROWS | EXTRA |
---------------------------------------------------------------------------------------------------
|  1 |      SIMPLE | testTable | const |       PRIMARY | PRIMARY |       4 | const |    1 |       |

为什么query1不使用索引,而ceilrand*10的计算结果最好是一个常数,然后可以与主键进行比较?优化器不应该这样工作吗?或者我在这里遗漏了一些明显的东西。

该键不能用于该查询,因为对每一行调用RAND,每次都返回不同的值

您可以尝试以下代码:

SET @rand_value := CEIL(RAND()*10);
EXPLAIN SELECT * FROM testTable WHERE id = @rand_value;
它首先计算一个随机值并将其分配给一个变量,然后在查询中使用它。 正如aneroid所指出的,限制1是无用的:因为条件应用于主键,所以查询永远不会返回超过一行

通过此查询,输出为:

| ID | SELECT_TYPE |     TABLE |  TYPE | POSSIBLE_KEYS |     KEY | KEY_LEN |   REF | ROWS | EXTRA |
---------------------------------------------------------------------------------------------------
|  1 |      SIMPLE | testTable | const |       PRIMARY | PRIMARY |       4 | const |    1 |       |
从:

每次执行WHERE时,都会重新计算WHERE子句中的RAND

因此,它不是将主键与常量进行比较,而是在本例中,每一行的每次值都在变化。如果删除查询中的限制1,您将看到更多行出现不同的匹配PK,这显示了每次重新评估的行为


编辑:请参阅Jocelyn的示例,作为一种先生成随机数,然后获取具有匹配PK id的行的方法。不需要限制1,顺便说一句,Najzero的评论中也有类似的说明。

在ceil/rand等条件导致系统首先获取所有行的情况下使用函数,以便能够将结果与该函数的每个结果进行比较。您最好使用外部选择获取随机整数值,然后使用它获取主键。+1是推荐用法的好例子。在这种情况下,由于id是主键,因此不需要限制1:-