J'y pensais il y a quelques jours après une optimisation SQL. Je pense que nous pouvons convenir que SQL est un "langage déclaratif" dans la définition de Wikipedia:
Paradigme de programmation qui exprime la logique du calcul sans décrire son flux de contrôle
Si vous pensez combien de choses se font derrière les rideaux (regarder les statistiques, décider si un index est utile, opter pour une jointure imbriquée, fusionnée ou de hachage, etc.), nous devons admettre que nous donnons juste un niveau élevé logique, et la base de données a pris en charge toute la logique de flux de contrôle de bas niveau.
Dans ce scénario également, l'optimiseur de base de données a parfois besoin de "conseils" de l'utilisateur pour obtenir les meilleurs résultats.
Une autre définition courante du langage "déclaratif" est (je ne trouve pas de source autoritaire):
Paradigme de programmation qui exprime le résultat souhaité du calcul sans décrire les étapes pour y parvenir (également abrégé par "décrire quoi, pas comment")
Si nous acceptons cette définition, nous rencontrons les problèmes décrits par le PO.
Le premier problème est que SQL nous donne plusieurs façons équivalentes de définir "le même résultat". C'est probablement un mal nécessaire: plus nous donnons de pouvoir expressif à une langue, plus elle a probablement différentes manières d'exprimer la même chose.
Par exemple, on m'a demandé une fois d'optimiser cette requête:
SELECT Distinct CT.cust_type, ct.cust_type_description
from customer c
INNER JOIN
Customer_type CT on c.cust_type=ct.cust_type;
Étant donné que les types étaient beaucoup moins que le client et qu'il y avait un index sur la cust_type
table client, j'ai réalisé une grande amélioration en le réécrivant comme suit:
SELECT CT.cust_type, ct.cust_type_description
from Customer_type CT
Where exists ( select 1 from customer c
Where c.cust_type=ct.cust_type);
Dans ce cas spécifique, lorsque j'ai demandé au développeur ce qu'il voulait réaliser, il m'a répondu "Je voulais tous les types de clients pour lesquels j'avais au moins un client", c'est d'ailleurs exactement la description de la requête de l'optimiseur.
Donc, si je pouvais trouver une requête équivalente et plus efficace, pourquoi l'optimiseur ne peut-il pas faire de même?
Ma meilleure supposition est que c'est pour deux raisons principales:
SQL exprime la logique:
puisque SQL exprime une logique de haut niveau, voudrions-nous vraiment que l'optimiseur nous «surpasse» nous et notre logique? Je crierais avec enthousiasme "oui" si ce n'était pour toutes les fois où je devais forcer l'optimiseur à choisir le chemin d'exécution le plus efficace. Je pense que l'idée pourrait être de permettre à l'optimiseur de faire de son mieux (révisant également notre logique) mais de nous donner un "mécanisme de conseil" pour venir à la rescousse quand quelque chose devient fou (ce serait comme avoir la roue + les freins dedans) une voiture autonome).
Plus de choix = plus de temps
Même le meilleur optimiseur RDBMS ne teste pas TOUS les chemins d'exécution possibles, car ils doivent être très rapides: à quel point serait-il bon d'optimiser une requête de 100 ms à 10 ms si je dois passer chaque fois 100 ms à choisir le meilleur chemin? Et c'est avec l'optimiseur respectant notre "logique de haut niveau". S'il devait également tester toutes les requêtes SQL équivalentes, le temps de l'optimiseur pourrait augmenter plusieurs fois.
Un autre bon exemple de réécriture de requête que le SGBDR n'est pas capable de faire est (à partir de cet article de blog intéressant )
SELECT t1.id, t1.value, SUM(t2.value)
FROM mytable t1
JOIN mytable t2
ON t2.id <= t1.id
GROUP BY t1.id, t1.value;
que ce qui peut être écrit comme ceci (fonctions analytiques requises)
SELECT id, value, SUM(t1.value) OVER (ORDER BY id)
FROM mytable
select whatever from sometable where FKValue in (select FKValue from sometable_2 where other_value = :param)
. Il devrait être trivial de voir comment reformuler cela avec unexists
ou unjoin
.