Dieser Artikel wurde von der Huawei Cloud Community geteilt: „ [GaussTech Issue 2] Analysis of the GaussDB SQL Query Statement Execution Process “, Autor: GaussDB-Datenbank.
Die Bedeutung von SQL für relationale Datenbanken liegt auf der Hand. Wie ein Dirigent eines Orchesters leitet er die richtige Interpretation des Werkes und die Harmonie und Einheit des Rhythmus. Als neue Generation relationaler verteilter Datenbanken verfügt Huawei Cloud GaussDB über eine hervorragende technische Leistung und Branchenwettbewerbsfähigkeit. Viele Menschen sind neugierig auf die Schlüsseltechnologien von GaussDB und haben Nachrichten im Forum hinterlassen:
Heute beginnen wir mit der GaussDB SQL-Engine und lernen den Ausführungsprozess von GaussDB SQL-Abfrageanweisungen kennen, einschließlich der Prinzipien und wichtigsten technischen Punkte der GaussDB SQL-Engine.
Wenn Sie während des Verständnisprozesses Fragen oder wichtige technische Punkte haben, können Sie an [Yunka Q&A] teilnehmen, um das Geheimnis der GaussDB-SQL-Engine aufzudecken, zu interagieren und Geschenke zu gewinnen und Nachrichten für die Interaktion mit Experten zu hinterlassen -one Beantworten Sie Fragen und Sie haben die Chance, Belohnungen für das Stellen von Fragen zu erhalten.
↓↓↓↓ Das Folgende ist der Text
Lassen Sie uns zunächst kurz die Systemstruktur von GaussDB vorstellen und dann den Ausführungsprozess von GaussDB-SQL-Abfrageanweisungen analysieren.
GaussDB-Systemarchitektur
Abbildung (1) Zentralisiert
Abbildung (2) Verteilung
Bei der Ausführung von GaussDB-SQL-Anweisungen sind folgende Schlüsselrollen beteiligt:
GTM |
Der Global Transaction Manager ist für die Generierung und Pflege global eindeutiger Informationen wie globale Transaktions-IDs, Transaktions-Snapshots, Zeitstempel und Sequenzinformationen verantwortlich. |
CN |
Koordinatorknoten. Verantwortlich für den Empfang von Zugriffsanfragen von Anwendungen und die Rückgabe von Ausführungsergebnissen an den Client; verantwortlich für die Zerlegung von Aufgaben und die Planung von Aufgaben-Shards, die auf jedem DN parallel ausgeführt werden sollen. Jeder CN ist mit jedem DN verbunden und jeder CN enthält eine Kopie der Metadaten mit demselben Metadateninhalt. |
DN |
Datenknoten. Verantwortlich für die Speicherung von Geschäftsdaten (Unterstützung von Zeilenspeicher, Spaltenspeicher und Hybridspeicher), die Ausführung von Datenabfrageaufgaben und die Rückgabe von Ausführungsergebnissen an CN. |
Unter diesen ist DN hauptsächlich für die Ausführung von GaussDB-SQL-Anweisungen verantwortlich. Seine logische Architektur ist in der folgenden Abbildung dargestellt:
Abbildung (3) Logische Architektur von GaussDB
GaussDB umfasst zwei Haupt-Engines: SQL Engine und Storage Engine . Die SQL-Engine wird manchmal als Abfrageprozessor bezeichnet und ihre Hauptfunktionen sind SQL-Analyse, Abfrageoptimierung und Abfrageausführung. Die SQL-Analyse führt eine lexikalische Analyse, Syntaxanalyse und semantische Analyse der eingegebenen SQL-Anweisung durch, um einen Abfragebaum zu generieren. Nachdem der Abfragebaum einer Regeloptimierung (RBO) und einer Kostenoptimierung (CBO) unterzogen wurde, wird ein Ausführungsplan generiert. Der Ausführende extrahiert, bearbeitet, aktualisiert, löscht und führt andere Vorgänge an relevanten Daten basierend auf dem Ausführungsplan aus, um die Ergebnisse zu erzielen, die der Benutzer abfragen möchte.
Die Speicher-Engine ist für die Verwaltung aller Daten-E/A verantwortlich. Sie umfasst die Datenlese- und -schreibverarbeitung (Verarbeitung von E/A-Anfragen für Zeilen, Indizes, Seiten, Zuordnungen und Zeilenversionen), die Datenpufferverwaltung (Pufferpool) und die Transaktion Manager. Unter anderem umfasst die Transaktionsverwaltung den Sperrmechanismus (Lock) und die Transaktionsprotokollverwaltung (XLOG), die ACID-Attribute verwalten.
Zwischen der SQL-Engine und der Speicher-Engine befindet sich die AM-Schicht (Access Method). AM kapselt die Speicherschicht, um mehrere Speicher-Engines (Astore, Ustore usw.) zu unterstützen. Die SQL-Schicht ruft die Speicherschicht nicht direkt auf, sondern über die AM-Schicht. Die AM-Schicht ruft je nach Speicher-Engine unterschiedliche Ausführungskörper auf.
Aus dem logischen Architekturdiagramm von GaussDB ist ersichtlich, dass der Entwurf der GaussDB-Architektur den Entwurfsprinzipien moderner Softwaresystemabstraktion und hierarchischer Entkopplung folgt, einschließlich: einheitlicher Transaktionsmechanismus, einheitliches Protokollsystem, einheitliches Parallelitätskontrollsystem, einheitliches Metainformationssystem usw einheitliches Cache-Verwaltungssystem. Daher weist die technische Architektur von GaussDB die folgenden Hauptmerkmale auf:
-
Unterstützt SQL-Optimierung, Ausführung und Entkopplung der Speicherschicht;
-
Unterstützt steckbare Speicher-Engines.
Ausführungsprozess der SQL-Abfrageanweisung
Der Ausführungsprozess einer SQL-Abfrageanweisung (SELECT) ist wie folgt:
Abbildung (4) Ausführungsprozess der Abfrageanweisung
Wie aus der obigen Abbildung ersichtlich ist, muss eine SQL-Anweisung durch SQL-Analyse einen Abfragebaum generieren, die Abfrage optimieren, um einen Ausführungsplan zu generieren, und den Ausführungsplan dann an den Abfrageausführer übertragen, um physische Bedienerausführungsvorgänge auszuführen.
SQL ist eine Beschreibungssprache zwischen relationaler Analysis und relationaler Algebra. Sie übernimmt die Beschreibung einiger logischer Operatoren in der relationalen Algebra, verzichtet jedoch auf den „prozeduralen“ Teil der relationalen Algebra. Die Hauptfunktion der SQL-Analyse besteht darin, eine SQL-Anweisung in einen Abfragebaum zu kompilieren, der aus relationalen Operatoren besteht, die normalerweise Untermodule für lexikalische Analyse, Syntaxanalyse und semantische Analyse umfassen.
Die Regeloptimierung (RBO) führt eine äquivalente relationale Algebra-Transformation auf der Grundlage des Abfragebaums durch, wandelt eine SQL-Anweisung in ein effizienteres äquivalentes SQL um und spielt eine Schlüsselrolle im Datenbankoptimierer. Insbesondere bei komplexen Abfragen kann es zu Leistungsverbesserungen um Größenordnungen führen.
Bei der Abfrageausführung werden SQL-Abfrageanweisungen gemäß dem Ausführungsplan ausgeführt. Die Rationalität der Wahl der zugrunde liegenden Speichermethode wirkt sich auf die Effizienz der Abfrageausführung aus.
Parser
1. Lexikalische Analyse : Identifizieren Sie die vom System unterstützten Schlüsselwörter, Bezeichner, Operatoren, Terminals usw. anhand der Abfrageanweisung und bestimmen Sie den inhärenten Teil der Sprache jedes Wortes.
Der SQL-Standard definiert SQL-Schlüsselwörter und grammatikalische Regelinformationen. Während des lexikalischen Analyseprozesses unterteilt GaussDB eine SQL-Anweisung basierend auf Schlüsselwortinformationen und Intervallinformationen in unabhängige atomare Einheiten, und jede Einheit wird als Wort angezeigt.
2. Grammatikanalyse : Verwenden Sie gemäß den definierten SQL-Grammatikregeln die in der lexikalischen Analyse generierten Wörter, um sie mit den Grammatikregeln abzugleichen und den entsprechenden Abstract Syntax Tree (AST) zu generieren.
3. Semantische Analyse : Überprüfen Sie die Gültigkeit des Syntaxbaums, prüfen Sie, ob die entsprechenden Tabellen, Spalten, Funktionen und Ausdrücke im Syntaxbaum über entsprechende Metadaten verfügen, und konvertieren Sie den abstrakten Syntaxbaum in einen Abfragebaum.
Der Prozess der semantischen Analyse ist auch der Prozess der semantischen Gültigkeitsbindung. Durch die Inspektion der semantischen Analyse wird der abstrakte Syntaxbaum in einen Abfragebaum umgewandelt. Abfragebäume können in Form von relationalen Algebra-Ausdrücken dargestellt werden.
Optimierer
Der Optimierer ist ein sehr wichtiges Mittel zur Verbesserung der Abfrageeffizienz. Er besteht aus zwei Teilen: Regeloptimierung und Abfrageoptimierung.
Die Regeloptimierung ist eine äquivalente relationale Algebra-Transformation, die auf dem Abfragebaum basiert. Da es sich um eine auf relationaler Algebra basierende Optimierungsform handelt, kann sie auch als algebraische Optimierung bezeichnet werden. Obwohl die durch zwei relationale Algebra-Ausdrücke erzielten Ergebnisse genau gleich sind, können ihre Ausführungskosten sehr unterschiedlich sein, was die Grundlage der Regeloptimierung bildet.
Die Regeloptimierung folgt zwei Grundprinzipien:
(1) Äquivalenz: Die Ausgabeergebnisse der ursprünglichen Anweisung und der umgeschriebenen Anweisung sind gleich.
(2) Effizienz: Die Ausführung der umgeschriebenen Anweisung dauert weniger lange als die ursprüngliche Anweisung und nutzt die Ressourcen effizienter.
GaussDB implementiert einige wichtige Techniken zur Regeloptimierung, wie zum Beispiel:
Prädikat-Pushdown : Lösen Sie die bedingte Filterung früher aus und reduzieren Sie die Anzahl der verarbeiteten Zeilen
Eliminierung redundanter Vorgänge : Eliminieren Sie redundante Tabellen und Spalten, um den Berechnungsaufwand zu reduzieren
Unterabfrage-Hochstufung : Nach der Hochstufung können mehr Join-Aufträge abgeglichen werden
Konvertierung von außen nach innen : Inner Join kann mehr Join-Aufträge abgleichen
Sublink-Werbung : Reduzieren Sie Subplan- und Broadcast-Operationen
Beseitigen Sie ungleiche Verknüpfungen : Reduzieren Sie NestLoop- und Broadcast-Vorgänge
Bei der Betreuung einer großen Anzahl von Kunden abstrahiert GaussDB Geschäfts-SQL-Nutzungsmuster und implementiert einige erweiterte Umschreiberegeln. In zukünftigen Kolumnen werden wir die Regeloptimierungstechnologie von GaussDB im Detail vorstellen.
Abfrageoptimierung
Die Abfrageoptimierung basiert auf der Ausgabe der „Regeloptimierung“ und kombiniert sie mit den internen statistischen Informationen der Datenbank, um die spezifische Ausführungsmethode der SQL-Anweisung, also den Ausführungsplan, zu planen. Basierend auf verschiedenen Optimierungsmethoden kann die Abfrageoptimierungstechnologie unterteilt werden in:
(1) CBO (kostenbasierte Optimierung, kostenbasierte Abfrageoptimierung): Schätzen Sie die Kosten der Kandidatenausführungspfade, die der SQL-Anweisung entsprechen, und wählen Sie den Ausführungspfad mit den niedrigsten Kosten aus den Kandidatenpfaden als endgültigen Ausführungsplan aus.
(2) ABO (AI Based Optimization, auf maschinellem Lernen basierende Abfrageoptimierung): Durch kontinuierliches Lernen historischer Erfahrungen abstrahiert ABO das Muster des Zielszenarios, bildet ein dynamisches Modell und optimiert das tatsächliche Szenario des Benutzers adaptiv, um so das zu erhalten optimaler Ausführungsplan.
GaussDB verwendet CBO-basierte Optimierungstechnologie und kombiniert sie mit ABO, um die Modellierungseffizienz, Schätzgenauigkeit und Anpassungsfähigkeit aktiv zu untersuchen. Die Schritte sind wie folgt:
Abbildung (5) Schritte zur Abfrageoptimierung
Statistisches Informationsmodell : Statistische Informationen sind der Grundstein für die Berechnung der Planpfadkosten. Die Genauigkeit statistischer Informationen spielt eine entscheidende Rolle bei der Schätzung der Zeilennummer und der Kostenschätzung im Kostenschätzungsmodell, was sich direkt auf die Qualität des Abfrageplans auswirkt. Zu den Merkmalen der GaussDB-Basistabellendaten gehören unterschiedliche Werte, MCV-Werte (Most Common Values), Histogramme usw.
Zeilenschätzung : Nachdem eine Einschränkung die Auswahlrate bestimmt hat, kann die Anzahl der Zeilen bestimmt werden, die für jeden geplanten Pfad verarbeitet werden müssen, und die Anzahl der Seiten, die verarbeitet werden müssen, kann basierend auf der Anzahl der vorzubereitenden Zeilen berechnet werden Kostenschätzung.
Kostenschätzung : Schätzen Sie die Ausführungskosten verschiedener Betreiber basierend auf der Datenmenge. Die Summe der Kosten jedes Betreibers ergibt die Gesamtkosten des Plans.
Wenn der geplante Pfad Seiten verarbeitet, fallen E/A-Kosten an, und wenn der geplante Pfad Tupel verarbeitet (z. B. Ausdrucksauswertung für Tupel), fallen CPU-Kosten an. Da es sich bei GaussDB um eine verteilte Datenbank handelt, fallen für die Übertragung von Daten zwischen CN und DN Kommunikationskosten an. Daher können die Gesamtkosten eines Plans wie folgt ausgedrückt werden:
Gesamtkosten = E/A-Kosten + CPU-Kosten + Kommunikationskosten
-
Pfadsuche: Verarbeiten Sie den Verbindungspfadsuchprozess durch Lösen des Pfadoptimalalgorithmus (dynamische Programmierung, genetischer Algorithmus) und finden Sie den optimalen Verbindungspfad mit minimalem Suchraum.
GaussDB verwendet eine Kombination aus Bottom-up- und Zufallssuchmodi. Der Suchprozess ist auch ein Prozess der Umwandlung von einem Abfragebaum in einen Ausführungsplan. Beispielsweise kann jede Tabelle unterschiedliche Scan-Operatoren haben, und logische Join-Operatoren können auch in verschiedene physische Join-Operatoren umgewandelt werden.
-
Plangenerierung: Konvertieren Sie den Abfrageausführungspfad in einen Ausführungsplan (PlanTree) und stellen Sie ihn dem Ausführenden zur Ausführung bereit.
Die Abfrageoptimierung kann lange dauern, insbesondere bei komplexen Abfragen. Das Plan-Caching ist eine wichtige Funktion von GaussDB. Es kann den Ausführungsplan einer Abfrageanweisung zwischenspeichern, sodass der Ausführungsplan im Cache bei der nächsten Ausführung derselben Abfrage direkt verwendet werden kann, wodurch wiederholte Berechnungen vermieden und die Abfrageleistung optimiert werden.
Verteilte Abfrageoptimierung
Da es sich um eine native verteilte Datenbank handelt, ist die Technologie zur verteilten Abfrageoptimierung besonders wichtig.
Die verteilte GaussDB-Architektur nutzt die Rechenressourcen jedes Knotens vollständig aus und ihre Gesamtleistung steigt linear mit zunehmender Knotengröße. Um die Leistung und Ressourcennutzung in einer verteilten Architektur zu maximieren, unterstützt GaussDB vier verteilte Pläne, nämlich den CN-Lightweight-Plan, den FQS-Plan (Fast Query Shipping), den Stream-Plan und den Remote-Query-Plan, wie in der folgenden Abbildung dargestellt:
Abbildung (6) Vier verteilte Pläne
-
CN Lightweight: Anweisungen werden zur Ausführung direkt an einen einzelnen DN gesendet (LIGHT_PROXY)
-
Ausführungsprinzip: CN übermittelt die Anweisungs-QPBE-Nachricht direkt über den Socket an den entsprechenden DN.
-
-
Anwendbare Szenarien: Die Anweisung kann direkt auf einem DN (Single-Shard-Anweisung) ausgeführt werden.
-
Ausgabe von FQS-Anweisungen (Fast Query Shipping): Plan für die Ausgabe von SQL-Anweisungen
(REMOTE_FQS_QUERY)
-
Ausführungsprinzip: CN generiert direkt einen RemoteQuery-Plan, ohne den Optimierer zu durchlaufen, und sendet ihn über die Executor-Logik an DN. Jeder DN generiert einen Ausführungsplan basierend auf der Pushdown-Anweisung und führt ihn aus. Die Ausführungsergebnisse werden im CN zusammengefasst.
-
-
-
Anwendbare Szenarien: Anweisungen können zur Ausführung vollständig an mehrere DNs weitergeleitet werden, und es ist keine Dateninteraktion zwischen DNs erforderlich.
-
-
Bereitstellung des STREAM-Plans: Verteilungsplan für den verteilten SQL-Plan (STREAM)
-
Ausführungsprinzip: CN generiert einen Ausführungsplan mit Stream-Operatoren basierend auf der ursprünglichen Anweisung über den Optimierer und sendet ihn zur Ausführung an DN. Während des DN-Ausführungsprozesses findet eine Dateninteraktion (Stream-Knoten) statt. Der Stream-Operator stellt Verbindungen zwischen DNs für den Datenaustausch her und CN fasst die Ausführungsergebnisse zusammen. DN übernimmt die meisten Berechnungen.
-
-
-
Anwendbare Szenarien: komplexe Anweisungen mit Dateninteraktion zwischen CN und DN sowie zwischen DN und DN während der Ausführung .
-
-
Remote-Query-Plan: Verteilter Plan zur Ausgabe einiger SQL-Anweisungen (REMOTE_QUERY)
-
Ausführungsprinzip: CN generiert über den Optimierer einen RemoteQuery-Plan und sendet jede RemoteQuery an DN. Nach der Ausführung werden die Zwischenergebnisdaten an CN gesendet. Anschließend führt CN die Ausführungsberechnung durch Der verbleibende Ausführungsplan übernimmt daher die meisten Berechnungen.
-
-
Anwendbare Szenarien: Es gibt nur sehr wenige Szenarien, die die Bedingungen der ersten drei Generationen nicht erfüllen , und die Leistung ist sehr schlecht.
In einer verteilten Architektur werden die Daten derselben Tabelle auf verschiedene Datenknoten verteilt. Beim Erstellen einer Tabelle können Sie wählen, ob die Daten in jeder Tabelle gehasht oder zufällig verteilt werden sollen. Um eine Verknüpfungsoperation zwischen zwei Tabellen korrekt durchzuführen, ist es möglicherweise erforderlich, die Daten der beiden Tabellen neu zu verteilen. Daher fügt der verteilte Ausführungsplan von GaussDB drei Stream-Operatoren hinzu, die dafür sorgen, dass die Daten eine bestimmte Verteilungsmethode bilden.
Abbildung (7) Stream-Operator
Beim Generieren eines verteilten Pfads wird berücksichtigt, ob sich die Daten in den beiden Tabellen und die Verbindungsbedingungen im selben Datenknoten befinden. Andernfalls wird der entsprechende Datenverteilungsoperator hinzugefügt. Der Umverteilungs-Stream-Operator wird basierend auf dem Prinzip ausgewählt, den Datenfluss zwischen DN-Knoten zu reduzieren.
Gerade auf der Grundlage der sinnvollen Verwendung von Stream-Operatoren ist es GaussDB möglich, große Datenmengen in einer verteilten Architektur zu verarbeiten. Die Optimierung von Stream-Operatoren ist auch ein wichtiger Bestandteil der GaussDB-Abfrageoptimierung.
Abbildung (8) GaussDB-Technologie zur verteilten Abfrageoptimierung
[ Wichtige technische Punkte ] Verteilte Abfrageoptimierung: vier verteilte Ausführungspläne und drei Stream-Operatoren.
Aktuator
Die vom Ausführenden empfangenen Anweisungen sind der vom Optimierer für die SQL-Abfrageanweisung generierte Ausführungsplan. Der Ausführungsplan besteht aus einigen Ausführungsoperatoren (Operatoren), Ausdrücken usw. Er arbeitet hauptsächlich mit dem Beziehungssatz und gibt schließlich die vom Benutzer gewünschten aus gewünschte Ergebnismenge. Im Folgenden sind einige gängige Arten von Ausführungsoperatoren aufgeführt:
1. Scanplan-Knoten
Der Scan-Knoten ist für das Extrahieren von Daten aus zugrunde liegenden Datenquellen verantwortlich, die aus dem Dateisystem oder dem Netzwerk stammen können. Im Allgemeinen befinden sich Scan-Knoten an den Blattknoten des Ausführungsbaums und dienen als Dateneingabequelle für die Ausführung. Typischerweise repräsentieren sie SeqScan, IndexScan und SubQueryScan.
Hauptmerkmale: Eingabedaten, Blattknoten, Ausdrucksfilterung
2. Kontrollplanknoten
Kontrolloperatoren bilden im Allgemeinen keine algebraischen Operatoren ab, sondern sind Operatoren, die für den Ausführenden eingeführt werden, um einige spezielle Prozesse wie Limit, RecursiveUnion und Union abzuschließen.
Hauptmerkmale: Wird zur Steuerung des Datenflusses verwendet
3. Planknoten materialisieren
Materialisierte Operatoren beziehen sich im Allgemeinen auf Algorithmusanforderungen. Bei der Verarbeitung der Operatorlogik müssen die Daten der unteren Ebene zwischengespeichert werden. Da die von den Operatoren der unteren Ebene zurückgegebene Datenmenge nicht im Voraus vorhergesagt werden kann, ist dies erforderlich Algorithmus, der nicht alle Daten platzieren kann, z. B. Agg, Sort.
Hauptmerkmal: Alle Daten müssen vor der Rücksendung gescannt werden
4. Join-Plan-Knotenoperatoren sind für die Verarbeitung der häufigsten Assoziationsvorgänge in Datenbanken konzipiert. Sie sind entsprechend unterschiedlichen Verarbeitungsalgorithmen und Dateneingabequellen in MergeJoin, NestLoop Join und HashJoin unterteilt.
Hauptmerkmale: Verwandte Abfrage
5. Andere Betreiber
Die Architektur und Technologie des Executors bestimmen auch die Gesamtbetriebseffizienz der Datenbankabfrageausführung. Die GaussDB-Ausführungs-Engine vereint die Eigenschaften moderner Hardware-Technologie vollständig und nutzt eine Vielzahl moderner Software-Technologien wie Vektorisierungs-Engines und LLVM für eine effiziente Ausführung.
Abbildung (9) Vollständig parallele Ausführungsarchitektur von GaussDB
GaussDB nutzt außerdem eine Vielzahl von Technologien, um die Abfrageausführungsleistung während der Ausführung verteilter Pläne zu verbessern. Wenn beispielsweise komplexe Abfragen ausgeführt werden, wird der Wiederausführungsoperator zur Ausführung an den DN-Knoten weitergeleitet, z. B. der AGG-Operator. Wenn der Pushdown-Operator ausgeführt wird, wird die Lokalität der Daten berücksichtigt und die Berechnung wird so weit wie möglich lokal durchgeführt, um den Übertragungsaufwand für Daten im Netzwerk zu reduzieren.
Wenn Sie Fragen haben oder sich für wichtige technische Punkte interessieren, können Sie in [Yunka Q&A] das Geheimnis der GaussDB-SQL-Engine lüften, miteinander interagieren und im Event-Beitrag eine Nachricht hinterlassen, um Geschenke zu gewinnen, und Experten werden antworten Sie können Ihre Fragen persönlich beantworten und haben auch die Möglichkeit, Anreize für das Stellen von Fragen zu erhalten.
Linus nahm die Sache selbst in die Hand, um zu verhindern, dass Kernel-Entwickler Tabulatoren durch Leerzeichen ersetzen. Sein Vater ist einer der wenigen Führungskräfte, die Code schreiben können, sein zweiter Sohn ist Direktor der Open-Source-Technologieabteilung und sein jüngster Sohn ist ein Kern Mitwirkender bei Open Source: Es dauerte ein Jahr, 5.000 häufig verwendete mobile Anwendungen zu konvertieren. Java ist die Sprache, die am anfälligsten für Schwachstellen von Drittanbietern ist. Wang Chenglu, der Vater von Hongmeng: Open Source Hongmeng ist die einzige architektonische Innovation im Bereich der Basissoftware in China. Ma Huateng und Zhou Hongyi geben sich die Hand, um „den Groll zu beseitigen.“ Ehemaliger Microsoft-Entwickler: Die Leistung von Windows 11 ist „lächerlich schlecht“. sind sehr herzerwärmend . Meta Llama 3 wird offiziell veröffentlicht