07. marts 2007 - 15:12Der 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.
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']."'
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.
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.
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.
Synes godt om
Ny brugerNybegynder
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.