Exécution de requêtes par lots en 1 seconde. Requêtes groupées pour les nuls. Méthodes Run() et RunBatch()

Cet article est destiné aux lecteurs familiarisés avec le langage SQL.

Le langage de requête 1C, utilisé depuis la version 8, est devenu aujourd'hui un outil utile pour travailler avec des bases de données, qui permet d'y lire, mais pas d'écrire. Syntaxiquement, le langage de requête est très similaire au langage SQL, mais en russe.

Ci-dessous un tableau de correspondance entre le langage de requête principal et les opérateurs SQL :

Opérateurs de langage de requête 1C

Instruction SQL

DIVERS

COMPOSÉ

PAR GROUPE

COMBINER

TRIER PAR

Et ce n'est pas une liste complète. Des informations de référence plus complètes sur les opérateurs de langage de requête disponibles peuvent être obtenues dans le concepteur de requêtes, qui sera abordé ci-dessous.

L'exécution d'une requête 1C à partir du code du programme s'effectue à l'aide de l'objet langage intégré « Requête ». Un exemple d'écriture d'une requête de base de données à l'aide du langage de programmation intégré :

Demande = Nouvelle demande ; Query.Text = "SELECT | Synonyme.Link AS Link |FROM | Directory.Directory1 AS Synonyme"; Sélectionner = Query.Run().Select(); While Selection.Next() Loop // Insérer le traitement de sélection SelectionDetailedRecords EndCycle;

La méthode « Run » exécute la requête, la méthode « Select » renvoie une valeur de type « SelectFromQueryResult ». Vous pouvez également utiliser la méthode Unload, qui renvoie une table de valeurs.

Les paramètres de la requête sont stockés dans la propriété « Paramètres » (dans ce cas, il s'agit d'une structure, donc toutes les méthodes de structure sont applicables ici - insertion, suppression, etc.).

Un exemple de définition du paramètre « Query.Parameters.Insert » (« Directory », DirectoryLink). Dans la requête, vous pouvez accéder aux paramètres à l'aide de l'esperluette « &Répertoire ». Ci-dessous un exemple de requête utilisant des paramètres :

Demande = Nouvelle demande ; Query.Text = "SELECT | Users.Link AS Link, | Users.Parent AS Parent, | Users.Name AS Name |FROM | Directory.Users AS Users |WHERE | Users.Link = &Directory"; Query.Parameters.Insert("Répertoire", DirectoryLink); Sélectionner = Query.Run().Select(); While Selection.Next() Loop // Insérer le traitement de sélection SelectionDetailedRecords EndCycle;

Rappelons que le langage de requête est destiné uniquement à lire les données de la base de données, il n'a donc pas d'analogues à des instructions SQL telles que INS ERT et UPDATE. Les données ne peuvent être modifiées que via le modèle objet du langage de programmation 1C intégré. Également dans le langage de requête 1C, il existe des opérateurs qui n'ont pas d'analogues en SQL, par exemple :

  • DANS LA HIÉRARCHIE
  • LIEU
  • INDEX PAR

DANS LA HIÉRARCHIE– permet de sélectionner tous les éléments du répertoire hiérarchique qui sont inclus dans la hiérarchie du lien transféré. Exemple de requête utilisant DANS LA HIÉRARCHIE:

SELECT Produits.Lien, Produits.Article FROM Répertoire.Produits AS Produits OÙ Produits.Lien DANS LA HIÉRARCHIE (&Citrus)"

Dans ce cas, le résultat renverra tous les éléments subordonnés du répertoire de nomenclature Citrus, quel que soit le nombre de niveaux hiérarchiques de ce répertoire.

Par exemple, la tâche consiste également à trouver un produit portant le nom « Pen ». Le produit doit être inclus dans la hiérarchie « Papeterie ». Marchandises », c’est-à-dire que nous n’avons pas besoin de chercher la poignée de porte. La structure de la nomenclature dans ce cas est la suivante :

Bureau

|_ Stylos plume |_ Stylo rouge |_ Stylo bleu |_ Stylos à encre |_ Règles

Accessoires

