Announcement

Collapse
No announcement yet.

Sql Tabelle mit memorystream übertragen

Collapse
X
  • Filter
  • Time
  • Show
Clear All
new posts

  • Sql Tabelle mit memorystream übertragen

    Hallo Leute,

    wie kann man eine komplette SQL Tabelle bzw. einen Datensatz in einen Stream verschicken vom IdTcpServer zum IdTcpClient ?
    Folgendes Problem stellt sich neuerdings...
    Auf einem Server habe ich MSSQL 2014.
    in dem Server sind Tabellen mit unterschiedlicher Struktur abgelegt.
    Strings, Integer, Datetime, Blobs usw.
    Nun möchte ich die Tabelle in einem Rutsch via Stream zum Client übertragen, wo eine lokale SQLite DB liegt mit der gleichen Struktur wie auf dem SQL Server.
    Zur Zeit wandele ich jeden DatenSatz über DataType des Feldes in eine String um und versende die Datensätze bzw. den Record mittels einer Stringliste.
    Solange kein BlobField auftaucht in der Tabelle geht das auch gut.
    Wenn ich nun aber ein Blobfield in der Tabelle habe muss ich den Umweg über einen FileStream machen, um den Inhalt des Feldes zu übertragen.
    Das macht einen grossen Aufwand an Abfragen nötig.
    Nun denke ich, das es auch einfacher gehen muss, wenn man den Datensatz unabhängig vom Datatype des Feldes in einen Stream packt, den zum Client sendet und dort wieder in die lokale Tabelle einfügt.
    Nun habe ich schon viel gegoogelt aber nichts passenden gefunden was mein Problem irgendwie lösen kann.
    Hat von euch jemand eine Idee oder einen Codeschnipsel wie ich das anpacken kann ?

    Vielen Dank für Eure Anregungen.

    Gruss Gerhard
    Zuletzt editiert von Gerhard Wascinski; 23.12.2016, 14:02.

  • #2
    Originally posted by Gerhard Wascinski View Post
    wie kann man eine komplette SQL Tabelle bzw. einen Datensatz in einen Stream verschicken vom IdTcpServer zum IdTcpClient ?
    Muss es unbedingt ein Stream sein? Unbedingt für BLOB?
    Worauf ich hinaus will:
    Was Du machst klingt im Prinzip nach Replikation.
    Bei MSSQL als Server gibt es Replikationsmechnismen. Ich schätze, statt sqLite nimmt man dann vlt eher SQL Express (früher MSDE, bin da nicht ganz auf dem Laufenden)

    Also bevor Du Dir irgendwelche Spezialitäten zusammenstrickst, mal ein Schritt zurücktreten und Überblick verschaffen.
    Fall es dann doch wirklich ein Stream sein soll ok. Oder falls es ohne SQLExpress / ohne MS Speziallösung gehen soll.
    Gruß, defo

    Comment


    • #3
      Hallo defo,

      im Prinzip ist es eine Replikation, allerdings ist der Hintergrund folgendes:
      Wir haben eine zentrale Datenbank in der Firma auf einem Server liegen. Für die Aussendienstmitarbeiter ist es wichtig, das bestimmte Daten lokal auf dem Laptop verfügbar sind um bei nicht vorhandener Internetverbindung trotzdem wichtige Daten zur Verfügung zu haben.
      Aber nicht alle Daten sind notwendig und es soll möglichst einfach zu handhaben sein.
      Daher eine SQLite lokal auf dem Laptop.
      Bisher war es auch nicht notwendig, Bilder oder PDFs bzw. Office-Dateien lokal zur Verfügung zu haben. Daher überträgt das Programm bisher per Stringlisten die Daten vom Server zum Client.
      Durch struktuelle Änderungen in unserer Firma zum 1.1.2017 liegt aber jetzt die Anforderung auf dem Tisch.
      Die Tabellen um Blobfelder zu erweiteren ist keine grosse Sache. Ebenso die Tabellen auf dem Client in der SQLite DB anzupassen.
      Wenn ich aber nun zur Übertragung von Blobfeldern vom Server zum Client Streams bemühen muss um diese zu senden bzw. zu empfangen dann macht es doch Sinn, gleich alle Felder der Datensätze in einer Zentralen Routine im Stream zu übertragen.
      Die Idee ist, den Stream zu erzeugen, dann die Größe jedes Feldes auf den Stream schreiben und dann den Feldinhalt gleich hintendran, unabhängig davon, was für einen "datatype" das Feld hat.
      Dann den Stream übertragen und im Client wieder einlesen. So erspare ich mir dann die Abfragen auf die Tabellen, ob Blobfelder vorhanden sind oder nicht, um die Blobfelder dann extra per Stream zu übertragen.
      Allerdings habe ich wenig Erfahrung mit Streams wie man sowas realisieren kann. Daher die Anfrage hier im Forum, wo man doch oft gute Denkansätze für Lösungen erhalten kann.

      Gruss Gerhard

      Comment


      • #4
        SQLite kann XML. Wahrscheinlich wohl auch die ServerDB. Mal prüfen, ob man nicht die Tabelle, die Datensätze so überträgt und dann einfügt
        Christian

        Comment


        • #5
          Originally posted by Gerhard Wascinski View Post
          im Prinzip ist es eine Replikation, allerdings .. ist der Hintergrund folgendes:

          Daher eine SQLite lokal auf dem Laptop.

          Wenn ich aber nun zur Übertragung von Blobfeldern vom Server zum Client Streams bemühen muss..

          Allerdings habe ich wenig Erfahrung mit Streams wie man sowas realisieren kann.

          Daher die Anfrage hier im Forum, wo man doch oft gute Denkansätze für Lösungen erhalten kann.
          Replikation ist Replikation. Daher SQLite? Woher? SQLite lokal zur Datenhaltung ist sicher keine schlechte Wahl, aber..
          Warum musst Du Streams bemühen? Und ja, wenn es so ist, dann kannst Du vielleicht auch den Rest damit erledigen. Aber Du hast keine Erfahrung mit Streams.

          (gute) Denkansätze.

          Dein Master ist eine (neue) MS SQL DB, kommerziell mit viel Schnickschnack. Dazu gibt es Express Editionen z.B. für lokale Replikation geschenkt, die Express Edition ist sozusagen der lokale Natural Fit zum Master statt SQLite. Damit sollte Replikation ganz gut funktionieren.
          Du kannst natürlich, weil Du die Herausforderung liebst, auch andere Ansätze verfolgen.

          Hier mal 2. Treffer von oben nach grober Recherche:
          https://technet.microsoft.com/de-de/...ql.90%29.aspx#
          Etwas veraltet, es sollte aber viele andere brauchbare Doku dazu geben.

          @Christian:
          Seit wann kann SQLite XML? Meinst Du vielleicht den SQLite XML Editor?
          Gruß, defo

          Comment


          • #6
            https://dzone.com/articles/importing-xml-data-sqlite

            https://www.sqlite.org/cvstrac/wiki?p=ImportingFiles

            https://www.sqlite.org/features.html
            Zuletzt editiert von Christian Marquardt; 27.12.2016, 17:23.
            Christian

            Comment


            • #7
              Hallo defo, hallo Christian,

              xml ist ein möglicher guter Ansatz. Muss mal recherieren, wie man damit am besten umgeht.

              Ein SQL Express Version dient als Serverapplikation.

              Auf den Client-PCs darf ich keine SQL-Server Version einsetzen sondern nur eine kleine Datenbank, die exklusiv von der ClientApp verwendet wird.
              Darum SQLite, die man ja auch einfach verschlüsseln kann.
              An der Vorgabe komme ich nicht vorbei, insofern ist die Replikation im eigendlichem Sinne nicht machbar.

              Es funktioniert ja auch alles ganz gut bisher.
              Lediglich die Forderung auch Blobfelder mit synchronisieren zu müssen liegt auf dem Tisch.
              Das muss doch eigentlich machbar sein, ohne den Programmcode gross ändern zu müssen.
              Blobfelder als Strings zu übertragen wird wohl schlecht machbar sein oder ?
              Daher die Idee über einen Memorystream.

              Gruss Gerhard

              Comment


              • #8
                Nein, keine gute Idee BLOB als String ohne weitere Konvertierung zu übertragen. Wenn dann BASE 64 kodiert o.a.

                Nun die VCL Zeiten sind lange her, aber m.E. war ein Memorystream etwas für den Speicher...nix zum übertragen.
                Christian

                Comment


                • #9
                  Originally posted by Gerhard Wascinski View Post
                  H

                  Auf den Client-PCs darf ich keine SQL-Server Version einsetzen sondern nur eine kleine Datenbank, die exklusiv von der ClientApp verwendet wird.

                  Lediglich die Forderung auch Blobfelder mit synchronisieren zu müssen liegt auf dem Tisch.
                  Hättest Du auch gleich sagen könne.

                  Es gibt
                  TBlobfield.LoadFromStream
                  TBlobfield.SaveToStream

                  http://www.delphipraxis.net/117340-b...-anzeigen.html

                  oder Load/Save|From|To<file>
                  http://stackoverflow.com/questions/1...sql-parameters
                  Gruß, defo

                  Comment


                  • #10
                    Hallo Christian, Hallo Defo,

                    Manchmal sieht man den Wald vor lauter Bäumen nicht....
                    In der Hilfe zu Delphi steht, das man Blobs per "AsWideString" in eine StringList integrieren kann... Tests zeigen bisher, dass das auch sogar funktioniert. <freu>
                    Das würde bedeuten, das ich über den .DataType nur eine weitere Zeile in der Case Anweisung einfügen muss...

                    Das zweite ist: wie defo sagt....

                    alle Felder in ein Blobfeld übertragen und dann mit blob.SaveToStream schreiben und im Client mit Blob.Loadfromstream wieder einlesen...
                    Tests zeigen, das auch das funktioniert... <freu>

                    Mal schauen, ob alle Sub-Routinen mit dem angepassten Routinen klar kommen, aber es sieht erstmal gut aus...

                    Vielen Dank für eure Denkanstösse.... werde Euch auf dem laufendem halten....

                    Gruss Gerhard.

                    Comment


                    • #11
                      Hallo Leute,
                      nach weiteren Tests hat sich gezeigt, das der Lösungsansatz über Strings nicht glücklich ist. Je größer der Inhalt der Blobfelder ist um so schneller schwindet die Performance.
                      Also eigentlich doch unbrauchbar.
                      Alle Datensatzfelder in ein einziges Blobfeld packen und dann per BlobStream übertragen ist auch ein grosser Aufwand, weil man ja die Längen der einzelnen Felder mit eintragen muss um dann beim Einlesen beim Client alles wieder auseinander zu pflücken.
                      Also auch nicht grade einfach.

                      Jetzt habe ich viel gelesen über DataSnap bzw. Multitier Anwendungen.
                      Wie das aussieht scheint das ein guter Ansatz zu sein. Allerdings wäre das neu für mich.
                      Wie denkt Ihr darüber ?

                      Gruss Gerhard

                      Comment


                      • #12
                        Würde jetzt sagen, dass das nicht viel ändert. Letztlich muss der Blob von A nach B transportiert werden.
                        Des Weiteren würde mir Infos fehlen:
                        - Wo schwindet die Performance
                        - Mengengerüst. Gehen wir von 2 MB pro Blob aus und in welcher Zeit benötigt der Client wieviele davon?
                        - Ein Performanceproblem kann doch nur beim Initialverteilen auftreten. D.h. ab einem Zeitpunkt sollen alle Blobinhalte auch auf den Clients sein. Da kann es sicher sein, dass die Verteilung dauert.
                        - Der Datenaustausch im laufenden Betrieb sollte natürlich die Anwendung nicht lahmlegen. D.h. dieser findet mit Threads oder gar in einer anderen Anwendung statt (bsp. Startet die Replizierung mit dem Start des Clients). Fordert der Client nun ein Blob an, welches noch nicht da ist, so wird das halt vorgezogen. Auch die Übermittlung zum Server sollte mindestens threadgesteuert laufen
                        Christian

                        Comment


                        • #13
                          Mmh, also die Stringlösung scheint ja irgendwie unsauber umgesetzt zu sein, wenn sie immer langsamer wird.
                          Arbeitest Du mit indizierten/sortierten Strings? Auch der Zugriff via FieldByName, .value und andere Varianten benötigen im Massenbetrieb auch unterschiedlich Laufzeit und sind mehr oder weniger empfehlenswert.
                          Es kommt mir irgendwie so vor, als ob Du sehr kleinteilig da rumwurschtelst und selbst vielleicht nicht mehr den Überblick hast?

                          Ich hab jedenfalls etwas den Faden verloren. Zum sortieren:
                          Du hast eine Lösung, der nur die BLOB Felder für Dokumente fehlen?
                          Wo ist das Problem, eine Tabelle im Server für Dokumente anzulgen, das Server BLOB Feld im Client zu laden und dann entweder auf Platte zu speichern mit Dateiverweis in der Tabelle oder alles wieder lokal in eine DB zu quetschen? Wenn Du nach dem Download die Datei gleich im Filesystem ablegst, kannst Du das auch gleich so stehen lassen und als Cache nutzen. (Dann fehlt natürlich etwas Zusatzlogik, die je File den Cachestatus überwacht und ggF. nachlädt- was aber ja sowieso irgendwie kontrolliert geschehen muss...)

                          Mit SQLite könntest Du serverseitig auch ein Programm anlegen, dass Differenzmengen in einzelne SQLlite DB je User verpackt und die dann nur runterladen zum Client und dort mit der vorhanden DB attachen (extra Befehl in SQLlite SQL) und von runtergeladener Differenzmenge zum lokalen Bestand inserten oder updaten.

                          Meine Delphizeiten sind schon etwas her, schau mal auf Delphipraxis.net (siehe auch Link im vorigen Post), da gibt es sehr viele Ansätze zu dem Thema.
                          Gruß, defo

                          Comment


                          • #14
                            Hallo Christian, hallo Defo,

                            Die Übermittlung der Daten vom Server zum Client ist wohl nicht threadgesteuert, weil ich dachte, das TIdTCPServer schon threadgesteuert arbeitet.
                            Insofern ist das ein Grund, warum es länger dauert.
                            Der Hauptgrund aber liegt wohl in der eigenen Routine, die die Stringliste verschlüsselt und am Client wieder entschlüsselt..
                            Je länger die Stringliste ist um so länger dauert es bis die verschlüsselte Stringliste gesendet wird.
                            Insofern hat defo wohl recht, das die Implementierung zur Zeit nicht grade sauber gelöst ist.
                            Desweiteren werden die Komponenten, die pro Anfrage benötigt werden nicht in einem Thread erzeugt sondern werden zentral bei der Anfrage erzeugt und nach Abschluss der Übertragung wieder frei gegeben. Kommt dann in der Zeit eine weitere Anfrage, dann muss die Anfrage warten bis die Komponenten wieder freigegeben sind.
                            Da bisher nur kleine Stringlisten übertragen wurden fiel das nicht so genau auf. Aber jetzt bei grossen Stringlisten macht sich das bemerkbar.
                            Daher habe ich etwas umgebaut.
                            Wenn in einer Tabelle ein Blobfeld gefunden wird, dann überträgt der Server dieses Feld über einen Blobstream, was wesentlich schneller geht.
                            Da die Tabellen im Server und im Client gleich strukturiert sind, weiss der Client also das er einen Blobstream für das Feld erhält.
                            Was zur Zeit wohl dann noch fehlt ist die Verlegung der Anfragen in einen Thread denke ich.

                            Defo, das Programm ist schon älter. Insofern muss ich den Programmcode noch genauer durchgehen, warum das damals so entwickelt wurde.
                            Im Dateisystem die Inhalte der Blobfelder abzulegen war eine Idee, die aber vom Kunden abgelehnt wurde.
                            Da die User einfach den Client und die SQLite-Datei kopieren, wenn sie von einem Computer zum anderen Computer umziehen, wollen die auch nicht noch eine Dateistruktur von der Festplatte mit kopieren. Das verstehe ich gut. Daher muss ich die Daten in Blobfelder ablegen.

                            Es gibt eine zentrale Tabelle auf dem Server, wo alle Änderungen pro Tabelle per Timestamp protokolliert werden.
                            Diese Tabelle wird vom Client angefordert und gelesen und die Unterschiede mit der eigenen zentralen Tabelle heraus gefiltert.
                            Dann werden die geänderten Datensätze pro Tabelle zwischen dem Server und dem Client übertragen.
                            Je weniger Datensätze geändert wurden um so weniger muss zum Client übertragen werden.
                            Da aber die Protokollierung der Änderungen nur pro Datensatz und nicht pro Datenfeld implementiert ist. muss der ganze Datensatz, wenn der geändert worden ist, übertragen werden.
                            Kommen nun die Blobfelder noch dazu, dann braucht das eben mehr Zeit.

                            Da habe ich wohl noch ein bißchen Arbeit vor mir um den Abgleich der Daten sauber und besser zu implemetieren.
                            Stellt sich die Frage, wie threadsicher TIdTCPServer ist...

                            Gruss Gerhard

                            P.S.

                            Ein User hat heute eine PDF-Datei abgelegt mit jeder Menge Graphiken. Größe ca. 25 MB...
                            Jetzt fragt der Kunde ob man auch die Office Datei direkt ablegen kann... damit ein andere User die weiter bearbeiten kann...
                            Also scheinen die User das nun als Dateitransfer benutzen zu wollen anstatt per Mail zu versenden wie vorher...
                            Zuletzt editiert von Gerhard Wascinski; 30.12.2016, 11:15.

                            Comment


                            • #15
                              Nun ja, bei solchen "Verfahren" muss man dann wohl doch auch Fragezeichen machen?
                              25MB sind 25MB, die übertragen werden müssen. Das ist mit schlechter Datenleitung schon eine kleine Qual.
                              Wenn das dann noch schlecht umgesetzt ist, sind es 25 MB plus viel Overhead.

                              Schlecht komprimierte Bilder oder ungeeignete Bildformate oder Kompressionsverfahren in Word oder PDF oder wo auch immer sind dann ebenfalls problematisch. Da kann aber vielleicht auch etwas über die Einstellungen in Word oder PDF geregelt werden.

                              Das Ganze dann noch redundant als Arbeitsversion in Word und PDF macht es nicht besser.
                              Und wenn die Mitarbeiter sowieso manuell Dokumente hin und her schieben, warum dann noch mal in einer DB?

                              Wenn dann noch in einem Datensatz ein Flag geändert wird und sei es nur ein Änderungsdatum, dann noch gleich den ganzen BLOB Inhalt wieder übertragen macht auch keinen Sinn oder?

                              Nochmal, mir scheint das alles sehr kleinteilig und letztlich nicht mehr zeitgemäß.
                              Für Dateisynchronisierung gibt es mittlerweile viele Angebote, auch kostenlose. Z.B. owncloud oder Konkurrenz.
                              Für Datensynchronisierung / Replikation ebenfalls (jenachdem welche Infrastruktur da ist)
                              Gruß, defo

                              Comment

                              Working...
                              X