MySQL ROW in Schleife

Spezielle Fragen zu PostgreSQL, MySQL, SQLite, SQL ...
Bosko
Foriker
Beiträge: 25
Registriert: Sa 20. Apr 2019, 08:57
Kontaktdaten:

MySQL ROW in Schleife

Beitrag von Bosko » Mi 24. Apr 2019, 17:11

hoi,

da ich aus der PHP Sprache komme wollte ich mal Fragen wie man dies (in vereinfachter Version)
umsetzen kann.

Code: Alles auswählen

$sql = "select * from product WHERE no_id!='1'";
$result = $db->query($sql);
while($row = $db->fetch_array($result)) {
	$name = $row['name'];
	$preis = $row['preis'];
	echo $name." / ".$preis;
	$gesamt += $row['preis'];
}
echo $gesamt;
dies ist ein beispeil aus meine PHP Code, da die DB größer ist und nicht alles angezeigt werden muss.

Gruß

PJBlack
Foriker
Beiträge: 1
Registriert: Sa 8. Dez 2018, 23:50
Kontaktdaten:

Re: MySQL ROW in Schleife

Beitrag von PJBlack » Do 25. Apr 2019, 12:34

nicht getestet aber könnte so funktionieren ...

Code: Alles auswählen

Public Sub GetSQLData()

    Dim Con As New Connection
    Dim Res As Result
    Dim SQL As String
    Dim Ausgabe As String
    Dim Gesamt As Float

    With Con
        Try .close
        ' .Type = "postgresql"
        .Type = "mysql"
        ' .Type = "sqlite"
        ' .Type = "odbc"
        ' .Port = "5432"
        .Port = "3306"

        .Name = "Datenbankname"
        .Host = "localhost"
        ' .host = "08.15.47.11"
        .Login = "Benutzername"
        .Password = "Benutzerpasswort"

        .Open
    End With
    SQL = "SELECT name, preis FROM product WHERE no_id !=1;"
    Res = Con.Exec(SQL)

    Ausgabe = ""
    Gesamt = 0.0

    While Res.Available
        Ausgabe &= Res!name & " / " & Res!preis & gb.NewLine
        Gesamt += CFloat(Res!preis)
        Res.MoveNext
    Wend

End

Bosko
Foriker
Beiträge: 25
Registriert: Sa 20. Apr 2019, 08:57
Kontaktdaten:

Re: MySQL ROW in Schleife

Beitrag von Bosko » Mi 1. Mai 2019, 14:16

Hoi,

ich muss das Thema nochmal aufgreifen, mein Problem ist, das wenn ich jetzt eine MySQL
Datenbank abfrage in einer FOR schleife laufen lasse (bei ca. 350 Zeilen, wächst) braucht
die MySQL Abfrage in der FOR Schleife ewig lange, ca. 1 bis 2 sec pro durchlauf, hier ein auszug
meines Scriptes:
gambas code
      For i = 1 To 350
        MySQL_RESULT = Global.MySQL.Exec("SELECT * FROM table WHERE id='" & i & "'")
        If MySQL_RESULT.Available = False Then
          Print "nicht gefunden"
        Endif
        Wait 0.0001
      Next
Ja, diese abfrage der MySQL muss in einer Schleife laufen, aber gibt es einen weg, der das beschleunigt?

Gruß

Benutzeravatar
tionov
Site Admin
Beiträge: 284
Registriert: So 18. Mai 2014, 22:40
Kontaktdaten:

Re: MySQL ROW in Schleife

Beitrag von tionov » Mi 1. Mai 2019, 15:51

Datenbankabfragen in Schleifen laufen zu lassen, ist grundsätzlich eine schlechte Idee. Und besonders hier, scheint mir. Was ist denn das, was du durch dieses Konstrukt erfahren möchtest? Kannst du mir sagen, was du da machen willst?

Ich meine, ich kann deinen Code schon lesen, aber den Sinn verstehe ich nicht.

