Les requêtes sur tables larges qui filtrent sur quelques colonnes tout en récupérant l'ensemble des colonnes engendrent un problème d'amplification des lectures. Un index columnstore gère efficacement le filtrage, mais la récupération de chaque colonne projetée via cet index s'avère coûteuse. Un index row store évite cette amplification, mais perd la vitesse de filtrage colonnaire. Hybrid Plan combine ces deux types d'index au sein d'une même exécution de requête afin de tirer parti des avantages de chacun.

Fonctionnement
Hybrid Plan divise l'exécution en deux étapes :
L'optimiseur utilise l'In-Memory Column Index (IMCI) pour filtrer les lignes et récupérer leurs clés primaires.
Le système exploite ces clés primaires pour rechercher les données complètes des lignes dans l'index primaire InnoDB.
Cette approche élimine l'amplification des lectures : IMCI effectue le balayage colonnaire rapide, tandis qu'InnoDB retourne uniquement les lignes correspondantes dans leur intégralité.
Applicabilité
Édition du cluster : PolarDB for MySQL Enterprise Edition
-
Versions prises en charge :
PolarDB for MySQL 8.0.1, révision 8.0.1.1.37 ou ultérieure
PolarDB for MySQL 8.0.2, révision 8.0.2.2.23.1 ou ultérieure
Cas d'utilisation
Requêtes sur tables larges retournant au moins 15 colonnes.
Limitations
Les tables fournissant des colonnes de sortie pour la requête doivent posséder une clé primaire explicitement définie.
Si Hybrid Plan ne parvient pas à accélérer une instruction SQL lente en raison de limitations telles que le type de table, contactez-nous pour obtenir de l'aide.
Paramètres
Deux paramètres régissent Hybrid Plan. Ils opèrent à différents niveaux et respectent un ordre de priorité clair :
imci_enable_hybrid_plan— contrôle la fonctionnalité de manière globale. Défini sur ON, ce paramètre permet à l'optimiseur d'évaluer chaque requête et d'appliquer automatiquement Hybrid Plan si le coût d'exécution estimé est réduit.imci_optimizer_switch— indice par requête. Spécifierforce_hybrid_index_search=ONdans un indice force l'utilisation de Hybrid Plan pour cette instruction, indépendamment de l'estimation de coût de l'optimiseur.
Priorité : Un indice par requête (force_hybrid_index_search=ON) prévaut sur la décision automatique de l'optimiseur. Ce dernier ne prend une décision qu'en l'absence d'indice et lorsque imci_enable_hybrid_plan est activé (ON).
| Paramètre | Valeur par défaut | Description |
|---|---|---|
imci_enable_hybrid_plan |
ON | Active Hybrid Plan globalement. Définissez ce paramètre sur OFF pour désactiver la fonctionnalité. |
imci_optimizer_switch |
force_hybrid_index_search=OFF |
Substitution par requête. Spécifiez force_hybrid_index_search=ON dans un indice pour imposer Hybrid Plan à une instruction spécifique. |
Activer et vérifier Hybrid Plan
Cette section prend SELECT * FROM t1; comme exemple.
Étape 1 : Se connecter au cluster
Connectez-vous au cluster PolarDB. Pour plus de détails, consultez Se connecter à un cluster de base de données.
Étape 2 : Activer la fonctionnalité
Définissez imci_enable_hybrid_plan sur ON. L'optimiseur applique alors automatiquement Hybrid Plan aux requêtes sur tables larges éligibles.
SET imci_enable_hybrid_plan=ON;
Étape 3 : Forcer l'utilisation de Hybrid Plan pour une requête spécifique (facultatif)
Si l'optimiseur ne sélectionne pas Hybrid Plan pour une requête (par exemple, si son estimation de coût favorise un autre plan), ajoutez un indice pour outrepasser cette décision :
SELECT /*+ SET_VAR(imci_optimizer_switch='force_hybrid_index_search=ON') */ * FROM t1;
Étape 4 : Vérifier que Hybrid Plan est actif
Exécutez EXPLAIN sur la requête pour confirmer l'utilisation de Hybrid Plan. Lorsqu'il est actif, le plan d'exécution inclut l'opérateur HybridIndexSearch.
EXPLAIN SELECT /*+ SET_VAR(imci_optimizer_switch='force_hybrid_index_search=ON') */ * FROM t1;
Sortie attendue :
+----+-------------------------+------+---------------------------------------------------------------+
| ID | Operator | Name | Extra Info |
+----+-------------------------+------+---------------------------------------------------------------+
| 1 | Select Statement | | IMCI Execution Plan (max_dop = 32, max_query_mem = unlimited) |
| 2 | └─HybridIndexSearch | | Used table: t1 |
| 3 | └─Compute Scalar | | |
| 4 | └─Table Scan | t1 | |
+----+-------------------------+------+---------------------------------------------------------------+
4 rows in set (0.02 sec)
L'opérateur HybridIndexSearch à la ligne 2 confirme que Hybrid Plan est actif. La ligne 1 affiche le contexte d'exécution IMCI ; la ligne 4 confirme le balayage de la table InnoDB pour la récupération complète des lignes.
Test de performance
Le test suivant utilise le jeu de données OnTime de ClickHouse. La table OnTime comporte 109 colonnes, ce qui en fait une table large représentative. Le schéma de la table a été modifié pour inclure une clé primaire explicite. Le schéma modifié est le suivant :
CREATE TABLE `ontime` (
`ID` int(11) NOT NULL AUTO_INCREMENT,
`Year` year(4) DEFAULT NULL,
`Quarter` tinyint(4) DEFAULT NULL,
`Month` tinyint(4) DEFAULT NULL,
`DayofMonth` tinyint(4) DEFAULT NULL,
`DayOfWeek` tinyint(4) DEFAULT NULL,
`FlightDate` date DEFAULT NULL,
`UniqueCarrier` char(7) DEFAULT NULL,
`AirlineID` int(11) DEFAULT NULL,
`Carrier` char(2) DEFAULT NULL,
`TailNum` varchar(50) DEFAULT NULL,
`FlightNum` varchar(10) DEFAULT NULL,
`OriginAirportID` int(11) DEFAULT NULL,
`OriginAirportSeqID` int(11) DEFAULT NULL,
`OriginCityMarketID` int(11) DEFAULT NULL,
`Origin` char(5) DEFAULT NULL,
`OriginCityName` varchar(100) DEFAULT NULL,
`OriginState` char(2) DEFAULT NULL,
`OriginStateFips` varchar(10) DEFAULT NULL,
`OriginStateName` varchar(100) DEFAULT NULL,
`OriginWac` int(11) DEFAULT NULL,
`DestAirportID` int(11) DEFAULT NULL,
`DestAirportSeqID` int(11) DEFAULT NULL,
`DestCityMarketID` int(11) DEFAULT NULL,
`Dest` char(5) DEFAULT NULL,
`DestCityName` varchar(100) DEFAULT NULL,
`DestState` char(2) DEFAULT NULL,
`DestStateFips` varchar(10) DEFAULT NULL,
`DestStateName` varchar(100) DEFAULT NULL,
`DestWac` int(11) DEFAULT NULL,
`CRSDepTime` int(11) DEFAULT NULL,
`DepTime` int(11) DEFAULT NULL,
`DepDelay` int(11) DEFAULT NULL,
`DepDelayMinutes` int(11) DEFAULT NULL,
`DepDel15` int(11) DEFAULT NULL,
`DepartureDelayGroups` int(11) DEFAULT NULL,
`DepTimeBlk` varchar(20) DEFAULT NULL,
`TaxiOut` int(11) DEFAULT NULL,
`WheelsOff` int(11) DEFAULT NULL,
`WheelsOn` int(11) DEFAULT NULL,
`TaxiIn` int(11) DEFAULT NULL,
`CRSArrTime` int(11) DEFAULT NULL,
`ArrTime` int(11) DEFAULT NULL,
`ArrDelay` int(11) DEFAULT NULL,
`ArrDelayMinutes` int(11) DEFAULT NULL,
`ArrDel15` int(11) DEFAULT NULL,
`ArrivalDelayGroups` int(11) DEFAULT NULL,
`ArrTimeBlk` varchar(20) DEFAULT NULL,
`Cancelled` tinyint(4) DEFAULT NULL,
`CancellationCode` char(1) DEFAULT NULL,
`Diverted` tinyint(4) DEFAULT NULL,
`CRSElapsedTime` int(11) DEFAULT NULL,
`ActualElapsedTime` int(11) DEFAULT NULL,
`AirTime` int(11) DEFAULT NULL,
`Flights` int(11) DEFAULT NULL,
`Distance` int(11) DEFAULT NULL,
`DistanceGroup` tinyint(4) DEFAULT NULL,
`CarrierDelay` int(11) DEFAULT NULL,
`WeatherDelay` int(11) DEFAULT NULL,
`NASDelay` int(11) DEFAULT NULL,
`SecurityDelay` int(11) DEFAULT NULL,
`LateAircraftDelay` int(11) DEFAULT NULL,
`FirstDepTime` varchar(10) DEFAULT NULL,
`TotalAddGTime` varchar(10) DEFAULT NULL,
`LongestAddGTime` varchar(10) DEFAULT NULL,
`DivAirportLandings` varchar(10) DEFAULT NULL,
`DivReachedDest` varchar(10) DEFAULT NULL,
`DivActualElapsedTime` varchar(10) DEFAULT NULL,
`DivArrDelay` varchar(10) DEFAULT NULL,
`DivDistance` varchar(10) DEFAULT NULL,
`Div1Airport` varchar(10) DEFAULT NULL,
`Div1AirportID` int(11) DEFAULT NULL,
`Div1AirportSeqID` int(11) DEFAULT NULL,
`Div1WheelsOn` varchar(10) DEFAULT NULL,
`Div1TotalGTime` varchar(10) DEFAULT NULL,
`Div1LongestGTime` varchar(10) DEFAULT NULL,
`Div1WheelsOff` varchar(10) DEFAULT NULL,
`Div1TailNum` varchar(10) DEFAULT NULL,
`Div2Airport` varchar(10) DEFAULT NULL,
`Div2AirportID` int(11) DEFAULT NULL,
`Div2AirportSeqID` int(11) DEFAULT NULL,
`Div2WheelsOn` varchar(10) DEFAULT NULL,
`Div2TotalGTime` varchar(10) DEFAULT NULL,
`Div2LongestGTime` varchar(10) DEFAULT NULL,
`Div2WheelsOff` varchar(10) DEFAULT NULL,
`Div2TailNum` varchar(10) DEFAULT NULL,
`Div3Airport` varchar(10) DEFAULT NULL,
`Div3AirportID` int(11) DEFAULT NULL,
`Div3AirportSeqID` int(11) DEFAULT NULL,
`Div3WheelsOn` varchar(10) DEFAULT NULL,
`Div3TotalGTime` varchar(10) DEFAULT NULL,
`Div3LongestGTime` varchar(10) DEFAULT NULL,
`Div3WheelsOff` varchar(10) DEFAULT NULL,
`Div3TailNum` varchar(10) DEFAULT NULL,
`Div4Airport` varchar(10) DEFAULT NULL,
`Div4AirportID` int(11) DEFAULT NULL,
`Div4AirportSeqID` int(11) DEFAULT NULL,
`Div4WheelsOn` varchar(10) DEFAULT NULL,
`Div4TotalGTime` varchar(10) DEFAULT NULL,
`Div4LongestGTime` varchar(10) DEFAULT NULL,
`Div4WheelsOff` varchar(10) DEFAULT NULL,
`Div4TailNum` varchar(10) DEFAULT NULL,
`Div5Airport` varchar(10) DEFAULT NULL,
`Div5AirportID` int(11) DEFAULT NULL,
`Div5AirportSeqID` int(11) DEFAULT NULL,
`Div5WheelsOn` varchar(10) DEFAULT NULL,
`Div5TotalGTime` varchar(10) DEFAULT NULL,
`Div5LongestGTime` varchar(10) DEFAULT NULL,
`Div5WheelsOff` varchar(10) DEFAULT NULL,
`Div5TailNum` varchar(10) DEFAULT NULL,
PRIMARY KEY (`ID`)
) ENGINE=InnoDB AUTO_INCREMENT=58592318 DEFAULT CHARSET=latin1 COMMENT='columnar=1'
Requête de test :
SELECT * FROM ontime ORDER BY ArrTime LIMIT 1000;
Toutes les requêtes ont été exécutées à froid.
| Stratégie d'exécution | Temps de requête |
|---|---|
| Row store uniquement | 232,48 secondes |
| Index columnstore (IMCI) uniquement | 2,56 secondes |
| Hybrid Plan | 0,33 seconde |
Pour cette charge de travail, Hybrid Plan est 7,8 fois plus rapide que l'index columnstore seul et 704 fois plus rapide que le row store seul.