2010-06-30 2 views
1

나는 특정 시점에서 하나의 연락처와 다른 연락처 사이의 관계에 대해보고 된 강도를 저장하는 contact_relationship 테이블을 가지고 있습니다.최적화 최적화 도움말 (연락처 간의 양방향 관계 강도 표시)

mysql> desc contact_relationship; 
+------------------+-----------+------+-----+-------------------+-----------------------------+ 
| Field   | Type  | Null | Key | Default   | Extra      | 
+------------------+-----------+------+-----+-------------------+-----------------------------+ 
| relationship_id | int(11) | YES |  | NULL    |        | 
| contact_id  | int(11) | YES | MUL | NULL    |        | 
| other_contact_id | int(11) | YES |  | NULL    |        | 
| strength   | int(11) | YES |  | NULL    |        | 
| recorded   | timestamp | NO |  | CURRENT_TIMESTAMP | on update CURRENT_TIMESTAMP | 
+------------------+-----------+------+-----+-------------------+-----------------------------+ 

는 이제 두 개의 행, 접촉이 하나있다 (의미 접점간에 양방향 관계들의리스트를 얻고 싶은 상대 A의 강도를 지정하는 B 접촉 관계 접촉 B의 강도와 다른 지정 - 양방향 관계의 강도는 두 강도 값 중 작은 값입니다.

쿼리는 내가 함께 왔어요되지만 꽤 느리다 :

select 
    mrcr1.contact_id, 
    mrcr1.other_contact_id, 
    case when (mrcr1.strength < mrcr2.strength) then 
     mrcr1.strength 
    else 
     mrcr2.strength 
    end strength 
from ( 
    select 
     cr1.* 
    from ( 
     select 
      contact_id, 
      other_contact_id, 
      max(recorded) as max_recorded 
     from 
      contact_relationship 
     group by 
      contact_id, 
      other_contact_id 
    ) as cr2 
    inner join contact_relationship cr1 on 
     cr1.contact_id = cr2.contact_id 
     and cr1.other_contact_id = cr2.other_contact_id 
     and cr1.recorded = cr2.max_recorded 
) as mrcr1, 
( 
    select 
     cr3.* 
    from ( 
     select 
      contact_id, 
      other_contact_id, 
      max(recorded) as max_recorded 
     from 
      contact_relationship 
     group by 
      contact_id, 
      other_contact_id 
    ) as cr4 
    inner join contact_relationship cr3 on 
     cr3.contact_id = cr4.contact_id 
     and cr3.other_contact_id = cr4.other_contact_id 
     and cr3.recorded = cr4.max_recorded 
) as mrcr2 
where 
    mrcr1.contact_id = mrcr2.other_contact_id 
    and mrcr1.other_contact_id = mrcr2.contact_id 
    and mrcr1.contact_id != mrcr1.other_contact_id 
    and mrcr2.contact_id != mrcr2.other_contact_id 
    and mrcr1.contact_id <= mrcr1.other_contact_id; 

사람은 속도를하는 방법에 대한 권장 사항이 있습니까?

사용자가 특정 사용자와 자신의 관계 강도를 두 번 이상 지정할 수 있으므로 각 연락처 쌍에 대한 최신 레코드 만 가져와야한다는 점에 유의하십시오.

업데이트 : 여기에 쿼리를 설명하는 결과 ...

+----+-------------+----------------------+-------+----------------------------------------------------------------------------------------+------------------------------+---------+-------------------------------------+-------+--------------------------------+ 
| id | select_type | table    | type | possible_keys                   | key       | key_len | ref         | rows | Extra       | 
+----+-------------+----------------------+-------+----------------------------------------------------------------------------------------+------------------------------+---------+-------------------------------------+-------+--------------------------------+ 
| 1 | PRIMARY  | <derived2>   | ALL | NULL                     | NULL       | NULL | NULL        | 36029 | Using where     | 
| 1 | PRIMARY  | <derived4>   | ALL | NULL                     | NULL       | NULL | NULL        | 36029 | Using where; Using join buffer | 
| 4 | DERIVED  | <derived5>   | ALL | NULL                     | NULL       | NULL | NULL        | 36021 |        | 
| 4 | DERIVED  | cr3     | ref | contact_relationship_index_1,contact_relationship_index_2,contact_relationship_index_3 | contact_relationship_index_2 | 10  | cr4.contact_id,cr4.other_contact_id |  1 | Using where     | 
| 5 | DERIVED  | contact_relationship | index | NULL                     | contact_relationship_index_3 | 14  | NULL        | 37973 | Using index     | 
| 2 | DERIVED  | <derived3>   | ALL | NULL                     | NULL       | NULL | NULL        | 36021 |        | 
| 2 | DERIVED  | cr1     | ref | contact_relationship_index_1,contact_relationship_index_2,contact_relationship_index_3 | contact_relationship_index_2 | 10  | cr2.contact_id,cr2.other_contact_id |  1 | Using where     | 
| 3 | DERIVED  | contact_relationship | index | NULL                     | contact_relationship_index_3 | 14  | NULL        | 37973 | Using index     | 
+----+-------------+----------------------+-------+----------------------------------------------------------------------------------------+------------------------------+---------+-------------------------------------+-------+--------------------------------+ 
+0

당신은 실행 계획을 게시 할 수 : 내 두 개의 임시 테이블

내 쿼리가 후하게 만들어? –

+0

사용중인 DBMS를 게시 할 수 있습니까? –

+0

mysql – emh

답변

0

당신은 가장 최근의 기록을 선택 많은 시간 로트을 많이 잃고입니다. 2 옵션 :

1- 데이터를 저장하는 방식을 변경하고 최근 레코드 만있는 테이블과 다른 레코드를 더 많이 가진 테이블을 사용하십시오.

2- DBMS에서 허용하는 경우 분석 요청을 사용하여 최신 레코드를 선택하십시오. 예를 들어

좋은 레코드 라인을 확보하면 쿼리가 훨씬 빨라질 것입니다.

+0

을 사용하고 있습니다. 임시 테이블을 사용하여 모든 최신 관계 행 (아래 참조)을 사용할 수 있다고 생각합니다. 감사합니다. – emh

0

Scorpi0의 대답은

create temporary table mrcr1 (
    contact_id int, 
    other_contact_id int, 
    strength int, 
    index mrcr1_index_1 (
     contact_id, 
     other_contact_id 
    ) 
) replace as 
    select 
     cr1.contact_id, 
     cr1.other_contact_id, 
     cr1.strength from ( 
      select 
       contact_id, 
       other_contact_id, 
       max(recorded) as max_recorded 
      from 
       contact_relationship 
      group by 
       contact_id, other_contact_id 
     ) as cr2 
     inner join 
      contact_relationship cr1 on 
       cr1.contact_id = cr2.contact_id 
       and cr1.other_contact_id = cr2.other_contact_id 
       and cr1.recorded = cr2.max_recorded; 

MySQL이 제한 어디이 있기 때문에 내가 (임시 테이블 이름 mrcr2로 두 번째)를 두 번해야했다하는 ... 어쩌면 내가 임시 테이블을 사용할 수 있습니다 생각에 저를 얻었다 하나의 쿼리에서 동일한 임시 테이블을 두 번 별칭으로 지정할 수 없습니다.

select 
    mrcr1.contact_id, 
    mrcr1.other_contact_id, 
    case when (mrcr1.strength < mrcr2.strength) then 
     mrcr1.strength 
    else 
     mrcr2.strength 
    end strength 
from 
    mrcr1, 
    mrcr2 
where 
    mrcr1.contact_id = mrcr2.other_contact_id 
    and mrcr1.other_contact_id = mrcr2.contact_id 
    and mrcr1.contact_id != mrcr1.other_contact_id 
    and mrcr2.contact_id != mrcr2.other_contact_id 
    and mrcr1.contact_id <= mrcr1.other_contact_id; 
+0

불행히도 프로덕션 환경에서는 임시 테이블을 만들 수있는 권한이 없습니다. ( – emh

+0

임시 테이블은 실제로 좋은 생각이 아닙니다. 구조를 변경해야한다는 상급자와 논의하십시오. 프로덕션 및 현재 쿼리 용 테이블 하나 프로덕션 테이블로 새 행을 삽입하는 로그 테이블 –

+0

임시 테이블이 나쁜 아이디어 인 이유를 설명 할 수 있습니까? – emh