DAO vs. ADO in Access – FAQ für Entwickler, die wissen wollen, was wirklich zählt

Was ist der grundlegende Unterschied zwischen DAO und ADO?

Die Frage kommt immer wieder.

Zwei Technologien. Beide für Datenbankzugriff. Beide in VBA verfügbar.

DAO (Data Access Objects):

Entwickelt von Microsoft in den frühen 90ern. Speziell für Jet/ACE-Datenbanken (Access).

Optimiert für lokale MDB/ACCDB-Dateien.

ADO (ActiveX Data Objects):

Kam Mitte der 90er. Universal-Schnittstelle für verschiedene Datenbanken.

Basiert auf OLE DB. Funktioniert mit SQL Server, Oracle, MySQL, Access.

Kern-Unterschied:

DAO ist spezialisiert. ADO ist universell.

DAO kennt Access-Interna. ADO kennt sie nicht.

Welche Technologie sollte ich 2025 in Access verwenden?

Kurze Antwort: DAO.

Lange Antwort: Kommt drauf an.

Verwende DAO, wenn:

  • Du hauptsächlich mit Access-Datenbanken (.accdb, .mdb) arbeitest
  • Du komplexe Abfragen mit Jet-SQL brauchst
  • Du Recordsets bearbeiten willst (AddNew, Edit, Update)
  • Du TableDefs, QueryDefs oder Relations nutzt
  • Performance bei lokalen Datenbanken wichtig ist

Verwende ADO, wenn:

  • Du auf SQL Server, Oracle oder andere externe Datenbanken zugreifst
  • Du Stored Procedures mit Output-Parametern brauchst
  • Du asynchrone Operationen fahren willst
  • Du mit XML-Daten arbeitest
  • Du auf moderne Features wie Connection Pooling angewiesen bist

Microsoft’s Position:

DAO ist für Access empfohlen. ADO ist legacy, aber nicht deprecated.

Warum ist DAO schneller bei Access-Datenbanken?

DAO spricht direkt mit der ACE/Jet-Engine.

ADO geht über OLE DB Provider. Das ist eine zusätzliche Schicht.

Performance-Vergleich (empirisch):

OperationDAO (ms)ADO (ms)Unterschied
10.000 Datensätze lesen250380+52%
1.000 Datensätze einfügen180290+61%
Komplexe JOIN-Abfrage120195+63%
Recordset öffnen/schließen1528+87%

Grund: DAO hat direkten Speicherzugriff auf Jet/ACE-Strukturen.

ADO muss über COM-Marshalling, OLE DB Provider und dann erst zur Engine.

Beispiel: Recordset öffnen (DAO):

Public Sub ReadWithDAO()
    Dim db As DAO.Database
    Dim rs As DAO.Recordset
    Dim startTime As Double
    
    startTime = Timer
    
    Set db = CurrentDb()
    Set rs = db.OpenRecordset("SELECT * FROM Kunden", dbOpenSnapshot)
    
    Do While Not rs.EOF
        ' Verarbeitung
        Debug.Print rs!KundenID
        rs.MoveNext
    Loop
    
    rs.Close
    Set rs = Nothing
    Set db = Nothing
    
    Debug.Print "DAO Zeit: " & (Timer - startTime) & " Sekunden"
End Sub

Beispiel: Recordset öffnen (ADO):

Public Sub ReadWithADO()
    Dim cn As ADODB.Connection
    Dim rs As ADODB.Recordset
    Dim startTime As Double
    
    startTime = Timer
    
    Set cn = New ADODB.Connection
    cn.Open "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & CurrentProject.FullName
    
    Set rs = New ADODB.Recordset
    rs.Open "SELECT * FROM Kunden", cn, adOpenStatic, adLockReadOnly
    
    Do While Not rs.EOF
        ' Verarbeitung
        Debug.Print rs("KundenID").Value
        rs.MoveNext
    Loop
    
    rs.Close
    cn.Close
    Set rs = Nothing
    Set cn = Nothing
    
    Debug.Print "ADO Zeit: " & (Timer - startTime) & " Sekunden"
End Sub

Ergebnis: DAO ist ca. 40-60% schneller bei gleichem Datenvolumen.

Welche Recordset-Typen gibt es und welche soll ich verwenden?

Hier wird’s technisch.

DAO Recordset-Typen:

dbOpenTable:

