【GaussDB (pour MySQL)】 Optimisation des requêtes Big IN

Cet article est partagé par la communauté Huawei Cloud « [Chronique sur la technologie MySQL] GaussDB (pour MySQL) Big IN Query Optimization », auteur : base de données GaussDB.

20240508-164135(WeLinkPC).jpg

Introduction au contexte

Dans un environnement de production, nous rencontrons souvent des instructions SQL métier client pour le filtrage et les requêtes, puis effectuons un traitement d'agrégation, et la liste de prédicats IN contient des milliers, voire des dizaines de milliers de valeurs constantes. Comme indiqué ci-dessous, le temps d'exécution de telles instructions est très long.

 

111.PNG

Optimisation MySQL

Lorsque MySQL open source traite la colonne IN (const1, const2, ....), s'il y a un index sur la colonne, l'optimiseur sélectionnera l'analyse de plage pour l'analyse, sinon il utilisera l'analyse complète de la table. La variable système range_optimizer_max_mem_size contrôle la mémoire maximale pouvant être utilisée lors de l'analyse du processus d'optimisation de plage. S'il y a de nombreux éléments de liste dans le prédicat IN, le contenu de chaque IN sera traité comme OU chacun OU occupe environ 230 octets. S'il y a beaucoup d'éléments, plus de mémoire sera utilisée. Si l'utilisation de la mémoire dépasse la mémoire maximale définie, l'optimisation de la plage échouera et l'optimiseur modifiera la stratégie, par exemple la conversion en une analyse de table complète, entraînant une diminution des performances des requêtes.

Pour ce problème d'optimisation, il peut être résolu en ajustant range_optimizer_max_mem_size. La mémoire définie par range_optimizer_max_mem_size est au niveau de la session. Chaque session exécutant ce type d'instruction occupera la même mémoire dans les grands scénarios de concurrence, cela entraînera une utilisation excessive de la mémoire de l'instance et un risque de MOO d'instance.

Pour les requêtes de plage, MySQL définit la variable système eq_range_index_dive_limit pour contrôler si l'optimiseur effectue une plongée d'index (index div) lors du traitement de requêtes de plage équivalentes. La plongée d'index utilise l'index pour compléter la description du nombre de tuples, ce qui peut obtenir des informations plus précises et optimiser la stratégie de requête, mais le temps d'exécution est également long. Lorsque le nombre de combinaisons IN dépasse un certain nombre, la plongée d'index n'est pas applicable. Le système utilise des valeurs d'informations statistiques d'index statiques pour sélectionner les index. Les résultats obtenus par cette méthode doivent être précis. Cela peut empêcher MySQL de faire bon usage de l'index, ce qui entraînera une régression des performances.

Optimisation Big IN de GaussDB (pour MySQL)

 
La méthode des problèmes de performances Big IN de GaussDB (pour MySQL) convertit les prédicats big IN en sous-requêtes IN. Par conséquent, la forme du prédicat IN est :
colonne IN (const1, const2, ....)
Convertir en sous-requête IN correspondante :
colonne IN (SELECT ... FROM table_temporaire)
Après les modifications ci-dessus, la requête de fonction IN devient une sous-requête IN et la sous-requête est une sous-requête non corrélée.
 
Pour les sous-requêtes IN non corrélées, l'optimiseur MySQL fournit une stratégie de matérialisation de semi-jointure pour le traitement d'optimisation. La stratégie de matérialisation de semi-jointure consiste à matérialiser les résultats de la sous-requête dans une table temporaire, puis à les joindre à l'apparence. Comme indiqué ci-dessous:
 

1.png

 

La concaténation peut s'effectuer dans deux ordres :

  • Analyse de matérialisation : indique une analyse complète de la table matérialisée, de la table matérialisée à l'apparence.
  • Recherche de matérialisation : indique que, depuis l'apparition de la table matérialisée, vous pouvez utiliser le générateur principal pour rechercher des données dans la table matérialisée.

Analyse physique et chimique

  1. Exécutez la sous-requête, utilisez l'index auto_distinct_key et dédupliquez les résultats en même temps ;
  2. Enregistrez les résultats de l'étape précédente dans le modèle de table temporaire 1 ;
  3. Obtenez une ligne de données de la table temporaire et recherchez la ligne qui répond aux conditions supplémentaires dans l'apparence ;
  4. Répétez l'étape 3 jusqu'à ce que le parcours de la table temporaire soit terminé.

