<link rel="stylesheet" href="styles-3GBANQL6.css">
← Zurück zum Blog

TypeORM

Optimierung komplexer Abfragen in TypeORM

Optimierung komplexer Abfragen in TypeORM

Einführung

TypeORM ist ein leistungsstarkes Object-Relational Mapping (ORM) Werkzeug für TypeScript und JavaScript. Es bietet eine robuste Möglichkeit, mit Datenbanken über TypeScript-Klassen und -Dekoratoren zu interagieren. Allerdings nehmen mit dem Wachstum der Anwendungen auch die Komplexität der Abfragen zu. In diesem Beitrag werden wir untersuchen, wie man komplexe Abfragen erkennt, sie optimiert und häufige Fallstricke vermeidet, die Abfragen schwerfällig und langsam machen können. Außerdem werden wir diskutieren, wie man Leistungsengpässe erkennt und die Abfrageleistung mit praktischen Beispielen verbessert.

Komplexe Abfragen verstehen

Eine komplexe Abfrage umfasst häufig mehrere Joins, Unterabfragen oder komplizierte Filterbedingungen. Hier sind Beispiele für komplexe Beziehungen in TypeORM:

Ein-zu-viele-Beziehung

In einer Ein-zu-viele-Beziehung kann eine Entität mit mehreren Instanzen einer anderen Entität verknüpft sein. Zum Beispiel kann ein Benutzer viele Beiträge haben.


@Entity()
export class User {
  @PrimaryGeneratedColumn()
  id: number;

  @Column()
  name: string;

  @OneToMany(() => User, user => post.benutzer)
  posts: Post[];
}

@Entity()
export class Post {
  @PrimaryGeneratedColumn()
  id: number;

  @Column()
  titel: string;

  @ManyToOne(() => User, user => post.posts)
  user: User;
}
    

Diese Abfrage ruft Benutzer und ihre Beiträge ab:


const user = await connection
  .getRepository(User)
  .createQueryBuilder('user')
  .leftJoinAndSelect('user.posts', 'post')
  .getMany();
    

Viele-zu-viele-Beziehung

In einer viele-zu-viele-Beziehung können mehrere Instanzen einer Entität mit mehreren Instanzen einer anderen Entität verknüpft sein. Zum Beispiel können Schüler in vielen Kursen eingeschrieben sein.


@Entity()
export class Student {
  @PrimaryGeneratedColumn()
  id: number;

  @ManyToMany(() => Course, course => course.student)
  @JoinTable()
  kurse: Kurs[];
}

@Entity()
export class Course {
  @PrimaryGeneratedColumn()
  id: number;

  @ManyToMany(() => Student, student => student.course)
  student: Student[];
}
    

Diese Abfrage ruft Schüler und ihre eingeschriebenen Kurse ab:


const student = await connection
  .getRepository(Schueler)
  .createQueryBuilder('student')
  .leftJoinAndSelect('student.course', 'sourse')
  .getMany();
    

Mit Cascade löschen

Cascade-Löschen kann nützlich sein, wenn eine Entität gelöscht wird, die mit anderen Entitäten verknüpft ist. Zum Beispiel sollten alle zugehörigen Beiträge gelöscht werden, wenn ein Benutzer gelöscht wird.


@Entity()
export class User {
  @PrimaryGeneratedColumn()
  id: number;

  @OneToMany(() => Post, post => post.user, { cascade: true })
  posts: Post[];
}
    

Um einen Benutzer zusammen mit seinen Beiträgen zu löschen:


await connection
  .getRepository(User)
  .delete(userId); // Alle zugehörigen Beiträge werden ebenfalls gelöscht
    

Häufige Fallstricke, die Abfragen schwerfällig machen

  • Übermäßige Joins: Das Joinen mehrerer großer Tabellen kann zu langsamen Abfragezeiten führen. Joine nur das, was du brauchst.
  • Fehlende Indizes: Das Nichtverwenden von Indizes bei häufig abgefragten Spalten kann die Leistung erheblich verlangsamen.
  • Unnötige Datenabfragen: Das Abrufen von mehr Daten als nötig kann die Antwortzeit aufblähen.
  • Verwendung von Unterabfragen: Unterabfragen können oft durch Joins ersetzt werden, um die Leistung zu verbessern.

Schwerfällige Abfragen erkennen

Das Erkennen von schwerfälligen Abfragen kann auf verschiedene Weise erfolgen:

  • Datenbank-Query-Logs: Aktiviere das Logging in deiner Datenbank, um zu sehen, welche Abfragen länger für die Ausführung benötigen.
  • Profilierungswerkzeuge: Verwende Profilierungswerkzeuge wie pgAdmin für PostgreSQL oder MySQL Workbench für MySQL, um die Abfrageleistung zu visualisieren.
  • TypeORM-Logging: TypeORM ermöglicht es dir, die ausgeführten Abfragen und deren Ausführungszeit zu protokollieren. Du kannst das Logging in deinen Verbindungsoptionen aktivieren:
  • 
    const connection = await createConnection({
      type: 'postgres',
      // ... andere Optionen ...
      logging: true, // Abfrage-Logging aktivieren
    });
          