|_ Poignées de porte |_ Poignée de porte simple |_ Poignée de porte de luxe

Nous écrivons la demande suivante :

SELECT Products.Link, Products.Article FROM Directory.Products AS Products WHERE Products.Name Like "Pen%" AND Products.Link IN HIERARCHY(&Stationery)"

Lors de l'utilisation du design DANS LA HIÉRARCHIE il faut tenir compte du fait que si vous passez un lien vide au paramètre « Office », l'exécution de la requête ralentira, puisque la plateforme vérifiera chaque élément pour voir s'il appartient à la racine.

LIEU– Cette instruction place le résultat dans une table temporaire. Exemple de demande :

SELECT Users.Link AS Link, Users.Parent AS Parent, Users.Name AS Name PLACE SelectedUsers FROM Directory.Users AS Users WHERE Users.Link = &Directory; SELECT SelectedUsers.Link AS Link, SelectedUsers.Parent AS Parent, SelectedUsers.Name AS Nom FROM SelectedUsers AS SelectedUsers

Cette requête SQL sera exécutée par plusieurs requêtes :

  • Création d'une table temporaire (la plateforme peut « réutiliser » des tables temporaires précédemment créées, donc la création n'a pas toujours lieu) ;
  • Placer les données dans une table temporaire ;
  • Exécuter la requête principale, à savoir SEL ECT à partir de cette table temporaire ;
  • Détruire/nettoyer une table temporaire.

Une table temporaire peut être détruite explicitement, via la construction DÉTRUIRE, ou implicitement - lors de la fermeture du gestionnaire de tables temporaire.

L'objet « Requête » du langage de programmation intégré possède une propriété « Temporary Table Manager », destinée à travailler avec des tables temporaires. Exemple de code :

MVT = Nouveau TemporaryTableManager(); Demande = Nouvelle demande ; Query.TemporaryTableManager = MVT ;

Après avoir exécuté une requête, la variable MVT peut être utilisée une seconde fois dans une autre requête, ce qui est sans doute un autre avantage de l'utilisation de tables temporaires. Dans ce cas, la table temporaire de la base de données sera supprimée lors de l'appel de la méthode « Close »...

MVT.Close();

...ou lors de l'effacement d'une variable de la mémoire, c'est-à-dire lors de l'exécution de la méthode dans laquelle la variable a été déclarée. Les tables temporaires augmentent la charge sur le sous-système de disque, vous ne devez donc pas créer trop de sous-systèmes temporaires (en boucle, par exemple) ou de sous-systèmes de gros volume.