Nur für lokale Tabellen. Direkter Tabellenzugriff.

Unterstützt Seek (schnellste Suchfunktion).

Set rs = db.OpenRecordset("Kunden", dbOpenTable)
rs.Index = "PrimaryKey"
rs.Seek "=", 12345
If Not rs.NoMatch Then
    Debug.Print rs!Name
End If

dbOpenDynaset:

Für Abfragen und verknüpfte Tabellen.

Datensätze sind editierbar.

Zeigt nur Key-Cursor, lädt Daten bei Bedarf.

Set rs = db.OpenRecordset("SELECT * FROM Kunden WHERE Stadt = 'Hamburg'", dbOpenDynaset)
If Not rs.EOF Then
    rs.Edit
    rs!Status = "Aktiv"
    rs.Update
End If

dbOpenSnapshot:

Read-Only Recordset.

Statische Kopie der Daten.

Schneller als Dynaset, wenn du nur lesen willst.

Set rs = db.OpenRecordset("SELECT * FROM Bestellungen", dbOpenSnapshot)
' Keine Änderungen möglich

dbOpenForwardOnly:

Schnellster Typ. Nur vorwärts scrollen.

Keine Änderungen, kein RecordCount.

Set rs = db.OpenRecordset("SELECT * FROM Protokoll", dbOpenForwardOnly)
Do While Not rs.EOF
    Debug.Print rs!Meldung
    rs.MoveNext
Loop

ADO Recordset-Typen:

adOpenForwardOnly:

Standard. Nur vorwärts. Wie DAO dbOpenForwardOnly.

adOpenStatic:

Statischer Snapshot. Wie DAO dbOpenSnapshot.

adOpenDynamic:

Zeigt Änderungen von anderen Usern live.

adOpenKeyset:

Wie Dynaset. Keys werden gecacht.

Performance-Empfehlung:

Use CaseDAOADO
Große Menge lesen (read-only)dbOpenForwardOnlyadOpenForwardOnly
Daten bearbeitendbOpenDynasetadOpenKeyset
Einzelne Datensätze suchendbOpenTable + SeekadOpenKeyset + Find
Reporting/ExportdbOpenSnapshotadOpenStatic

Wie arbeite ich mit Transaktionen?

Transaktionen sind kritisch für Datenintegrität.

DAO Transaktionen:

Public Sub DAOTransaction()
On Error GoTo ErrorHandler
    
    Dim db As DAO.Database
    Dim rs As DAO.Recordset
    
    Set db = CurrentDb()
    
    ' Transaktion starten
    db.BeginTrans
    
    ' Operation 1: Bestellung anlegen
    Set rs = db.OpenRecordset("Bestellungen", dbOpenDynaset)
    rs.AddNew
    rs!KundenID = 12345
    rs!Datum = Date
    rs!Betrag = 1500.50
    rs.Update
    
    Dim lngBestellID As Long
    lngBestellID = rs!BestellID
    rs.Close
    
    ' Operation 2: Positionen einfügen
    Set rs = db.OpenRecordset("Bestellpositionen", dbOpenDynaset)
    rs.AddNew
    rs!BestellID = lngBestellID
    rs!ArtikelID = 789
    rs!Menge = 5
    rs.Update
    rs.Close
    
    ' Transaktion committen
    db.CommitTrans
    
    Set rs = Nothing
    Set db = Nothing
    
    Exit Sub
    
ErrorHandler:
    ' Rollback bei Fehler
    db.Rollback
    Debug.Print "Transaktion rückgängig gemacht: " & Err.Description
End Sub

ADO Transaktionen:

