2013-06-03 5 views
1

그래서 프로젝트에 대해 다음을 수행하고 싶습니다.subselect를 사용하면 복잡한 쿼리가 실제로 느려집니다.

3 개의 테이블이 있습니다. 지금은 먼저이 문제 우리는 (세 번째는 이해를 돕기위한 것입니다) :

author {id, name} 
authorship {id, id1, id2} 
paper {id, title} 

저자는 authorship.id2가 paper.id를 의미, author.id을 말한다 종이와 authorship.id1와 저자를 연결합니다.

내가하고 싶은 일은 두 명의 저자 사이의 공통 논문의 양에 의해 결정되는 각 저자와 가장자리에 대한 노드가있는 그래프를 만드는 것입니다.

w=1 - union_of_common_papers/intersection_of_common_papers 

그래서 내가 만든 것을 공동 저자의 모든 부부 플러스 노동 조합의 양 및 일반 논문의 교차를 반환하는 SQL 스크립트 (유래의 도움으로). 그 후에 나는 자바로 데이터를 사용할 것이다. 그건 다음

SELECT DISTINCT a1.name, a2.name, (
    SELECT concat(count(a.id2), ',', count(DISTINCT a.id2)) 
    FROM authorship a 
    WHERE a.id1=a1.id or a.id1=a2.id) as weight 
FROM authorship au1 
INNER JOIN authorship au2 ON au1.id2 = au2.id2 AND au1.id1 <> au2.id1 
INNER JOIN author a1 ON au1.id1 = a1.id 
INNER JOIN author a2 ON au2.id1 = a2.id; 

이 내 일을 수행하고 같은 목록을 반환

나는 두 숫자를 볼 수 있습니다 무게
+-----------------+---------------------+---------+ 
| name   | name    | weight | 
+-----------------+---------------------+---------+ 
| Kurt   | Michael    | 161,157 | 
| Kurt   | Miron    | 138,134 | 
| Kurt   | Manish    | 19,18 | 
| Roy    | Gregory    | 21,20 | 
| Roy    | Richard    | 74,71 | 
.... 

A, B는 교차점이 어디 바는의 조합이다 b를 공통 논문.

하지만이 작업에는 많은 시간이 걸립니다. 그리고 모든 오버 헤드가 모든 레코드 (1M +)이 2mins 미만 반환 된 라인이없이 추가적인 부속

(SELECT concat(count(a.id2), ',', count(DISTINCT a.id2)) 
    FROM authorship a 
    WHERE a.id1=a1.id or a.id1=a2.id) as weight 

입니다. 내가 명령 줄

내가 그것을 최적화하는 방법 어떤 아이디어를 통해 리눅스에 MySQL을 사용 더 1.5mins

보다 50 기록이 필요로하는이 라인 ?

  • 저자는 ~ 13 만 개 기록
  • 저자 ~ 1,300,000 기록
  • 쿼리가 ~ 1,200,000 기록

이이 쿼리에 대한 반환을 설명 무엇을 반환해야 있습니다. 그것을 어떻게 사용하는지 모른다.

+----+--------------------+-------+--------+---------------------+-----------+---------+--------------+---------+-----------------+ 
| id | select_type  | table | type | possible_keys  | key  | key_len | ref   | rows | Extra   | 
+----+--------------------+-------+--------+---------------------+-----------+---------+--------------+---------+-----------------+ 
| 1 | PRIMARY   | a1 | ALL | PRIMARY    | NULL  | NULL | NULL   | 124768 | Using temporary | 
| 1 | PRIMARY   | au1 | ref | NewIndex1,NewIndex2 | NewIndex1 | 5  | dblp.a1.ID |  4 | Using where  | 
| 1 | PRIMARY   | au2 | ref | NewIndex1,NewIndex2 | NewIndex2 | 5  | dblp.au1.id2 |  1 | Using where  | 
| 1 | PRIMARY   | a2 | eq_ref | PRIMARY    | PRIMARY | 4  | dblp.au2.id1 |  1 |     | 
| 2 | DEPENDENT SUBQUERY | a  | ALL | NewIndex1   | NULL  | NULL | NULL   | 1268557 | Using where  | 
+----+--------------------+-------+--------+---------------------+-----------+---------+--------------+---------+-----------------+ 

답변

0

외부 쿼리의 조인에서 직접 데이터를 가져올 수 있어야합니다.

id2 고유 번호를 두 저자 모두 동일하게 계산하여 공통적으로 논문 수를 계산할 수 있습니다. (그렇지 않으면이 두 번 계산 때문에)

당신은 별개의 각 저자에 대한 논문을 뺀 공통점 사람의 수와 논문의 총 수를 셀 수 있습니다 : 데이터 구조에서

SELECT a1.name, a2.name, 
     COUNT(distinct case when au1.id2 = au2.id2 then au1.id2 end) as CommonPapers, 
     COUNT(distinct au1.id2) + COUNT(distinct au2.id2) - COUNT(distinct case when au1.id2 = au2.id2 then au1.id2 end) as TotalPapers 
FROM authorship au1 INNER JOIN 
    authorship au2 
    ON au1.id2 = au2.id2 AND au1.id1 <> au2.id1 INNER JOIN 
    author a1 
    ON au1.id1 = a1.id INNER JOIN 
    author a2 
    ON au2.id1 = a2.id 
group by a1.name, a2.name; 

, id1id2은 형편없는 이름입니다. idauthoridpaper과 같은 것을 고려 했습니까?

위 쿼리는 초기 내부 조인으로 인해 교차를 올바르게 계산하지만 전체는 계산하지 않습니다. 이 문제를 해결하는 한 가지 방법은 full outer join이지만 MySQL에서는 허용되지 않습니다. 추가 하위 쿼리를 사용하면 다음과 같이 할 수 있습니다.

SELECT a1.name, a2.name, 
     COUNT(distinct case when au1.id2 = au2.id2 then au1.id2 end) as CommonPapers, 
     (ap1.NumPapers + ap2.NumPapers - COUNT(distinct case when au1.id2 = au2.id2 then au1.id2 end) 
     ) as TotalPapers 
FROM authorship au1 INNER JOIN 
    authorship au2 
    ON au1.id2 = au2.id2 AND au1.id1 <> au2.id1 INNER JOIN 
    author a1 
    ON au1.id1 = a1.id INNER JOIN 
    author a2 
    ON au2.id1 = a2.id inner join 
    (select au.id1, count(*) as numpapers 
     from authorship au 
    ) ap1 
    on ap1.id1 = au1.id1 inner join 
    (select au.id1, count(*) as numpapers 
     from authorship au 
    ) ap2 
    on ap2.id1 = au2.id1 inner join 
group by a1.name, a2.name; 
+0

ID 이름에 대해 완전히 맞습니다. 나는 너의 제안을 확인하고있다. – serkef

+0

아니요, 실제로 작동하지 않습니다. 영원히 달리기 같이 보인다. 그리고 나는 한도를 5로 설정했습니다. – serkef

+0

'author (id)'와'authorship (id2, id1)'에 대한 색인이 있습니까? 그들은 도움이 될 수 있습니다. 데이터 행이 많습니다. 그 중 한 논문에 저자가 1000 명이 있다면 그 자료는 실제로 증가합니다. –

관련 문제