sql >> Base de Datos >  >> RDS >> Oracle

¿Qué hay de malo con los cursores?

Lo que está mal con los cursores es que a menudo se abusa de ellos, tanto en Oracle y en MS SQL .

Los cursores son para mantener un conjunto de resultados estable que puede recuperar fila por fila. Se crean implícitamente cuando se ejecuta la consulta y se cierran cuando finaliza.

Por supuesto, mantener un conjunto de resultados de este tipo requiere algunos recursos:locks , latches , memory , incluso disk space .

Cuanto más rápido se liberen estos recursos, mejor.

Mantener un cursor abierto es como mantener abierta la puerta de un frigorífico

No lo haces durante horas sin necesidad, pero eso no significa que nunca debas abrir tu nevera.

Eso significa que:

  • No obtienes tus resultados fila por fila y los sumas:llamas al SQL de SUM en su lugar.
  • No ejecuta la consulta completa y obtiene los primeros resultados del cursor:agrega un rownum <= 10 condición a su consulta

, etc.

En cuanto a Oracle , procesar sus cursores dentro de un procedimiento requiere el infame SQL/PLSQL context switch lo que sucede cada vez que obtienes un resultado de un SQL consulta fuera del cursor.

Implica pasar grandes cantidades de datos entre subprocesos y sincronizar los subprocesos.

Esta es una de las cosas más irritantes en Oracle .

Una de las consecuencias menos evidentes de ese comportamiento es que, en la medida de lo posible, deben evitarse los disparadores en Oracle.

Crear un activador y llamar a un DML La función es igual a abrir el cursor, seleccionar las filas actualizadas y llamar al código de activación para cada fila de este cursor.

La mera existencia del disparador (incluso el disparador vacío) puede ralentizar un DML operación 10 times o más.

Un script de prueba en 10g :

SQL> CREATE TABLE trigger_test (id INT NOT NULL)
  2  /

Table created

Executed in 0,031 seconds
SQL> INSERT
  2  INTO   trigger_test
  3  SELECT level
  4  FROM   dual
  5  CONNECT BY
  6     level <= 1000000
  7  /

1000000 rows inserted

Executed in 1,469 seconds
SQL> COMMIT
  2  /

Commit complete

Executed in 0 seconds
SQL> TRUNCATE TABLE trigger_test
  2  /

Table truncated

Executed in 3 seconds
SQL> CREATE TRIGGER trg_test_ai
  2  AFTER INSERT
  3  ON trigger_test
  4  FOR EACH ROW
  5  BEGIN
  6     NULL;
  7  END;
  8  /

Trigger created

Executed in 0,094 seconds
SQL> INSERT
  2  INTO   trigger_test
  3  SELECT level
  4  FROM   dual
  5  CONNECT BY
  6     level <= 1000000
  7  /

1000000 rows inserted

Executed in 17,578 seconds

1.47 segundos sin disparador, 17.57 segundos con un gatillo vacío sin hacer nada.