Segt Php mysql script för skapande av ett diagram

Permalänk
Medlem

Segt Php mysql script för skapande av ett diagram

Hej!

Jag har en egenhemsida där jag använder php och mysql för att få fram de senaste 30 dagarnas elförbrukning per dag.

Detta visar jag i ett stapeldiagram men jag har upptäckt att det tar väldigt lång tid för webservern att skapa detta diagram och jag undrar om det går att förbättra mitt mysql anrop.

Jag har kommit fram till att det är denna while loop som tar tid att köra. Nu vet jag att många inte gillar att felsöka andras kod men jag har lyckat lokalisera problemet till dessa kodrader:

$i = 31; while ( $i >= 1) { $tempdata = @mysql_query("SELECT countvalue,date FROM count_tb WHERE DATE(date) = DATE_SUB(CURRENT_DATE, INTERVAL $i DAY)"); $row = @mysql_fetch_array($tempdata); $ini = $row['countvalue']; $timestamp = $row['date']; $sec = $i - 1; $tempdata = @mysql_query("SELECT countvalue,date FROM count_tb WHERE DATE(date) = DATE_SUB(CURRENT_DATE, INTERVAL $sec DAY)"); $row = @mysql_fetch_array($tempdata); $fin = $row['countvalue'];

Det jag hämtar från databasen är alltså två stycken heltal och två tidsstämplar och detta görs 30 gånger.

Kan inte förstå att denna loop skall ta sådan tid att köra. Jag har andra script som hämtar betydligt mer information från databasen där väntetiden typ mindre än en sekund. Här får jag vänta upp till 5-6 sek. Vilket är lång för en startsida.

Hälsningar/Berga

Permalänk
Inaktiv

Försök att hämta allt i en query istället, nu kör du 61st.

Dessutom ändrar du aldrig värdet på $i så det blir en oändlig loop, lite kod som försvunnit kanske?

Permalänk
Medlem

Jag tog bort största delen av koden efter att ha felsökt själv. Därför är inte $i++ med.

Hehe, skall man försöka sträva efter så få "query's" som möjligt? Antar att detta kan speeda upp de hela. Men jag har programmerat så tidigare vilket har fungerat bra.

De smidiga med att köra flera querys är ju att jag endast behöver hämta det första/sista talet för just den dagen. (Jag lagrar ett tal var tredje minut i tabellen. Vilket blir en jäkla massa tal per dag.) Det är så jag räknar ut dagens totala elförbrukning.

Permalänk
Inaktiv
Skrivet av Berga:

Hehe, skall man försöka sträva efter så få "query's" som möjligt? Antar att detta kan speeda upp de hela. Men jag har programmerat så tidigare vilket har fungerat bra.

Ja, hade jag sett någon som gör flera Querys när det inte behövts hade deras kod inte fått vara med. Det tar jättelång tid att göra en förfrågan mot databasen (kanske kan ta upp till en sekund om du har otur), men databasen i sig är jättesnabb på att göra saker på sin sida. Det tar säkerligen mycket längre tid att hämta tusen element ur 10 tabeller med en fråga än att hämta 2 element ur 2 tabeller med 2 frågor

Så antingen lägger du upp alla data smartare i databasen, eller så ställer du frågan smartare. Det kan vara bra att lära sig lite om exempelvis joins.

Permalänk
Hedersmedlem

Instämmer med att du bör försöka minimera antalet databasanrop. Utöver JOINs så kan databasen i sig oftast genomföra en del beräkningar "på plats" så att man inte behöver överföra data för att direkt behöva manipulera denna, men det beror på applikation. Det är ingen överraskning att databaser ofta kan vara effektiva på att manipulera just data.

Du skulle också kunna snabba upp hanteringen genom att inte använda det i praktiken utdaterade `mysql`-biblioteket, utan övergå till `mysqli` eller `pdo`. Se Choosing an API [php.net] för mer information. Då får du s k "prepared statements" på köpet. Jag har funnit hastighetsskillnaden vara betydande även i rätt enkla fall (även om det kanske inte handlat om storleksordningar).

I detta fall så kan du kanske antingen se till att låta databasen räkna ut de relevanta siffrorna direkt att ge dig, eller så kan du göra ett stort anrop till databasen som ger dig datan att manipulera inifrån PHP. Att göra multipla små anrop är som nämnts ofta ett sätt att sänka prestanda.

Visa signatur

Nu med kortare användarnamn, men fortfarande bedövande långa inlägg.

Permalänk
Medlem

Så få anrop som möjligt verka vara grejen! Gårdagens stora lärdom.

mysqli säger du, är de alltså ett förbättrat bibliotek som går att använda på befintlig MySql databas? (med tillräckligt ny version installerad på servern).

Hur bearbetar ni enklast stora mängder information i php då? Loopar ni igenom hela "matrisen" och plockar ut de nödvändiga. Jag har ca 144000 rader och skall endast använda ca 60st rader.

Permalänk
Medlem
Skrivet av Berga:

Så få anrop som möjligt verka vara grejen! Gårdagens stora lärdom.

mysqli säger du, är de alltså ett förbättrat bibliotek som går att använda på befintlig MySql databas? (med tillräckligt ny version installerad på servern).

Hur bearbetar ni enklast stora mängder information i php då? Loopar ni igenom hela "matrisen" och plockar ut de nödvändiga. Jag har ca 144000 rader och skall endast använda ca 60st rader.

Loopa igenom 144000 rader och välja ut med PHP, jadu, har man oändligt med hårdvaruresurser och inte vet vart man skall göra åt allt så visst, men nej, man hämtar ju självklart bara dom raderna man vill ha från databasen innan man överhuvudtaget tänker på att låta PHP använda dom.

Visa signatur

Hur kan syltkakor överleva i det vilda utan ögon?

Permalänk
Medlem

Hehe..sant, får ursäkta mitt hjärnsläpp. Naturligtvis får jag försöka göra ett smart anrop dvs anropa de ca 60 raderna och loopa igenom dessa sedan.

Rätt så intressant detta, hur man kan optimera koden så att datorn arbetar med effektivt. Tack för hjälpen alla.

Permalänk
Medlem
Skrivet av Berga:

Så få anrop som möjligt verka vara grejen! Gårdagens stora lärdom.

mysqli säger du, är de alltså ett förbättrat bibliotek som går att använda på befintlig MySql databas? (med tillräckligt ny version installerad på servern).

Hur bearbetar ni enklast stora mängder information i php då? Loopar ni igenom hela "matrisen" och plockar ut de nödvändiga. Jag har ca 144000 rader och skall endast använda ca 60st rader.

Om du hela tiden vill ha de 60 senaste posterna i databasen och du har 144000 rader så kan du göra på flera sätt:
Använd dig av ORDERBY och LIMIT för att välja de 60 senaste. Kan bli långsamt beroende på databasens storlek.

Varje gång du sätter in data i databasen så kan du köra ett script som sparar de 60 senaste raderna i en egen tabell. Sen behöver du bara välja alla rader i den nya tabellen. Rekommenderar den här metoden

Det här är ytterligare ett sätt att göra på:

SELECT * FROM [din-tabell] WHERE [id] > (SELECT MAX([id]) - 60 FROM [din-tabell])

Det förutsätter att du har ett index på ID.

Permalänk
Medlem
Skrivet av joss:

Om du hela tiden vill ha de 60 senaste posterna i databasen och du har 144000 rader så kan du göra på flera sätt:
Använd dig av ORDERBY och LIMIT för att välja de 60 senaste. Kan bli långsamt beroende på databasens storlek.

Varje gång du sätter in data i databasen så kan du köra ett script som sparar de 60 senaste raderna i en egen tabell. Sen behöver du bara välja alla rader i den nya tabellen. Rekommenderar den här metoden

Det låter ju jäkligt smart att ha ett tabell färdig, redo att användas. Då behöver ju inte servern arbeta med detta när sidan skall läsas i webbläsaren.

Jag inte varit så tydligt med vad jag skall göra för anrop. Jag skall anropa databasen efter 30st rader. En rad per dag de senaste trettio dagarna dvs första raden skapad för varje dygn. Detta ger alltså raden som är närmast tolvslaget de senaste trettio dygnen. Jag använder mig av tidstämpeln för att hitta dessa.

Får se om jag lyckar klura ut det innan någon annan gör det.

Permalänk
Medlem

Jag löste det snabbast. (Googlade och hittade ett bra anrop som jag modifiera lite)

Vette fasen vad jag har gjort men detta gjorde susen. Det här med joins verka vara ovärdeligt.

Där
countvalue är ett lagrat heltal i tabellen
count_tb är tabellen
date är tidstämpeln
B är nyskapad tabell

SELECT B.countvalue,date FROM ( SELECT DATE(date) date_dt,MIN(date) date FROM count_tb WHERE DATE(date) >= DATE_SUB(CURRENT_DATE, INTERVAL 30 DAY) AND DATE(date) < DATE(CURRENT_DATE) GROUP BY DATE(date) ) A LEFT JOIN count_tb B USING (date)

Permalänk
Hedersmedlem
Skrivet av Berga:

Det låter ju jäkligt smart att ha ett tabell färdig, redo att användas. Då behöver ju inte servern arbeta med detta när sidan skall läsas i webbläsaren.

Jag inte varit så tydligt med vad jag skall göra för anrop. Jag skall anropa databasen efter 30st rader. En rad per dag de senaste trettio dagarna dvs första raden skapad för varje dygn. Detta ger alltså raden som är närmast tolvslaget de senaste trettio dygnen. Jag använder mig av tidstämpeln för att hitta dessa.

Får se om jag lyckar klura ut det innan någon annan gör det.

Ett annat sätt som du enkelt skulle kunna göra detta på är att ha ett skript som körs automatiskt vid midnatt varje dag och genererar en statisk bildfil som sedan serveras direkt till användare. Då kommer du bara behöva köra den "jobbiga" beräkningen en gång om dagen, och ingen användare kommer ens märka den tid det tar att generera bilden. Om datan är så statisk som den verkar så skulle jag snarast rekommendera detta som ett enkelt sätt att helt ta bort prestandaproblematiken.

Visa signatur

Nu med kortare användarnamn, men fortfarande bedövande långa inlägg.

Permalänk
Medlem
Skrivet av phz:

Ett annat sätt som du enkelt skulle kunna göra detta på är att ha ett skript som körs automatiskt vid midnatt varje dag och genererar en statisk bildfil som sedan serveras direkt till användare. Då kommer du bara behöva köra den "jobbiga" beräkningen en gång om dagen, och ingen användare kommer ens märka den tid det tar att generera bilden. Om datan är så statisk som den verkar så skulle jag snarast rekommendera detta som ett enkelt sätt att helt ta bort prestandaproblematiken.

Jag löste prestandaproblematiken med anropet ovan men beroende på hur hemsidan utvecklar sig så kanske jag lägger denna beräkning separat i framtiden.

Jag ett liknande script där istället för att anropa den första raden som skapades under det senaste 30 dygnen så anropar jag första skapade raderna de senaste 12 månaderna.

Jag funderar på att göra ett anrop där jag utnyttjar verktyget JOIN. Jag vet inte hur jag skall skapa en temporär tabell som min tabell matchas mot.

Vad jag fattar för så skapas en tabell i anropet ovan enligt:

2013-06-22 00:00:00 . . . 2013-07-19 00:00:00 2013-07-20 00:00:00 2013-07-21 00:00:00 2013-07-22 00:00:00

Det jag försöker skapa nu är ett tabell enligt nedan:

2012-05-01 00:00:00 . . 2013-04-01 00:00:00 2013-05-01 00:00:00 2013-06-01 00:00:00 2013-07-01 00:00:00

Är det någon som har något tips hur man gör detta? Det skapas ju inte en tabell i själva databasen utan endast under anropet vad jag förstår.

Permalänk
Medlem
Skrivet av Berga:

Jag löste prestandaproblematiken med anropet ovan men beroende på hur hemsidan utvecklar sig så kanske jag lägger denna beräkning separat i framtiden.

Jag ett liknande script där istället för att anropa den första raden som skapades under det senaste 30 dygnen så anropar jag första skapade raderna de senaste 12 månaderna.

Jag funderar på att göra ett anrop där jag utnyttjar verktyget JOIN. Jag vet inte hur jag skall skapa en temporär tabell som min tabell matchas mot.

Vad jag fattar för så skapas en tabell i anropet ovan enligt:

2013-06-22 00:00:00 . . . 2013-07-19 00:00:00 2013-07-20 00:00:00 2013-07-21 00:00:00 2013-07-22 00:00:00

Det jag försöker skapa nu är ett tabell enligt nedan:

2012-05-01 00:00:00 . . 2013-04-01 00:00:00 2013-05-01 00:00:00 2013-06-01 00:00:00 2013-07-01 00:00:00

Är det någon som har något tips hur man gör detta? Det skapas ju inte en tabell i själva databasen utan endast under anropet vad jag förstår.

Det borde bara vara att byta
DATE_SUB(CURRENT_DATE, INTERVAL 30 DAY)
till
DATE_SUB(CURRENT_DATE, INTERVAL 1 YEAR)

Visa signatur

He who hasn't hacked assembly language as a youth has no heart. He who does so as an adult has no brain.
~John Moore

Permalänk
Medlem

Nja inte riktigt. De jag försöker åstadkomma är att hämta första skapade raden i varje månad. 12 månader bakåt dvs.

2012-05-01 00:00:00 . . 2013-04-01 00:00:00 2013-05-01 00:00:00 2013-06-01 00:00:00 2013-07-01 00:00:00

Använder jag

SELECT B.countvalue,date FROM ( SELECT DATE(date) date_dt,MIN(date) date FROM count_tb WHERE DATE(date) >= DATE_SUB(CURRENT_DATE, INTERVAL 1 YEAR) AND DATE(date) < DATE(CURRENT_DATE) GROUP BY DATE(date) ) A LEFT JOIN count_tb B USING (date)

ger detta den första skapade raden för varje dygn, ett helt år tillbaka från nu. Resultatet blir 365st anropade rader.

Så de är lite klurigare.

Permalänk
Medlem

ah, ok
testa:

WHERE DATE(date) >= DATE_SUB(CURRENT_DATE, INTERVAL 1 YEAR)
AND DAYOFMONTH(date) = 1

Visa signatur

He who hasn't hacked assembly language as a youth has no heart. He who does so as an adult has no brain.
~John Moore

Permalänk
Medlem

Se där, det fungerade bra! Tackar.

Verkar som man får ta å läsa på lite kring datum funktioner och temporära tabeller samt join funktionen.