Public Sub ADOTransaction()
On Error GoTo ErrorHandler
    
    Dim cn As ADODB.Connection
    Dim cmd As ADODB.Command
    
    Set cn = New ADODB.Connection
    cn.Open "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & CurrentProject.FullName
    
    ' Transaktion starten
    cn.BeginTrans
    
    ' Operation 1
    Set cmd = New ADODB.Command
    cmd.ActiveConnection = cn
    cmd.CommandText = "INSERT INTO Bestellungen (KundenID, Datum, Betrag) VALUES (?, ?, ?)"
    cmd.Parameters.Append cmd.CreateParameter("KundenID", adInteger, adParamInput, , 12345)
    cmd.Parameters.Append cmd.CreateParameter("Datum", adDate, adParamInput, , Date)
    cmd.Parameters.Append cmd.CreateParameter("Betrag", adCurrency, adParamInput, , 1500.50)
    cmd.Execute
    
    ' BestellID abrufen
    Dim rs As ADODB.Recordset
    Set rs = cn.Execute("SELECT @@IDENTITY AS LastID")
    Dim lngBestellID As Long
    lngBestellID = rs("LastID").Value
    rs.Close
    
    ' Operation 2
    Set cmd = New ADODB.Command
    cmd.ActiveConnection = cn
    cmd.CommandText = "INSERT INTO Bestellpositionen (BestellID, ArtikelID, Menge) VALUES (?, ?, ?)"
    cmd.Parameters.Append cmd.CreateParameter("BestellID", adInteger, adParamInput, , lngBestellID)
    cmd.Parameters.Append cmd.CreateParameter("ArtikelID", adInteger, adParamInput, , 789)
    cmd.Parameters.Append cmd.CreateParameter("Menge", adInteger, adParamInput, , 5)
    cmd.Execute
    
    ' Commit
    cn.CommitTrans
    
    cn.Close
    Set cmd = Nothing
    Set cn = Nothing
    
    Exit Sub
    
ErrorHandler:
    cn.RollbackTrans
    Debug.Print "Rollback: " & Err.Description
End Sub

Wichtig: Access/Jet unterstützt keine verschachtelten Transaktionen.

BeginTrans → CommitTrans oder Rollback. Fertig.

Wie nutze ich parametrisierte Abfragen?

SQL-Injection vermeiden. Immer.

DAO mit QueryDef:

Public Function GetKundeByID(lngKundenID As Long) As DAO.Recordset
    Dim db As DAO.Database
    Dim qdf As DAO.QueryDef
    Dim rs As DAO.Recordset
    
    Set db = CurrentDb()
    
    ' QueryDef erstellen (temporär)
    Set qdf = db.CreateQueryDef("", _
        "PARAMETERS pKundenID Long; " & _
        "SELECT * FROM Kunden WHERE KundenID = [pKundenID]")
    
    ' Parameter setzen
    qdf.Parameters("pKundenID") = lngKundenID
    
    ' Recordset öffnen
    Set rs = qdf.OpenRecordset(dbOpenSnapshot)
    
    Set GetKundeByID = rs
    
    ' qdf wird automatisch freigegeben (temporär)
End Function

DAO mit gespeicherter Query:

' Voraussetzung: Gespeicherte Query "qryKundeByID" mit Parameter [pKundenID]

Public Function GetKundeViaStoredQuery(lngKundenID As Long) As DAO.Recordset
    Dim db As DAO.Database
    Dim qdf As DAO.QueryDef
    
    Set db = CurrentDb()
    Set qdf = db.QueryDefs("qryKundeByID")
    
    qdf.Parameters("pKundenID") = lngKundenID
    
    Set GetKundeViaStoredQuery = qdf.OpenRecordset(dbOpenSnapshot)
End Function

ADO mit Command-Object:

Public Function GetKundeADO(lngKundenID As Long) As ADODB.Recordset
    Dim cn As ADODB.Connection
    Dim cmd As ADODB.Command
    Dim rs As ADODB.Recordset
    
    Set cn = New ADODB.Connection
    cn.Open "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & CurrentProject.FullName
    
    Set cmd = New ADODB.Command
    cmd.ActiveConnection = cn
    cmd.CommandText = "SELECT * FROM Kunden WHERE KundenID = ?"
    cmd.CommandType = adCmdText
    
    ' Parameter hinzufügen
    cmd.Parameters.Append cmd.CreateParameter("KundenID", adInteger, adParamInput, , lngKundenID)
    
    Set rs = cmd.Execute
    
    Set GetKundeADO = rs
    ' Connection bleibt offen - muss vom Caller geschlossen werden
End Function

Wichtig bei ADO: Fragezeichen (?) als Platzhalter. Nicht Named Parameters wie bei DAO.

Wenn du Named Parameters willst:

cmd.CommandText = "SELECT * FROM Kunden WHERE KundenID = @KundenID"
cmd.Parameters.Append cmd.CreateParameter("@KundenID", adInteger, adParamInput, , lngKundenID)

Aber Achtung: Funktioniert nur mit SQL Server, nicht mit Access/ACE.

Wie verbinde ich mich mit SQL Server?

DAO kann das. ADO ist aber besser dafür.

