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

Quand les requêtes (SELECT) sont-elles prévues ?

Je ne peux pas parler de l'interface Perl côté client elle-même, mais je peux éclairer le côté serveur PostgreSQL.

PostgreSQL a des instructions préparées et des instructions non préparées. Les instructions non préparées sont analysées, planifiées et exécutées immédiatement. Ils ne le font pas non plus prend en charge la substitution de paramètres. Sur un simple psql shell, vous pouvez afficher leur plan de requête comme ceci :

tmpdb> explain select * from sometable where flag = true;

D'autre part, il existe des instructions préparées :elles sont généralement (voir "exception" ci-dessous) analysées et planifiées en une étape et exécutées dans une deuxième étape. Ils peuvent être réexécutés plusieurs fois avec des paramètres différents, car ils le font prend en charge la substitution de paramètres. L'équivalent en psql est-ce :

tmpdb> prepare foo as select * from sometable where flag = $1;
tmpdb> explain execute foo(true);

Vous pouvez voir que le plan est différent du plan dans la déclaration non préparée, car la planification a déjà eu lieu dans le prepare phase comme décrit dans la doc pour PRÉPARER :

Cela signifie également que le plan n'est PAS optimisé pour les paramètres substitués :dans les premiers exemples, vous pouvez utiliser un index pour flag car PostgreSQL sait que sur un million d'entrées, seules dix ont la valeur true . Ce raisonnement est impossible lorsque PostgreSQL utilise une instruction préparée. Dans ce cas, un plan est créé qui fonctionnera pour toutes les valeurs de paramètres possibles aussi bonnes que possible. Cela pourrait exclure l'index mentionné car la récupération de la meilleure partie de la table complète via un accès aléatoire (en raison de l'index) est plus lente qu'un simple balayage séquentiel. Le PRÉPARER doc le confirme :

BTW - Concernant la mise en cache du plan, le PRÉPARER doc a aussi quelque chose à dire :

De plus, il n'y a pas de mise en cache automatique du plan et pas de mise en cache/réutilisation sur plusieurs connexions.

EXCEPTION :J'ai mentionné "habituellement". Le psql affiché les exemples ne sont pas vraiment utilisés par un adaptateur client comme Perl DBI. Il utilise un certain protocole . Ici le terme "requête simple" correspond à la "requête non préparée" dans psql , le terme "requête étendue " correspond à une "requête préparée" à une exception près :il existe une distinction entre (une) "instruction sans nom" et (éventuellement plusieurs) "instructions nommées". Concernant les instructions nommées, le doc dit :

et aussi :

Donc, dans ce cas, la planification se fait sans paramètres comme décrit ci-dessus pour PREPARE - rien de nouveau.

L'exception mentionnée est la "déclaration sans nom". Le doc dit :

Et voici l'avantage :bien que l'instruction sans nom soit "préparée" (c'est-à-dire qu'elle puisse avoir une substitution de paramètres), elle peut également adapter le plan de requête aux paramètres réels.

BTW :La gestion exacte de l'instruction sans nom a changé plusieurs fois dans les versions précédentes du serveur PostgreSQL. Vous pouvez rechercher les anciens documents pour plus de détails si vous le souhaitez vraiment.

Justification - Perl / n'importe quel client :

Comment un client comme Perl utilise le protocole est une question complètement différente. Certains clients comme le pilote JDBC pour Java disent essentiellement :même si le programmeur utilise une instruction préparée, les cinq premières exécutions (environ) sont mappées en interne sur une "requête simple" (c'est-à-dire effectivement non préparée), après quoi le pilote passe à " déclaration nommée ».

Ainsi, un client a ces choix :

  • Forcer la (re)planification à chaque fois en utilisant le protocole "requête simple".
  • Planifier une fois, exécuter plusieurs fois en utilisant le protocole "requête étendue" et l'"instruction nommée" (la planification peut être mauvaise car la planification est effectuée sans paramètres).
  • Analyser une fois, planifiez chaque exécution (avec la version actuelle de PostgreSQL) en utilisant le protocole "requête étendue" et l'"instruction sans nom" et en obéissant à d'autres choses (fournissez des paramètres pendant le message "parse")
  • Jouez à des astuces complètement différentes, comme le pilote JDBC.

Ce que fait Perl actuellement :je ne sais pas. Mais le "hareng rouge" mentionné n'est pas très improbable.