0
votes

Optimisation SQL - Exécuter la fonction une seule fois pour chaque identifiant distinct dans une requête jointe

Je suis un développeur full stack avec peu de connaissances en SQL.

Considérez ce code ->

(j'ai réduit ma grande requête à ceci pour cerner mon doute)

< pre> XXX

Je crois que get_lowest_due_date () est en cours d'exécution pour toutes les valeurs fileId renvoyées par la requête Join (même les doublons).

Est-il possible de faire exécuter la fonction uniquement pour des valeurs uniques de fileId ? J'essaye d'optimiser la requête.


0 commentaires

4 Réponses :


1
votes

Vous pouvez essayer:

SELECT get_lowest_due_date(a.fileId)
FROM (SELECT f.fileId 
      FROM File f
      JOIN Order o 
      ON o.fileId =  f.fileId
      GROUP BY f.fileId) a

La requête interne renvoie des identifiants de fichier uniques


0 commentaires

0
votes

Une fonction scalaire est appelée pour chaque ligne renvoyée par l'instruction select à partir de laquelle elle est appelée et oui les fonctions scalaires ne fonctionnent pas bien.

Vous pouvez convertir cette fonction scalaire en une fonction à valeur de table en ligne, ( donc la table renvoie une table au lieu d'une valeur scalaire), et utilisez CROSS APPLY ou OUTER APPLY pour appeler la fonction.

Définition de la fonction:

 SELECT *
    FROM File f
    JOIN Order o 
     ON o.fileId =  f.fileId
    CROSS APPLY  get_lowest_due_date(f.fileId)

Votre nouvelle requête:

CREATE FUNCTION dbo.get_lowest_due_date (@fileId INT)
RETURNS TABLE 
AS
RETURN 
(
  /* or whatever your logic is */
 SELECT Value from SomeTable WHERE fileId = @fileId
);


0 commentaires

1
votes

Une fonction stockée SQL (ou une procédure stockée) peut être DETERMINISTIC. Cela signifie que le résultat de votre fonction dépend uniquement de sa valeur d'entrée et non d'autres choses. Par exemple, GETDATE () n'est pas déterministe et SQRT ((x * x) + (y * y)) l'est.

Lorsqu'une fonction est DETERMINISTIC, l'optimiseur de serveur évite d'appeler la fonction plusieurs fois pour les mêmes valeurs. Si la fonction n'est pas déterministe, l'optimiseur de serveur n'a généralement pas cette liberté.

Si votre fonction contient du SQL, il peut être judicieux de refactoriser votre requête en une structure JOIN ou similaire qui place directement le SQL de la fonction dans votre requête. Cela permettra à l'optimiseur MySQL d'incorporer ses opérations de la meilleure façon possible.

En tout cas, votre exemple appelle votre fonction pour chaque valeur de File.fileId . Vous pouvez le forcer à fonctionner uniquement avec des valeurs distinctes en utilisant une requête imbriquée comme celle-ci.

 SELECT get_lowest_due_date(fileId)
   FROM (
           SELECT DISTINCT f.fileId
             FROM File f
            JOIN Order o 
                 ON o.fileId =  f.fileId
        ) f


0 commentaires

0
votes

Dans le contexte de votre question, vous avez probablement d'autres colonnes, donc renvoyer uniquement des identifiants de fichiers distincts n'est pas une option.

Pour votre exemple, vous pouvez appeler la fonction dans une sous-requête sur Fichier :

select fo.*,
       max(first_lowest_due_date) over (partition by fileid) as lowest_due_date
from (select . . .,
             (case when row_number() over (partition by fileid order by orderid) = 1
                   then get_lowest_due_date(f.fileId) 
              end) as first_lowest_due_date
      from file f join
           orders o
           on o.fileid = f.fileid
     ) fo;

Il existe d'autres astuces que vous pouvez utiliser, telles que:

SELECT f.*
FROM (SELECT f.*, get_lowest_due_date(f.fileId) as lowest_due_date
      FROM File f
     ) f JOIN
     Order o 
     ON o.fileId =  f.fileId;

Cela dit, je suppose que vous pensez qu'une fonction définie par l'utilisateur est une bonne idée. SQL n'est pas un langage de programmation et - hélas - les fonctions définies par l'utilisateur ont des performances plutôt lamentables. Si possible, je suggérerais de supprimer la fonction, peut-être en utilisant une vue ou une fonction en ligne à valeur table.


0 commentaires