我们有两个表,消息和客户合同定义如下:
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条客户合同行。尽管customer_id和contractnumber上都有索引,但是上面的查询大约需要4秒钟才能执行。 “解释”(在MySQL Workbench中)显示了对客户合同的全表扫描,查询成本为628,000。
问题:
1)当我在这些表上有索引时,为什么对客户合同进行全表扫描?表现不佳的原因是什么?
2)如何重写此查询以使其表现出色?
答案 0 :(得分:0)
我建议尝试在消息表customer_id,合同编号上检查复合索引并检查性能,并尝试避免在select中使用*。
答案 1 :(得分:0)
我想我终于找到了答案。我上面的示例表创建代码未显示字符编码(对我来说是个学习,请不要捷径示例代码!)。事实证明,customercontacts表使用utf8编码,而消息表使用utf8mb4编码。
当连接不同字符编码的列时,将无法使用索引。
这回答了“为什么会这样”。为了解决这个问题,我们修改了utf8m4表以将索引列的编码降级为utf8(同时将其余表的编码保持为utf8mb4)。这对我们来说是固定的性能。
答案 2 :(得分:-1)
我考虑添加一个INTEGER“ id”字段作为客户合同的主键,然后通过customercontracts_id而不是消息表中的contractnumber进行引用。您应该已经看到了性能上的改善。
或者,您可以尝试在两个contractnumber列上添加FULLTEXT索引,但是我建议您选择第一个选项。