Auf jeden Fall solltest du das, was du von der DB willst, in einer einzigen Abfrage holen und erst dann auswerten. In Mysql sollte es etwa so gehen:

"SELECT id FROM mytable WHERE id not BETWEEN 1 AND 350;"
Alles Gute,

4tionov

Bosko
Foriker
Beiträge: 25
Registriert: Sa 20. Apr 2019, 08:57
Kontaktdaten:

Re: MySQL ROW in Schleife

Beitrag von Bosko » Mi 1. Mai 2019, 17:34

also um genauer darauf einzugehen handelt es sich hierbei um eine SQL synchronisation,
von MySQL zu SQlite und dann SQlite zu MySQL, in der ersten instanz My -> lite klappt alles
ohne probleme und die geschwindigkeit ist top, wie oben das beispiel ist es lite -> My, die For
Schleife läuft die SQlite durch, die SQlite ID soll dann bei der MySQL abgefragt werden, ob dieser
Eintrag vorhanden ist, wenn nein, soll die Zeile in der SQlite gelöscht werden,
eigentlich klappt das auch, so wie oben in der abgespeckten Version, nur das
die geschwinfigkeit sich zu wünschen übrig lässt, komme mir vor die 56K Modem, kenne das von PHP
her das 350 Durchläufe keine Sekunde als ausgabe dauert, hier aber pro ID eine bis zwei SEkunden.

hoffe es ist verständlich was ich vor habe.

Benutzeravatar
tionov
Site Admin
Beiträge: 284
Registriert: So 18. Mai 2014, 22:40
Kontaktdaten:

Re: MySQL ROW in Schleife

Beitrag von tionov » Mi 1. Mai 2019, 20:20

Bosko hat geschrieben:
Mi 1. Mai 2019, 17:34
hoffe es ist verständlich was ich vor habe.
Ja, ist verständlich. Warum da Mysql so langsam ist, verstehe ich nun auch nicht. Kannst du mal ein
shell code
"SELECT id FROM table WHERE id='" & i & "';"
machen? Alternativ:
gambas code
MySQL_RESULT = Global.MySQL.Exec("SELECT count(id) as icount FROM table WHERE id='" & i & "';")

If MySQL_RESULT!icount = 0 then
     Print "nicht gefunden"
Endif

Und kannst du mal das Wait weglassen?
Alles Gute,

4tionov

Bosko
Foriker
Beiträge: 25
Registriert: Sa 20. Apr 2019, 08:57
Kontaktdaten:

Re: MySQL ROW in Schleife

Beitrag von Bosko » Do 2. Mai 2019, 05:58

Guten Morgen,

leider auch nicht, bei genau 362 durchläufen braucht das Script bei mehreren Test zwischen 29 und 35 Sekunden,
das eindeutig zu viel, um es besser zu verstehen hier mal der Code:

global.class gambas code
Static Public MySQL As New Connection
Static Public SQlite As New Connection

Static Public Procedure SQlite_Con(Optional SQlite_First As Boolean = False) As Boolean

  Dim SQlite_Type, SQlite_Host, SQlite_Name As String
  SQlite_Type = "sqlite3"
  SQlite_Host = User.Home &/ "KaS_POS/DB/"
  SQlite_Name = "KaS_POS.sqlite"
  
  If Exist(SQlite_Host & SQlite_Name) = False Then
    If IsDir(SQlite_Host) = False Then
      Mkdir SQlite_Host
    Endif
    SQlite.Type = SQlite_Type
    SQlite.Host = SQlite_Host
    SQlite.Name = ""
    SQlite.Open
    SQlite.Databases.Add(SQlite_Name)
    SQlite.Close
    Wait 0.5
  Endif
  SQlite.Close
  SQlite.Type = SQlite_Type
  SQlite.Host = SQlite_Host
  SQlite.Name = SQlite_Name
  SQlite.Open
  
  If Error Then
    Return False
  Else
    Return True
  Endif
  
Catch
  Return False
  
End

