【问题标题】:Why would an indexed column return results slowly when querying for `IS NULL`?为什么查询“IS NULL”时,索引列返回结果很慢?
【发布时间】:2014-10-07 09:33:36
【问题描述】:

我有一个包含 2500 万行的表,并有适当的索引。

但是添加子句AND status IS NULL 会将超快查询变成疯狂的慢查询。

请帮我加快速度。

查询:

SELECT 
    student_id,
    grade,
    status
FROM 
    grades
WHERE 
        class_id = 1
    AND status IS NULL       -- This line delays results from <200ms to 40-70s!
    AND grade BETWEEN 0 AND 0.7
LIMIT 25;

表:

CREATE TABLE IF NOT EXISTS `grades` (
  `student_id` BIGINT(20) NOT NULL,
  `class_id` INT(11) NOT NULL,
  `grade` FLOAT(10,6) DEFAULT NULL,
  `status` INT(11) DEFAULT NULL,
  UNIQUE KEY `unique_key` (`student_id`,`class_id`),
  KEY `class_id` (`class_id`),
  KEY `status` (`status`),
  KEY `grade` (`grade`)
) ENGINE=INNODB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

本地开发会立即显示结果(

你能指出正确的调试方向吗?

解释:

+----+-------------+--------+-------------+-----------------------+-----------------+---------+------+-------+--------------------------------------------------------+
| id | select_type | table  | type        | possible_keys         | key             | key_len | ref  | rows  | Extra                                                  |
+----+-------------+--------+-------------+-----------------------+-----------------+---------+------+-------+--------------------------------------------------------+
|  1 | SIMPLE      | grades | index_merge | class_id,status,grade | status,class_id | 5,4     | NULL | 26811 | Using intersect(status,class_id); Using where          |
+----+-------------+--------+-------------+-----------------------+-----------------+---------+------+-------+--------------------------------------------------------+

【问题讨论】:

  • explain select ... 输出什么?
  • @juergend 在上面添加了解释。
  • 请注意,没有 ORDER BY 的 LIMIT 几乎没有意义
  • 并将 FLOAT 更改为 DECIMAL
  • ORDER BY 加快查询备份的事实,虽然本身是一个很好的建议,但并不是问题的答案.. 不要依赖它来加速将来的类似查询.

标签: mysql sql optimization null query-optimization


【解决方案1】:

SELECT 语句每个表只能使用一个索引。

大概之前的查询刚刚使用唯一索引class_id 对您的条件class_id=1 进行了扫描。这可能会在检查其他条件之前很好地过滤您的结果集。

优化器“错误地”为第二个查询选择了 class_idstatus 上的索引合并,并检查了 26811 行,这可能不是最佳的。您可以通过将USING INDEX (class_id) 添加到FROM 子句的末尾来暗示class_id 索引。 您可能会对(class_id,status,grade) 上的复合索引感到高兴,它可以更快地运行查询,因为它可以匹配前两个,然后对grade 进行范围扫描。不过,我不确定这如何与 null 一起使用。

我猜ORDER BY 推动优化器再次选择class_id 索引并将您的查询返回到原来的速度。

【讨论】:

    猜你喜欢
    • 2020-05-04
    • 1970-01-01
    • 2013-11-11
    • 1970-01-01
    • 2021-09-03
    • 2014-09-17
    • 2021-12-11
    • 1970-01-01
    • 2014-09-24
    相关资源
    最近更新 更多