Avatar billede phliplip Nybegynder
07. marts 2007 - 15:12 Der er 7 kommentarer og
1 løsning

mysql: forbedring af SQL/metode til udtræk af meget data

Hej (My)SQL Eksperter,

Indledningsvis vil jeg lige starte med at give jer den funktion som jeg vil referere til:

function get_tracker_stats($sid, $pid, $stamps) {
  //create a DB object
  $db = new DB_Sql;

  if(is_array($stamps)) {
    foreach($stamps as $key => $stamp) {
      for($i = 1; $i <= 3; $i++) {
        $query = "SELECT count(tracker.id) AS clicks, count(tracker_return.id) as returns FROM tracker LEFT JOIN tracker_return ON (tracker.id=tracker_return.tracker_id AND tracker_return.status_id<'3'".(($sid > 0) ? " AND tracker_return.supplier_id='".$sid."'" : "").") WHERE tracker.status_id<'3'".(($sid > 0) ? " AND tracker.supplier_id='".$sid."'" : "")." ".(($pid > 0) ? " AND tracker.partner_id='".$pid."'" : "")." AND tracker.type_id='".$i."' AND tracker.timestamp>'".$stamp['start']."' AND tracker.timestamp<'".$stamp['stop']."'";
        $db->query($query);
        $row = $db->fa();
        $result[0][$key][$i] = $row['clicks'];
        $result[1]['total_clicks'] += $row['clicks'];
        $result[1]['total_returns'] += $row['returns'];
      }
      $result[0][$key]['start'] = $stamp['start'];
      $result[0][$key]['stop'] = $stamp['stop'];
    }
  }

  return $result;
}

Ovenstående funktion virker, men det foregår meget langsom!

$stamps som bliver givet som parameter er et array der indeholder start og stop unix timestamps. Functionen looper så det array igennem og forespørger databasen 3 gange for hver start/stop.

Dvs. at hvis jeg fx vil trække data ud for en hel måned er det 31 x 3 = 93 database kald.

Grunden til at der bliver loopet 3 gange for hver er fordi jeg har 3 mulige typer af data, og vil gerne have antal af hver type.

Jeg har kigget lidt på UNION, men hvis jeg får det til at spille, ville det så give performance da den alt afhængig af hvordan jeg får det lavet kalder databasen enten 31 eller 1 gang.

Alle input er velkomne!

Mvh. Philip
Avatar billede phliplip Nybegynder
07. marts 2007 - 15:15 #1
Har lige gjort SQL'en lidt mere overskuelig for jer;


SELECT
  count(tracker.id) AS clicks,
  count(tracker_return.id) as returns
FROM
  tracker
LEFT JOIN
  tracker_return
ON
    (tracker.id=tracker_return.tracker_id
  AND
    tracker_return.status_id<'3'".(($sid > 0) ? "
  AND
    tracker_return.supplier_id='".$sid."'" : "").")
WHERE
  tracker.status_id<'3'".(($sid > 0) ? "
AND
  tracker.supplier_id='".$sid."'" : "")." ".(($pid > 0) ? "
AND
  tracker.partner_id='".$pid."'" : "")."
AND
  tracker.type_id='".$i."'
AND
  tracker.timestamp>'".$stamp['start']."'
AND
  tracker.timestamp<'".$stamp['stop']."'
Avatar billede erikjacobsen Ekspert
07. marts 2007 - 15:18 #2
Een sql-sætning skulle være nok.

1) Du fjerner: AND tracker.type_id='".$i."'
2) Du laver timestamp intervallet fra første til sidste sekund i måneden

Derefter løber du hele resultatet igennem og anbringer de rigtig steder i dine arrays, med PHP-kode.

Ok - det var kun en skitse. Jeg synes bare det var synd for din database ;)
Avatar billede phliplip Nybegynder
07. marts 2007 - 15:20 #3
erik:

Ja.. sådan var det også tidligere... men fik en memory overflow sidst på måneden!
Avatar billede phliplip Nybegynder
07. marts 2007 - 15:21 #4
Eller.. kan ikke lige huske hvad det hedder ;) Men det der hvor der i hvertfald ikke er mere hukomelse tilrådighed :P

^^ Kan være jeg har fået sådan en eftersom jeg ikke kan huske det !-)
Avatar billede phliplip Nybegynder
07. marts 2007 - 15:32 #5
Argh... prøver sq at tage lidt af det gamle og lidt af det nye ;) Tror jeg har fundet noget der godt kunne æde en del hukkommelse!
Avatar billede erikjacobsen Ekspert
07. marts 2007 - 15:44 #6
Problemet er nu nok det der timestamp.

Du bruger det til at identificere datoen, men det kan SQL ikke bruge til at finde datoen. Hvis du havde et felt yderligere, som var datoen,  '2007-03-07', så ville du kunne lave en GROUP BY på datoen, indenfor den måned du vælger. Så får du kun ca. 90 rækker ud.  Jeg vil ikke anbefale dig at begynde at regne på timestamp for at finde datoen - det sløver.
Avatar billede jbone1 Nybegynder
07. marts 2007 - 22:57 #7
Jeg vil ellers anbefale at man altid bruger integer (unixtime) når der rodes med potentielt mange date ... så som logs.
Fordi det internt i mySql serveren er hutigere at arbejde med numre end datoer og samtidigt sparer du plads.
Avatar billede phliplip Nybegynder
08. marts 2007 - 14:43 #8
Jeg fik det til at virke og kører super hurtigt ;)

Smeltede noget af det gamle sammen med noget af det nye.

Den gamle funktion hentede faktisk alle records ned i et collector array og returnerede det.. hvorefter det array blev loopet igennem og regnet på. Nu laver den udregningerne i den while() der looper recordset'et igennem og returnerer de beregnede data.
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
Computerworld tilbyder specialiserede kurser i database-management

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