使用两列的相等比较与依赖子查询的结果进行连接

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

我试图通过在为每个嵌套循环找到一条记录时停止来优化连接。

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|

解决方案是什么??

感谢您的阅读。

sql mysql join subquery
1个回答
0
投票

从 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);

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