2010-11-22 3 views
2

테이블은 calling_party 및 called_party 열로 구성되며 레코드는 호출자 역할을하고 다른 하나는 파티라고하는 두 사용자 간의 연결을 설명합니다.공통 및 모든 이웃을 계산하는 다음 쿼리를 최적화하기위한 제안은 무엇입니까?

동일한 두 명의 사용자가 두 개의 연결을 가질 수 있습니다.이 경우 방향이 변경되면 역할/발신자 역할이 전환됩니다.

원본 테이블 (monthly_connections)에서 일반 및 전체 이웃의 수가 저장되는 common_neighbors 및 total_neighbors 열을 추가했습니다. 이 전화의 공통 이웃과 상대방과 총 6 개 이웃이있다

alt text

관찰 된 연결이 경우 : 용어가 일반적인 명확히하고 total_neighbors하기 위해 나는 다음과 같은 이미지를 추가했다. 이 두 값을 얻기 위하여

나는 다음과 같은 저장 프로 시저를 썼다 :

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 

같은 뭔가하지만 난이 23M의 레코드를 반복하고 그들 모두에 대해 여러 쿼리를 호출하는 것보다 빠를 수 있다고 생각, 전체 목록을 얻을 수있는 called_party에 가입 할 수 있습니다.

관련 문제