2011-01-05 4 views
1

이 사이트 나 다른 사이트에서 다른 질문이 중복되는 경우 사과 드리지만 데이터베이스 검색에 익숙하지 않아서 내 답변을 찾는 데 사용할 키워드를 알 수 없습니다.MySQL : 테이블 A와 B의 어느 행이 선형 시간으로 테이블 C의 행에 의해 참조되는지 결정하는 방법?

구조 조정의 자유가 부족한 저조한 ​​데이터베이스로 작업하고 있습니다. 이 데이터베이스에는 최적화가 필요한 쿼리와 관련된 세 개의 테이블 ('회사 A', '회사 B'및 'items')가 있습니다. 'companiesA'및 'companiesB'은 열 값이 같지만 두 개의 서로 다른 그룹의 회사를 나타내며 다른 열 이름을 사용한다는 점에서 동일한 방식으로 회사를 설명합니다. 본질적으로, ID 및 회사 이름 열은 'companiesB'에서 '도움이'와 'companiesA'에서 'aName'및 'IDB'와 'nameB'이다. 'items'에는 두 개의 회사 테이블 중 하나에서 외래 키 값을 포함하는 'companyID'열이 포함되어 있습니다.

최적화해야하는 쿼리는 행의 회사에 관련된 항목이 있는지 여부를 나타내는 추가 열과 함께 이름 열로 정렬 된 두 테이블의 통합에서 페이지의 가치가있는 회사 ID와 이름을 가져옵니다. 이 쿼리는 사용자가 프런트 엔드에서 요청한 경우 회사 이름별로 필터링 할 수도 있습니다. 현재 상태에서, 나는 그것이 THETA (회사 * 항목)에 엄청나게 느린 시간, 실행 생각 : 항목 열이 쿼리 반환로 실제 수를 포함하는 것이 중요하지 않습니다

select 
    a.aID as companyID, 
    a.aName as companyName, 
    (select 
    count(companyID) 
    from 
    items 
    where 
    companyID = a.aID 
) as items 
from 
    companiesA as a 
where 
    a.aName like '%<string>%' 

union 

select 
    b.idB as companyID, 
    b.nameB as companyName, 
    (select 
    count(companyID) 
    from 
    items 
    where 
    companyID = b.idB 
) as items 
from 
    companiesB as b 
where 
    b.nameB like '%<string>%' 

order by 
    companyName ASC 
limit 
    [optional_starting_index, ] 50; 

을 (그것은이었다 전체 'items'테이블에 관한 값을 깔끔하게 반환 할 수있는 유일한 방법입니다. 나는 1500 개의 회사와 9000 개의 아이템으로이 알고리즘은 7 초 밖에 걸리지 않는다고 스스로 운이 좋다고 생각합니다.

내가 직접 테이블에 액세스 할 수있는 다른 언어로이 글을 쓰고 있다면 쉽게 O (회사 + 항목) 시간에이 글을 쓸 수 있지만 어떻게해야 하는지를 알기가 어렵습니다. MySQL. 가능하면 저장된 함수 나 프로 시저없이이 작업을 수행 할 수 있습니까? 필자는 필요하다면 추가 할 수 있지만, phpMyAdmin을 통해 서버의 호스트가 GUI로 데이터베이스에 액세스하는 것을 허용하기 때문에 추가하는 데 어려움이 있습니다.

답변

1

이 솔루션에서 나는 각 테이블의 회사 이름이 Union All을 사용하여 고유하다는 과감한 가정을 취했습니다. 그렇지 않은 경우 Union으로 다시 전환 할 수 있지만 목록을 고유하게 만들면 성능이 저하됩니다. 기본적으로 파생 테이블을 사용하여 상관 관계가있는 하위 쿼리가 카운트를 반환하지 않아도됩니다.

Select Companies.CompanyID, Companies.CompanyName 
    , Coalesce(ItemTotals.ItemCount,0) As ItemCount 
From (
     Select a.aID As CompanyID, a.aName As CompanyName 
     From companiesA As a 
     Where a.aName Like '%<string>%' 
     Union All 
     Select b.IDB, b.nameB 
     From companiesB As b 
     Where b.bName Like '%<string>%' 
     ) As Companies 
    Left Join (
       Select companyID, Count(*) As ItemCount 
       From items 
       Group By companyID 
       ) As ItemTotals 
      On ItemTotals.companyID = Companies.CompanyID 
Order By Company.CompanyName 

다음은 다른 변형입니다. 이것은 상관 관계가있는 하위 쿼리를 두 개의 Group By 쿼리로 바꾼 것을 제외하고는 원본과 비슷합니다. 이전처럼 두 테이블 사이의 이름과 ID가 상호 배타적 인 경우 Union All을 사용하면 Union을 사용해야합니다.

Select Z.CompanyId, Z.CompanyName, Z.ItemCount 
From (
     Select A.companyID, A.aName As CompanyName 
      , Count(I.CompanyID) As ItemCount 
     From companiesA As A 
      Left Join items As I 
       On I.CompanyId = A.CompanyId 
     Where A.aName Like '%<string>%' 
     Group By A.companyID, A.aName 
     Union All 
     Select B.companyID, B.bName, Count(I.CompanyID) 
     From companiesB As B 
      Left Join items As I 
       On I.CompanyId = B.CompanyId 
     Where B.bName Like '%<string>%' 
     Group By B.companyID, B.bName 
     ) As Z 
Order By Z.CompanyName 
+0

D : 많이 배우겠습니다! 더 빠릅니다. – sadakatsu

+0

두 버전을 테스트했습니다. 첫 번째 게임은 0.2 초 미만으로 실행됩니다. 두 번째는 6.5 초 (내 버전과 동등)이므로 실행되지 않습니다. 대답을 주셔서 감사합니다. 이것은 많이 가르쳐 왔습니다. – sadakatsu

관련 문제