2011-12-22 2 views
2

저는 오랫동안이 문제로 고생했습니다. 이 쿼리는 세트 작은 데이터에 매우 빠르게 실행되지만 테이블이 100,000 + 행 성장할 때 실행하는 데 몇 분에 30에서 취 "null이 아님"을 사용하는 왼쪽 조인 쿼리의 최적화

SELECT accounts.id 
     , accounts.name 
     , ..etc.. 
FROM accounts 
     LEFT JOIN (
      SELECT distinct secr.record_id as id 
      FROM securitygroups secg 
        INNER JOIN securitygroups_users secu 
        ON secg.id = secu.securitygroup_id 
         AND secu.deleted = 0 
         AND secu.user_id = 'seed_chris_id' 
        INNER JOIN securitygroups_records secr 
        ON secg.id = secr.securitygroup_id 
         AND secr.deleted = 0 
         AND secr.module = 'Accounts' 
      WHERE secg.deleted = 0 
     ) securitygroup_join ON securitygroup_join.id = accounts.id 
WHERE ((accounts.assigned_user_id ='seed_chris_id' 
      OR securitygroup_join.id is not null)) 
     AND accounts.deleted=0 
ORDER BY 
     accounts.date_entered 
DESC LIMIT 0,21 

는 기본적으로 사용자가 레코드 (계정을 소유 한 모든 행을 반환해야합니다. assigned_user_id)이거나 레코드와 연관된 그룹의 구성원입니다 (securitygroup_join.id가 널이 아님). 이 쿼리는 프레임 워크에 의해 특정 방식으로 구축되어 일부 제약에 직면합니다. 쉽게 구현할 수없는 가능한 솔루션은이를 UNION으로 변경하는 것입니다. 그 경로를 피하고 싶습니다. 과거에는 "어디에서 ... in"절을했지만 그보다 더 나쁜 수행을했습니다. 필요에 따라 조인, where 절을 추가하거나 인덱스를 조작 할 수 있지만 쿼리 구조의 다른 급격한 변경은 쉽게 수행 할 수 없습니다.

답변

3

LEFT JOIN 대신 WHERE EXISTS을 시도해 볼 수 있습니다. 예 :

SELECT accounts.id 
     , accounts.name 
     , ..etc.. 
FROM accounts 
WHERE ((accounts.assigned_user_id ='seed_chris_id' 
     OR EXISTS (SELECT 1 
        FROM securitygroups secg 
          INNER JOIN securitygroups_users secu 
          ON secg.id = secu.securitygroup_id 
           AND secu.deleted = 0 
           AND secu.user_id = 'seed_chris_id' 
          INNER JOIN securitygroups_records secr 
          ON secg.id = secr.securitygroup_id 
           AND secr.deleted = 0 
           AND secr.module = 'Accounts' 
         WHERE secr.record_id = accounts.id 
           AND secg.deleted = 0) 
     )) 
    AND accounts.deleted=0 
ORDER BY 
    accounts.date_entered 
DESC LIMIT 0,21 

테스트하지 않았으므로 성능이 향상 될 수는 있지만 시도해 볼 가치가 있습니다.

+0

+1 : 시도해 볼만한 가치가 있습니다. MS SQL Server는 이것을 매우 잘 최적화합니다. MySQL도 시도해 봅니다. – MatBailie

+0

securitygroups_records 테이블에서 700k 행을 가진 db에 대해 제안 된 변경 사항은 약 3.2 초에서 실행되지만 원래 쿼리는 17.8 초에서 실행됩니다. 나는 그것이 좋은 개선이라고 말한다. 나는 처음부터 존재하지 않는다고 생각하지 않았다. 감사! – egg

+0

좋습니다! 다행히 도울 수있어. –