none
ACCESS und Datagrid... RRS feed

  • Frage

  • Habe jetzt mal eine simple Tabelle genommen ( einer der kleinsten von unseren Kunden mit ca. 300000 Sätzen )

     

    Binde die ACCESS Mappe mit :

     

            Dim cString As String
            Dim oDb As New OleDbConnection
            Dim oDs As System.Data.DataSet
            Dim oAdapter As System.Data.OleDb.OleDbDataAdapter


            cDatenpfad = "C:\winprojekte\vbwinwawi\daten\"
            cDatenbank = "WinWaWi.mdb"


            oDb = WindowsApplication1.WinWaWi.oDatenbanken.oConnection

            cString = "SELECT Top 10 * FROM Artikel"

            oAdapter = New System.Data.OleDb.OleDbDataAdapter(cString, oDb)
            oDs = New System.Data.DataSet
            oAdapter.Fill(oDs)

            Me.DataGridView1.DataSource = oDs.Tables(0)

     

    oConnection kommt aus den ersten Versuchen einer "globalen" Klasse :

            oConnection.ConnectionString =
                "Provider=Microsoft.Jet.OLEDB.4.0;" &
                "Data Source=" + cDatenpfad + cDatenbank

            oConnection.Open()

     

    Das dauert ca. 11 Sekunden bis das Grid auf einem lokalen Rechner mit power unter der Haube angezeigt wird...

    Mache ich hier was falsch ? 11 Sekunden sind für die lächerliche Anzahl definitiv viel zu viel, zumal das ganze noch lokal auf C:\ liegt...

    In ACCESS selber wenn ich da n doppelklick auf die Tabelle mache sind die Daten ja auch in einer gefühlten Sekunde vorhanden und werden angezeigt.

    Gibts also irgendwie eine nativere Anbindung an ACCESS mit VB ?

    Danke euch,

    Mario

     

    Donnerstag, 17. Juni 2010 09:59

