MySql 优化器不使用 varchar 上的索引
MySql optimizer doesn't use the index on varchar
我有一个 table 定义为
CREATE TABLE `article` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`field1` varchar(1024) NOT NULL,
`priority` int(11) NOT NULL,
`prodcode` varchar(64) NOT NULL,
`status` int(8) NOT NULL,
`error` varchar(1024) DEFAULT NULL,
`ctime` datetime DEFAULT CURRENT_TIMESTAMP,
`mtime` datetime DEFAULT NULL,
`event` varchar(50) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `article_prodcode_idx` (`prodcode`),
KEY `article_status_idx` (`status`),
KEY `article_priority_idx` (`priority`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
这个table包含大约4000万条记录。
当我 运行 查询像
SELECT * FROM article WHERE prodcode='a-4536-x-bef45-green';
优化器“决定”这样的查询不必使用任何索引(“EXPLAIN SELECT...”导致
+----+-------------+----------+------+---------------+------+---------+------+----------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+----------+------+---------------+------+---------+------+----------+-------------+
| 1 | SIMPLE | article | ALL | NULL | NULL | NULL | NULL | 39415251 | Using where |
+----+-------------+----------+------+---------------+------+---------+------+----------+-------------+
如果我添加例如另一个字段,如优先级或状态,优化器只使用此类索引,而不是 article_prodcode_idx 索引。问题是查询扫描了全部 4000 万条记录,结果在 100 秒后出现。为什么那里没有使用索引?
我也检查了这个答案:MySQL partial indexes on varchar fields and group by optimization 但我没有找到我的问题的任何答案。我应该怎么做才能让查询 return 结果...很快?
谢谢
经过深入检查,我解决了问题。在某些方面,我在描述问题时犯了错误。事实上,在我的脚本中,我有类似
SET @pc='a-4536-x-bef45-green';
...
SELECT * FROM article WHERE prodcode=@pc;
而在其他一些方面我有
SELECT * FROM article WHERE prodcode='a-4536-x-bef45-green';
第一种情况,没有使用索引。在第二个中,一切都按预期进行。
这是第一个查询的解释:
EXPLAIN FORMAT=JSON SELECT * FROM article WHERE prodcode=@pc;
{
"query_block": {
"select_id": 1,
"table": {
"table_name": "article",
"access_type": "ALL",
"rows": 39498773,
"filtered": 100,
"attached_condition": "(convert(`shop`.`article`.`prodcode` using utf8mb4) = (@`pc`))"
}
}
}
这是第二个
EXPLAIN FORMAT=JSON SELECT * FROM article WHERE prodcode='a-4536-x-bef45-green';
{
"query_block": {
"select_id": 1,
"table": {
"table_name": "article",
"access_type": "ref",
"possible_keys": [
"article_prodcode_idx"
],
"key": "article_prodcode_idx",
"used_key_parts": [
"prodcode"
],
"key_length": "194",
"ref": [
"const"
],
"rows": 2,
"filtered": 100,
"index_condition": "(`shop`.`article`.`prodcode` = 'a-4536-x-bef45-green')"
}
}
}
我尝试了很多次,例如
SELECT * FROM article WHERE prodcode in (@pc, 'another code');
但结果总是一样的:如果涉及变量,则不使用索引。
知道了,我更改了我的脚本以便不再使用 SET,一切都开始 运行 很好。
我还是很想知道为什么...不过至少问题解决了
我有一个 table 定义为
CREATE TABLE `article` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`field1` varchar(1024) NOT NULL,
`priority` int(11) NOT NULL,
`prodcode` varchar(64) NOT NULL,
`status` int(8) NOT NULL,
`error` varchar(1024) DEFAULT NULL,
`ctime` datetime DEFAULT CURRENT_TIMESTAMP,
`mtime` datetime DEFAULT NULL,
`event` varchar(50) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `article_prodcode_idx` (`prodcode`),
KEY `article_status_idx` (`status`),
KEY `article_priority_idx` (`priority`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
这个table包含大约4000万条记录。 当我 运行 查询像
SELECT * FROM article WHERE prodcode='a-4536-x-bef45-green';
优化器“决定”这样的查询不必使用任何索引(“EXPLAIN SELECT...”导致
+----+-------------+----------+------+---------------+------+---------+------+----------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+----------+------+---------------+------+---------+------+----------+-------------+
| 1 | SIMPLE | article | ALL | NULL | NULL | NULL | NULL | 39415251 | Using where |
+----+-------------+----------+------+---------------+------+---------+------+----------+-------------+
如果我添加例如另一个字段,如优先级或状态,优化器只使用此类索引,而不是 article_prodcode_idx 索引。问题是查询扫描了全部 4000 万条记录,结果在 100 秒后出现。为什么那里没有使用索引?
我也检查了这个答案:MySQL partial indexes on varchar fields and group by optimization 但我没有找到我的问题的任何答案。我应该怎么做才能让查询 return 结果...很快?
谢谢
经过深入检查,我解决了问题。在某些方面,我在描述问题时犯了错误。事实上,在我的脚本中,我有类似
SET @pc='a-4536-x-bef45-green';
...
SELECT * FROM article WHERE prodcode=@pc;
而在其他一些方面我有
SELECT * FROM article WHERE prodcode='a-4536-x-bef45-green';
第一种情况,没有使用索引。在第二个中,一切都按预期进行。 这是第一个查询的解释:
EXPLAIN FORMAT=JSON SELECT * FROM article WHERE prodcode=@pc;
{
"query_block": {
"select_id": 1,
"table": {
"table_name": "article",
"access_type": "ALL",
"rows": 39498773,
"filtered": 100,
"attached_condition": "(convert(`shop`.`article`.`prodcode` using utf8mb4) = (@`pc`))"
}
}
}
这是第二个
EXPLAIN FORMAT=JSON SELECT * FROM article WHERE prodcode='a-4536-x-bef45-green';
{
"query_block": {
"select_id": 1,
"table": {
"table_name": "article",
"access_type": "ref",
"possible_keys": [
"article_prodcode_idx"
],
"key": "article_prodcode_idx",
"used_key_parts": [
"prodcode"
],
"key_length": "194",
"ref": [
"const"
],
"rows": 2,
"filtered": 100,
"index_condition": "(`shop`.`article`.`prodcode` = 'a-4536-x-bef45-green')"
}
}
}
我尝试了很多次,例如
SELECT * FROM article WHERE prodcode in (@pc, 'another code');
但结果总是一样的:如果涉及变量,则不使用索引。
知道了,我更改了我的脚本以便不再使用 SET,一切都开始 运行 很好。
我还是很想知道为什么...不过至少问题解决了