Langsame SQL-Abfragen: Wie ich SQL-Performance-Tuning durchführe, damit Berichte wieder schnell laden

Wenn der Bericht zu lange lädt

Du klickst auf „Bericht öffnen“.
Und wartest.
Und wartest.

Access hängt nicht.
Die SQL-Abfrage ist einfach zu langsam.

Ursachen? Viele.
Lösungen? Gibt’s.
Ich zeig Dir, wie ich rangehe.

1. Kein SELECT *

SELECT * ist bequem.
Aber tödlich für die Performance.

Beispiel:

SELECT * FROM tblRechnung WHERE Jahr = 2024

Access lädt alle Felder.
Auch Memo-Felder. Auch Anhänge.

Besser:

SELECT Rechnungsnummer, Datum, BetragNetto FROM tblRechnung WHERE Jahr = 2024

Nur das, was Du wirklich brauchst.
Alles andere bremst nur.

2. Indexe prüfen – und setzen

Ohne Index scannt Access die ganze Tabelle.

So prüfe ich per VBA:

Sub ZeigeIndexe(tabName As String)
    Dim tdf As TableDef
    Dim idx As Index

    Set tdf = CurrentDb.TableDefs(tabName)
    For Each idx In tdf.Indexes
        Debug.Print idx.Name, idx.Fields
    Next idx
End Sub

Wenn z. B. Jahr nicht indiziert ist, dauert jede WHERE-Klausel länger.
Dann:

CurrentDb.Execute "CREATE INDEX idx_Jahr ON tblRechnung (Jahr)"

Hilft sofort.
Aber: Nicht zu viele Indexe – sonst bremst das beim Schreiben.

3. Abfragen verschachtelt? Entkoppeln.

Komplexe Berichte nutzen oft Unterabfragen.
Beispiel:

SELECT * FROM 
(SELECT KundeID, SUM(Betrag) AS Umsatz FROM tblRechnung GROUP BY KundeID) AS Umsatz
INNER JOIN tblKunde ON Umsatz.KundeID = tblKunde.KundeID

Das ist schwer zu optimieren.
Besser: Zwei Abfragen.

  1. qryUmsatzKunde
  2. Bericht nutzt qryUmsatzKunde direkt

Das entlastet Access.
Und Du kannst jede Abfrage einzeln testen.

4. WHERE statt HAVING

Viele nutzen HAVING, obwohl es nicht nötig ist:

SELECT KundeID, SUM(Betrag) AS Gesamt FROM tblRechnung 
GROUP BY KundeID
HAVING SUM(Betrag) > 1000

Besser:

SELECT KundeID, SUM(Betrag) AS Gesamt FROM tblRechnung 
WHERE Betrag > 0 
GROUP BY KundeID
HAVING SUM(Betrag) > 1000

WHERE filtert vor dem Aggregat.
HAVING filtert nachher.
Großer Unterschied in der Laufzeit.

5. Recordsets statt gebundene Berichte

Gebundene Berichte können langsam laden, wenn die Abfrage komplex ist.
Ich lade die Daten lieber per VBA vor.

Public Sub BerichtMitRecordset()
    Dim rs As DAO.Recordset
    Dim rpt As Report

    Set rs = CurrentDb.OpenRecordset("qrySchnelleDaten", dbOpenSnapshot)
    DoCmd.OpenReport "rptUmsatz", acViewPreview, , , acHidden
    Set rpt = Reports("rptUmsatz")
    Set rpt.Recordset = rs
    rpt.Visible = True
End Sub

Das macht vor allem bei Berichten mit Parametern Sinn.
Performance steigt. Stabilität auch.

6. Temporäre Tabellen nutzen

Wenn die Datenmenge groß ist, splitte ich die Schritte.

CurrentDb.Execute "DELETE FROM tmpUmsatz"

CurrentDb.Execute "INSERT INTO tmpUmsatz " & _
    "SELECT KundeID, SUM(Betrag) AS Gesamt FROM tblRechnung " & _
    "GROUP BY KundeID"

Bericht läuft dann nur noch gegen tmpUmsatz.
Schnell. Kein Rechnen mehr zur Laufzeit.

7. SQL analysieren per Performance-Zeitmessung

Ich messe Abfragezeiten in VBA:

Sub MesseAbfragezeit()
    Dim t1 As Single, t2 As Single
    Dim rs As DAO.Recordset

    t1 = Timer
    Set rs = CurrentDb.OpenRecordset("qryLangsam", dbOpenSnapshot)
    t2 = Timer

    Debug.Print "Abfragezeit: " & Format(t2 - t1, "0.000") & " Sekunden"
    rs.Close
End Sub

Alles über 0,5 Sekunden schaue ich mir an.
Und zerlege es, bis es schnell ist.

8. Backend: SQL Server statt Jet

Wenn die Datenbank groß wird (>1 GB), reicht Access nicht mehr.
Dann splitte ich:

  • Access-Frontend bleibt
  • Tabellen im SQL Server (per ODBC)

Abfragen laufen dort schneller.
Du kannst mit Views, Indexen und Stored Procedures arbeiten.
Und brauchst keinen Umweg über lokale Abfragen mehr.

Schrauben statt schimpfen.

Langsame Berichte sind kein Schicksal.
Meist sind es nur kleine Dinge, die bremsen.
SELECT *
Keine Indexe
Falsche Aggregation

Ich schau mir die SQL immer an.
Und dann wird’s schnell.
Wie’s sein soll.

Kategorien:

Schlagwörter:

Keine Antworten

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert