mysql 复杂规则查询中慢速左连接的可能解决方案

nqwrtyyt  于 2023-05-05  发布在  Mysql
关注(0)|答案(2)|浏览(193)

我有一个symfony存储库方法,它获取一个相当复杂的数据集,然后将其放置在CSV文件中的导出管理器类。我不想把处理导出工作的整个代码,但我设法chatch查询变慢的点,所以我的问题是关于任何其他替代方案,使查询更快,而不是代码本身。因此,获取的数据是一些“站点”数据,它具有多个“成员资格”,然后具有“用户”。所以问题是,当我的查询试图将用户信息连接到站点时,它会减慢执行速度。它看起来像这样:

$qb->leftJoin('s.memberships', 'ex_sm', 'WITH', 'ex_sm.revokedAt IS NULL');
$qb->leftJoin('ex_sm.user', 'ex_jappr', 'WITH', 'ex_sm.approverJobReactiveWeight IS NOT NULL');

有几件事(我试过或穿过我的脑海可以帮助)提到:

  • 我检查了表,所有链接的列都有一个索引,并且它们是相同的int数据类型。
  • 我写了一篇关于DQL性能问题的文章,其中提到过度使用DQL左连接调用会降低性能,因为它们会一遍又一遍地重新Map同一个实体对象。这里提到的一个可能的解决方案是获取主数据集,然后在集合中循环,直接从字段的实体类向每个元素添加附加(连接数据字段)。这可能会起作用(不确定它会有多大的影响),问题是我有一个非常复杂的遗留代码,我不想触及导出管理器的逻辑,因为这将需要太多的测试。导出管理器需要一个查询生成器类,因此我必须在查询本身中找到解决方案。
  • 这个问题肯定是由连接引起的,而不是“WITH”子句或附加条件。我尝试用简单的leftJoin调用查询,结果相同。
  • 我知道leftJoin方法可以相互链接调用,代码看起来是这样的,因为其中一些调用在if语句中使用。
  • 我花了2天时间尝试在这里和其他网站找到的所有排序的东西。

有6种不同的用户类型,现在我只是调用了上面的脚本,它花了33分钟来返回数据。我们谈论的是512个网站,这不是一个庞大的数据集合。所以我的问题是在这样一个复杂的查询中,是否有其他DQL或任何Doctrine方法来简化或减少leftJoins的调用数,并以某种方式提高性能?
更新:我认为问题来自索引,所以我给予了一些关于关系的细节:'memberships'实体来自名为'access'的表,其模型中与用户的关系如下所示:

/**
 * The user this membership encapsulates.
 *
 * @ORM\ManyToOne(targetEntity="User", inversedBy="siteMemberships", cascade={"persist"})
 * @ORM\JoinColumn(name="security_identity_id", referencedColumnName="id")
 *
 * @var User
 */
protected $user;

下面是分配给'security_identity_id'列

的索引的屏幕截图
而相关的User来自具有此关系的“user”表,指向membershipt

/**
 * @ORM\OneToMany(targetEntity="SiteMembership", mappedBy="user", cascade={"persist"}, fetch="EXTRA_LAZY")
 */
protected $siteMemberships;

主键是实体中的“id”。希望这能让你更好地了解这个问题。我不是一个sqlMaven,但尝试了所有我发现和理解到目前为止。
更新:以下是执行的查询:

SELECT s0_.name AS name_0, s0_.id AS id_1, GROUP_CONCAT(DISTINCT u1_.name SEPARATOR ', ') AS sclr_2 FROM site s0_ 
  LEFT JOIN access a2_ ON s0_.id = a2_.entity_id 
  AND a2_.type IN ('site_member') 
  AND (a2_.revoked_at IS NULL) 
  LEFT JOIN user u1_ ON a2_.security_identity_id = u1_.id 
  AND (a2_.approver_job_reactive_weight IS NOT NULL)

这将返回第一个站点记录及其加入的成员资格和用户属性。但即使是这一排的fething也需要超过2分钟。
下面是访问(成员实体)表的创建表信息

'CREATE TABLE `access` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `buddy_id` int(11) DEFAULT NULL,
  `security_identity_id` int(11) DEFAULT NULL,
  `revoked_at` datetime DEFAULT NULL,
  `created_at` datetime NOT NULL,
  `updated_at` datetime NOT NULL,
  `type` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
  `approver_job_reactive_weight` int(11) DEFAULT NULL,
  `entity_id` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `access_idx` (`type`,`security_identity_id`,`entity_id`,`buddy_id`),
  KEY `IDX_6692B54395CE8D6` (`buddy_id`),
  KEY `IDX_6692B54DF9183C9` (`security_identity_id`),
  KEY `IDX_6692B5481257D5D` (`entity_id`),
  KEY `idx_revoked_id_approver_type` (`revoked_at`,`entity_id`,`approver_job_reactive_weight`,`approver_job_planned_weight`,`type`),
  KEY `idx_user_site_access` (`revoked_at`,`security_identity_id`,`buddy_id`,`type`),
  KEY `idx_user` (`security_identity_id`),
  KEY `idx_user_id` (`security_identity_id`),
  CONSTRAINT `FK_6692B54DF9183C9` FOREIGN KEY (`security_identity_id`) REFERENCES `user` (`id`)
)
ENGINE=InnoDB AUTO_INCREMENT=262441 DEFAULT CHARSET=utf8 
COLLATE=utf8_unicode_ci'

我删除了一些不相关的栏目。

ca1c2owp

ca1c2owp1#

当执行LEFT JOIN时,ON需要说明表是如何相关的。WHERE子句通常使用IS NULLIS NOT NULL来表示是排除还是包含右侧行。
LEFT JOININNER JOIN的速度基本相同。但是我需要查看SELECT的索引(SHOW CREATE TABLE)和SQL,看看是否有其他问题。

更多

替换

KEY `IDX_6692B5481257D5D` (`entity_id`),

INDEX(entity_id, type, revoked_at)
ar5n3qh5

ar5n3qh52#

你加入了很多方面。这就是慢下来的原因

$qb->leftJoin('s.memberships', 'ex_sm', 'WITH', 'ex_sm.revokedAt IS NULL');

会员越多,查询速度越慢。我不知道如何是完整的查询,但你可以从成员表开始查询,或者你可以做第二个查询。

相关问题