Static Public Procedure MySQL_Con(Optional MySQL_First As Boolean = False) As Boolean
  
  With MySQL
    Try .close
    .Type = "mysql"
    .Port = "3306"
    .Name = "db1*****"
    .Host = "*****.de"
    .Login = "dbusr*****"
    .Password = "sag_ich_nicht"
  End With
  
  Try MySQL.Open
  
  If Error Then
    'Print Error.Text
    Return False
  Else
    Return True
  Endif
Catch
  Return False
  
End

Static Public Sub Main()
  
  KaS_Start.show 
  
End
KaS_Start.class gambas code
Public Sub Form_Open()
  
  If Not Global.MySQL_Con(True) Then
    isMySQL = 0
  Endif
  If Not Global.SQlite_Con(True) Then
    Wait
  Endif
  
  StartProgram()
  
End

Private Sub StartProgram()
  Dim i As Integer
  Dim MySQL_RESULT, SQlite_RESULT As Result
  Dim DB_QUERY, sql_p_id As String
  
      SQlite_RESULT = Global.SQlite.Exec("SELECT * FROM KaS_POS_product;")
      SQlite_RESULT.MoveFirst
      For i = 0 To SQlite_RESULT.Count - 1
        ProgressBar1.Value = ProgressBar1.Value + ((1 / SQlite_RESULT.Count) / 2)
        KaS_Status.Text = "Bearbeite Datenbank Eintrag " & i & " von " & SQlite_RESULT.Count        
        MySQL_RESULT = Global.MySQL.Exec("SELECT count(id) as icount FROM pos_product WHERE id='" & SQlite_RESULT!id & "';")
        If MySQL_RESULT!icount = 0 Then
          Global.SQlite.Exec("DELETE FROM KaS_POS_product WHERE id='" & SQlite_RESULT!id & "';")
        Endif        
        SQlite_RESULT.MoveNext
        Wait 
      Next

End
Hier das wichtigste, solte so auch laufen, ist eine abgespreckte Version aber mit teilen drin warum ich z.B.
das WAIT brauche...
Ich weiß nicht warum die MySQL so lange braucht, auf dem Server läuft sie Schnell sowie im ersten Teil des
Scriptes (hier nicht zu sehen)...
Vielleicht habe ich ein Denk Fehler aber als PHP wird die MySQL geöffnet und dann die Query abgefragt, am
Script Ende wird die MySQL geschlossen, kann es sein, das hier bei jedem Durchlauf die MySQL geöffnet/geschlossen
wird, so schaut es für mich aus, sorry bin neuling mit Gambas ;)

Gruß

Benutzeravatar
tionov
Site Admin
Beiträge: 284
Registriert: So 18. Mai 2014, 22:40
Kontaktdaten:

Re: MySQL ROW in Schleife

Beitrag von tionov » Do 2. Mai 2019, 06:49

Setz mal den Profiler von Gambas an um genau festzustellen, wo da wirklich Zeit verbraucht wird. Debuggen->Profilierung aktivieren.

Nimm trotzdem mal die Wait raus. Wait braucht man eigentlich nur, um den Bildschirm zu zeichnen oder auf Klicks zu reagieren. Das hast du hier nicht. Wenn du mit Git versionierst kannst du einfach mal einen Testbranch machen und da rumspielen, ohne was kaputt zu machen.
Alles Gute,

4tionov

Bosko
Foriker
Beiträge: 25
Registriert: Sa 20. Apr 2019, 08:57
Kontaktdaten:

Re: MySQL ROW in Schleife

Beitrag von Bosko » Do 2. Mai 2019, 07:27

tionov hat geschrieben:
Do 2. Mai 2019, 06:49
Wenn du mit Git versionierst...
hmm, das Verstehe ich nun nicht was du mit Git meinst, in Gambas?

WAIT ist berechtig drin, da es eine GUI dazu gibt wo ein ProgressBar und Co. mit angezeigt werden, die mal der
Profiler, wo man sehen kann, das die SQL in der zweiten Instanz viel zu lange brauch...
Bildschirmfoto vom 2019-05-02 08-16-59.png
Bildschirmfoto vom 2019-05-02 08-16-59.png (204.09 KiB) 215 mal betrachtet
1* = MySQL For -> SQlite überprüfung
Läuft Schnell