Antworten

  • Hallo Mario,

    11 Sekunden sind wirklich reichlich viel...
    Hängt da ein freundlicher Virenscanner (oder anderes) dazwischen?

    Der Zugriff via Microsoft.Jet.OLEDB.4.0 ist der bevorzugte Weg für Access Datenbanken (zumindest bis 2003).
    Was unter .NET ebenso fix (oder langsam) geht, als wenn Du die Datenank unter Access selbst
    oder einer anderen OleDb Anwendung (z. B. VB Classic) öffnest.

    Anmerkungen am Rande:
    Du solltest Deine Verbindungszeichenfolge in die Settings verlagern
    und jeweils nur für den Zugriff öffnen, klassisches Muster wäre dabei:

      Public Function GetArtikelDataSet() As DataSet
        Dim dataSet As New DataSet("ArtikelDataSet")
        Using adapter As New OleDbDataAdapter( _
          "SELECT TOP 10 * FROM Artikel", _
          My.Settings.AccessConnectionString)
    
          adapter.MissingMappingAction = MissingMappingAction.Passthrough
          adapter.MissingSchemaAction = MissingSchemaAction.AddWithKey
    
          adapter.Fill(dataSet, "Artikel")
        End Using
        Return dataSet
      End Function
    

    Das Connection Pooling sorgt schon für ein Recyceln der Verbindung.
    (Und dauert bei meinen Artikeln um die 30 ms, ob 10 oder 1000 Zeilen)

    Präfixe wie "o" sind überflüssig, denn unter .NET ist alles ein Objekt - auch ein String ;-)
    Schau Dir bei Gelegenheit mal an: Entwurfsrichtlinien zum Entwickeln von Klassenbibliotheken
    Damit wird der Code für Dich und andere am Ende leserlicher.

    Gruß Elmar

    Donnerstag, 17. Juni 2010 10:27
  • Hi Mario,
    Access baut die Bindung zur Datenbank bereits mit dem Laden der Access-Datei auf. Für die Anzeige werden dann erst einmal nur die Daten geladen, die zur Anzeige benötigt werden. Der Rest wird nachgeladen.

    In Deinem Beispiel baust du die Verbindung auf, lädst dann ALLE Daten und bindest dann die Daten an das Grid. Das dauert natürlich länger als in der Access-Oberfläche. Wenn du es genau so machen willst wie in der Access-Oberfläche, dann lade die Daten asynchron nach. Hier mal eine Demo dazu:

    UI-Klasse (einfach in den Codeteil eines leeren Windows in eine VB Anwendung kopieren):

    Public Class Form1
    
     Private vm As New ViewModel
     Private btnload As New Button With {.Text = "Laden", .Dock = DockStyle.Top}
     Private dgv As New DataGridView With {.Dock = DockStyle.Fill, .DataSource = vm.BS}
    
     Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
      Me.Controls.AddRange(New Control() {dgv, btnload})
      AddHandler btnload.Click, AddressOf vm.LoadData
     End Sub
    
    End Class
    

    Und dazu die Klasse mit der Ladefunktion:

    Imports System.Data.OleDb
    Imports System.ComponentModel
    
    Public Class ViewModel
    
     Public Property BS As New BindingSource
    
     Private cn As New OleDbConnection(My.Settings.cnMdb)
     Private da As New OleDbDataAdapter With {.MissingSchemaAction = MissingSchemaAction.AddWithKey}
     Private cmd As New OleDbCommand("", cn)
     Private dt As New DataTable
    
     Dim WithEvents bgw As New BackgroundWorker
    
     Public Sub LoadData(ByVal sender As Object, ByVal e As EventArgs)
      cmd.CommandText = "SELECT top 100 * FROM Status"
      da.SelectCommand = cmd
      da.Fill(dt)
      da.SelectCommand = cmd
      BS.DataSource = dt
      bgw.RunWorkerAsync()
     End Sub
    
     Private Sub bgw_DoWork(ByVal sender As Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles bgw.DoWork
      Dim dt2 As New DataTable
      cmd.CommandText = "SELECT * FROM Status"
      da.Fill(dt2)
      dt.Merge(dt2)
     End Sub
    
     Private Sub bgw_RunWorkerCompleted(ByVal sender As Object, ByVal e As System.ComponentModel.RunWorkerCompletedEventArgs) Handles bgw.RunWorkerCompleted
      BS.ResetBindings(False)
     End Sub
    
    End Class
    

    --
    Viele Gruesse
    Peter

    Donnerstag, 17. Juni 2010 12:20
  • so, nach einer Nacht und einem ordentlichen Kaffee denke ich habe ich meinen "Fehler" gefunden...

    Ich hatte angenommen das ich die ACCESS-Tables mit meiner dBase Datenbank vergleichen kann. Da ACCESS die ALLE Daten ja sofort zu verfügung stellt wenn sie geöffnet wird.. Dem scheint ja aber nicht so zu sein. Wenn ich die ACCESS wie eine SQL Tabelle vergleiche dann ist die Performance ok .. muss ich mein Konzept halt doch noch mal ändern, erst den Benutzer zu fragen "welche Daten möchtest du dann sehen" und dann erst mit einer WHERE Bedingung die Ergebnisse liefern. Unter dem Gesichtspunkt ist die ACCESS Tabelle auf unserem künstlich gedrosselten Programmier-Test-Server dann doch sogar ein Tick schneller als der SQL2005...

    @Elmar .. der Zeitverlust passiert wirklich nur im Fill() nicht das Datagrid, das  stellt die Daten in einwandfreier Zeit zur Verfügung...

    Danke euch !

    Freitag, 18. Juni 2010 06:49

Alle Antworten

  • Hallo Mario,
            cString = "SELECT Top 10 * FROM Artikel"

    Das dauert ca. 11 Sekunden bis das Grid auf einem lokalen Rechner mit power unter der Haube angezeigt wird...

    Mache ich hier was falsch ? 11 Sekunden sind für die lächerliche Anzahl definitiv viel zu viel, zumal das ganze noch lokal auf C:\ liegt...

    pack mal ein ORDER BY <Spalte> ins Statement. Alternativ (nur zum probieren) das hier:

    SELECT Spalte1, Spalte2, ... FROM Artikel WHERE <IdSpalte> < 100

    Wenn letzteres schneller ist, liegts wohl an fehlenden Indizes.

     


    Gruß, Stefan
    Microsoft MVP - Visual Developer ASP/ASP.NET
    http://www.asp-solutions.de/ - Consulting, Development
    http://www.aspnetzone.de/ - ASP.NET Zone, die ASP.NET Community
    Donnerstag, 17. Juni 2010 10:10
    Moderator
  • Hallo Mario,

    11 Sekunden sind wirklich reichlich viel...
    Hängt da ein freundlicher Virenscanner (oder anderes) dazwischen?

    Der Zugriff via Microsoft.Jet.OLEDB.4.0 ist der bevorzugte Weg für Access Datenbanken (zumindest bis 2003).
    Was unter .NET ebenso fix (oder langsam) geht, als wenn Du die Datenank unter Access selbst
    oder einer anderen OleDb Anwendung (z. B. VB Classic) öffnest.

    Anmerkungen am Rande:
    Du solltest Deine Verbindungszeichenfolge in die Settings verlagern
    und jeweils nur für den Zugriff öffnen, klassisches Muster wäre dabei:

      Public Function GetArtikelDataSet() As DataSet
        Dim dataSet As New DataSet("ArtikelDataSet")
        Using adapter As New OleDbDataAdapter( _
          "SELECT TOP 10 * FROM Artikel", _
          My.Settings.AccessConnectionString)
    
          adapter.MissingMappingAction = MissingMappingAction.Passthrough
          adapter.MissingSchemaAction = MissingSchemaAction.AddWithKey
    
          adapter.Fill(dataSet, "Artikel")
        End Using
        Return dataSet
      End Function
    

    Das Connection Pooling sorgt schon für ein Recyceln der Verbindung.
    (Und dauert bei meinen Artikeln um die 30 ms, ob 10 oder 1000 Zeilen)

    Präfixe wie "o" sind überflüssig, denn unter .NET ist alles ein Objekt - auch ein String ;-)
    Schau Dir bei Gelegenheit mal an: Entwurfsrichtlinien zum Entwickeln von Klassenbibliotheken
    Damit wird der Code für Dich und andere am Ende leserlicher.

    Gruß Elmar

    Donnerstag, 17. Juni 2010 10:27
  •  
    "Elmar Boye" schrieb im Newsbeitrag news:cdc8da08-fbfc-44c1-a250-3e9a681e88ba...

    ...

    Anmerkungen am Rande:
    Du solltest Deine Verbindungszeichenfolge in die Settings verlagern
    und jeweils nur für den Zugriff öffnen, klassisches Muster wäre dabei:

     ...

    Das Connection Pooling sorgt schon für ein Recyceln der Verbindung.
    (Und dauert bei meinen Artikeln um die 30 ms, ob 10 oder 1000 Zeilen)

    Hi Elmar,
    für Acces ist das eine denkbar ungünstige Arbeitsweise. Leider funktioniert das ConnectionPooling mit Access bei größerer Anwenderzahl nicht wirklich. Ich habe da mal viel Aufwand in die Suche undefinierter Abbrüche gesteckt und Ursache war letztendlich das ständige Öffnen und Schließen der Verbindung im Programm mit eingeschaltetem ConnectionPooling. Die Fehlerausschriften sagten nur "undefinierter Fehler" und im Fehlerfall war irgendwie die ldb kaputt. Warum beim ConnectionPooloing die ldb zerstört wird, kann ich nicht sagen. Der Fehler war in einem Strestest mit einem eifachen Programm mit hoher Belastung (mehrere Anwender, länger andauernde Abfragen) sporadisch nachweisbar. Das Programm selbst war ein WebService, der mit der Jet 4.0 mit einer Access 2003 Datei gearbeitet hat. Da dieser Fehler immer bei höherer Belastung auftrat und ich gerade dann immer wenig Zeit hatte, habe ich das Problem nicht weiter verfolgt und habe einfach nur den Zugriff mit gleichen SQL Anweisungen auf einem SQL 2000 Server ausgeführt. Da traten keine Fehler mehr auf.


    --
    Viele Gruesse

    Peter

    Donnerstag, 17. Juni 2010 11:14
  • huhu,

    wie gesagt, ohn Änderung an der Tabelle, wenn ich die mit ACCESS doppelklicke, zack alle 30000 Datensätze sind da..

    Hab ein ORDER BY Artikel eingenaut => keine Verbesserung

    Eine direkte Feldauswahl mit Artikel, Nummer, Bezeichnung => bringt natürlich bisl was aber immernoch viiiel zu lange

    Hab ein Primärschlüssel vergeben ( fehlte in der Tabelle noch ), aber auch das bringt keine Verbesserung...

    Virenscanner ist ruhig, scannt nur einmal die Tabelle beim "open" ... so wie es sein soll...

    Danke @Elmar für die Entwurfsrichtlinien... muss ich mich erst eingewöhnen ( bin noch DOS-Clipper und VO Syntaxe gewöhnt, wird etwas dauern bis ich mich da eingestellt habe auf VB )

    Was könnte denn sonst für ein Problem da sein? Ich bin halt nur vewundert das mit ACCESS direkt alle Datensätze dsofort zu sehen sind ohne Erkennbare Verzögerung und unter VB mit diesem kleinen Knopf gefühlte 11 Sekunden dauert... sind zwar 30000, aber das eher die kleinere Varainte der Daten mit den ich hier hantiere :)

     

     

    Donnerstag, 17. Juni 2010 11:16
  • Hi Mario,
    Access baut die Bindung zur Datenbank bereits mit dem Laden der Access-Datei auf. Für die Anzeige werden dann erst einmal nur die Daten geladen, die zur Anzeige benötigt werden. Der Rest wird nachgeladen.

    In Deinem Beispiel baust du die Verbindung auf, lädst dann ALLE Daten und bindest dann die Daten an das Grid. Das dauert natürlich länger als in der Access-Oberfläche. Wenn du es genau so machen willst wie in der Access-Oberfläche, dann lade die Daten asynchron nach. Hier mal eine Demo dazu:

    UI-Klasse (einfach in den Codeteil eines leeren Windows in eine VB Anwendung kopieren):

    Public Class Form1
    
     Private vm As New ViewModel
     Private btnload As New Button With {.Text = "Laden", .Dock = DockStyle.Top}
     Private dgv As New DataGridView With {.Dock = DockStyle.Fill, .DataSource = vm.BS}
    
     Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
      Me.Controls.AddRange(New Control() {dgv, btnload})
      AddHandler btnload.Click, AddressOf vm.LoadData
     End Sub
    
    End Class
    

    Und dazu die Klasse mit der Ladefunktion:

    Imports System.Data.OleDb
    Imports System.ComponentModel
    
    Public Class ViewModel
    
     Public Property BS As New BindingSource
    
     Private cn As New OleDbConnection(My.Settings.cnMdb)
     Private da As New OleDbDataAdapter With {.MissingSchemaAction = MissingSchemaAction.AddWithKey}
     Private cmd As New OleDbCommand("", cn)
     Private dt As New DataTable
    
     Dim WithEvents bgw As New BackgroundWorker
    
     Public Sub LoadData(ByVal sender As Object, ByVal e As EventArgs)
      cmd.CommandText = "SELECT top 100 * FROM Status"
      da.SelectCommand = cmd
      da.Fill(dt)
      da.SelectCommand = cmd
      BS.DataSource = dt
      bgw.RunWorkerAsync()
     End Sub
    
     Private Sub bgw_DoWork(ByVal sender As Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles bgw.DoWork
      Dim dt2 As New DataTable
      cmd.CommandText = "SELECT * FROM Status"
      da.Fill(dt2)
      dt.Merge(dt2)
     End Sub
    
     Private Sub bgw_RunWorkerCompleted(ByVal sender As Object, ByVal e As System.ComponentModel.RunWorkerCompletedEventArgs) Handles bgw.RunWorkerCompleted
      BS.ResetBindings(False)
     End Sub
    
    End Class
    

    --
    Viele Gruesse
    Peter

    Donnerstag, 17. Juni 2010 12:20
  • Hallo Mario,

    schon das einmalige Scannen bei Öffnen von Dateien (und vermutlich bei der LDB dito) würde mich nerven!
    Und die 30ms waren inkl. einiger sinnfreier Bilddaten, die die in NG verwendete Beispieltabelle
    vor etlichen Jahren mal verpaßt gekriegt hatte (fiel mir gerade erst auf ;-)
    Auch haben Virenscanner oft die Angewohnheit unbekannte Programme genauer unter die Lupe
    zunehmen, was den Start zusätzlich verzögert, da während einer Entwicklung immer ein neues entsteht.
    Also lege den Scanner mal still bzw. schliesse das Verzeichnis mit der MDB/LDB aus.

    Der gezeigte Code-Schnippsel ist insofern auf Dauer ineffizienter, weil jedesmal das DataSet erzeugt werden muß,
    was aber kaum den Unterschied erklären dürfte - günstiger ist ein einmaliges FillSchema (oder ein typisiertes DataSet ).
    Auch muß beim Binden an das DataGridView einiges zusätzlich getan werden, wenn das Schema nicht von vornherein festliegt
    Was aber alles mehr auf .NET Seite liegt und unabhängig von der Jet/OleDb immer passiert.

    Access ist im übrigen nur bedingt vergleichbar, da es "mogelt". Es zeigt das Datenblatt (oder Formular) bereits an,
    sobald es genügend Daten für eine Seite zusammen hat. Ein DataAdapter muß aber erst alles lesen,
    bevor die Anzeige überhaupt in die Gänge kommt.

    Um nur den Abruf zu messen, verwende die Stopwatch-Klasse , für oben:

        Dim sw = Stopwatch.StartNew()
        Dim dataSet = GetArtikelDataSet()
        ' Me.DataGridView1.DataSource = dataSet
        ' Me.DataGridView1.DataMember = "Artikel"
        sw.Stop()
        Console.WriteLine("{0} => {1} ({2})", dataSet.Tables(0).TableName, dataSet.Tables(0).Rows.Count, sw.ElapsedMilliseconds)
    
    und vergleiche mit/ohne Zuweisen der DataSource und auch nach meheren Durchläufen
    (aber auch mit DataGridView bleibt es hier weit unter einer Sekunde).

    Gruß Elmar

    Donnerstag, 17. Juni 2010 13:41
  • so, nach einer Nacht und einem ordentlichen Kaffee denke ich habe ich meinen "Fehler" gefunden...

    Ich hatte angenommen das ich die ACCESS-Tables mit meiner dBase Datenbank vergleichen kann. Da ACCESS die ALLE Daten ja sofort zu verfügung stellt wenn sie geöffnet wird.. Dem scheint ja aber nicht so zu sein. Wenn ich die ACCESS wie eine SQL Tabelle vergleiche dann ist die Performance ok .. muss ich mein Konzept halt doch noch mal ändern, erst den Benutzer zu fragen "welche Daten möchtest du dann sehen" und dann erst mit einer WHERE Bedingung die Ergebnisse liefern. Unter dem Gesichtspunkt ist die ACCESS Tabelle auf unserem künstlich gedrosselten Programmier-Test-Server dann doch sogar ein Tick schneller als der SQL2005...

    @Elmar .. der Zeitverlust passiert wirklich nur im Fill() nicht das Datagrid, das  stellt die Daten in einwandfreier Zeit zur Verfügung...

    Danke euch !

    Freitag, 18. Juni 2010 06:49
  • Hallo Mario,

    das Access MDB-Dateiformat ist schon ein bißchen komplexer als das von Dbase -
    und das vom SQL Server noch ein wenig mehr.

    Wo man beim Ur-DBase von einer gleichen Satzgröße ausgehen konnte
    und über Berechnung (Zeile * Satzbreite) + Dateiheader die jeweilige Zeilen fand,
    bemühen die Jet wie der SQL Server Nachschlagealgorithmen (mit unterschiedlicher Komplexität).

    Aber daran liegt es am Ende kaum. Der wesentliche Unterschied bei .NET DataSets ist,
    dass die Daten vollständig im Speicher gehalten werden. Was mehr Ressourcen auf
    Programmseite benötigt - und den Speicher sprengen kann, wenn man es ungeschickt anstellt ;-).

    Ein Kriterium ist somit Pflicht und ebenso eine Spaltenlistee bei breiten Tabellen,
    die nur die Daten abruft die man wirklich anzeigen will.

    Wobei Du Abfrage-Leistungen deutlich unter 500ms erreichen solltest,
    sonst ist vermutlich mehr im Argen.

    Gruß Elmar

    Freitag, 18. Juni 2010 07:11
  • Hallo Mario,
    Ich hatte angenommen das ich die ACCESS-Tables mit meiner dBase Datenbank vergleichen kann. Da ACCESS die ALLE Daten ja sofort zu verfügung stellt wenn sie geöffnet wird.. Dem scheint ja aber nicht so zu sein. Wenn ich die ACCESS wie eine SQL Tabelle vergleiche dann ist die Performance ok .. muss ich mein Konzept halt doch noch mal ändern, erst den Benutzer zu fragen "welche Daten möchtest du dann sehen" und dann erst mit einer WHERE Bedingung die Ergebnisse liefern. Unter dem Gesichtspunkt ist die ACCESS Tabelle auf unserem künstlich gedrosselten Programmier-Test-Server dann doch sogar ein Tick schneller als der SQL2005...

    ehrlich gesagt hab ich nicht verstanden, was Du meinst.

    Falls Du vorher sämtliche Daten ausgelesen hast und dann hinterher erst über die WHERE Clause ein zweites Statement, nun mit Filter, abgesetzt hast, könnte ich die üble Performance nachvollziehen. Ansonsten aber nicht.

     


    Gruß, Stefan
    Microsoft MVP - Visual Developer ASP/ASP.NET
    http://www.asp-solutions.de/ - Consulting, Development
    http://www.aspnetzone.de/ - ASP.NET Zone, die ASP.NET Community
    Freitag, 18. Juni 2010 07:13
    Moderator
  • Hallo Stefan,

    dBase ist so das beim öffnen der Datei sofort ALLE Daten zur Verfügung stehen.

    Da ACCESS beim Doppelklick ebenfalls "augenscheinlich" alle Daten zur Verfügung stellt dachte ich das läuft genauso bei einem SELECT * FROM ...

    Aber dem ist nicht so... Ich muss ein leeres Datagrid erst anzeigen und den Benutzer fragen was er sehen will :

    Artikelnr. : 4711

    Und dann erst einen SELECT * From Artikel WHERE Artikelnr Like = '"+cArtikel+"%'" machen... dann sind die Abfragen schnell genug...

    Also ACCESS nicht vergleichen mit dem dBase Verhalten, sondern ACCESS vergleichen mit dem SQL Verhalten...

    So meinte ich das... und unter dem Gesichtspunkt sind für zeige alle 300000 Datensäte in voller Breite ( ca. 137 Spalten mit Memofeldern (!)) 11 Sekunden völlig ok...

    Wenn ich einen SELECT mache mit einer WHERE Bedingung dann ist es deutlich unter 1 Sekunde...zumindest wenn die Ergebnissmenge nicht mehr als 10000 Daten zurückliefert :) Da ist dann der SQL-Server wieder schneller...

    Mir nur etwas schleierhaft der Zusammenhang :

    a) ich mach erst eine SQL Abfrage in dem Adapter...

    b) dann lese ich alle Daten in ein Dataset mit dem zeitraubenden Fill()

    c) und dann fülle ich das Gridview mit dem Dataset

    Finde das sehr umständlich irgendwie und dachte das das Gridview direkt mit einer SQL Abfrage zusammenarbeiten kann... so halte ich die Daten doch 3 mal im Speicher...

    Auch muss ich mir noch überlegen wer macht die ORDER BY Geschichte... ich kann in allen 3 Varianten im SELECT Statement direkt, im Dataset und dann noch (auch durch den Benutzer ) im Datagrid sortieren...

     

     

     

     

     

    Freitag, 18. Juni 2010 08:31
  • Hallo Mario,

    dBase ist so das beim öffnen der Datei sofort ALLE Daten zur Verfügung stehen.

    Da ACCESS beim Doppelklick ebenfalls "augenscheinlich" alle Daten zur Verfügung stellt dachte ich das läuft genauso bei einem SELECT * FROM ...

    ist auch so. Ich wüsste nicht, wo hier der große Unterschied liegen soll. Auch Access ist eine dateibasierte Datenbank, die im Speicher landet (und dadurch ab und an auch mal nicht mehr funktioniert :)

    Aber dem ist nicht so... Ich muss ein leeres Datagrid erst anzeigen und den Benutzer fragen was er sehen will :

    Artikelnr. : 4711

    Und dann erst einen SELECT * From Artikel WHERE Artikelnr Like = '"+cArtikel+"%'" machen... dann sind die Abfragen schnell genug...

    Das ist eine der normalen Vorgehensweise, da man nicht unbedingt _alle_ Daten anzeigt und dann dann den User entscheiden lässt, was er sehen will.

    In dem Fall wäre eine seitenweise Anzeige über ein Paging sicherlich sinnvoller (alternativ dynamisches Nachladen der Daten)

    So meinte ich das... und unter dem Gesichtspunkt sind für zeige alle 300000 Datensäte in voller Breite ( ca. 137 Spalten mit Memofeldern (!)) 11 Sekunden völlig ok...

    Letzteres sehe ich bis zur Anzeige als Ok an. Allerdings frage ich mich, ob deine DB Struktur wirklich so optimal ist. Ich kenne nur wenig Fälle, in denen man mehr als 100 Spalten in einer Tabelle braucht und wo es nicht sinnvoller wäre, die Struktur zu splitten, um Redundanzen zu vermeiden). Aber ich kenne deine Anforderungen ja nicht, evtl. braucht man das hier ja so.
    Mir nur etwas schleierhaft der Zusammenhang :

    a) ich mach erst eine SQL Abfrage in dem Adapter...

    b) dann lese ich alle Daten in ein Dataset mit dem zeitraubenden Fill()

    c) und dann fülle ich das Gridview mit dem Dataset

    Punkt "b)" heißt, Du liest alle 300.000 Datensätze ein? Falls ja, selbst schuld :) Es wird ein Schwein auch nur annähernd alle Datensätze brauchen. In deinem Fall kannst Du besser die ersten x Datensätze über ein SQL Statement laden und die weiteren Datensätze auf weitere Seiten verteilen (Paging) bzw. dynamisch nachladen. Filter werden dann über die WHERE Clause gelöst, die die Ergebnisliste einschränkt.



    Gruß, Stefan
    Microsoft MVP - Visual Developer ASP/ASP.NET
    http://www.asp-solutions.de/ - Consulting, Development
    http://www.aspnetzone.de/ - ASP.NET Zone, die ASP.NET Community
    Freitag, 18. Juni 2010 08:46
    Moderator
  • Hallo Elmar,

    wie Peter Fleischer auch schon angemerkt hat, ist
    es beim Arbeiten mit einer Access.mdb nicht
    empfehlenswert die Connection für jeden Zugriff
    zu öffnen und wieder zu schliessen.
    Jedes Öffnen und jedes Schliessen der Verbindung
    bedeutet einen schreibenden Zugriff auf die zugehörige *.ldb
    und erhöht so die Gefahr einer Beschädigung der *.mdb
    bei einem Mehrbenutzerbetrieb.

    Für das Arbeiten mit Access.mdb kann ich nur empfehlen:
    Die benötigte Connection beim erstmaligen Bedarf öffnen,
    dabei ConnectionPooling ausschalten (OLE DB Services=-4 im
    Connectionstring) und dann bis zum letztmaligen Bedarf
    geöffnet lassen. Damit gibt es während der gesamten
    Programmlaufzeit einen einzigen Zugriff auf die *.ldb beim
    Öffnen und einen weiteren beim Schliessen der Connection.

    Diese Arbeitsweise hat sich bei mir in vielen Mehrbenutzer-
    anwendungen bewährt und vermeidet auch das bei *.mdb
    immer wieder beklagte Beschädigen der *.mdb.

    Hallo Mario,

    unter www.gssg.de -> Visual Basic -> VB.net
    findest Du die Beispiele

        -> OLEDB1 (Access.mdb)
        -> OLEDB2 (Access.mdb)
    und
        -> DB CommandObjekte / DataReader

    Alle diese Beispiele arbeiten mit einer Access.mdb
    und ausgeschaltetem ConnectionPooling.

    Gruß aus St.Georgen
    Peter Götz
    www.gssg.de (mit VB-Tipps u. Beispielprogrammen)

    Montag, 21. Juni 2010 07:04
  • Hallo Peter,

    ich will das Thema hier nicht in einem Anfänger-Thread ausarten lassen, zumal es
    a) etliche Male anderweitig diskutiert wurde,
    b) meine Antwort an Peter Fleischer vom Freitag im Orkus dieses Forums
    entschwunden zu sein scheint ;-((

    Die Problematik der LDB ist mir (als ehemaliger Access MVP, der KB 239114 immer
    noch aus dem Stegreif als meistzitierten KB Artikel führt) ebenso bekannt
    wie Dir ebenso wie die anfängliche Probleme die das Connection Pooling bei
    seiner Einführung insbesondere bei der Jet zeigte.

    Nur ist das zum einen einige Jahre her: Pooling in the Microsoft Data Access Components
    und zumindest das Problem weitgehend ausgestanden - naja, soweit sich bei Microsoft noch
    jemand um die Jet 4.0 kümmert (was ich mindestens ebenso bedauere ;-((

    Und von Haus aus ist das Connection Pooling nicht schädlicher als andere Seiteneffekte.
    Denn bei den üblichen Zugriffsmustern von Anwendungen (die man mit der Jet zuverlässig
    implementieren kann), führt es zu keinen häufigeren Zugriffen.
    Mit "üblichen Zugriffsmustern" bezeichne ich hier, das eine Anwendung kurzzeitig
    mehrere Abrufe (zum Beispiel Laden/Aktualisieren von DataSets) durchführt und
    danach häufig auch einige Zeit verwaist auf dem Bildschirm ruht - weil ein Sachbearbeiter
    was anders wie telefonieren, simmsen, Fußball gucken, etc. macht ;-)

    In den Fällen findet ein Schließen nach einer Wartezeit statt, nicht aber während
    der Aktivitätsphase (siehe Artikel oben - wers nicht glaubt,  mag den Process Monitor
    der Sysinternals bemühen).

    Meine Empfehlung beruht am Ende darauf, keine Sonderbehandlung für einen Provider
    zu verwenden, da dadurch unterschiedliche Programmiermuster verwendet und
    durchgehalten werden müssen (Hier: Mario experimierte mit SQL Server wie Access).
    Und ein Connection Pooling für größe Anwendungen (mit SQL Server) unabdingbar wird.

    Entscheidet man sich ausschließlich für einen Provider, so kann bei ausschließlicher Verwendung
    der Jet bzw. auch ACE ein "Tuning" lohnen, bis hin zu dem nur dort möglichen direkten Zugriff
    (wenn auch nicht mit OleDb Client Hausmittelchen ;-)

    Nur es von vorneherein darauf auszulegen, ist einer Portabilität (so man sie jemals haben muß)
    nicht gerade förderlich.
    Und nun mag sich jeder, die ihm besser gefallene Antwort raussuchen ;-)

    Gruß Elmar

    Montag, 21. Juni 2010 09:23
  •  
    "Elmar Boye" schrieb im Newsbeitrag news:61e1058c-bbd4-4a19-adb1-6072f00b403e...

    ...
    b) meine Antwort an Peter Fleischer vom Freitag im Orkus dieses Forums
    entschwunden zu sein scheint ;-((

    Hi Elmar,
    ich kann leider auch Deine Antwort nicht sehen.

    Die Problematik der LDB ist mir (als ehemaliger Access MVP, der KB 239114 immer
    noch aus dem Stegreif als meistzitierten KB Artikel führt) ebenso bekannt
    wie Dir ebenso wie die anfängliche Probleme die das Connection Pooling bei
    seiner Einführung insbesondere bei der Jet zeigte.

    Nur ist das zum einen einige Jahre her: Pooling in the Microsoft Data Access Components
    und zumindest das Problem weitgehend ausgestanden - naja, soweit sich bei Microsoft noch
    jemand um die Jet 4.0 kümmert (was ich mindestens ebenso bedauere ;-((

    Das Problem ist nicht ausgestanden und ich konnte es problemlos reproduzieren.

    Die Theorie zum ConnectionPooling ist klar und es sollte auch funktionieren. Ich konnte es bereits mit 2 Nutzern reproduzieren. Ich habe die mdb im WebService mit etwas länger andauernde Abfragen (z.B. JOIN mit Where-Klassel über einige tausend Datensätze) genutzt. Beim Connection.Open kam nach einiger Zeit "undefinierter Fehler" und der ApplicationPool musste neu gestartet werden, um wieder einen Zugriff zu ermöglichen.

    Falls Interesse besteht, kann ich den Test nochmals durchführen.


    --
    Viele Gruesse

    Peter

    Montag, 21. Juni 2010 10:01