INDEX PAR– cet opérateur est utilisé conjointement avec l'opérateur LIEU. Lors de la création d'une table temporaire, cet opérateur peut indexer la table en cours de création, ce qui accélère considérablement son utilisation (mais uniquement si l'index correspond à votre requête).

Consultation gratuite d'experts

Merci pour votre requête!

Un spécialiste 1C vous contactera dans les 15 minutes.

Caractéristiques de certains opérateurs de langage de requête

POUR CHANGER– cet opérateur est destiné à verrouiller une table de requête spécifique (ou toutes les tables qui participent à la requête). Le verrouillage est réalisé en appliquant un verrou en U à la table. En SQL, cela est implémenté via l'indice UPDLOCK. Cette conception est nécessaire pour éviter les blocages. Exemple de demande avec une construction POUR CHANGER:

SELECT Users.Link AS Link, Users.Parent AS Parent, Users.Name AS Name FROM Directory.Users AS Users LEFT JOIN Directory.RFK AS RFK BY Users.RFK = RFK.Link POUR CHANGER Directory.Users

Dans cet exemple, le verrou U sera placé sur la table Utilisateurs. Si vous ne spécifiez pas de table pour un verrou, celui-ci sera imposé à toutes les tables participant à la requête. Il est important de noter que cette conception ne fonctionne que dans les configurations dans lesquelles le mode de gestion automatique des verrous est activé.



COMPOSÉ– la requête prend en charge les connexions GAUCHE/DROITE, COMPLET, INTÉRIEUR, qui correspond aux jointures en SQL – LEFT/RIGHT JOIN, OUTER JOIN, INNER JOIN.

Cependant, lorsque vous utilisez le générateur de requêtes, vous ne pourrez pas faire REJOIGNEZ À DROITE. Le constructeur échangera simplement les tables, mais l'opérateur sera toujours gaucher. Pour cette raison, vous ne verrez jamais l'utilisation d'une jointure à droite dans 1C.

Syntaxiquement, la connexion ressemble à ceci :

SELECT Table1.Link AS Link FROM Directory.Directory1 AS Table1 LEFT JOIN Directory.Directory2 AS Table2 BY Table1.Attributes = Table2.Attributes

Le langage de requête 1C ne dispose pas d'opérateur pour rejoindre un produit cartésien (CROSS JOIN). Cependant, l’absence d’opérateur ne signifie pas que le langage de requête ne prend pas en charge une telle connexion. Si nécessaire, vous pouvez joindre des tables comme ceci :

SELECT Table1.Link AS Link FROM Directory.Directory1 AS Table1 LEFT JOIN Directory.Directory2 AS Table2 BY TRUE

Comme le montre l'exemple, la clé de connexion est définie PAR VRAI, c'est-à-dire que chaque ligne d'une table correspond à une ligne d'une autre. Le type de jointure (LEFT, RIGHT, FULL, INNER) n'est pas important si vous avez des lignes dans les deux tables, mais s'il n'y a pas de lignes dans l'une des tables (disons la table) - le résultat sera différent. Par exemple, lors de l'utilisation INTERNE le résultat de la connexion sera vide. En utilisant GAUCHE DROITE le résultat de la jointure sera ou non des données selon la table que nous rejoignons - avec des données ou non. En utilisant COMPLET Les données seront toujours connectées (naturellement, uniquement à partir d'une table, puisque l'autre est vide) ; le choix du type de connexion dépend de la tâche spécifique de l'application.

Un petit indice visuel sur le fonctionnement des différents types de connexion :



COMME. Contrairement à l'opérateur SQL similaire - LIKE, le modèle pour COMME peut être spécifié en utilisant uniquement certains caractères spéciaux :

  • % (pourcentage) : une séquence contenant un nombre quelconque de caractères arbitraires ;
  • _ (trait de soulignement) : un caractère arbitraire ;
  • / - le caractère suivant doit être interprété comme un caractère normal.

RÉSULTATS DU LOGICIEL L'analogue de SQL est l'opérateur ROLLUP. Exemple d'utilisation de l'opérateur RÉSULTATS:

SELECT Produits.Prix AS Prix, Produits.Produit AS Produit FROM Répertoire.Nomenclature AS Produits RÉSULTATS MOYENNE (Prix) PAR Produit

Le résultat sera comme ceci :

Lit

9833,333

Fer

Stylo

C'est-à-dire qu'une ligne supplémentaire est ajoutée au résultat contenant la valeur du champ par lequel le regroupement est effectué et la valeur de la fonction d'agrégation.

Travailler avec des requêtes par lots

1C vous permet de travailler avec des lots de demandes. Dans une requête batch, les textes de requête sont séparés par des points-virgules (;). La demande batch 1C est exécutée séquentiellement. Exemple de texte de demande par lots :

SELECT Users.Link AS Link, Users.Parent AS Parent, Users.Name AS Name FROM Directory.Users AS Users ;
SELECT Work Schedule.User AS User, Work Schedule.Date AS Date, Work Schedule.Working Hours AS Working Hours FROM Register Information.Work Schedule AS Work Schedule

Pour obtenir le résultat de toutes les requêtes incluses dans un package, vous devez utiliser la méthode « ExecutePackage » de l'objet requête, au lieu de « Run ». Cette méthode exécute toutes les requêtes de manière séquentielle. Le résultat de la requête est un tableau de résultats pour chaque requête du package, et la séquence de placement dans le tableau est la même que la séquence de requêtes dans le texte du package.

Lorsque l'on considère un langage de requête, il convient de mentionner une fonctionnalité telle que les tables virtuelles. Les tables virtuelles ne sont pas présentes dans la base de données ; elles constituent une sorte de wrapper qui est exécuté côté SGBD sous forme de requête utilisant des sous-requêtes. Exemple de requête 1C utilisant des tables virtuelles :

SELECT RegisterLiabilitiesTurnovers.Liability AS Liability FROM RegisterAccumulations.RegisterLiabilities.Turnovers() AS RegisterLiabilitiesTurnovers

Une telle requête au SGBD ressemblerait à ceci :

SEL ECT T1.Fld25931RRef FROM (SELECT T2._Fld25931RRef AS Fld25931RRef, CAST(SUM(T2._Fld25936) AS NUMERIC(38, 8)) AS Fld25936Turnover_, CAST(SUM(T2._Fld25937) AS NUMERIC(38, 8) ) AS Fld25937Turnover_ FR OM dbo._AccumRgTn25938 T2 WH ERE ((T2._Fld949 = @P1)) ET ((T2._Fld25936 @P2 OU T2._Fld25937 @P3)) GROUPE PAR T2._Fld25931RRef AVANT (CAST(SUM(T2._Fld2 ) 5936 ) AS NUMERIC(38, 8))) 0.0 OU (CAST(SUM(T2._Fld25937) AS NUMERIC(38, 8))) 0.0) T1>>>>