Recherche matérialisée

  1. Exécutez d'abord la sous-requête ;
  2. Enregistrez les résultats obtenus à l'étape précédente dans une table temporaire ;
  3. Prenez une ligne de données de l'apparence, accédez à la table temporaire matérialisée pour trouver les lignes qui répondent aux conditions supplémentaires, utilisez la clé primaire de la table matérialisée et analysez une ligne à la fois ;
  4. Répétez 3 jusqu'à ce que vous ayez vu l'intégralité du look.

L'optimiseur choisit différents ordres de concaténation en fonction de la taille de l'apparence interne. Dans des scénarios réels, la quantité de données dans les tables généralement interrogées est très importante, des dizaines de millions voire des centaines de millions ; le nombre d'éléments dans la liste IN est bien inférieur au nombre de tables, et l'optimiseur choisira la matérialisation ; -méthode d'analyse pour l'analyse Si la clé primaire est utilisée lors de l'index de requête d'apparence, le nombre total de lignes analysées après optimisation est N. Lorsque M est beaucoup plus grand que N, l'amélioration des performances sera très évidente.

Instructions

Le paramètre rds_in_predicate_conversion_threshold est un commutateur permettant de modifier la fonction de requête en bas du prédicat IN. Lorsque le nombre d'éléments dans la liste de prédicats IN de l'instruction SQL dépasse la valeur du paramètre, la stratégie d'optimisation sera lancée. La fonction est utilisée via la valeur de cette variable. Voici un exemple simple illustrant l’utilisation de l’optimisation :

Structure du tableau

créer la table t1(id int, a int, key idx1(a));
Vérifiez les phrases
sélectionnez * à partir de t1 où a in (1,2,3,4,5);

Définissez set rds_in_predicate_conversion_threshold = 0 et définissez range_optimizer_max_mem_size=1 pour désactiver la grande fonction d'optimisation du prédicat IN et la stratégie d'optimisation de l'analyse de plage. Vérifiez le plan d'exécution de l'instruction de requête ci-dessus. Les résultats sont les suivants :

> définissez rds_in_predicate_conversion_threshold = 0 ; > définissez range_optimizer_max_mem_size=1 ; > expliquer sélectionner * from t1 où a in (1,2,3,4,5);  
Le résultat est le suivant :
+---------+-------------+-------+------------+------+-- -------------+------+---------+------+------+----- -----+-------------+ | identifiant | sélectionnez_type | tableau | cloisons | tapez | clés_possibles | clé | key_len | réf | lignes | filtré | Supplémentaire | +---------+-------------+-------+------------+------+-- -------------+------+---------+------+------+----- -----+-------------+ | 1 | SIMPLES | t3 | NULL | TOUS | clé1 | NULL | NULL | NULL | 3 | 50,00 | Utiliser où | +---------+-------------+-------+------------+------+-- -------------+------+---------+------+------+----- -----+-------------+ 1 ligne dans l'ensemble, 2 avertissements (0,00 sec)  
afficher des avertissements ; +---------+------+-------------------------------- -------------------------------------------------- -----------------------------------------+ | Niveau | Codes | Messages | +---------+------+-------------------------------- -------------------------------------------------- -----------------------------------------+ | Avertissement | 3170 | Capacité mémoire de 1 octet pour 'range_optimizer_max_mem_size' dépassée. L'optimisation de la plage n'a pas été effectuée pour cette requête. | | Remarque | 1003 | /* select#1 */ sélectionnez `test`.`t3`.`id` AS `id`,`test`.`t3`.`a` AS `a` de `test`.`t3` où (` test`.`t3`.`a` dans (3,4,5)) | +-------------+------+-------------------------------- -------------------------------------------------- -----------------------------------------+ 2 lignes dans l'ensemble (0,00 sec)

Il a été constaté qu'un avertissement avait été signalé lors de l'exécution de l'instruction ci-dessus. Les informations d'avertissement montraient que, comme la mémoire utilisée pendant le processus d'optimisation de plage dépassait range_optimizer_max_mem_size, l'optimisation de la limite de plage n'était pas utilisée pour l'instruction. Par conséquent, le type d'analyse devient ALL et devient une analyse de table complète.

Définissez set rds_in_predicate_conversion_threshold = 3 pour activer l'option d'optimisation des grands prédicats IN, ce qui signifie que lorsque les éléments de la liste des prédicats IN dépassent 3, la stratégie d'optimisation des requêtes de grande file d'attente IN sera activée. Exécutez l'instruction EXPLAIN FORMAT=TREE pour voir si l'optimisation prend effet.

