如何使这个功能更有效?使用非常大的文件

时间:2018-06-15 02:03:53

标签: sql postgresql plpgsql database-cursor

我在这些函数中使用了一个非常大的csv文件(大约716k行)。他们使用一个小文件快速工作,但是如此大量的行我已经离开了一个小时,它甚至没有结束。 事情是在某种程度上我称之为'LIMPIA_REPETIDOS()'函数

    CREATE OR REPLACE FUNCTION LIMPIA_REPETIDOS() 
    RETURNS VOID AS $$

    DECLARE 
        REP RECORD;
        cursor1 CURSOR FOR SELECT DISTINCT usuario, fecha_hora_ret FROM auxi;            

    begin
        open cursor1;
        LOOP
            FETCH cursor1 INTO REP;
            EXIT WHEN NOT FOUND;
            PERFORM GUARDA(REP.usuario, REP.fecha_hora_ret);
        END LOOP;
        CLOSE cursor1;
    end;

    $$ LANGUAGE PLPGSQL;



    CREATE OR REPLACE FUNCTION GUARDA
    (myid auxi.usuario%TYPE, my_time auxi.fecha_hora_ret%type) RETURNS VOID AS $$


    DECLARE
        mycursor CURSOR FOR
        SELECT * FROM auxi
        WHERE myid = usuario AND my_time = fecha_hora_ret
        ORDER BY tiempo_uso ASC;
        CANT INT;
        devolucion TIMESTAMP;
        mystruct RECORD;
        mystruct2 RECORD;


    BEGIN

     OPEN mycursor;
     CANT = 0;
            FETCH mycursor INTO mystruct;
                    FETCH mycursor INTO mystruct2;

                            IF mystruct2.usuario = mystruct.usuario AND mystruct2.fecha_hora_ret = mystruct.fecha_hora_ret THEN
                                     devolucion = crear_fecha_hora_devolucion(mystruct2.tiempo_uso, mystruct2.fecha_hora_ret);
                                     INSERT INTO RECORRIDO_FINAL VALUES(mystruct2.periodo, mystruct2.usuario, mystruct2.fecha_hora_ret, mystruct2.est_origen, mystruct2.est_origen, devolucion);

                            ELSE
                                    devolucion = crear_fecha_hora_devolucion(mystruct.tiempo_uso, mystruct.fecha_hora_ret);
                                    INSERT INTO RECORRIDO_FINAL VALUES(mystruct.periodo, mystruct.usuario, mystruct.fecha_hora_ret, mystruct.est_origen, mystruct.est_origen, devolucion);

                            END IF;


     CLOSE mycursor;   

   END;
   $$ LANGUAGE PLPGSQL; 

我在这里做的是从一个名为'auxi'的表中选择行,该表包含该文件中的所有行(除了一些具有空值但速度足够快的行),然后将它们转移到另一个行。问题是当'auxi'中有两行或更多行具有'usuario'和'fecha_hora_ret'的相同值时,我必须通过'tiempo_uso'对它们进行排序,然后选择第二行。我不知道为什么需要这么多时间。 我怎样才能让它更快?

表auxi有PRIMARY KEY(periodo,usuario,fecha_hora_ret,est_origen,est_destino,tiempo_uso) enter image description here 和table recorrido_final PRIMARY KEY(usuario,fecha_hora_ret) enter image description here

我很绝望,我不知道该怎么办。

2 个答案:

答案 0 :(得分:0)

代码中的LOOP和附加函数调用可能导致性能下降。您是否可以通过以下查询为其他PK列的每个组合选择tiempo_uso的最大值:

select
    periodo,
    usuario,
    fecha_hora_ret,
    est_origen,
    est_destino,
    max(tiempo_uso) as max_tiempo_uso
from
    auxi
group by
    periodo,
    usuario,
    fecha_hora_ret,
    est_origen,
    est_destino;

并将其用作INSERT INTO语句的数据源?这避免了代码中的函数调用和循环。

答案 1 :(得分:0)

使用游标处理数据通常非常低效且不需要,因为在大多数情况下它会被set-prcessing取代。

如果您需要查找最新的行,您可以使用简单的ROW_NUMBER:

select periodo, usuario, fecha_hora_ret, est_origen, est_origen
  ,crear_fecha_hora_devolucion(tiempo_uso, fecha_hora_ret) as devolucion
FROM
 (
    select periodo, usuario, fecha_hora_ret, est_origen, est_origen
      ,crear_fecha_hora_devolucion(tiempo_uso, fecha_hora_ret) as devolucion
      ,row_number() -- most recent row per usuario/fecha_hora_ret
       over (partition by usuario, fecha_hora_ret
             ORDER BY tiempo_uso DESC) as rn
    from auxi
 ) as dt
where rn = 1