我试图通过在为每个嵌套循环找到一条记录时停止来优化连接。
Mysql版本是8.0.29
我发现我可以通过下面问题中的一列相等性比较来做到这一点,但很难找到一种使用复合主键来做到这一点的方法。
在连接表上使用 LIMIT 1 进行 MySQL JOIN
让我首先写下重现问题的查询
create table foo (id int unsigned, fooValue int, barValue binary(32), primary key (id), index fooV (fooValue));
create table bar (id int unsigned, barValueChecksum int unsigned, barValue binary(32), primary key (id, barValueChecksum), index checksum (barValueChecksum));
我正在尝试找出具有特定值的
bar
的所有 foo
explain select * from foo
left join bar on (bar.id, bar.barValueChecksum)
= (select b.id, b.barValueChecksum from bar b
where b.barValueChecksum = crc32(foo.barValue)
and b.barValue = foo.barValue)
where foo.fooValue = 10;
它返回令人沮丧的结果
id|select_type |table|partitions|type|possible_keys|key |key_len|ref |rows|filtered|Extra |
--+------------------+-----+----------+----+-------------+--------+-------+-----+----+--------+------------------------------------------+
1|PRIMARY |foo | |ref |fooV |fooV |5 |const| 1| 100.0| |
1|PRIMARY |bar | |ALL | | | | | 1| 100.0|Using where; Using join buffer (hash join)|
2|DEPENDENT SUBQUERY|b | |ref |checksum |checksum|4 |func | 1| 100.0|Using index condition; Using where |
优化器尝试使用散列连接,更糟糕的是,
PRIMARY
没有出现在表possible_keys
的
bar
部分中
我可以通过分离比较来实现与我想要的类似的结果,但它运行子查询两次
explain select * from foo
left join bar on (bar.id
= (select b.id from bar b
where b.barValueChecksum = crc32(foo.barValue)
and b.barValue = foo.barValue))
and (bar.barValueChecksum
= (select b.barValueChecksum from bar
b where b.barValueChecksum = crc32(foo.barValue)
and b.barValue = foo.barValue))
where foo.fooValue = 10;
结果如下
id|select_type |table|partitions|type |possible_keys |key |key_len|ref |rows|filtered|Extra |
--+------------------+-----+----------+------+----------------+--------+-------+---------+----+--------+----------------------------------+
1|PRIMARY |foo | |ref |fooV |fooV |5 |const | 1| 100.0| |
1|PRIMARY |bar | |eq_ref|PRIMARY,checksum|PRIMARY |8 |func,func| 1| 100.0|Using where |
3|DEPENDENT SUBQUERY|b | |ref |checksum |checksum|4 |func | 1| 100.0|Using index condition; Using where|
2|DEPENDENT SUBQUERY|b | |ref |checksum |checksum|4 |func | 1| 100.0|Using index condition; Using where|
解决方案是什么??
感谢您的阅读。
从 MySQL 8.0.14 开始,您可以使用横向联接来实现此目的。如果使用正确的索引,它可能会非常有效。
例如你可以这样做:
select *
from foo
left join lateral (
select b.*
from bar b
where b.barValueChecksum = crc32(foo.barValue)
and b.barValue = foo.barValue
limit 1
) on true
where foo.fooValue = 10;
以下索引可以加快主过滤器和连接的速度:
create index ix1 on foo (fooValue);
create index ix1 on bar (barValueChecksum, b.barValue);