Avatar billede reason Nybegynder
20. august 2001 - 14:01 Der er 27 kommentarer og
2 løsninger

mm.mysql og performance

jeg har lavet en lille app der stå og skal opdateren en mysql server (som står på et andet netværk) over internettet. Mit problem er at det kører rimeligt langsomt og jeg har lokaliseret problemmet til den methoed der sender statements til mysql serveren. app\'en sender ca 200 statements (100 SELECT og 100 UPDATE/INSERT INTO på ca 35 s på en 256kbit/s ADSL - dette tog ca 55s på min 1xISDN)

nogle ide hvad det kan være?
er det pga forbindelsen, mm.mysql, eller ??
Avatar billede disky Nybegynder
20. august 2001 - 14:06 #1
Det kan være rigtigt mange ting, linie, belastning, dårligt design af database eller program, osv.
Avatar billede delbing Nybegynder
20. august 2001 - 14:25 #2
Prøv at pinge din server (i en dosprompt skriv \"ping \" efterfulgt af ip-addresse eller url).
Hver af dine select og update statements, samt hver ny række du kigger på, vil tage så lang tid. Lad os sige du kigger på i gennemsnit 5 rækker pr select, så er det 700*pingtid, lad os sige pingtiden er på 50 ms, vupti så har du dine 35 sekunder.
Hvis denne lille test og overslagsregning giver noget der nærmer sig de 35 sekunder, så er det vilkårene for at arbejde over nettet. Flyt serveren tættere på hvis det ikke er acceptabelt. Find ud af at skære ned på antallet af statements. Lav en applikation der står og kører på serveren - du sender opgaverne til den i et hug, den udfører dem, og sender den data du skal bruge tilbage. Det her er det samme som ekstern hukommelses algoritmer: antallet af overførsler er det eneste der i praksis tager nogen tid. Behandlingen af dataen tager forsvindende lidt tid i sammenligning
Avatar billede reason Nybegynder
20. august 2001 - 14:35 #3
nu kan jeg ikke lige pinge serveren pt men jeg kan sige at mine SELECT/UPDATE kun på virker 1 række hver
Avatar billede disky Nybegynder
20. august 2001 - 14:37 #4
som delbing siger er årsagen næsten med sikkerhed delay på nettet.

Den understreges af at isdn er langsommere, der er delaytiden nemlig længere.

Lav et program på din server, som læser en textfil og udfører de sql statements der skal laves.

Din maskine sender så denne textfil til serveren i et hug.

Det skulle speede det hele op til den tid det tager at sende textfilen.
Avatar billede delbing Nybegynder
20. august 2001 - 14:47 #5
reason: ok (hvor mange rækker UPDATE påvirker er for resten ligegyldigt, da der kun sendes et tal tilbage der siger hvor mange rækker der blev opdateret).
Dvs. at du har ca. 300 forespørgsler (100 Statement.executeQuery(), 100 ResultSet.next(), og 100 Statement.executeUpdate()). En pingtid på ca. 115 ms ville forklare tidsforbruget (hvis du da kan pinge den, hvad er årsagen til at du ikke kan pinge den?)
Avatar billede reason Nybegynder
20. august 2001 - 14:53 #6
delbing jeg kunne ikke pinge fordi jeg pinge den forkert server. her er ping tiden frad en rigtige server:

Reply from 213.129.19.165: bytes=32 time=40ms TTL=243
Reply from 213.129.19.165: bytes=32 time=20ms TTL=243
Reply from 213.129.19.165: bytes=32 time=20ms TTL=243
Reply from 213.129.19.165: bytes=32 time=20ms TTL=243

disky ok men jeg har ikke direkte adgang til serveren så det med at lave et program til serveren gå ikke.
Avatar billede disky Nybegynder
20. august 2001 - 14:54 #7
reason: så må du umiddelbart leve med den delay tid.
Avatar billede reason Nybegynder
20. august 2001 - 18:19 #8
ok så lad mig spørger på en anden måde
hvordan kan dette gøres bedre

  private void addDataToDB() throws SQLException, UnsupportedEncodingException, IOException {
    //update database
    String SQL=\"SELECT * FROM Province WHERE Name=\'\"+Name+\"\'\";
    ResultSet RS = stmt.executeQuery(SQL);

    String SQL2=\"\";
    if (RS.next()) {
      SQL2 = \"UPDATE Province SET \"+type+\"=\"+Value+\", Island=\"+Island+\", Kingdom=\"+Kingdom+\", Updated=1 WHERE Name=\'\"+Name+\"\'\";
    }
    else {
      SQL2 = \"INSERT INTO Province SET Name=\'\"+Name+\"\', Island=\"+Island+\", Kingdom=\"+Kingdom+\", \"+type+\"=\"+Value+\", Race=\"+Race+\", Updated=1\";
    }
    RS.close();
    stmt.executeUpdate(SQL2);
  }
Avatar billede disky Nybegynder
21. august 2001 - 09:13 #9
ud over jeg ikke kan lide din måde at sætte {}\'ere på er der ikke meget at gøre.

Problemmet er at din sql server er for langt væk.

Men du kan få et webhotel hos f.eks. www.levonline.com hvor de understøtter mysql, Jsp, servlets osv. Så slipper du helt for dit problem.
Avatar billede delbing Nybegynder
21. august 2001 - 11:05 #10
Dit problem er at du laver det serielt - bruger kun en connection, og står og venter på at den bliver færdig med hver forespørgsel, før du går i gang med den næste.
Du har helt klart et arkitektur-problem, men hvis du ikke har muligheden for at installere en applikation på serveren, kan det gøres bedre.
Bare lad alle forespørgslerne køre parallelt.
Indsættelsen af hvert væsen(?) håndteres af en ny Thread, som laver sin egen Connection og kun opdaterer sit eget væsen.
Hvis applikationen står og opdaterer tit er det nok en god ide at lave en ThreadPool og/eller ConnectionPool, da både Threads og Connections er resurser som der er stor gevinst i at genbruge, men det er en anden snak.
Avatar billede disky Nybegynder
21. august 2001 - 11:23 #11
jeg må give delbing helt ret.

Fyr dine sql\'ere af fra hver sin tråd, måske 10 af gangen.


Forresten er du ved at lave et turn based, rollespil ?
Avatar billede reason Nybegynder
21. august 2001 - 11:47 #12
nej det er til en turn baseret online spil der hedder utopia
http://games.swirve.com/utopia
Avatar billede reason Nybegynder
21. august 2001 - 11:49 #13
ok jeg prøver at skrive programmet om med nogle threads og nogle pools og ser om det hjælper
Avatar billede reason Nybegynder
21. august 2001 - 13:04 #14
hmm det hjælp ikke en skid at lave programmet multithreadet faktisk blev det langsommere (ca 50% langsommere)
Avatar billede disky Nybegynder
21. august 2001 - 13:09 #15
så har du ikke lavet det ordentligt :)