On voit que cela ne ressemble pas à SQL, puisqu'il existe une sous-requête, un regroupement. Les tables virtuelles, dans l'ensemble, sont du « sucre syntaxique », c'est-à-dire qu'elles sont créées, en général, pour faciliter le développement de requêtes, afin que les requêtes soient plus compactes et plus lisibles.

Seuls les registres ont des tables virtuelles, mais les tables virtuelles disponibles dans un registre peuvent être vues dans le concepteur de requêtes.



Lorsque vous utilisez des tables virtuelles, vous devez toujours fournir une condition de sélection. Sinon, des problèmes de performances pourraient survenir.



Dans le corps de la requête, cela ressemble à ceci :

Registre d'accumulation Registre des passifs Chiffre d'affaires (, Opération = &Opération) AS Chiffre d'affaires du Registre des passifs.

Pour faciliter l'écriture de requêtes, c'est-à-dire la création de textes de requête, dans 1C, il existe un constructeur qui peut être appelé via le menu contextuel (bouton droit de la souris) :



Dans le concepteur de requêtes, vous pouvez voir une liste complète des fonctions et opérateurs du langage de requête pris en charge.


Le Query Builder est un outil visuel très flexible pour créer des requêtes de toute complexité. Il est uniquement disponible en mode configurateur. En mode Entreprise, il existe ce qu'on appelle une « Console de requêtes » : il s'agit d'un traitement externe fourni sur le disque ITS. Pour une application gérée, la console de requêtes peut être téléchargée depuis its.1c.ru.

Une description du travail dans le concepteur de requêtes dépasse le cadre de cet article, elle ne sera donc pas abordée en détail.

Raisons des performances de requête sous-optimales

Vous trouverez ci-dessous une liste des principales raisons (mais pas toutes) qui conduisent à une exécution lente des requêtes.

  • Utiliser des jointures avec des sous-requêtes

Il n'est pas recommandé d'effectuer une jointure avec des sous-requêtes ; les sous-requêtes doivent être remplacées par des tables temporaires. La concaténation de sous-requêtes peut entraîner des pertes de performances importantes, et la vitesse d'exécution des requêtes sur différents SGBD peut varier considérablement. La vitesse d'exécution de ces requêtes est également sensible aux statistiques du SGBD. La raison de ce comportement est que l'optimiseur de SGBD ne peut pas toujours déterminer correctement le plan d'exécution optimal de la requête, car l'optimiseur ne sait rien du nombre de lignes que la sous-requête renverra après son exécution.

  • Utilisation de tables virtuelles dans les jointures de requêtes

Les tables virtuelles au niveau du SGBD sont exécutées sous forme de sous-requêtes, les raisons sont donc les mêmes que dans le premier paragraphe.

  • Utiliser des conditions dans une requête qui ne correspondent pas aux index existants

