Dieser Artikel wurde von der Huawei Cloud Community geteilt „ [MySQL Technology Column] GaussDB (for MySQL) Big IN Query Optimization “, Autor: GaussDB-Datenbank.
Hintergrundeinführung
In einer Produktionsumgebung stoßen wir häufig auf geschäftliche SQL-Anweisungen von Kunden zum Filtern und Abfragen und führen dann eine Aggregationsverarbeitung durch, und die IN-Prädikatliste enthält Tausende oder sogar Zehntausende konstanter Werte. Wie unten gezeigt, ist die Ausführungszeit solcher Anweisungen sehr lang.
MySQL-Optimierung
Wenn Open-Source-MySQL die Spalte IN (const1, const2, ...) verarbeitet und ein Index für die Spalte vorhanden ist, wählt der Optimierer den Bereichsscan zum Scannen aus, andernfalls verwendet er den vollständigen Tabellenscan. Die Systemvariable range_optimizer_max_mem_size steuert den maximalen Speicher, der während der Analyse des Bereichsoptimierungsprozesses verwendet werden kann. Wenn das IN-Prädikat viele Listenelemente enthält, wird der Inhalt jedes IN als OR behandelt. Wenn es viele Elemente gibt, wird mehr Speicher verwendet. Wenn die Speichernutzung den definierten maximalen Speicher überschreitet, schlägt die Bereichsoptimierung fehl und der Optimierer ändert die Strategie, z. B. die Konvertierung in einen vollständigen Tabellenscan, was zu einer Verringerung der Abfrageleistung führt.
Dieses Optimierungsproblem kann durch Anpassen von range_optimizer_max_mem_size gelöst werden. Der durch „range_optimizer_max_mem_size“ definierte Speicher befindet sich auf Sitzungsebene. Jede Sitzung, die diese Art von Anweisung ausführt, belegt den gleichen Speicher. In großen Parallelitätsszenarien führt dies zu einer übermäßigen Instanzspeichernutzung und dem Risiko von Instanz-OOM.
Für Bereichsabfragen definiert MySQL die Systemvariable eq_range_index_dive_limit, um zu steuern, ob der Optimierer bei der Verarbeitung äquivalenter Bereichsabfragen einen Indextauchgang (index div) durchführt. Beim Indextauchen wird der Index verwendet, um die Beschreibung der Anzahl der Tupel zu vervollständigen, wodurch genauere Informationen erhalten und eine bessere Optimierung der Abfragestrategie ermöglicht werden können. Die Laufzeit ist jedoch auch lang. Wenn die Anzahl der IN-Kombinationen eine bestimmte Anzahl überschreitet, ist das Indextauchen nicht anwendbar. Das System verwendet statistische Informationswerte für statische Indizes, um Indizes auszuwählen. Dies kann dazu führen, dass MySQL den Index nicht sinnvoll nutzen kann, was zu Leistungseinbußen führt.
Große IN-Optimierung von GaussDB (für MySQL)
Spalte IN (const1, const2, ....)
Spalte IN (SELECT ... FROM temporary_table)
Die Verkettung kann in zwei Reihenfolgen erfolgen:
-
Materialisierungsscan: Zeigt einen vollständigen Tabellenscan der materialisierten Tabelle von der materialisierten Tabelle bis zum Erscheinungsbild an.
-
Materialisierungssuche: Gibt an, dass Sie vom Erscheinungsbild bis zur materialisierten Tabelle den Haupt-Builder verwenden können, um nach Daten in der materialisierten Tabelle zu suchen.
Physikalischer und chemischer Scan
-
Führen Sie die Unterabfrage aus, verwenden Sie den Index auto_distinct_key und deduplizieren Sie gleichzeitig die Ergebnisse.
-
Speichern Sie die Ergebnisse des vorherigen Schritts in der temporären Tabellenvorlage 1;
-
Rufen Sie eine Datenzeile aus der temporären Tabelle ab und suchen Sie die Zeile, die die Zusatzbedingungen im Erscheinungsbild erfüllt.
-
Wiederholen Sie Schritt 3, bis die Durchquerung der temporären Tabelle abgeschlossen ist.
Materialisierte Suche
-
Führen Sie zuerst die Unterabfrage aus.
-
Speichern Sie die im vorherigen Schritt erhaltenen Ergebnisse in einer temporären Tabelle.
-
Nehmen Sie eine Datenzeile aus dem Erscheinungsbild, gehen Sie zur materialisierten temporären Tabelle, um Zeilen zu finden, die die Zusatzbedingungen erfüllen, verwenden Sie den Primärschlüssel der materialisierten Tabelle und scannen Sie jeweils eine Zeile.
-
Wiederholen Sie Schritt 3, bis Sie den gesamten Look gesehen haben.
Der Optimierer wählt abhängig von der Größe des inneren Erscheinungsbilds unterschiedliche Verkettungsreihenfolgen. In realen Szenarien ist die Datenmenge in den im Allgemeinen abgefragten Tabellen sehr groß, Dutzende Millionen oder sogar Hunderte Millionen. Die Anzahl der Elemente in der IN-Liste ist viel kleiner als die Anzahl der Tabellen, und der Optimierer wählt die Materialisierung -scan-Methode zum Scannen. Wenn der Primärschlüssel während der Darstellung des Abfrageindex verwendet wird, beträgt die Gesamtzahl der gescannten Zeilen nach der Optimierung N. Wenn M viel größer als N ist, ist die Leistungsverbesserung sehr offensichtlich.
Anweisungen
Der Parameter rds_in_predicate_conversion_threshold ist ein Schalter zum Ändern der Abfragefunktion am Ende des IN-Prädikats. Wenn die Anzahl der Elemente in der IN-Prädikatliste der SQL-Anweisung den Wert des Parameters überschreitet, wird die Optimierungsstrategie gestartet. Die Funktion wird über den Wert dieser Variablen verwendet. Das Folgende ist ein einfaches Beispiel, das den Einsatz der Optimierung veranschaulicht:
Tabellenstruktur
Tabelle erstellen t1(id int, a int, key idx1(a));
Wählen Sie * aus t1 aus, wobei a in (1,2,3,4,5);
Setzen Sie „set rds_in_predicate_conversion_threshold = 0“ und „range_optimizer_max_mem_size = 1“, um die Optimierungsfunktion für große IN-Prädikate und die Optimierungsstrategie für den Bereichsscan zu deaktivieren. Die Ergebnisse sind wie folgt:
> set rds_in_predicate_conversion_threshold = 0; > set range_optimizer_max_mem_size=1; > erklären select * from t1 where a in (1,2,3,4,5); Das Ergebnis ist wie folgt: +----+-------------+-------+------------+------+-- -------------+------+---------+------+------+----- -----+-------------+ | id | select_type | Tisch | Partitionen | Typ | mögliche_schlüssel | Schlüssel | key_len | ref | Reihen | gefiltert | Extra | +----+-------------+-------+------------+------+-- -------------+------+---------+------+------+----- -----+-------------+ | 1 | EINFACH | t3 | NULL | ALLE | Schlüssel1 | NULL | NULL | NULL | 3 | 50,00 | Verwenden von where | +----+-------------+-------+------------+------+-- -------------+------+---------+------+------+----- -----+-------------+ 1 Zeile im Satz, 2 Warnungen (0,00 Sek.) Warnungen anzeigen; +---------+------+-------------------------------- -------------------------------------------------- ----------------------------------------+ | Ebene | Code | Nachricht | +---------+------+-------------------------------- -------------------------------------------------- -----------------------------------------+ | Warnung | 3170 | Die Speicherkapazität von 1 Byte für „range_optimizer_max_mem_size“ wurde überschritten. Für diese Abfrage wurde keine Bereichsoptimierung durchgeführt. | | Hinweis | 1003 | /* select#1 */ select `test`.`t3`.`id` AS `id`,`test`.`t3`.`a` AS `a` from `test`.`t3` where (` test`.`t3`.`a` in (3,4,5)) | +---------+------+-------------------------------- -------------------------------------------------- -----------------------------------------+ 2 Reihen im Satz (0,00 Sek.)
Es wurde festgestellt, dass bei der Ausführung der obigen Anweisung eine Warnung gemeldet wurde. Die Warninformationen zeigten, dass die Bereichsbegrenzungsoptimierung nicht für die Anweisung verwendet wurde, da der während des Bereichsoptimierungsprozesses verwendete Speicher den Wert von „range_optimizer_max_mem_size“ überschritt. Dadurch ändert sich der Scantyp in „ALL“ und wird zu einem vollständigen Tabellenscan.
Setzen Sie set rds_in_predicate_conversion_threshold = 3, um die Optimierungsoption für große IN-Prädikate zu aktivieren. Dies bedeutet, dass die Optimierungsstrategie für große IN-Warteschlangenabfragen aktiviert wird, wenn die Elemente der IN-Prädikatliste 3 überschreiten. Führen Sie die Anweisung EXPLAIN FORMAT=TREE aus, um zu sehen, ob die Optimierung wirksam wird.
> set rds_in_predicate_conversion_threshold = 3; > EXPLAIN format=tree select * from t1 where a in (1,2,3,4,5); +------------------------------------------------- -------------------------------------------------- -------------------------------------------------- -------------------------------------------------- -------------------------------------------------- -------+ | ERKLÄREN | +------------------------------------------------- -------------------------------------------------- -------------------------------------------------- -------------------------------------------------- -------------------------------------------------- -------+ | -> Innerer Join mit verschachtelter Schleife (Kosten = 0,70 Zeilen = 1) -> Filter: (t1.a ist nicht null) (Kosten = 0,35 Zeilen = 1) -> Tabellenscan auf t1 (Kosten = 0,35 Zeilen = 1) -> Einzelzeilenindexsuche für <in_predicate_2> mit <auto_distinct_key> (a=t1.a) (Kosten=0,35 Zeilen=1) | +------------------------------------------------- -------------------------------------------------- -------------------------------------------------- -------------------------------------------------- -------------------------------------------------- -------+ 1 Zeile im Satz (0,00 Sek.)
Die Tabelle <in_predicate_*> (* ist eine Zahl) im Ausführungsplan ist eine in Big INTool erstellte temporäre Tabelle, in der alle Daten in der IN-Prädikatliste gespeichert werden.
Nutzungsbeschränkungen
Zu den von der Big IN-Optimierung unterstützten Abfrageanweisungen gehört die folgende Anweisungsliste:
-
wählen
-
Einfügen...auswählen
-
ersetzen...auswählen
-
Standpunkt der Unterstützung
-
STMT vorbereitet
Einschränkungen und Einschränkungen
Die Big IN-Rotorabfrage verwendet die von MySQL bereitgestellte Unterabfrageoptimierungslösung, um die Leistung zu erzielen. Daher gelten die folgenden Einschränkungen bei der Verwendung, da sonst die Leistung beeinträchtigt wird.
-
Szenarien, in denen die Indizierung nicht verwendet werden kann, werden nicht unterstützt
-
Unterstützt nur die Konstante IN LIST (einschließlich NOW(), ? und andere Anweisungen, die keine Tabellenabfragen beinhalten)
-
Gespeicherte Prozeduren/Funktionen/Trigger werden nicht unterstützt
-
Nicht unterstützt oder nicht vorhanden
Typischer Szenario-Testvergleich
Die Tabellenteststruktur ist wie folgt:
CREATE TABLE `sbtest1` ( `id` int NOT NULL AUTO_INCREMENT, `k` int NOT NULL DEFAULT '0', `c` char(120) NOT NULL DEFAULT '', `pad` char(60) NOT NULL DEFAULT '' , PRIMARY KEY (`id`), KEY `k_1` (`k`) ) ENGINE=InnoDB; Das Datenvolumen der Tabelle beträgt 1000 W. > wähle count(*) aus sbtest1; +----------+ | count(*) | +----------+ | 10000000 | +----------+
Die Abfrageanweisung lautet wie folgt: Das Bedingungsfeld ist indiziert und die IN-Liste enthält 10.000 konstante Zahlen.
Wählen Sie count(*) aus sbtest1 aus, wobei k in (2708275,5580784,7626186,8747250,228703,4589267,5938459,6982345,2665948,4830545,4929382,8723757,354179,19 03875,5111120,5471341,7098051,3113388,2584956,6550102 ,2842606,2744112,7077924,4580644,5515358,1787655,6391388,6044316,2658197,5628504,413887,6058866,3321587,1430333,445303,7 373496,9133196,6760595,4735642,4756387,9845147,9362192,7271805,4351748,6625915 ,3813276,4236692,8308973,4407131,9481423,3301846,432577,810938,3830320,6120078,6765157,6456566,6649509,1123840,2906490,9 965014,3725748, ... );
Der Leistungsvergleich ist in der folgenden Abbildung dargestellt:
Es ist ersichtlich, dass nach der In-List-Optimierung die Leistung im Vergleich zur ursprünglichen Methode um das 36-fache verbessert wird.
High-School-Schüler erstellen ihre eigene Open-Source-Programmiersprache als Coming-of-Age-Zeremonie – scharfe Kommentare von Internetnutzern: Unter Berufung auf die Verteidigung hat Apple den M4-Chip RustDesk veröffentlicht. Inländische Dienste wurden wegen grassierenden Betrugs eingestellt . In Zukunft plant er, ein unabhängiges Spiel auf der Windows-Plattform Taobao (taobao.com) zu produzieren. Webversionsoptimierungsarbeiten neu starten, Ziel für Programmierer, Visual Studio Code 1.89 veröffentlicht Java 17, die am häufigsten verwendete Java LTS-Version, Windows 10 hat eine Marktanteil von 70 %, Windows 11 geht weiter zurück ; Google unterstützt Hongmeng bei der Übernahme von Open-Source-Rabbit-R1;