2* = SQlite For -> MySQL überprüfung
Läuft lange

Bosko
Foriker
Beiträge: 25
Registriert: Sa 20. Apr 2019, 08:57
Kontaktdaten:

Re: MySQL ROW in Schleife

Beitrag von Bosko » Do 2. Mai 2019, 13:11

Hab nun mal ein bissel Rumgespielt, da ich hier im Forum was gefunden habe wegen DB Connect:

Dbs.modul gambas code
Public Db1 As New Connection
Public Db2 As New Connection

Public Sub _init()

  startconnections

End

Private Sub startconnections()

  If Not Db1.Opened Then
    Db1.Type = "sqlite3"
    Db1.Host = User.Home &/ "KaS_POS/DB/"
    Db1.Name = "KaS_POS.sqlite"
    Db1.Open()
  Endif
  If Not Db2.Opened Then
    Db2.Type = "mysql"
    Db2.Host = ""
    Db2.Name = ""
    Db2.Login = ""
    Db2.Password = ""
    Db2.Open()
  Endif

End
Main.Module gambas code
Public Sub Main()  
  
  Dim i As Integer
  Dim $con1, $con2 As Connection
  Dim row1, row2 As Result
  
  $con1 = Dbs.Db1
  $con2 = Dbs.Db2
  
  row1 = $con1.Exec("SELECT * FROM KaS_POS_product;")  
  row1.MoveFirst
  For i = 0 To row1.Count - 1
    row2 = $con2.Exec("SELECT count(id) as icount FROM pos_product WHERE id='" & row1["id"] & "';")
    row1.MoveNext
  Next
  
End
Läuft ausschliesslich unter der Konsole ohne Ausgabe, aber das ergebniss lässt sicch zu wünschen übrig:
Bildschirmfoto vom 2019-05-02 14-07-12.png
Bildschirmfoto vom 2019-05-02 14-07-12.png (29.24 KiB) 213 mal betrachtet
also dauert auch über 30 Sekunden bei 362 Einträgen, hmm

Benutzeravatar
tionov
Site Admin
Beiträge: 284
Registriert: So 18. Mai 2014, 22:40
Kontaktdaten:

Re: MySQL ROW in Schleife

Beitrag von tionov » Do 2. Mai 2019, 16:39

Der Code, den du gefunden hast, ist von mir. Das ist etwas eleganter, Connections aufzubauen, aber macht im Prinzip dasselbe wie dein Code.

Ist die Mysql DB remote, auf einem anderen Host? Greifst du übers Internet darauf zu oder läuft sie lokal auf der selben Maschine?

Mit Git meine ich, dass das Projektverzeichnis von Git versioniert ist, also einen Ordner .git enthält. Git ist superpraktisch, nicht nur in diesem Fall.
Alles Gute,

4tionov

Bosko
Foriker
Beiträge: 25
Registriert: Sa 20. Apr 2019, 08:57
Kontaktdaten:

Re: MySQL ROW in Schleife

Beitrag von Bosko » Do 2. Mai 2019, 18:46

Ja meine MySQL läuft auf ein Server Extern, habe nun mit XAMPP getestet und siehe da, es liegt an der Verbindung zum Server,
die Localen PHP Datein brauchen auch ewig zum Server über MySQL, also liegt es nicht am Script sondern an der Verbindung.

Schmeckt mir gar nicht... gibt es vllt eine lösung um die Geschwinfigkeit zu optimieren in den Prozessen....

Benutzeravatar
tionov
Site Admin
Beiträge: 284
Registriert: So 18. Mai 2014, 22:40
Kontaktdaten:

Re: MySQL ROW in Schleife

Beitrag von tionov » Do 2. Mai 2019, 19:19