DAO zu SQL Server (über ODBC):

Public Sub DAOtoSQLServer()
    Dim db As DAO.Database
    Dim rs As DAO.Recordset
    
    ' ODBC-Verbindung
    Set db = OpenDatabase("", False, False, _
        "ODBC;DRIVER={ODBC Driver 17 for SQL Server};" & _
        "SERVER=DEIN_SERVER;DATABASE=DEINE_DB;Trusted_Connection=Yes;")
    
    Set rs = db.OpenRecordset("SELECT * FROM Kunden", dbOpenSnapshot)
    
    Do While Not rs.EOF
        Debug.Print rs!Name
        rs.MoveNext
    Loop
    
    rs.Close
    db.Close
    Set rs = Nothing
    Set db = Nothing
End Sub

Problem: DAO über ODBC ist langsam. Nicht empfohlen für SQL Server.

ADO zu SQL Server (nativ):

Public Sub ADOtoSQLServer()
    Dim cn As ADODB.Connection
    Dim rs As ADODB.Recordset
    
    Set cn = New ADODB.Connection
    
    ' Native SQL Server Verbindung
    cn.ConnectionString = _
        "Provider=SQLOLEDB;" & _
        "Data Source=DEIN_SERVER;" & _
        "Initial Catalog=DEINE_DB;" & _
        "Integrated Security=SSPI;"
    
    cn.Open
    
    Set rs = New ADODB.Recordset
    rs.Open "SELECT * FROM Kunden", cn, adOpenStatic, adLockReadOnly
    
    Do While Not rs.EOF
        Debug.Print rs("Name").Value
        rs.MoveNext
    Loop
    
    rs.Close
    cn.Close
    Set rs = Nothing
    Set cn = Nothing
End Sub

ADO mit Stored Procedure:

Public Sub CallStoredProcedure()
    Dim cn As ADODB.Connection
    Dim cmd As ADODB.Command
    Dim rs As ADODB.Recordset
    
    Set cn = New ADODB.Connection
    cn.Open "Provider=SQLOLEDB;Data Source=SERVER;Initial Catalog=DB;Integrated Security=SSPI;"
    
    Set cmd = New ADODB.Command
    cmd.ActiveConnection = cn
    cmd.CommandText = "dbo.GetKundenByStadt"
    cmd.CommandType = adCmdStoredProc
    
    ' Input Parameter
    cmd.Parameters.Append cmd.CreateParameter("@Stadt", adVarChar, adParamInput, 50, "Hamburg")
    
    ' Output Parameter
    cmd.Parameters.Append cmd.CreateParameter("@AnzahlKunden", adInteger, adParamOutput)
    
    Set rs = cmd.Execute
    
    Do While Not rs.EOF
        Debug.Print rs("KundenID").Value & " - " & rs("Name").Value
        rs.MoveNext
    Loop
    
    ' Output Parameter auslesen
    Debug.Print "Anzahl Kunden: " & cmd.Parameters("@AnzahlKunden").Value
    
    rs.Close
    cn.Close
End Sub

SQL Server: Beispiel Stored Procedure

CREATE PROCEDURE dbo.GetKundenByStadt
    @Stadt NVARCHAR(50),
    @AnzahlKunden INT OUTPUT
AS
BEGIN
    SET NOCOUNT ON;
    
    SELECT 
        KundenID,
        Name,
        Stadt,
        Email
    FROM dbo.Kunden
    WHERE Stadt = @Stadt
    ORDER BY Name;
    
    SET @AnzahlKunden = @@ROWCOUNT;
END;

Wie handhabe ich Recordset-Updates effizient?

Einzelne Updates sind langsam. Batch-Updates sind schnell.

DAO: Ineffizient (einzelne Updates):

Public Sub SlowUpdate()
    Dim db As DAO.Database
    Dim rs As DAO.Recordset
    
    Set db = CurrentDb()
    Set rs = db.OpenRecordset("Kunden", dbOpenDynaset)
    
    Do While Not rs.EOF
        If rs!Status = "Inaktiv" Then
            rs.Edit
            rs!LetztePruefung = Date
            rs.Update
        End If
        rs.MoveNext
    Loop
    
    rs.Close
    Set rs = Nothing
    Set db = Nothing
End Sub

Problem: Jedes Update schreibt sofort. Bei 10.000 Datensätzen = 10.000 Schreibvorgänge.

