2010-11-22 26 views
2

該表由call_party和called_pa​​rty列組成,記錄描述兩個用戶之間的連接,其中一個扮演主叫方角色,另一個扮演主叫方角色。任何有關優化以下查詢的建議,這些查詢包括普通和所有鄰居?

相同的兩個用戶可以有兩個連接 - 在這種情況下,當方向改變時,角色主叫/被叫方被切換。

在原始表(monthly_connections)中,我添加了common_neighbors和total_neighbors的附加列,其中存儲了常見鄰居和總鄰居的數量。爲了澄清,術語共同和total_neighbors添加以下圖像:

alt text

在這種情況下所觀察到的連接有主叫的2個共同鄰居和被叫方6個總鄰居。

爲了得到這兩個值我寫了下面的存儲過程:

CREATE PROCEDURE [dbo].[spCountNeighbors] 

AS 

Declare 
@CallingParty varchar(50), 
@CalledParty varchar(50), 
@RecordsUpdated int 

SET @CallingParty ='a' 
SET @RecordsUpdated = 0 
PRINT GETDATE() 
WHILE @CallingParty IS NOT NULL BEGIN 
    SET @CallingParty = NULL 
    SELECT TOP 1 @CallingParty = calling_party, @CalledParty = called_party FROM monthly_connections WHERE common_neighbors IS NULL 
    --PRINT @CallingParty 
    IF @CallingParty IS NOT NULL BEGIN 
    WITH callingPartyNeighbors AS 
    (
     SELECT called_party as neighbor FROM monthly_connections WHERE calling_party = @CallingParty 
     UNION 
     SELECT calling_party as neighbor FROM monthly_connections WHERE called_party = @CallingParty 
    ), 
    calledPartyNeighbors AS 
    (
     SELECT calling_party as neighbor FROM monthly_connections WHERE called_party = @CalledParty 
     UNION 
     SELECT called_party as neighbor FROM monthly_connections WHERE calling_party = @CalledParty 
    ) 

     UPDATE mc SET common_neighbors = (SELECT COUNT (*) FROM 
     (
     SELECT neighbor FROM callingPartyNeighbors 
     INTERSECT 
     SELECT neighbor FROM calledPartyNeighbors 
     ) 
     t1 
     ), 
     total_neighbors = (SELECT COUNT (*) FROM 
     (
     SELECT neighbor FROM callingPartyNeighbors 
     UNION 
     SELECT neighbor FROM calledPartyNeighbors 
     ) 
     t2 
     ) 
     FROM monthly_connections mc WHERE (mc.calling_party = @CallingParty AND mc.called_party = @CalledParty) OR (mc.called_party = @CallingParty AND mc.calling_party = @CalledParty); 
     SET @RecordsUpdated = @RecordsUpdated + @@ROWCOUNT 
     PRINT @RecordsUpdated 
    END 
END 
PRINT @RecordsUpdated 

的程序上面應該去通過連接其中包含的每一行23M的連接和更新值common_neighbors和total_neighbors表。然而,問題在於程序太慢 - 更新1000條記錄需要212秒。

爲了加快執行時間,我真的很感謝你們中的任何人提出了上述過程的任何修正。

謝謝!

回答

0

以下腳本會爲您的存儲過程生成與common_neighbors相同的輸出。不過,儘管如此,我感覺它並不完全(但)是你需要的,但是你可能會爲它提出一些新的想法。

DECLARE @monthly_connections TABLE (
    calling_party VARCHAR(50) 
    , called_party VARCHAR(50) 
    , common_neighbors INTEGER 
    , total_neighbors INTEGER) 

INSERT INTO @monthly_connections 
      SELECT '1', '3', NULL, NULL 
UNION ALL SELECT '2', '4', NULL, NULL 
UNION ALL SELECT '3', '2', NULL, NULL 
UNION ALL SELECT '3', '4', NULL, NULL 
UNION ALL SELECT '3', '6', NULL, NULL 
UNION ALL SELECT '3', '7', NULL, NULL 
UNION ALL SELECT '4', '5', NULL, NULL 
UNION ALL SELECT '8', '4', NULL, NULL 

;WITH q AS (
    SELECT calling_party, called_party 
    FROM @monthly_connections mc1 
    UNION ALL 
    SELECT called_party, calling_party 
    FROM @monthly_connections mc1 
) 
UPDATE @monthly_connections 
SET  common_neighbors = common_neighbors.cnt 
FROM @monthly_connections mc 
     INNER JOIN (
      SELECT q1.calling_party, q1.called_party, cnt = COUNT(*) 
      FROM q q1 
        INNER JOIN q q2 ON q2.calling_party = q1.called_party       
        INNER JOIN q q3 ON q3.calling_party = q2.called_party 
            AND q3.called_party = q1.calling_party 
      GROUP BY 
        q1.calling_party, q1.called_party 
     ) common_neighbors ON common_neighbors.calling_party = mc.calling_party 
           AND common_neighbors.called_party = mc.called_party 


SELECT * 
FROM @monthly_connections   
0

在你的程序中,你正在做很多的子查詢,我想這是你的性能損失的主要來源。 難道你不能只用一個大連接替換多個查詢,然後過濾它嗎? 喜歡的東西

SELECT T.calling_party, T.called_party, A.called_party, B.called_party 
from table T 
join table as A 
on T.calling_party = A.calling_party 
join table as B 
on T.calling_party = B.calling_party 
where A.called_party = B.called_party --to get the commong neighbour 

你可能會需要另一個加盟的called_pa​​rty得到完整的名單,但我認爲這可能比通過23M記錄迭代,並呼籲所有的人都多次查詢速度更快。