Hvordan har du opbygget det.

Avatar billede reason Nybegynder
21. august 2001 - 13:24 #16
ok jeg lavede den methoed addDataToDB() om til en class som \"extends Thread\" og den bruger jeg således

new addToDB(type, Name, Island, Kingdom, Race, Value).start();

Avatar billede disky Nybegynder
21. august 2001 - 13:27 #17
hmmm, og det er langsommere siger du ?

Du har husket at putte funktionaliteten ind i en run() metode ?


At det er langsommere forstår jeg ikke helt, understøtter mysql serveren multiple brugere ?
Avatar billede reason Nybegynder
21. august 2001 - 13:28 #18
package targetfinder;

import java.io.*;
import java.sql.*;

public class addToDB extends Thread {
  private String type, Name, Island, Kingdom, Value;
  private int Race;

  public addToDB(String type, String Name, String Island, String Kingdom, int Race, String Value) {
    this.type=type; this.Name=Name; this.Island=Island; this.Kingdom=Kingdom; this.Race=Race; this.Value=Value;
  }

  public void run() { // throws SQLException, UnsupportedEncodingException, IOException
    //update database
    //Database connection
    try {
      Class.forName(\"org.gjt.mm.mysql.Driver\");
    } catch(java.lang.ClassNotFoundException e) {
      System.out.println(\"ClassNotFoundException: \"+e.getMessage());
    }
    try {
      Connection con = DriverManager.getConnection(\"jdbc:mysql://mysql.kellberg.com:3306/kellberg?user=*&password=*\");

      Statement stmt = con.createStatement();

      String SQL=\"SELECT * FROM Province WHERE Name=\'\"+Name+\"\'\";
      ResultSet RS = stmt.executeQuery(SQL);

      String SQL2=\"\";
      if (RS.next()) {
        SQL2 = \"UPDATE Province SET \"+type+\"=\"+Value+\", Island=\"+Island+\", Kingdom=\"+Kingdom+\", Updated=1 WHERE Name=\'\"+Name+\"\'\";
      }
      else {
        SQL2 = \"INSERT INTO Province SET Name=\'\"+Name+\"\', Island=\"+Island+\", Kingdom=\"+Kingdom+\", \"+type+\"=\"+Value+\", Race=\"+Race+\", Updated=1\";
      }
      RS.close();
      //ResultSet RS2 = stmt.executeQuery(SQL2);
      stmt.executeUpdate(SQL2);
      stmt.close();
      con.close();
      RS = null;
      stmt = null;
      con = null;
      //RS2.close();
      //System.out.println(Name+\"\'s thread done\");
    } catch (Exception e) {
      System.out.println(\"\\nException: \"+e.getMessage());
      e.printStackTrace();
    }
  }
}
Avatar billede delbing Nybegynder
21. august 2001 - 13:28 #19
har hver tråd sin egen Connection? I din metode ser det ud til at den bruger en global Connection?
Avatar billede disky Nybegynder
21. august 2001 - 13:30 #20
lav thread og connection pooling,

og ikke for at være grov, men strukturer din kode lidt :)

Den konstruktør er temmeligt rodet, med alt på en linie
Avatar billede reason Nybegynder
21. august 2001 - 13:37 #21
delbing betyder Connection con = DriverManager.getConnection(\"jdbc:mysql://mysql.kellberg.com:3306/kellberg?user=*&password=*\");
ikke at jeg laver ny connection ?

>og ikke for at være grov, men strukturer din kode lidt :)
hvad mener du?

>Den konstruktør er temmeligt rodet, med alt på en linie
nu er den jo ikke så avanceret så det gør noget

Avatar billede disky Nybegynder
21. august 2001 - 13:40 #22
det er bare en dårlig vane at begynde på.

Og to som er lidt religion:

man starter ikke en variable med stort bogstav.
jeg bryder mig ikke om din måde at sætte tuborg på :) (meget religion)


og så er der ingen grund til:
      RS = null;
      stmt = null;
      con = null;

De objektet ryger ud af scope lige efter
     
Avatar billede delbing Nybegynder
21. august 2001 - 13:41 #23
reason: jo, du laver en ny connection, jeg så ikke  du havde lagt koden ind før jeg postede mit svar :)
Avatar billede delbing Nybegynder
21. august 2001 - 13:42 #24
Skriv din email, så sender jeg dig en ConnectionPool hvis du ikke har en.
Avatar billede reason Nybegynder
21. august 2001 - 13:45 #25
ok det med null var bare for at prøve (ville være helt sikker på de røg ud
mht det med {} så er det sådan de gør hos sun og jeg holder mig til deres religion : )

og det variable der begynder med stort er en smutter jeg har hugget fra en tutorial
Avatar billede reason Nybegynder
21. august 2001 - 13:47 #26
ok delbing men så skal jeg bruge en email addresse : )
Avatar billede reason Nybegynder
21. august 2001 - 13:48 #27
eller jeg kunne skrive min michael@kellberg.com
Avatar billede reason Nybegynder
22. august 2001 - 00:28 #28
hmm det connection pool ting virkede heller ikke så godt så jeg besluttede at gøre noget andet.
Jeg kunne ½ antallet af Update/Insert og det reducerede også tiden med ca 50%. Så langt så godt.

Men da det stadig ikke var godt nok så besluttede jeg at prøve noget andet. Jeg sletter hele databasen før jeg begynder på min update og bruger kun Insert Into og kan på den måde spare endnu 50% statements. Effekten af dette var dog lagt over de 50% da jeg nu er nede på 4-5 sek på 100 statements hvilket må siges at være pænt godt.

Anyway tak for hjælpen.
Avatar billede disky Nybegynder
22. august 2001 - 08:26 #29
reason:
Det er jo en god ting det går hurtigere :)
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview
Kategori
Kurser inden for grundlæggende programmering

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester