【发布时间】:2021-06-15 11:24:05
【问题描述】:
我正在尝试优化这个 MySQL 查询,但在理解执行计划方面经验不足我很难理解执行计划。
我的问题是:你能帮我理解为什么New Query的查询执行计划比Original query差吗?即使新查询在 Prod 中表现更好。
重现这种情况所需的 SQL 是 here
最后还保留了相关的表定义(表 bill_range 使用外键 bill_id 引用账单)
原始查询在 PROD 中需要 10 秒才能完成
select *
from bill_range
where (4050 between low and high )
order by bill_id limit 1;
而 新查询(我正在强制/建议使用索引)在 PROD 中需要 5 秒才能完成
select *
from bill_range
use index ( bill_range_low_high_index)
where (4050 between low and high )
order by bill_id limit 1;
但执行计划给出的建议是原始查询更好(这是我的理解似乎错误的部分)
- 原始查询的列“类型”建议 index 而新查询 说所有
- “键”列是 bill_id(可能是 FK 上的索引) 原始查询和 Null 用于新查询
- 原始查询的列“行”为 1,而新查询的列“行”为 9
因此,鉴于所有这些信息,这并不意味着新查询实际上比原始查询更糟糕。 如果这是真的,为什么新查询的性能更好?还是我读错了执行计划。
表格定义
CREATE TABLE bill_range (
id int(11) NOT NULL AUTO_INCREMENT,
low varchar(255) NOT NULL,
high varchar(255) NOT NULL,
PRIMARY KEY (id),
bill_id int(11) NOT NULL,
FOREIGN KEY (bill_id) REFERENCES bill(id)
);
CREATE TABLE bill (
id int(11) NOT NULL AUTO_INCREMENT,
label varchar(10),
PRIMARY KEY (id)
);
create index bill_range_low_high_index on bill_range( low, high);
注意:我提供 2 个表的定义的原因是因为原始查询决定使用基于外键的索引来计费表
【问题讨论】:
-
索引的基数是多少?如果它的基数很差,使用索引也无济于事。
-
查询没有使用
bill表,为什么需要它的定义? -
优化器并不总是正确的,您的基准可能无法重现。例如,当您在 10 秒时对第一个查询进行基准测试时,当时可能有其他进程在 MySQL 上运行。通常,您希望避免强制使用索引,因为 MySQL 比您更聪明(大多数时候)。
-
@Barmar 在 PROD 中 bill_range_low_high_index 的基数为 200K
-
不不!不要将数字 (
4500) 与VARCHAR进行比较!!修复它,然后重新检查这里讨论的所有内容;它可能不再有效。
标签: mysql sql indexing query-optimization