> définissez rds_in_predicate_conversion_threshold = 3 ; > expliquer format=tree select * from t1 où a in (1,2,3,4,5); +------------------------------------------------- -------------------------------------------------- -------------------------------------------------- -------------------------------------------------- -------------------------------------------------- -------+ | EXPLIQUER | +------------------------------------------------- -------------------------------------------------- -------------------------------------------------- -------------------------------------------------- -------------------------------------------------- -------+ | -> Jointure interne de boucle imbriquée (coût = 0,70 lignes = 1) -> Filtre : (t1.a n'est pas nul) (coût = 0,35 lignes = 1) -> Analyse de table sur t1 (coût = 0,35 lignes = 1) -> Recherche d'index sur une seule ligne sur <in_predicate_2> à l'aide de <auto_distinct_key> (a=t1.a) (cost=0,35 rows=1) | +------------------------------------------------- -------------------------------------------------- -------------------------------------------------- -------------------------------------------------- -------------------------------------------------- -------+ 1 ligne dans l'ensemble (0,00 sec)

La table <in_predicate_*> (* est un nombre) dans le plan d'exécution est une table temporaire construite dans Big INTool, qui stocke toutes les données de la liste de prédicats IN.

Restrictions d'utilisation

Les instructions de requête prises en charge par l'optimisation Big IN incluent la liste d'instructions suivante :

  • choisir
  • Insérer...sélectionner
  • remplacer...sélectionner
  • point de vue du soutien
  • STMT préparé

Contraintes et limites

La requête Big IN rotor utilise la solution d'optimisation de sous-requête fournie par mysql pour atteindre les performances. Par conséquent, il existe les restrictions d'utilisation suivantes, sinon cela réduira les performances.

  • Les scénarios dans lesquels l'indexation ne peut pas être utilisée ne sont pas pris en charge
  • Prend uniquement en charge la constante IN LIST (y compris NOW(), ? et d'autres instructions qui n'impliquent pas de requêtes de table)
  • Les procédures/fonctions/déclencheurs stockés ne sont pas pris en charge
  • Non pris en charge ou absent

Comparaison de tests de scénarios typiques

La structure du test du tableau est la suivante :

CREATE TABLE `sbtest1` ( `id` int NON NULL AUTO_INCREMENT, `k` int NON NULL PAR DÉFAUT '0', `c` char(120) NON NULL PAR DÉFAUT '', `pad` char(60) NON NULL PAR DÉFAUT '' , CLÉ PRIMAIRE (`id`), CLÉ `k_1` (`k`) ) MOTEUR=InnoDB ;  
Le volume de données de la table est de 1000w.
> sélectionnez count(*) dans sbtest1 ; +----------+ | compte(*) | +----------+ | 10000000 | +----------+

L'instruction de requête est la suivante, dans laquelle le champ de condition est indexé et la liste IN contient 10 000 nombres constants.

sélectionnez count (*) à partir de sbtest1 où k in (2708275,5580784,7626186,8747250,228703,4589267,5938459,6982345,2665948,4830545,4929382,8723757,354179,1903 875,5111120,5471341,7098051,3113388,2584956,6550102 ,2842606,2744112,7077924,4580644,5515358,1787655,6391388,6044316,2658197,5628504,413887,6058866,3321587,1430333,445303,73 73496,9133196,6760595,4735642,4756387,9845147,9362192,7271805,4351748,6625915 ,3813276,4236692,8308973,4407131,9481423,3301846,432577,810938,3830320,6120078,6765157,6456566,6649509,1123840,2906490,99 65014,3725748, ... );

La comparaison des performances est présentée dans la figure ci-dessous :

2.png

On peut constater qu'après l'optimisation en liste, les performances sont améliorées de 36 fois par rapport à la méthode d'origine.

Cliquez pour suivre et découvrir les nouvelles technologies de Huawei Cloud dès que possible~

 

Les lycéens créent leur propre langage de programmation open source en guise de cérémonie de passage à l'âge adulte - commentaires acerbes des internautes : S'appuyant sur la défense, Apple a publié la puce M4 RustDesk. Les services nationaux ont été suspendus en raison d'une fraude généralisée. À l'avenir, il envisage de produire un jeu indépendant sur la plateforme Windows Taobao (taobao.com) Redémarrer le travail d'optimisation de la version Web, destination des programmeurs, Visual Studio Code 1.89 publie Java 17, la version Java LTS la plus couramment utilisée, Windows 10 a un part de marché de 70 %, Windows 11 continue de décliner Open Source Daily | Google soutient Hongmeng pour prendre le relais ; l'anxiété et les ambitions de Microsoft ont fermé la plate-forme ouverte ;
{{o.name}}
{{m.nom}}

Je suppose que tu aimes

Origine my.oschina.net/u/4526289/blog/11105468
conseillé
Classement