我有一个很大的表(大约30M行),它通常运行得很快(每个请求5-6ms).有时一个请求需要花费很多时间(大约60秒).

下面是表格 struct :

CREATE TABLE table (
  id int(11) NOT NULL,
  A int(11) NOT NULL,
  B varchar(32) NOT NULL,
  C tinyint(1) NOT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1;

ALTER TABLE `table`
  ADD PRIMARY KEY (id),
  ADD KEY A (A),
  ADD KEY B (B);

索引A的基数为2m,索引B的基数为1k.

我的请求是:

SELECT * FROM table
WHERE A = someAvalue
    AND B = 'some B value'
    AND C = 0
ORDER BY id DESC
LIMIT 1;

以及解释的结果:

id|select_type|table|type|possible_keys|key|key_len|ref  |rows|Extra 
1 |SIMPLE     |table|ref |A,B          |B  |34     |const|1   |Using index condition; Using where; Using filesort 

key_lenrows与本例无关,因为它来自示例查询

如果我删除AND C = 0个请求,则运行正常时间量.当索引A和B没有返回值时,这个请求似乎变得疯狂了.

所以这里我的问题是:为什么在这种情况下添加一个非索引字段可以使请求在60秒以上而不是几毫秒内运行?

推荐答案

有几个可能的原因可以解释这种行为:

  • 索引效率降低:您的查询最初使用的是列A和列B上的索引.然而,当您添加非索引条件C=0时,数据库不再能够有效地仅使用索引来筛选行.它必须判断与A和B上的条件匹配的每一行的C列.这个过程可能很耗时,特别是在匹配A和B的行数很大的情况下.

  • 全表扫描或逐行过滤:由于C没有索引,因此数据库可能会在使用A和B进行过滤后执行全表扫描或逐行判断,这会显著增加查询时间,尤其是对于像您这样的大表.

  • 查询执行计划更改:包含非索引字段可能会更改数据库的查询优化器生成的执行计划.优化器可能会 Select 效率较低的路径,因为在非索引字段上进行筛选会增加复杂性.

  • 用于排序的文件排序:EXPLAIN输出指示使用"使用文件排序",这是一个可能很慢的操作,尤其是在处理大型中间结果集时.有了额外的非索引字段,排序操作变得更加复杂.

  • 资源使用效率低下:当添加额外条件时,查询可能需要更多内存和CPU时间来处理额外的筛选和排序,这可能会减慢资源受限环境中的执行速度.

  • 数据偏斜:如果C中的值的分布偏斜(即,只有极少数的行具有C = 0),数据库可能最终会扫描表的很大一部分来找到相关的行,从而导致更长的执行时间.

Mysql相关问答推荐

Mysql-查找缺少列的表

无法确定查询逻辑

数据导入和默认目标架构空列表. (Mysql 工作台 8)

根据 MySql 中同一表中的多列 Select 多列

如何在 MySQL 中使用从 SELECT IF 返回的布尔值

我在 mysql 查询中需要帮助,我想在年龄之间按年龄过滤器分组,并显示 0 计数之间找不到的数据

相关查询 - 在派生表中,我可以有多个嵌套级别吗?

正则表达式模式相当于 mysql 中的 %word%

mySQL 中的主数据库和 IF 错误?

MariaDB 下的慢速更新、删除和插入查询

MySQL函数查找两个日期之间的工作日数

如何使用 phpmyadmin 复制数据库?

MySQL Workbench 无法加载 mysql.proc

在 PHP/MySQL 中将日期时间存储为 UTC

从 MySQL JSON 数据类型中提取不带引号的值

你能推荐一个免费的 Linux 轻量级 MySQL GUI 吗?

MySQL更新查询与左连接和分组依据

为什么在 MySQL 中使用外键约束?

数据截断:第 1 行的logo列数据太长

邮箱地址可接受的字段类型和大小?