복잡한 교리 쿼리에서 왼쪽 조인을 느리게 하는 가능한 솔루션
<p>저는 상당히 복잡한 데이터 세트를 가져온 다음 내보내기 관리자 클래스에 의해 CSV 파일에 배치되는 심포니 저장소 메소드를 가지고 있습니다. 내보내기 작업을 처리하는 전체 코드를 넣고 싶지는 않지만 쿼리가 느려지는 지점을 정확히 찾아낼 수 있었기 때문에 코드 자체보다는 쿼리를 더 빠르게 만드는 다른 대안에 대해 질문하고 있습니다.
따라서 가져온 데이터는 여러 "멤버십"과 "사용자"를 포함하는 일부 "사이트" 데이터입니다.그래서 문제는 내 쿼리가 사용자 정보를 사이트에 연결하려고 할 때 실행 속도가 느려진다는 것입니다. 다음과 같습니다:</p>
<pre class="brush:php;toolbar:false;">$qb->leftJoin('s.memberships', 'ex_sm', 'WITH', 'ex_sm.revokedAt IS NULL');
$qb->leftJoin('ex_sm.user', 'ex_jappr', 'WITH', 'ex_sm.approverJobReactiveWeight는 NULL이 아닙니다');</pre>
<p>몇 가지 언급할 사항(시도했거나 도움이 될 것이라고 생각한 것): </p>
<li>테이블을 확인했는데 연결된 모든 열에 인덱스가 있고 모두 동일한 int 데이터 유형입니다. </li>
<li>DQL Left Join 호출을 과도하게 사용하면 동일한 엔터티 개체를 계속해서 다시 매핑하기 때문에 성능이 저하될 수 있다는 DQL 성능 문제에 대한 기사를 다시 작성했습니다. 언급된 한 가지 가능한 해결책은 기본 데이터 세트를 가져온 다음 필드의 엔터티 클래스에서 직접 각 요소에 추가(연결된 데이터 필드)를 추가하는 컬렉션을 반복하는 것입니다. 이것이 효과가 있을 수 있습니다(얼마나 영향을 미칠지는 확실하지 않음). 문제는 내가 가지고 있는 레거시 코드가 매우 복잡하고 너무 많은 테스트가 필요하기 때문에 내보내기 관리자 논리를 건드리고 싶지 않다는 것입니다. 내보내기 관리자에는 쿼리 빌더 클래스가 필요하므로 쿼리 자체에서 솔루션을 찾아야 합니다. </li>
<li>문제의 원인은 확실히 WITH 절이나 추가 조건이 아니라 조인 때문입니다. 동일한 결과로 일반 leftJoin 호출을 사용하여 쿼리를 호출해 보았습니다. </li>
<li>leftJoin 메소드 호출이 서로 연결될 수 있다는 것을 알고 있습니다. 일부 호출이 if 문에서 사용되기 때문에 코드는 다음과 같습니다. </li>
<li>여기와 다른 사이트에서 찾은 모든 것을 이틀 동안 시도해 보았습니다. </li>
</ul>
<p>6가지 다른 사용자 유형이 있습니다. 이제 위의 사용자 유형을 가져오기 위해 스크립트를 호출하기만 하면 되며 데이터를 반환하는 데 33분이 걸렸습니다. 우리는 512개 사이트에 대해 이야기하고 있는데 이는 거대한 데이터 모음이 아닙니다.그래서 내 질문은: 이렇게 복잡한 쿼리에서 leftJoins에 대한 호출 수를 단순화하거나 줄이고 어떻게든 성능을 향상시킬 수 있는 또 다른 DQL이나 Doctrine 방법이 있습니까? </p>
<p>업데이트:
문제가 색인에 있다고 생각하여 관계에 대한 몇 가지 세부 정보를 제공했습니다.
"멤버십" 엔터티는 "access"라는 테이블에서 나오며 해당 모델에서 사용자와의 관계는 다음과 같습니다. </p>
<pre class="brush:php;toolbar:false;">/*** 이 멤버십이 캡슐화하는 사용자입니다.
*
* @ORMManyToOne(targetEntity="User", inversedBy="siteMemberships", cascade={"persist"})
* @ORMJoinColumn(name="security_identity_id", referencedColumnName="id")
*
* @var 사용자*/
보호된 $user;</pre>
<p>이것은 "security_identity_id" 열에 할당된 인덱스의 스크린샷입니다.
</p>
<p>관련 사용자는 멤버십을 가리키는 관계가 있는 사용자 테이블에서 나옵니다</p>
<pre class="brush:php;toolbar:false;">/*** @ORMOneToMany(targetEntity="SiteMembership", mappedBy="user", cascade={"persist"}, fetch="EXTRA_LAZY")*/
보호된 $siteMemberships;</pre>
<p>기본 키는 엔터티의 "id"입니다.이것이 상황을 더 나은 관점으로 보기를 바랍니다. 나는 SQL 전문가는 아니지만 내가 찾은 모든 것을 시도했고 지금까지 알아낼 수 있습니다. </p>
<p>업데이트:
실행된 쿼리는 다음과 같습니다. </p>
<pre class="brush:php;toolbar:false;">SELECT s0_.name AS name_0, s0_.id AS id_1, GROUP_CONCAT(DISTINCT u1_.name SEPARATOR ', ') AS sclr_2 FROM 사이트 s0_
LEFT JOIN 액세스 a2_ ON s0_.id = a2_.entity_id
AND a2_.type IN ('site_member')
그리고 (a2_.revoked_at는 NULL입니다)
LEFT JOIN 사용자 u1_ ON a2_.security_identity_id = u1_.id
AND (a2_.approver_job_reactive_weight는 NULL이 아닙니다)</pre>
<p>이렇게 하면 회원 자격 및 사용자 권한과 함께 첫 번째 사이트 기록이 반환됩니다. 하지만 이 행조차 2분 이상 걸립니다. </p>
<p>(멤버 엔터티) 테이블에 접근하기 위한 테이블 생성 정보는 다음과 같습니다</p>
<pre class="brush:php;toolbar:false;">'CREATE TABLE `액세스`(
`id` int(11) NOT NULL AUTO_INCREMENT,
`buddy_id` int(11) 기본 NULL,
`security_identity_id` int(11) 기본 NULL,
`revoked_at` 날짜/시간 DEFAULT NULL,
`created_at` 날짜/시간은 NULL이 아닙니다.
`updated_at` 날짜/시간은 NULL이 아닙니다.
`type` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
`approver_job_reactive_weight` int(11) 기본 NULL,
`entity_id` int(11) 기본 NULL,
기본 키(`id`),
고유 키 `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`),
제약 조건 `FK_6692B54DF9183C9` 외래 키(`security_identity_id`) 참조 `user`(`id`)
)
엔진=InnoDB AUTO_INCREMENT=262441 기본 CHARSET=utf8
COLLATE=utf8_unicode_ci'</pre>
<p>관련 없는 열을 일부 삭제했습니다. </p>