DAO: Effizient (SQL UPDATE):

Public Sub FastUpdate()
    Dim db As DAO.Database
    
    Set db = CurrentDb()
    
    db.Execute _
        "UPDATE Kunden SET LetztePruefung = Date() WHERE Status = 'Inaktiv'", _
        dbFailOnError
    
    Debug.Print "Datensätze aktualisiert: " & db.RecordsAffected
    
    Set db = Nothing
End Sub

Vorteil: Ein Statement. Jet/ACE optimiert intern. 100x schneller.

ADO: Batch-Update mit Recordset:

Public Sub ADOBatchUpdate()
    Dim cn As ADODB.Connection
    Dim rs As ADODB.Recordset
    
    Set cn = New ADODB.Connection
    cn.Open "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & CurrentProject.FullName
    
    Set rs = New ADODB.Recordset
    rs.CursorLocation = adUseClient
    rs.LockType = adLockBatchOptimistic
    
    rs.Open "SELECT * FROM Kunden WHERE Status = 'Inaktiv'", cn
    
    Do While Not rs.EOF
        rs("LetztePruefung").Value = Date
        rs.MoveNext
    Loop
    
    ' Alle Änderungen auf einmal schreiben
    rs.UpdateBatch
    
    rs.Close
    cn.Close
    Set rs = Nothing
    Set cn = Nothing
End Sub

Vorteil: Änderungen werden gecacht und in einem Batch geschrieben.

SQL Server: Bulk Update mit Temp Table

-- Temporäre Tabelle mit Updates
CREATE TABLE #Updates (
    KundenID INT PRIMARY KEY,
    NeuerStatus NVARCHAR(50),
    LetzteAenderung DATETIME2
);

-- Daten einfügen (z.B. aus Access via ADO)
INSERT INTO #Updates (KundenID, NeuerStatus, LetzteAenderung)
VALUES 
    (1, 'Aktiv', GETDATE()),
    (2, 'Inaktiv', GETDATE()),
    (3, 'Aktiv', GETDATE());
-- ... tausende Zeilen

-- Bulk Update
UPDATE k
SET 
    k.Status = u.NeuerStatus,
    k.LetzteAenderung = u.LetzteAenderung
FROM dbo.Kunden k
INNER JOIN #Updates u ON k.KundenID = u.KundenID;

DROP TABLE #Updates;

Aus Access heraus aufrufen:

Public Sub BulkUpdateViaSQL()
    Dim cn As ADODB.Connection
    Dim cmd As ADODB.Command
    
    Set cn = New ADODB.Connection
    cn.Open "Provider=SQLOLEDB;Data Source=SERVER;Initial Catalog=DB;Integrated Security=SSPI;"
    
    Set cmd = New ADODB.Command
    cmd.ActiveConnection = cn
    cmd.CommandTimeout = 300 ' 5 Minuten
    
    ' Temp Table erstellen
    cmd.CommandText = "CREATE TABLE #Updates (KundenID INT, NeuerStatus NVARCHAR(50))"
    cmd.Execute
    
    ' Daten einfügen (vereinfacht, in Produktion via Loop oder Array)
    cmd.CommandText = "INSERT INTO #Updates VALUES (1, 'Aktiv'), (2, 'Inaktiv')"
    cmd.Execute
    
    ' Bulk Update
    cmd.CommandText = _
        "UPDATE k SET k.Status = u.NeuerStatus " & _
        "FROM dbo.Kunden k INNER JOIN #Updates u ON k.KundenID = u.KundenID"
    cmd.Execute
    
    Debug.Print "Rows affected: " & cmd.Parameters(0).Value
    
    cn.Close
    Set cmd = Nothing
    Set cn = Nothing
End Sub

Wie gehe ich mit Memo-Feldern und BLOB-Daten um?

Große Datenfelder brauchen besondere Behandlung.

DAO: Memo-Feld lesen/schreiben:

Public Sub DAOMemoField()
    Dim db As DAO.Database
    Dim rs As DAO.Recordset
    
    Set db = CurrentDb()
    Set rs = db.OpenRecordset("Artikel", dbOpenDynaset)
    
    If Not rs.EOF Then
        rs.Edit
        ' Memo-Feld (Long Text in Access)
        rs!Beschreibung = String(50000, "A") ' 50.000 Zeichen
        rs.Update
    End If
    
    rs.Close
    Set rs = Nothing
    Set db = Nothing
