2010-06-30 38 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 | 
+------------------+-----------+------+-----+-------------------+-----------------------------+ 

現在我想的雙向關係的觸點之間的列表(含義有兩排,其中一個接觸的指定與觸點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

你能後的執行計劃? – 2010-06-30 05:56:59

+0

你可以發佈你正在使用的DBMS嗎? – 2010-06-30 07:13:07

+0

我正在使用mysql – emh 2010-06-30 07:27:17

回答

0

你失去了很多很多很多的時間來選擇最近的記錄。 2選項:

1-改變數據備份的方式,使表格只包含最近的記錄,另一個表格更像歷史記錄。

2-如果您的DBMS允許您執行此操作,請使用分析請求選擇最近的記錄。類似於

Select first_value(strength) over(partition by contact_id, other_contact_id order by recorded desc) 
from contact_relationship 

一旦你有良好的記錄行,我認爲你的查詢將會快得多。

+0

你讓我想我可以使用臨時表來提取所有最新的關係行(見下文)。 謝謝! – emh 2010-06-30 08:19:58

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; 

這是我必須做兩次(第二次到一個名爲mrcr2臨時表),因爲MySQL有一個限制,你在一個查詢中不能將相同的臨時表兩次混淆。

與我的兩個臨時表創建然後我的查詢變爲:

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 2010-06-30 08:21:25

+0

),臨時表並不是一個好主意,與您的上級爭辯說,您必須更改結構,一個表用於生產和當前查詢,另一個表日誌表在生產表更新時插入新行 – 2010-06-30 08:50:16

+0

你能解釋爲什麼臨時表是一個壞主意嗎? – emh 2010-06-30 17:08:17