我有一个简单的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
仍然挂起。
那么,为什么OR
和c_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 | |
+----------------+--------------+------+-----+---------+-------+
它有两个索引:
- 仅
c_timestamp
上的idx_timestamp
索引 licenses
索引是(c_license_sign
,c_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
,但实际使用的key
是idx_timestamp
(为什么?(。
至少,如果有人遇到类似的问题,您可以尝试使用显式索引。