作者回复: MySQL 5.6就开始支持semijoin了,不过8.0中支持的场景更多。 5.6,5.7不会自动转换exists,8.0开始支持exists的转换。 这是5.7 semijoin的官方文档:https://dev.mysql.com/doc/refman/5.7/en/semijoins.html
作者回复: 这个执行计划是先从 ID为1的获取一行数据,再驱动相关子查询。 使用explain extended + show warnings,能看到转换后的SQL: select `rep`.`stat_item_detail`.`item_id` AS `item_id`,sum(`rep`.`stat_item_detail`.`sold`) AS `sold` from `rep`.`stat_item_detail` where <in_optimizer>( `rep`.`stat_item_detail`.`item_id`, <exists>(<index_lookup>(<cache>(`rep`.`stat_item_detail`.`item_id`) in stat_item_detail on idx_item_id where ((`rep`.`stat_item_detail`.`gmt_create` >= '2026-04-26 10:30:00') and (<cache>(`rep`.`stat_item_detail`.`item_id`) = `rep`.`stat_item_detail`.`item_id`))))) group by `rep`.`stat_item_detail`.`item_id`。 这是5.5中的执行计划。在8.0里,我试了下,如果关闭semijoin优化,执行计划有点不一样, mysql> explain select item_id, sum(sold) as sold from stat_item_detail where item_id in ( select item_id from stat_item_detail where Gmt_create >= '2026-04-26 10:30:00') group by item_id; +----+-------------+------------------+-------+----------------------------+----------------+---------+--------+ | id | select_type | table | type | possible_keys | key | key_len | rows | +----+-------------+------------------+-------+----------------------------+----------------+---------+--------+ | 1 | PRIMARY | stat_item_detail | index | idx_item_id | idx_item_id | 4 | 903690 | | 2 | SUBQUERY | stat_item_detail | range | idx_item_id,idx_gmt_create | idx_gmt_create | 5 | 10 | +----+-------------+------------------+-------+----------------------------+----------------+---------+--------+