Abfragen optimieren: Best Practices

Hier sind einige Strategien zur Optimierung deiner TypeORM-Abfragen:

  • Analyse von Ausführungsplänen: Verwende Datenbanktools, um den Ausführungsplan für deine Abfragen zu analysieren und Engpässe zu identifizieren.
  • Indizes effektiv nutzen: Stelle sicher, dass du Indizes auf den häufigsten Abfragefeldern anwendest, um die Leistung zu verbessern:
  • 
    @Entity()
    export class User {
      @PrimaryGeneratedColumn()
      id: number;
    
      @Column()
      @Index() // Index zur Spalte "name" hinzufügen
      name: string;
    
      // andere Spalten...
    }
          
  • Datenabruf optimieren: Verwende select, um nur die benötigten Spalten abzurufen, anstatt gesamte Entitäten:
  • 
    const benutzer = await connection
      .getRepository(User)
      .createQueryBuilder('user')
      .select(['user.id', 'user.name']) // Nur notwendige Spalten auswählen
      .getMany();
          
  • JOIN-Operationen verfeinern: Reduziere die Anzahl der Joins und stelle sicher, dass sie notwendig sind. Verwende innerJoin anstelle von leftJoin, wenn du nur passende Datensätze benötigst:
  • 
    const user = await connection
      .getRepository(User)
      .createQueryBuilder('user')
      .innerJoin('user.posts', 'post')
      .getMany();
          
  • LIMIT und OFFSET verwenden: Bei der Abfrage von großen Datensätzen verwende LIMIT und OFFSET, um die Anzahl der zurückgegebenen Datensätze zu beschränken:
  • 
    const user = await connection
      .getRepository(User)
      .createQueryBuilder('user')
      .skip(0) // Start bei 0
      .take(10) // Nimm 10 Datensätze
      .getMany();
          
  • SELECT DISTINCT vermeiden: Wenn möglich, verwende keine DISTINCT-Klausel, da dies die Leistung negativ beeinflussen kann.
  • Unterabfragen minimieren: Verwende Joins anstelle von Unterabfragen, um die Leistung zu verbessern.
  • EXISTS anstelle von IN wählen: EXISTS ist in der Regel schneller als IN, da es die Auswertung stoppt, sobald ein Datensatz gefunden wird:
  • 
    const userWithPosts = await connection
      .getRepository(User)
      .createQueryBuilder('user')
      .where(qb => {
        const subQuery = qb
          .subQuery()
          .select('1')
          .from(Post, 'post')
          .where('post.userId = user.id');
        return 'EXISTS ' + subQuery.getQuery();
      })
      .getMany();
          
  • Effiziente Paginierung implementieren: Implementiere eine effiziente Paginierung mit LIMIT und OFFSET, um große Datenmengen besser zu verwalten.
  • OR-Bedingungen minimieren: OR-Bedingungen können die Abfrageleistung beeinträchtigen. Verwende stattdessen UNION, wenn möglich.
  • Unnötige Berechnungen vermeiden: Führe keine Berechnungen in deiner SQL-Abfrage durch, wenn sie in deinem Code erfolgen können.
  • Regelmäßige Überprüfung und Verfeinerung: Überprüfe und verfeinere deine Abfragen regelmäßig, um sicherzustellen, dass sie effizient bleiben.
  • Daten und Anforderungen verstehen: Ein klares Verständnis der Daten und der Geschäftsanforderungen ist entscheidend für die Optimierung von Abfragen.
  • Optimierung der Verwendung temporärer Tabellen: Wenn du komplexe Berechnungen oder Abfragen durchführen musst, ziehe in Betracht, temporäre Tabellen zu verwenden, um die Leistung zu steigern.

Fazit

Die Optimierung komplexer Abfragen in TypeORM ist entscheidend, um die Leistung deiner Anwendung bei steigender Komplexität aufrechtzuerhalten. Durch das Erkennen häufiger Fallstricke, die Nutzung bewährter Verfahren und den Einsatz von Tools zur Erkennung schwerfälliger Abfragen kannst du die Effizienz deiner Datenbankinteraktionen erheblich steigern.

Denk daran, dass effiziente Abfragen zu einer besseren Anwendungsleistung, einer verbesserten Benutzererfahrung und niedrigeren Serverkosten führen. Halte diese Strategien im Hinterkopf, während du mit TypeORM arbeitest, und deine Anwendung wird von den Leistungsverbesserungen enorm profitieren!

LASSEN SIE UNS ETWAS NEUES BAUEN

Aus Ihrer Idee kann die nächste gute Softwarelösung entstehen.

Erzählen Sie uns, was Sie entwickeln, verbessern oder neu denken möchten.

Projekt besprechen