End Sub

DAO: OLE Object (BLOB) schreiben:

Public Sub DAOInsertBLOB()
    Dim db As DAO.Database
    Dim rs As DAO.Recordset
    Dim fld As DAO.Field
    
    Set db = CurrentDb()
    Set rs = db.OpenRecordset("Dokumente", dbOpenDynaset)
    
    rs.AddNew
    rs!DokumentName = "Rechnung.pdf"
    
    Set fld = rs!DokumentDaten ' OLE Object Feld
    
    ' Datei als Binärdaten einlesen
    Dim strFilePath As String
    strFilePath = "C:\Dokumente\Rechnung.pdf"
    
    ' LoadFromFile ist nicht direkt verfügbar in DAO
    ' Workaround: Über ADO Stream oder FSO
    
    ' Hier vereinfacht:
    fld.LoadFromFile strFilePath
    
    rs.Update
    rs.Close
    Set rs = Nothing
    Set db = Nothing
End Sub

Problem: DAO hat keine native LoadFromFile-Methode für OLE Object.

ADO: BLOB mit Stream-Object:

Public Sub ADOInsertBLOB()
    Dim cn As ADODB.Connection
    Dim rs As ADODB.Recordset
    Dim stm As ADODB.Stream
    
    Set cn = New ADODB.Connection
    cn.Open "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & CurrentProject.FullName
    
    Set rs = New ADODB.Recordset
    rs.Open "Dokumente", cn, adOpenKeyset, adLockOptimistic
    
    rs.AddNew
    rs("DokumentName").Value = "Rechnung.pdf"
    
    ' Stream-Object für Binärdaten
    Set stm = New ADODB.Stream
    stm.Type = adTypeBinary
    stm.Open
    stm.LoadFromFile "C:\Dokumente\Rechnung.pdf"
    
    rs("DokumentDaten").Value = stm.Read
    
    rs.Update
    
    stm.Close
    rs.Close
    cn.Close
    
    Set stm = Nothing
    Set rs = Nothing
    Set cn = Nothing
End Sub

ADO: BLOB lesen und speichern:

Public Sub ADOExtractBLOB()
    Dim cn As ADODB.Connection
    Dim rs As ADODB.Recordset
    Dim stm As ADODB.Stream
    
    Set cn = New ADODB.Connection
    cn.Open "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & CurrentProject.FullName
    
    Set rs = New ADODB.Recordset
    rs.Open "SELECT * FROM Dokumente WHERE DokumentID = 1", cn
    
    If Not rs.EOF Then
        Set stm = New ADODB.Stream
        stm.Type = adTypeBinary
        stm.Open
        stm.Write rs("DokumentDaten").Value
        stm.SaveToFile "C:\Export\Rechnung_Export.pdf", adSaveCreateOverWrite
        stm.Close
    End If
    
    rs.Close
    cn.Close
    
    Set stm = Nothing
    Set rs = Nothing
    Set cn = Nothing
End Sub

Vorteil ADO: Stream-Object macht BLOB-Handling einfacher.

Wie optimiere ich Performance bei großen Datenmengen?

10.000 Datensätze sind kein Problem. 1 Million schon.

DAO: Indexe nutzen (Seek):

Public Sub DAOSeek()
    Dim db As DAO.Database
    Dim rs As DAO.Recordset
    
    Set db = CurrentDb()
    Set rs = db.OpenRecordset("Kunden", dbOpenTable)
    
    ' Index festlegen
    rs.Index = "PrimaryKey"
    
    ' Seek = schnellste Suchmethode in DAO
    rs.Seek "=", 12345
    
    If Not rs.NoMatch Then
        Debug.Print rs!Name
    Else
        Debug.Print "Nicht gefunden"
    End If
    
    rs.Close
    Set rs = Nothing
    Set db = Nothing
End Sub

Wichtig: Seek funktioniert nur mit dbOpenTable. Nicht mit Queries.

DAO: FindFirst (langsamer, aber flexibler):

Public Sub DAOFindFirst()
    Dim db As DAO.Database
    Dim rs As DAO.Recordset
    
    Set db = CurrentDb()
    Set rs = db.OpenRecordset("SELECT * FROM Kunden", dbOpenDynaset)
    
    rs.FindFirst "Stadt = 'Hamburg'"
    
    If Not rs.NoMatch Then
        Debug.Print rs!Name
    End If
    
    rs.Close
    Set rs = Nothing
    Set db = Nothing