Bosko hat geschrieben:
Do 2. Mai 2019, 18:46
Schmeckt mir gar nicht... gibt es vllt eine lösung um die Geschwinfigkeit zu optimieren in den Prozessen....
Ok. Da ist also dein Problem. Wir sind wieder am Beginn. Abfragen in Loops zu stellen, ist schlecht. Grund ist, dass eine Abfrage an die DB einen hohen Overhead mit sich bringt, der kaum sichtbar ist, wenn nur eine gestellt wird, aber massiv zum Tragen kommt, wenn in Loops viele hintereinander gefeuert werden. Das wird mit einem DB-Server hinter einer langsamen Verbindung naturgemäß noch schlimmer.

Warum willst du Sqlite lokal und Mysql remote syncen, wie viele Tuples (Datensätze) erwartest du und wie groß sind die Tuples?
Alles Gute,

4tionov

Bosko
Foriker
Beiträge: 25
Registriert: Sa 20. Apr 2019, 08:57
Kontaktdaten:

Re: MySQL ROW in Schleife

Beitrag von Bosko » Do 2. Mai 2019, 19:53

also, ich habe ein Warenwirtschaftssystem in PHP geschrieben, nun möchte ich dazu eine GUI erstellen,
die Online und Offline Arbeiten kann. Sollte keine Verbinung zur MySQL bestehen, greift das System auf
die SQlite zurück, diese wird bei Starten des Programmes immer überprüft ob neue Artikel vor handen
sind. Anders rum genauso, wenn ein Artikel (Offline), geändert, gelöscht oder ein neuer Angelegt wird,
wird dieser zur Haupt DB übertragen.

Daher läuft im der zweiten Instanz die schleife von SQlite, die die Daten zur MySQL überprüft...

Aktuell sind 362 Produkte drin und eigentlich sollen es noch mehr werden, das programm Sollte
schon 5k Produkte pro Sec verarbeiten können, da viele Daten nicht enthalten sind...

Benutzeravatar
tionov
Site Admin
Beiträge: 284
Registriert: So 18. Mai 2014, 22:40
Kontaktdaten:

Re: MySQL ROW in Schleife

Beitrag von tionov » Do 2. Mai 2019, 20:53

5k Tuples/sec kannst du nicht synchronisieren, wenn du keine Bandbreite hast. Bei 1KB pro Tuple brauchst du schon 5MB Bandbreite für Daten ohne Verwaltungs-Overhead. Dass Overhead viel Geschwindigkeit nimmt, hast du ja gerade erfahren.

Warum willst du eigentlich offline arbeiten? Das macht alles extrem viel schwerer. Hast du Clients in der Sahara oder Arktis? Doppelte Datenhaltung ist eine vertrackte Sache. Und Sync so vieler Daten beim Programmstart ... das ist definitiv keine gute Idee.

Du könntest theoretisch

... zur Laufzeit im Hintergrund syncen.
... intelligentere Methoden erarbeiten, Diffs zu entdecken und abzugleichen, z.B. mit errechneten Hashes über hunderte Tupel zugleich, um Unterschiede zu entdecken, usw ...
... dazu natürlich gescheite Datenbanken nehmen und nicht Sqlite und Mysql.

Aber ich wette, du kriegst immense Schwierigkeiten, wenn du mit mehreren Clients arbeitest. Relationale DB wurden dazu gemacht, dass eine DB im Zentrum sitzt und viele Clients daran arbeiten. Oder Multimaster, die sich syncen und jeweils viele Clients bedienen. Aber das Cachen von Daten ist da nicht vorgesehen. Das würde die relationale Integrität zerstören. Stelle dir vor ein Client löscht (offline) Daten, die ein anderer (offline) bei sich bearbeitet hat. Schon kracht alles zusammen.

Ich sage daher: Vergiss es. Jedenfalls das, was du da vorhast mit Sqlite und Mysql.
Alles Gute,

4tionov

Antworten

Wer ist online?

Mitglieder in diesem Forum: 0 Mitglieder und 0 Gäste