尽管索引,MySQL糟糕的选择查询性能

问题描述 投票:0回答:3

我们有两个表,消息和客户合同,定义如下:

create table customercontracts (customer_id varchar(20), 
                                contractnumber varchar(20), 
                                role varchar(4));
alter table customercontracts add index contractnumber (contractnumber);

create table messages (customer_id varchar(20), 
                                contractnumber varchar(20), 
                                message varchar(400));
alter table messages add index contractnumber (contractnumber);
alter table messages add index customer_id (customer_id );

和这样的查询:

select * from messages m, customercontracts c 
 where m.customer_id = '12345' 
   and c.contractnumber = m.contractnumber;

大约有4,000个消息行和3,000,000个customercontracts行。尽管customer_id和contractnumber都有索引,但上述查询大约需要4秒才能执行。 'Explain'(在MySQL Workbench中)显示了对customercontracts的全表扫描,查询成本为628,000。

问题:

1)当我在这些表上有索引时,为什么对customercontracts进行全表扫描?表现不佳的原因是什么?

2)如何重写此查询以获得高效?

mysql
3个回答
0
投票

我建议尝试综合索引按摩表客户ID,合同号和检查性能,尽量避免在选择中使用*。


0
投票

我想我终于找到了答案。我上面的示例表创建代码没有显示字符编码(为我学习,不要快捷示例代码!)。事实证明,customercontacts表以utf8编码,而messages表以utf8mb4编码。

当连接不同字符编码的列时,不能使用索引。

这回答了“为什么会发生这种情况”。为了解决这个问题,我们修改了utf8m4表,将索引列的编码降级为utf8(同时保持表的其余部分的编码为utf8mb4)。这为我们提供了固定的性能。


-1
投票

我会考虑添加一个INTEGER“id”字段作为customercontracts的主键,然后通过customercontracts_id而不是messages表中的contractnumber引用。你应该看到性能有所改善。

或者,您可以尝试在两个contractnumber列上添加FULLTEXT索引,但我建议您选择第一个选项。

© www.soinside.com 2019 - 2024. All rights reserved.