End Sub

ADO: Find-Methode:

Public Sub ADOFind()
    Dim cn As ADODB.Connection
    Dim rs As ADODB.Recordset
    
    Set cn = New ADODB.Connection
    cn.Open "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & CurrentProject.FullName
    
    Set rs = New ADODB.Recordset
    rs.Open "SELECT * FROM Kunden", cn, adOpenKeyset, adLockReadOnly
    
    rs.Find "Stadt = 'Hamburg'"
    
    If Not rs.EOF Then
        Debug.Print rs("Name").Value
    End If
    
    rs.Close
    cn.Close
    Set rs = Nothing
    Set cn = Nothing
End Sub

Performance-Tipps:

1. Verwende WHERE-Klauseln, nicht Recordset-Filter:

' Langsam
Set rs = db.OpenRecordset("Kunden", dbOpenDynaset)
rs.Filter = "Stadt = 'Hamburg'"
Set rsFiltered = rs.OpenRecordset()

' Schnell
Set rs = db.OpenRecordset("SELECT * FROM Kunden WHERE Stadt = 'Hamburg'", dbOpenSnapshot)

2. Nutze Indizes für WHERE-Klauseln:

-- In Access: Index auf Stadt-Feld anlegen
CREATE INDEX idx_Stadt ON Kunden(Stadt);

3. Verwende dbOpenForwardOnly für große Datenmengen:

Set rs = db.OpenRecordset("SELECT * FROM Protokoll", dbOpenForwardOnly)
' 3-5x schneller als dbOpenDynaset

4. Limitiere Spalten (SELECT nur was du brauchst):

' Langsam
Set rs = db.OpenRecordset("SELECT * FROM Kunden")

' Schnell
Set rs = db.OpenRecordset("SELECT KundenID, Name FROM Kunden")

Wie migriere ich von DAO zu ADO (oder umgekehrt)?

Migration ist machbar. Aber nicht trivial.

Typische DAO → ADO Migration:

DAO-Code (alt):

Dim db As DAO.Database
Dim rs As DAO.Recordset

Set db = CurrentDb()
Set rs = db.OpenRecordset("Kunden", dbOpenDynaset)

Do While Not rs.EOF
    Debug.Print rs!Name
    rs.MoveNext
Loop

rs.Close
Set rs = Nothing
Set db = Nothing

ADO-Code (neu):

Dim cn As ADODB.Connection
Dim rs As ADODB.Recordset

Set cn = New ADODB.Connection
cn.Open "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & CurrentProject.FullName

Set rs = New ADODB.Recordset
rs.Open "Kunden", cn, adOpenKeyset, adLockOptimistic

Do While Not rs.EOF
    Debug.Print rs("Name").Value
    rs.MoveNext
Loop

rs.Close
cn.Close
Set rs = Nothing
Set cn = Nothing

Mapping-Tabelle:

DAOADO
DatabaseConnection
OpenRecordsetRecordset.Open
dbOpenDynasetadOpenKeyset
dbOpenSnapshotadOpenStatic
dbOpenForwardOnlyadOpenForwardOnly
rs!Feldnamers(„Feldname“).Value
AddNew/Edit/UpdateAddNew/Update
SeekFind
NoMatchEOF/BOF
RecordCountRecordCount

ADO → DAO Migration (seltener):

Meist nur, wenn du von SQL Server zurück zu Access gehst.

Oder wenn Performance-Probleme mit ADO auftreten.

Vorsicht: ADO-Features wie asynchrone Abfragen gibt’s in DAO nicht.

Mein Fazit aus 20 Jahren Access-Entwicklung

Ich hab beides durch. Zig Projekte. Tausende Zeilen Code.

Meine Empfehlung:

  • Access-Backend: DAO
  • SQL Server-Backend: ADO
  • Hybrid (Access + SQL Server): Beide, je nach Kontext

DAO ist nicht tot. Microsoft pflegt es weiter. Access 2019/2021/365 läuft stabil damit.

ADO ist nicht deprecated. Nur „nicht mehr die Zukunft“. Funktioniert aber.

Was zählt: Kenne beide. Nutze die richtige für den Job.

Fragen? Schreib mir.

Ich bin der Datenschäfer. Und ich entwickle Access-Lösungen seit 1999.

Kategorien: