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.
4 Réponses :
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
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 );
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
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.