SQL est-il déclaratif?

22

Je pose la question car tant de questions que je vois en SQL se résument à: "C'est lent. Comment puis-je l'accélérer"? Ou sont des didacticiels indiquant "Faites de cette façon et non de cette façon car c'est plus rapide".

Il me semble qu'une grande partie de SQL sait exactement comment une expression serait exécutée et à partir de cette connaissance, elle choisit des styles d'expression qui fonctionnent mieux. Cela ne cadre pas avec un aspect de la programmation déclarative - celui de quitter le système pour décider de la meilleure façon d'effectuer le calcul avec vous en spécifiant simplement ce que le calcul doit produire.

Un moteur SQL ne devrait-il pas se soucier de savoir si vous l'avez utilisé in, existsou joins'il est vraiment déclaratif, ne devrait-il pas simplement vous donner la bonne réponse dans un délai raisonnable si possible par l'une des trois méthodes? Ce dernier exemple est provoqué par ce post récent qui est du type mentionné dans mon paragraphe d'ouverture.

Index

Je suppose que l'exemple le plus simple que j'aurais pu utiliser concerne la création d'un index pour une table. Le gumph ici sur w3schools.com essaie même de l'expliquer comme quelque chose d'invisible par l'utilisateur qui est là pour des raisons de performances. Leur description semble mettre les indices SQL dans le camp non déclaratif et ils sont régulièrement ajoutés à la main pour des raisons purement de performance.

Est-il vrai que leur est quelque part une base de données SQL idéale qui est beaucoup plus déclarative que tous les autres, mais parce que c'est bon, on n'en entend pas parler?

Paddy3118
la source
@FrustratedWithFormsDesigner: Je sais exactement ce que cela signifie. 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 un existsou un join.
Mason Wheeler
En utilisant un raisonnement similaire, je suppose que les expressions régulières sont une méthode d'expression plus déclarative car je vois rarement des questions de performance auxquelles il est répondu "vous devriez l'écrire de cette façon pour obtenir de meilleures performances". Je suis en train de me casser la tête et je me souviens à moitié d'une question concernant les affirmations négatives par derrière ou à venir dans une expression rationnelle lente où la réponse était de réécrire l'expression rationnelle d'une manière différente pour faire de même en moins de temps.
Paddy3118
La performance est un détail d'implémentation. Les performances de presque toutes les implémentations IN pourraient être comparables ou meilleures que EXISTS et JOIN si les développeurs du processeur de requêtes estimaient que c'était une priorité.
JustinC
1
@JustinC, cela semble être plus qu'un détail étant donné la prépondérance des questions SQL orientées performances et des astuces pour un langage soi-disant déclaratif?
Paddy3118
Il n'y a pas de définition claire d'un langage de programmation déclaratif, et il est donc inutile d'en parler. Certaines langues sont de niveau supérieur à d'autres, c'est tout.
gardenhead

Réponses:

21

SQL est théoriquement déclaratif. Mais vous savez ce qu'ils disent de la différence entre la théorie et la pratique ...

À la base, le concept de "programmation déclarative" n'a jamais été vraiment efficace, et ne le sera probablement jamais tant que nous n'aurons pas un compilateur basé sur l'IA capable de regarder le code et de répondre à la question "quelle est l'intention de ce code?" intelligemment, de la même manière que la personne qui l'a écrit. Au cœur de chaque langage déclaratif se trouve tout un tas de codes impératifs essayant frénétiquement de résoudre ce problème sans l'aide d'une IA.

Souvent, cela fonctionne étonnamment bien, car les cas les plus courants sont des cas courants , que les personnes qui ont écrit l'implémentation du langage connaissaient et ont trouvé de bons moyens de les gérer. Mais vous vous heurtez à un cas de bord que l'implémentateur n'a pas pris en compte et vous voyez les performances se dégrader rapidement car l'interpréteur est obligé de prendre le code beaucoup plus littéralement et de le gérer de manière moins efficace.

Mason Wheeler
la source
3
Jamais vraiment efficace? SQL, LINQ, Knockout.js, Prolog, langage ELM. Vous voudrez peut-être vérifier à nouveau. J'utilise principalement des technologies déclaratives en ce moment.
brian
5
@brian: Et tous dégénèrent assez rapidement lorsque vous rencontrez un cas de bord auquel personne n'a pensé. Je suppose que j'aurais dû dire "jamais vraiment efficace dans le cas général ".
Mason Wheeler
Quand votre réponse est-elle définie pour se dégrader, car elle est stockée dans une base de données SQL Server? :) J'ai rarement rencontré un cas de bord dans aucun d'entre eux qui ne pouvait pas être résolu dans le cadre. Je vois d'où vous venez, mais les cas marginaux ne me causent vraiment pas beaucoup de peine à quel point il est bénéfique et facile de raisonner environ 99% du code déclaratif. C'est comme dire que Clojure ou F # est mauvais parce que vous avez dû utiliser un type mutable pour résoudre votre problème.
brian
11
@brian: I rarely hit an edge case in any of them that couldn't be solved within the framework.Oui, c'est tout l'intérêt: avoir à trouver un moyen de les résoudre dans le cadre, car le cadre n'est pas assez intelligent pour le résoudre pour vous comme vous l'aviez déclaré à l'origine.
Mason Wheeler
Qu'en est-il de sélectionner ... pour la mise à jour? Cela semble une commande impérative.
Jesvin Jose
6

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_typetable 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
Insac
la source
1
L'exemple de réécriture de la jointure dans un existe est intéressant. Une règle générale que j'essaie d'imprimer aux développeurs SQL est que l'utilisation de DISTINCT est une odeur de code - soit la requête, soit le modèle de données, est très probablement erroné, et une approche différente doit être recherchée.
David Aldridge