MySQL的exists子查询在8.0中的表现明显比5.7差

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

我希望将我的 MySQL 数据库从 5.7.33 升级到 8.0.28。我将它与 Laravel 应用程序一起使用,该应用程序使用使用存在子查询的

whereHas
方法生成查询。然而,我注意到这两个版本之间的性能大幅下降 - 从约 5 毫秒到 4 秒。

以下是疑问:

select * from `categories` where exists (select * from `jobs` inner join `category_job` on `jobs`.`id` = `category_job`.`job_id` where `categories`.`id` = `category_job`.`category_id`) order by `name` asc

如果我完全删除存在的子查询,查询会再次恢复到合理的速度 - 大约 5 毫秒,那么有趣的是。

select * from `categories` order by `name` asc

我想了解的是为什么两个版本之间的性能变化如此之大 - 如果我的 SQL 中存在可以改进的错误(或者可能在框架中进行更改以避免问题) - 或者这个这只是 MySQL 中的性能回归,我必须忍受它。

我知道第一个查询需要更多工作,并且存在子查询会变慢,但我不明白简单地升级 MySQL 会产生怎样的效果。


当我使用 EXPLAINS 运行查询时,我在 5.7 和 8.0 之间也得到了不同的结果(另请注意,数据库具有相同的索引):

5.7:

id 选择类型 桌子 分区 类型 可能的键 key_len 参考 过滤 额外
1 小学 类别 全部 27 100.00 使用地点;使用文件排序
2 依赖子查询 类别_工作 参考 category_job_category_id_index,category_job_job_id_index category_job_category_id_index 8 jobsnearme.categories.id 35253 100.00
2 依赖子查询 工作 eq_ref 小学 小学 8 jobsnearme.category_job.job_id 1 100.00 使用索引

8.0:

id 选择类型 桌子 分区 类型 可能的键 key_len 参考 过滤 额外
1 简单 类别 全部 小学 30 100.00 使用文件排序
1 简单 eq_ref 8 jobsnearme.categories.id 1 100.00
2 物化 工作 索引 小学 jobs_company_id_index 9 718220 100.00 使用索引
2 物化 类别_工作 参考 category_job_category_id_index,category_job_job_id_index category_job_job_id_index 8 jobsnearme.jobs.id 1 100.00

这是 8.0 的

SHOW CREATE TABLE category_job

CREATE TABLE `category_job` (
  `id` bigint unsigned NOT NULL AUTO_INCREMENT,
  `category_id` bigint unsigned NOT NULL,
  `job_id` bigint unsigned NOT NULL,
  PRIMARY KEY (`id`),
  KEY `category_job_category_id_index` (`category_id`),
  KEY `category_job_job_id_index` (`job_id`),
  CONSTRAINT `category_job_category_id_foreign` FOREIGN KEY (`category_id`) REFERENCES `categories` (`id`),
  CONSTRAINT `category_job_job_id_foreign` FOREIGN KEY (`job_id`) REFERENCES `jobs` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=1070585 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
mysql subquery mysql-8.0
2个回答
0
投票

尝试在optimizer_switch中设置

semijoin=off
并检查EXPLAIN结果

SET optimizer_switch = 'semijoin=off';

-2
投票

多对多表模式中常见的低效率问题。

这样会更快:

CREATE TABLE `category_job` (
  `category_id` bigint unsigned NOT NULL,
  `job_id` bigint unsigned NOT NULL,
  PRIMARY KEY (category_id, job_id),
  KEY (job_id, category_id)
) ENGINE=InnoDB
© www.soinside.com 2019 - 2024. All rights reserved.