Si dans les conditions de la demande (dans l'opérateur ou conditions de table virtuelle) utilise des champs qui ne sont pas tous inclus dans l'index, cette requête sera exécutée à l'aide du scan de table de construction SQL ou du scan d'index (en tout ou en partie). Cela affectera non seulement le temps d'exécution de la requête, mais également un verrou S excessif sera placé sur des lignes supplémentaires, ce qui à son tour peut conduire à une escalade de verrouillage, c'est-à-dire que la table entière sera verrouillée.

  • Utilisation de OR dans les conditions de requête

Utiliser l'opérateur logique OU en conception peut également entraîner une analyse de la table. Cela se produit car le SGBD ne peut pas utiliser correctement l'index. Au lieu de OU vous pouvez utiliser le design COMBINEZ TOUT.

  • Réception de données via un point pour les champs de type composite

Il n'est pas recommandé d'obtenir des valeurs via un point (dans la construction CHOISISSEZ OÙ), car si l'attribut objet s'avère être un type complexe, la jointure se produira avec chaque table incluse dans ce type complexe. En conséquence, la requête du SGBD sera nettement plus compliquée, ce qui peut empêcher l'optimiseur de choisir le bon plan d'exécution de requête.

La plateforme 1C Enterprise vous permet d'exécuter plusieurs requêtes séquentiellement à la fois. En 1C, cela s'appelle un package de requête. Au sein d'un package, chaque requête est séparée par un point-virgule.

Pour réaliser une exécution étape par étape des requêtes dans un package, en règle générale, des tables temporaires sont initialement créées, puis les conditions de leur partage, telles que les filtres, les jointures et les unions, sont formées. Grâce à cela, le résultat final est atteint. Les tables temporaires obtenues à la suite de requêtes dans un lot continuent d'exister jusqu'à la fin du lot dans son ensemble ou jusqu'à l'exécution d'une requête détruisant les tables temporaires.

De plus, l'utilisation de requêtes batch et de tables temporaires augmente considérablement la lisibilité de l'ensemble du segment de ce code. Les requêtes complexes contenant également des requêtes imbriquées peuvent être très difficiles à comprendre. Cependant, si vous divisez une requête longue et complexe en plusieurs, et même utilisez des tables temporaires, cela améliorera non seulement la perception, mais entraînera dans la plupart des cas des performances accrues.

Un autre détail important en faveur des requêtes par lots dans 1C est que, contrairement à nous, nous pouvons obtenir séparément le résultat de chaque requête dans le lot.

Un exemple de création d'un paquet de requêtes en langage 1C

Pour voir un exemple de création d'un package de requêtes, nous utiliserons le concepteur de requêtes, que nous appellerons pour plus de clarté depuis la console de requêtes. Ainsi, nous pouvons immédiatement voir le résultat de l’exécution du package.

Créons une simple demande par lots. Je suggère d'insérer immédiatement le texte de la demande dans , puis de l'ouvrir et de voir comment le paquet de demandes est formé. Ajoutez une nouvelle requête à la console et collez le texte suivant :

Obtenez 267 leçons vidéo sur 1C gratuitement :

Lien autoportant,
Autonome.Parent,
Autonome.
Autonome. Code de sélection rapide,
Nom autonome.
Autoportant.Type,
Autonome. Hors bilan,
Autonome.
DEPUIS
Plan comptable autosuffisant AS Autosuffisant.

Autonome.Link = &Compte
;
////////////////////////////////////////////////////////////////////////////////

CHOISIR
Types autoportantsSubconto.Numéro de ligne AS Numéro de ligne,
Types autoportants de Subconto.ViewSubconto AS TypeSubconto,
Self-supportingTypesSubconto.TypeSubconto.Name AS Nom,
Self-supportingTypesSubconto.TypeSubconto.ValueType ASValueType,
Self-supportingTypesSubconto.OnlyTurnover AS OnlyTurnover,
Self-supportingTypesSubconto.Summary AS Sommatif
DEPUIS
Plan comptable autonome. Types de sous-compte AS Types de sous-conto.

Self-supportingTypesSubaccount.Link = &Compte
TRIER PAR
TypesSubconto.NumberLines autoportants

Pour moi, cela ressemble à ceci :

Passons maintenant au concepteur de requêtes. Ici, nous nous intéresserons à l’onglet « Demander un package » :

Comme vous pouvez le constater, nous avons un paquet de deux demandes. En double-cliquant sur l'un d'entre eux, vous pouvez procéder à son édition :

Cliquez sur le bouton « Ok » et essayez de voir le résultat de la demande par lots.

Définissons le paramètre "Compte". Vous pouvez sélectionner n'importe quel compte dans le plan comptable. Comme vous l'avez probablement déjà deviné, ce paquet de requêtes devrait recevoir les propriétés du compte. Cliquez sur « Exécuter » et voyez le résultat :

Méthodes Run() et RunBatch()

Blog de l'entreprise 1C GOODWILL

La plateforme 1C Enterprise vous permet d'exécuter plusieurs requêtes séquentiellement à la fois. En 1C, cela s'appelle un package de requête. Au sein d'un package, chaque requête est séparée par un point-virgule.

Pour réaliser une exécution étape par étape des requêtes dans un package, en règle générale, des tables temporaires sont initialement créées, puis les conditions de leur partage, telles que les filtres, les jointures et les jointures, sont formées. Grâce à cela, le résultat final est atteint. Les tables temporaires obtenues à la suite de requêtes dans un lot continuent d'exister jusqu'à la fin du lot dans son ensemble ou jusqu'à l'exécution d'une requête détruisant les tables temporaires.

De plus, l'utilisation de requêtes batch et de tables temporaires augmente considérablement la lisibilité de l'ensemble du segment de ce code. Les requêtes complexes contenant également des requêtes imbriquées peuvent être très difficiles à comprendre. Cependant, si vous divisez une requête longue et complexe en plusieurs, et même utilisez des tables temporaires, cela améliorera non seulement la perception, mais entraînera dans la plupart des cas des performances accrues.

Un autre détail important en faveur des requêtes par lots dans 1C est que, contrairement aux requêtes imbriquées, nous pouvons obtenir séparément le résultat de chaque requête du lot.

Un exemple de création d'un paquet de requêtes en langage 1C

Pour voir un exemple de création d'un package de requêtes, nous utiliserons le concepteur de requêtes, que nous appellerons, pour plus de clarté, depuis la console de requêtes. Ainsi, nous pouvons immédiatement voir le résultat de l’exécution du package.

Créons une simple demande par lots. Je suggère de coller immédiatement le texte de la requête dans la console, puis d'ouvrir le constructeur et de voir comment le package de requête est formé. Ajoutez une nouvelle requête à la console et collez le texte suivant :

Autonome.Parent,

Autonome.

Autonome. Code de sélection rapide,

Nom autonome.

Autoportant.Type,

Autonome. Hors bilan,

Autonome.

Plan comptable autosuffisant AS Autosuffisant.

////////////////////////////////////////////////////////////////////////////////

Types autoportantsSubconto.Numéro de ligne AS Numéro de ligne,

Types autoportants de Subconto.ViewSubconto AS TypeSubconto,

Self-supportingTypesSubconto.TypeSubconto.Name AS Nom,

Self-supportingTypesSubconto.TypeSubconto.ValueType ASValueType,

Self-supportingTypesSubconto.OnlyTurnover AS OnlyTurnover,

Self-supportingTypesSubconto.Summary AS Sommatif

Plan comptable autonome. Types de sous-compte AS Types de sous-conto.

TRIER PAR

TypesSubconto.NumberLines autoportants

Pour moi, cela ressemble à ceci :

Passons maintenant au concepteur de requêtes. Ici, nous nous intéresserons à l’onglet « Demander un package » :

Comme vous pouvez le constater, nous avons un paquet de deux demandes. En double-cliquant sur l'un d'entre eux, vous pouvez procéder à son édition :

Cliquez sur le bouton « Ok » et essayez de voir le résultat de la demande par lots.

Définissons le paramètre "Compte". Vous pouvez sélectionner n'importe quel compte dans le plan comptable. Comme vous l'avez probablement déjà deviné, ce package de requête doit recevoir les propriétés du compte. Cliquez sur « Exécuter » et voyez le résultat :

Méthodes Run() et RunBatch()

En plus de la méthode Execute(), qui exécutera une par une toutes les requêtes d'un lot et renverra le résultat de la dernière requête, dans 1C il existe une méthode ExecuteBatch(). Il renvoie un tableau d'échantillons de chaque requête du lot. Dans l’exemple ci-dessus, c’est exactement la méthode.

ArrayResults = Query.ExecuteBatch();

Selection1 = ArrayResults.Select();

Si Select1.Next() Alors

//Actions avec sélection 1

fin si;

SelectionViewsSubconto = ArrayResults.Select();

L'article Travailler avec des requêtes par lots dans 1C 8.3 et 8.2 est apparu pour la première fois sur le blog de la société 1C GOODWILL.

ils augmentent considérablement la lisibilité, ce qui réduit le risque d'erreurs => cela me suffit.

Le langage de requête intégré de 1C:Enterprise version 8.0 n'avait pas la possibilité d'utiliser des tables temporaires et d'écrire des requêtes par lots. Dans le même temps, il était souvent nécessaire d'effectuer des calculs complexes au sein d'une seule requête (c'est-à-dire un cycle d'interaction entre client - serveur 1C:Enterprise - serveur SGBD). Pour résoudre de tels problèmes, des sous-requêtes ont été utilisées - des appels non pas à des objets de métadonnées, mais à des sélections à partir de ces objets. En règle générale, les sous-requêtes étaient effectuées avec regroupement et étaient souvent utilisées dans les jointures.

L'optimiseur de serveur SGBD (quel que soit le SGBD que vous utilisez) ne peut pas toujours optimiser correctement une telle requête. Dans ce cas, le problème pour l'optimiseur est de choisir la bonne méthode de connexion. Il existe plusieurs algorithmes pour joindre deux échantillons. Le choix de l'un ou l'autre algorithme dépend du nombre d'enregistrements qui seront contenus dans l'un ou l'autre échantillon. Si vous joignez deux tables physiques, le SGBD peut facilement déterminer la taille des deux échantillons en fonction des statistiques disponibles. Si l’une des sélections jointes est une sous-requête, il devient alors très difficile de comprendre combien d’enregistrements elle renverra. Dans ce cas, le SGBD peut commettre une erreur dans le choix d'un plan, ce qui entraînera une baisse catastrophique des performances des requêtes.

La réécriture de la requête à l'aide de la méthode ci-dessus vise à simplifier le travail de l'optimiseur de SGBD. Dans la requête réécrite, toutes les sélections participant aux jointures seront des tables physiques, et le SGBD pourra déterminer facilement la taille de chaque sélection. Cela permettra au SGBD d'être assuré de sélectionner le plan le plus rapide de tous les plans possibles. De plus, le SGBD fera le bon choix quelles que soient les conditions. Une requête réécrite de cette manière fonctionnera aussi bien sur n'importe quel SGBD, ce qui est particulièrement important lors du développement de solutions de circulation. De plus, une requête ainsi réécrite est mieux lisible, plus facile à comprendre et à déboguer.

Il faut comprendre qu'en réécrivant la requête de cette manière, nous avons peut-être introduit un certain ralentissement en raison d'une surcharge supplémentaire - la création de tables temporaires. Si le SGBD ne se trompe pas dans le choix d'un plan, il exécutera probablement l'ancienne requête plus rapidement que la nouvelle. Toutefois, ce ralentissement sera toujours extrêmement faible. L'ampleur du ralentissement dépend du SGBD utilisé et des performances matérielles. Dans un cas typique, la création d'une table temporaire peut prendre plusieurs millisecondes. Autrement dit, ces ralentissements ne peuvent pas avoir d'impact notable sur les performances du système et, en règle générale, ils peuvent être ignorés.