mariadb 为什么我选择索引字段和非索引字段有时需要很长时间

hfyxw5xn  于 12个月前  发布在  其他
关注(0)|答案(3)|浏览(203)

我有一个很大的表(大约30 M行),它通常运行得很快(每个请求5- 6 ms)。有时一个请求需要很多时间(大约60秒)。
这里的表结构:

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的基数为2 M,索引B的基数为1 k。
我的请求是:

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秒以上而不是几毫秒内运行?

9bfwbjaz

9bfwbjaz1#

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

  • 索引效率损失:您的查询最初使用的是列A和B上的索引。但是,当您添加非索引条件C = 0时,数据库无法再仅使用索引有效地筛选行。它必须检查C列中与A和B上的条件匹配的每一行。此过程可能很耗时,尤其是在与A和B匹配的行数很大的情况下。
  • 全表扫描或逐行过滤:由于C没有索引,数据库可能会在使用A和B进行过滤后执行全表扫描或逐行检查,从而显著增加查询时间,特别是对于像您这样的大表。
  • 查询执行计划更改:包含非索引字段可能会更改数据库查询优化器生成的执行计划。由于在非索引字段上进行筛选会增加复杂性,优化器可能会选择效率较低的路径。
  • 用于排序的文件排序:EXPLAIN输出指示使用了“Using filesort”,这是一个可能很慢的操作,特别是当它处理大型中间结果集时。使用额外的非索引字段,排序操作变得更加复杂。
  • 资源利用效率低下:当您添加额外的条件时,查询可能需要更多的内存和CPU时间来处理额外的筛选和排序,这可能会降低资源受限环境中的执行速度。
  • 数据偏斜:如果C中的值的分布是倾斜的(即,只有很少的行具有C = 0),则数据库可能最终扫描表的很大一部分以找到相关的行,从而导致更长的执行时间。
f8rj6qna

f8rj6qna2#

为什么我选择索引字段和非索引字段有时需要很长时间?
第一个重要的问题是MyISAM存储引擎的使用,请切换到InnoDB。MyISAM只支持表锁,即使是select语句。
参见What are the main differences between InnoDB and MyISAM?
然后在你的表上添加以下索引。

alter table your_table add index c_a_b(C,A,B)

字符串

erhoui1w

erhoui1w3#

Ekans,策略性放置的括号使用应避免C = 0的表扫描。
SELECT * FROM my_table WHERE(A = someAvalue AND B = 'some B value')AND C = 0 ORDER BY id DESC LIMIT 1;
请验证您的MySQL版本,并让我们知道这个解决方案需要多长时间。
并张贴解释请比较。

相关问题