2017-03-14 13 views
0

나는 25mln 행 테이블에서 각 행을 가져 와서 이전 행과 비교하는 매우 간단한 plpgsql 함수를 작성합니다. 2 개의 형제 행이 같은 열 "AOGUID" 인 경우, 그것들이 리턴됩니다. 내가 알고있는 것처럼이유가 무엇입니까 <query> LOOP가 기본 쿼리보다 속도가 훨씬 빠릅니까?

CREATE or replace FUNCTION get_duplicate_zemli() RETURNS setof character varying AS $$ 
DECLARE 
    each_zemla character varying; 
    prev_zemla character varying; 
BEGIN 
    FOR each_zemla IN SELECT "AOGUID" FROM "Zemla" ORDER BY "AOGUID" LOOP 
     if (prev_zemla = each_zemla) then 
      return next each_zemla; 
     end if; 
     prev_zemla:= each_zemla; 
    END LOOP; 
END; 
$$ LANGUAGE plpgsql; 

,이 기능은 나에게이 사실이 아니다

SELECT "AOGUID" FROM "Zemla" ORDER BY "AOGUID" 

불행하게도 일반 쿼리 시간 가까운 시간에 실행해야합니다. 일반 쿼리는 한 시간 만에 실행되지만 함수는 80 시간 내에 실행됩니다!

plpgsql 함수가 일반 쿼리보다 훨씬 느리게 실행되는 이유와 성능을 어떻게 향상시킬 수 있는지 설명 할 수 있습니까?

PS :

explain SELECT "AOGUID" FROM "Zemla" ORDER BY "AOGUID" 

가 Zemla "인덱스에서만 zemla_aoguid_not_unique를 사용하여 스캔", " 비용 (= 0.56..3336281.02 행 = 25,852,488 폭 = 37)"

+1

관련 없음 - 창 기능을 사용하지 않는 이유는 무엇입니까? 예를 들어'lag' 또는'lead? '에 대해서 .. –

+3

일반 SQL로 할 수 있다면 for 루프 (또는 PL/pgSQL)를 사용하지 마십시오. –

+0

@a_horse_with_no_name : [절대로 말하지 마십시오.] (http://dba.stackexchange.com/questions/166374/grouping-or-window/166397#166397)이 경험 법칙은 예외입니다. –

답변

0

검사 비용 그러한 qry의 :

explain with pre94 as (
    SELECT "AOGUID", lag("AOGUID") over (ORDER BY "AOGUID") = "AOGUID" test_eq FROM "Zemla" 
) 
select "AOGUID" from pre94 where test_eq 

내가 믿는 창 함수는 당신을 도울 수있다. 귀하의 작업을 더 잘 누른 다음 자체 기능을 만들었습니다.

당신이 9.4 or later

+0

이 qry는 50-70 배 빠릅니다. 더 향상시킬 수 있습니까? 나는 "FILTERR" ''' 에 대한 답을 이해하지 못하는 이상 ( SELECT "AOGUID"에서 "AOGUID", 지연 ("AOGUID") ("AOGUID"BY ORDER) = FROM "AOGUID"test_eq 을 선택 "Zemla" ) eq 여기서 test_eq ' – alexey2baranov

+0

은 그렇게 생각하지 않습니다. - 여전히 비교가 필요합니다. 나는 당신에게 postgres의 버전을 알지 못해서 9.4와 함께 제공되는 기능에 대한 의견을 말했습니다. –

+0

9.5 'CTE Scan on pre94 (비용 = 5311965.00..5838177.행 82 = 13,155,320 폭 = 516) " 필터 : test_eq" CTE의 pre94 " -> WindowAgg 비용 (= 4785752.18..5311965.00 행 = 26,310,641 폭 = 37)" -> 정렬 비용 (= 4785752.18..4851528.78 = 행 26310641 너비 = 37) "정렬 키 :"Zemla "."AOGUID "" -> "Zemla"의 Seq 스캔 (비용 = 0.00 .. 823646.41 행 = 26310641 너비 = 37)' – alexey2baranov

1

를 사용하는 경우 또한 당신은 FILTER으로 QRY 줄일 수 있습니다 어쩌면 내가 당신의 쿼리를 잘못 읽고 있어요,하지만 당신은 단 한 번 "Zemla"보다 더 나타나는 AOGUID 항목을 식별하지 않습니다? 그룹화 된 단일 쿼리로 수행 할 수 없습니까?

SELECT "AOGUID" FROM "Zemla" 
GROUP BY "AOGUID" 
HAVING COUNT(*) > 1 
ORDER BY "AOGUID"