Datenbankzugriff Access zu langsam

  • VB.NET
  • .NET (FX) 4.0

Es gibt 7 Antworten in diesem Thema. Der letzte Beitrag () ist von SchorschCode.

    Datenbankzugriff Access zu langsam

    Hallo,

    in einer Access2000-Datenbank habe ich eine Tabelle tblArtikel ; der Primärschlüssel setzt sich zusammen aus den Feldern SUCHBEGRIFF und ARTNR. Das Feld ARTORGNR ist ebenfalls indiziert. Nun muss der Inhalt einer Textdatei durchgelesen und einige Felder in tblArtikel müssen aktualisiert werden. Eventuell muss auch ein neuer Datensatz angeelgt werden.

    Das klappt auch soweit prima, ist allerdings sehr langsam (läuft etwa 10 Minuten). Die Textdatei enthält ca. 3.500 Datensätze, die Tabelle tblArtikel etwa 25.000.

    Die Tabelle tblArtikel enthält in der Realität über 100 Felder. Ich öffne Sie daher mit dem SQL-Befehl.

    Hier die Codeschnipsel:

    Zunächst die Definitionen:

    VB.NET-Quellcode

    1. Option Strict On
    2. Imports System.Data.OleDb
    3. Imports System.IO
    4. ...
    5. Dim strINH As String
    6. Dim intANF As Integer
    7. Dim intEND As Integer
    8. Dim strARTORGNR As String
    9. Dim cmb As New OleDb.OleDbCommandBuilder
    10. Dim conDB As New OleDbConnection
    11. Dim dt01 As New DataTable ' tblArtikel
    12. Dim cm01 As New OleDb.OleDbCommand
    13. Dim da01 As New OleDb.OleDbDataAdapter
    14. Dim dr01 As DataRow
    15. Dim dr01s() As DataRow
    16. Dim strSQLART As String


    Nun die Datenbank und das Öffnen der Tabelle:

    VB.NET-Quellcode

    1. conDB.ConnectionString = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=C:\QUISY70\QPSFIL70.MDB;Jet OLEDB:System Database=C:\TESTDB\TESTWRKGRP.MDW;User ID=TESTUSER;Password=TESTPWD;"
    2. strSQLART = "SELECT tblArtikel.SUCHBEGRIFF, tblArtikel.ARTNR, tblArtikel.ARTORGNR, tblArtikel.MWST, tblArtikel.EKPREIS, "
    3. strSQLART = strSQLART & "tblArtikel.VKPREIS, tblArtikel.LZPRAEND "
    4. strSQLART = strSQLART & "FROM tblArtikel;"
    5. With cm01
    6. .Connection = conDB
    7. .CommandText = strSQLART
    8. .CommandType = CommandType.TableDirect
    9. End With
    10. With da01
    11. .SelectCommand = cm01
    12. End With
    13. da01.MissingSchemaAction = MissingSchemaAction.AddWithKey
    14. da01.Fill(dt01)


    Und so wird das Ganze verarbeitet:

    VB.NET-Quellcode

    1. Dim srIMP As New IO.StreamReader("C:\TESTDB\ARTIKEL_TEST.TXT", System.Text.Encoding.Default)
    2. Do
    3. strINH = srIMP.ReadLine
    4. If IsNothing(strINH) Then
    5. Exit Do
    6. End If
    7. '
    8. ' die Felder strSUCHBEGRIFF und strARTNR wurden bereits gefüllt...
    9. intANF = 15
    10. intEND = Strings.InStr(intANF, strINH, ";", CompareMethod.Text) ' Org.-Artikelnummer
    11. If intEND > 0 Then
    12. strARTORGNR = CStr(Strings.Mid(strINH, intANF, intEND - intANF))
    13. End If
    14. intANF = intEND + 1
    15. ' danach werden MWST, EKPREIS und VKPREIS gefüllt
    16. ' wenn Datensatz fehlt -> anlegen, ansonsten verändern
    17. strKRIT = "ARTORGNR = '" & strARTORGNR & "'"
    18. dr01s = dt01.Select(strKRIT)
    19. If dr01s.Length = 0 Then
    20. bolNEU = True
    21. dr01 = dt01.NewRow
    22. dr01!SUCHBEGRIFF = Strings.Left(strSUCHBEGRIFF, 15)
    23. dr01!ARTNR = strARTNR
    24. dr01!ARTORGA = strARTORGNR
    25. Else
    26. bolNEU = False
    27. dr01 = dr01s(0)
    28. End If
    29. dr01!MWST = intMWST
    30. dr01!EKPREIS = dblEKPREIS
    31. dr01!VKPREIS = dblVKPREIS
    32. If bolNEU Then
    33. dt01.Rows.Add(dr01)
    34. End If
    35. cmb = New OleDbCommandBuilder(da01)
    36. da01.Update(dt01)
    37. Loop
    38. cm01.Dispose()
    39. da01.Dispose()
    40. dt01.Clear()
    41. dt01.Dispose()


    Ich habe die Vermutung, dass der Befehl

    VB.NET-Quellcode

    1. dr01s = dt01.Select(strKRIT)

    gar nicht auf den Index zugreift.

    Was mache ich falsch? Jeder Tipp ist willkommen!

    Danke, Gruß
    Schorsch
    Was ist, wenn du mal versuchst die Änderungen, die gemacht werden als SQL Query zu überführen, diese in einer Liste abspeicherst und die Liste danach Eintrag für Eintrag abarbeitest?
    In general (across programming languages), a pointer is a number that represents a physical location in memory. A nullpointer is (almost always) one that points to 0, and is widely recognized as "not pointing to anything". Since systems have different amounts of supported memory, it doesn't always take the same number of bytes to hold that number, so we call a "native size integer" one that can hold a pointer on any particular system. - Sam Harwell
    Damit ich das richtig verstehe: Du lädst die Daten aus der Access Datei in eine DataTable rein, bearbeitest dort die Datensätze und schreibst sie (warscheinlich) am Ende wieder in die DB weg?

    Dazu eine Frage: zweigst du die Daten, die du aus der DB hast und (automatisch) bearbeiten willst, dem User an? Es kann sein, dass das aktualisieren der Oberfläche eine Menge Zeit nimmt. Versuch einfach mal das UI-Updaten zu deaktivieren (SuspendLayout und ResumeLayout). Oder alternativ: Überlegt dir, ob es für dich nicht sinn machen würde, die Datensätze In-Memory zu halten. Und nur bei Bedarf anzuzeigen und ansonsten:
    Aus Datenbank lesen, bearbeiten und wieder zurück schreiben.
    In general (across programming languages), a pointer is a number that represents a physical location in memory. A nullpointer is (almost always) one that points to 0, and is widely recognized as "not pointing to anything". Since systems have different amounts of supported memory, it doesn't always take the same number of bytes to hold that number, so we call a "native size integer" one that can hold a pointer on any particular system. - Sam Harwell
    Danke für Deine Unterstützung!

    Die Daten werden nicht angezeigt.

    Aus Datenbank lesen, bearbeiten und wieder zurück schreiben.


    Das ist eigentlich mein Plan. Die Textdatei wird also sequentiell gelesen, dann wird nachgeschaut, ob die Artikelnummer da ist. Wenn ja, verändere ich den Datensatz, ansonsten lege ich ihn neu an. Programm funktioniert ja auch und macht alles, was ich möchte.

    Nur eben zu langsam.

    Ich finde aber nirgends einen Hinweis auf das Lesen über Indizes. In VB6 hätte ich ja geschrieben

    Visual Basic-Quellcode

    1. RS.Index = "ARTORGNR"
    2. RS.Seek "=", strARTORGNR


    Ich gebe aber hier nirgendwo den Index an. Oder lädt

    VB.NET-Quellcode

    1. da01.MissingSchemaAction = MissingSchemaAction.AddWithKey

    automatisch alle Indizes der Tabelle und der Befehl

    VB.NET-Quellcode

    1. dr01s = dt01.Select(strKRIT)

    sucht sich automatisch den passenden Index? Das wäre ja ein nie gekannter Komfort :) .
    Also, es wäre erstmal sehr interessant zu wissen, welcher Befehl denn da so lange dauert.

    Dann würde ich aus Erfahrung sagen dass bei einer Access-Db mit so einer überschaubaren Anzahl an Datensätzen und einer reinen SELECT-Abfrage ohne JOINs die Indizierung keinen Geschwindigkeitsgewinn bringt - im Gegenteil, wenn man Stringfelder (was ja zumindest SUCHBEGRIFF höchstwahrscheinlich ist) indiziert kann das sogar bremsen!

    Drittens vermute ich dass dich dieses Konstrukt ausbremst:

    VB.NET-Quellcode

    1. If bolNEU Then
    2. dt01.Rows.Add(dr01)
    3. End If
    4. cmb = New OleDbCommandBuilder(da01)
    5. da01.Update(dt01)
    6. Loop


    Ich kann gerade nicht nachvollziehen wozu dieser CommandBuilder gebraucht werden soll... Ich würde das ungefähr so machen (ungetestet und ohne Garantie) ;)

    VB.NET-Quellcode

    1. strKRIT = "ARTORGNR = '" & strARTORGNR & "'"
    2. dr01s = dt01.Select(strKRIT)
    3. If dr01s.Length = 0 Then
    4. bolNEU = True
    5. dr01 = dt01.NewRow
    6. Else
    7. bolNEU = False
    8. dr01 = dr01s(0)
    9. End If
    10. dr01!SUCHBEGRIFF = Strings.Left(strSUCHBEGRIFF, 15)
    11. dr01!ARTNR = strARTNR
    12. dr01!ARTORGA = strARTORGNR
    13. dr01!MWST = intMWST
    14. dr01!EKPREIS = dblEKPREIS
    15. dr01!VKPREIS = dblVKPREIS
    16. If bolNEU Then
    17. dt01.Rows.Add(dr01)
    18. End If
    19. Loop
    20. da01.Update(dt01)


    Wichtig - das Update nur einmal zum Schluss außerhalb des Loops. Sonst speicherst Du ja 3500 mal die komplette Tabelle - und das dauert seine Zeit!