为什么当使用OR运算符将条件组合在一起时,这个简单的SELECT MySQL查询会挂起



我有一个简单的MySQL查询,它神秘地永远挂起。

查询#1以下查询有效(仅使用第一个许可证(,并按预期返回空集。

SELECT c_desc, c_timestamp FROM t_usage WHERE c_license_sign='license001' ORDER BY c_timestamp DESC limit 1;


查询#2以下查询有效(仅使用第二个许可证(,并按预期返回1行。

SELECT c_desc, c_timestamp FROM t_usage WHERE c_license_sign='license002' ORDER BY c_timestamp DESC limit 1;


查询#3下面的查询永远挂起(使用"第一个许可证OR第二个许可证"(,我必须使用Ctrl+C才能退出。尽管挂起时CPU和内存使用量似乎都没有增加。

SELECT c_desc, c_timestamp FROM t_usage WHERE c_license_sign='license001' OR
c_license_sign='license002' ORDER BY c_timestamp DESC limit 1;

这是查询#3 的EXPLAIN

+------+-------------+---------+-------+---------------+---------------+---------+------+------+-------------+
| id   | select_type | table   | type  | possible_keys | key           | key_len | ref  | rows | Extra       |
+------+-------------+---------+-------+---------------+---------------+---------+------+------+-------------+
|    1 | SIMPLE      | t_usage | index | licenses      | idx_timestamp | 6       | NULL |  706 | Using where |
+------+-------------+---------+-------+---------------+---------------+---------+------+------+-------------+


查询#4但是,此查询有效(使用OR但删除了c_desc(,并按预期返回1行。

SELECT c_timestamp FROM t_usage WHERE c_license_sign='license001' OR
c_license_sign='license002' ORDER BY c_timestamp DESC limit 1;

保持c_desc和移除c_timestamp仍然挂起。


那么,为什么ORc_desc在一起会导致挂起呢

这就是表模式(我删除了一些不必要的列(。没有主键(预期(。它有超过150万张唱片。

+----------------+--------------+------+-----+---------+-------+
| Field          | Type         | Null | Key | Default | Extra |
+----------------+--------------+------+-----+---------+-------+
| c_custid       | int(11)      | YES  |     | NULL    |       |
| c_license_sign | varchar(255) | YES  | MUL | NULL    |       |
| c_desc         | longtext     | YES  |     | NULL    |       |
| c_timestamp    | datetime     | YES  | MUL | NULL    |       |
+----------------+--------------+------+-----+---------+-------+

它有两个索引:

  1. c_timestamp上的idx_timestamp索引
  2. licenses索引是(c_license_signc_timestamp(上的复合索引

我使用mysql版本15.1 Distrib 10.3.31-MariaDB,用于Linux(x86_64(,使用readline 5.1

如果您总是要获取最新记录,最好在licences索引的c_timestamp列中添加DESC

INDEX licences (c_license_sign, c_timestamp DESC)

我想在找到解决方案后回答我自己的问题。解决方案:使用显式索引。有效的查询是

SELECT c_desc, c_timestamp FROM t_usage USE INDEX(licenses)
WHERE c_license_sign='license001' OR c_license_sign='license002'
ORDER BY c_timestamp DESC limit 1;

显式使用其他索引(idx_timestamp(将以与不使用显式索引相同的方式挂起。

不幸的是,我无法解释原因。可以用作提示的是EXPLAIN结果。它说possible_keys只是licenses,但实际使用的keyidx_timestamp(为什么?(。

至少,如果有人遇到类似的问题,您可以尝试使用显式索引。

最新更新