Oracle
 sql >> Base de données >  >> RDS >> Oracle

Quel est le problème avec les curseurs ?

Ce qui ne va pas avec les curseurs, c'est qu'ils sont souvent abusés, à la fois dans Oracle et en MS SQL .

Le curseur sert à conserver un jeu de résultats stable que vous pouvez récupérer ligne par ligne. Ils sont implicitement créés lors de l'exécution de votre requête et fermés lorsqu'elle est terminée.

Bien sûr, conserver un tel jeu de résultats nécessite certaines ressources :locks , latches , memory , voire disk space .

Plus ces ressources sont libérées rapidement, mieux c'est.

Laisser un curseur ouvert, c'est comme garder la porte d'un réfrigérateur ouverte

Vous ne le faites pas pendant des heures sans nécessité, mais cela ne signifie pas que vous ne devriez jamais ouvrir votre réfrigérateur.

Cela signifie que :

  • Vous n'obtenez pas vos résultats ligne par ligne et ne les additionnez pas :vous appelez le SQL est SUM à la place.
  • Vous n'exécutez pas la requête entière et n'obtenez pas les premiers résultats du curseur :vous ajoutez un rownum <= 10 condition à votre requête

, etc.

Comme pour Oracle , le traitement de vos curseurs à l'intérieur d'une procédure nécessite le fameux SQL/PLSQL context switch qui se produit à chaque fois que vous obtenez un résultat d'un SQL requête hors du curseur.

Cela implique de transmettre de grandes quantités de données entre les threads et de synchroniser les threads.

C'est l'une des choses les plus irritantes dans Oracle .

L'une des conséquences les moins évidentes de ce comportement est que les déclencheurs dans Oracle doivent être évités si possible.

Création d'un déclencheur et appel d'un DML fonction revient à ouvrir le curseur en sélectionnant les lignes mises à jour et en appelant le code déclencheur pour chaque ligne de ce curseur.

La simple existence du déclencheur (même le déclencheur vide) peut ralentir un DML opération 10 times ou plus.

Un script de test sur 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 secondes sans déclencheur, 17.57 secondes avec un déclencheur vide ne faisant rien.