Hallo,

Een website die ik gemaakt hebt ik gehost bij een redelijk bekende hosting. Nu kreeg ik vandaag een e-mail, dat een bepaald script 50% CPU gebruikt van de MySQL-server.
Wat kan ik als oplossing gebruiken? De query is:


SELECT *, naam.id as pers_id, plaatsen.naam as plaatsnaam, MID(geboortedatum,7,4) as gjaar FROM naam, plaatsen WHERE achternaam REGEXP '^(achternaam)$' && voornaam like '%'  AND naam.plaats = plaatsen.id  AND ((MID(geboortedatum,7,4) <= 2000 AND MID(geboortedatum,7,4) >= 1880) OR (MID(geboortedatum,1,4) <= 2000 AND MID(geboortedatum,1,4) >= 1880)) AND geboortedatum != '' 


Er is vast en zeker een beter en snellere manier voor deze query. Waar waarschijnlijk de meeste CPU vreter zit is: MID(geboortedatum,1,4)

De query haalt uit drie of soms vier verschillende tabellen zijn gegegens.
Steffan
Ik vind je QUERY wel wat vreemd:


SELECT
ster,
naam.id AS pers_id,
plaatsen.naam AS plaatsnaam, MID(geboortedatum,7,4) AS gjaar
FROM
naam,
plaatsen
WHERE
achternaam REGEXP '^(achternaam)$'
&&
voornaam LIKE '%'
AND naam.plaats = plaatsen.id
AND ((MID(geboortedatum,7,4) <= 2000
AND MID(geboortedatum,7,4) >= 1880)
OR (MID(geboortedatum,1,4) <= 2000
AND MID(geboortedatum,1,4) >= 1880))
AND geboortedatum != ''

ik snap het renamen niet waarom noem je de tabellen niet gewoon zo? Renamen doe je met name bij functies als SUM() en COUNT() ed En je vraagt alles met * dat neemt ook veel rekenkracht van de CPU
Dit heb ik gedaan, omdat ik bij het maken van de tabellen niet nagedacht heb over dubbele namen. Dus 'naam' komt 2 keer voor, in twee tabellen.
En moet je naam en plaatsen niet aan elkaar knopen?
Zo krijg je toch bij elke naam alle plaatsen?

EDIT ik zie het zo voor me dat je bij elke naam weet welke plaats erbij hoort dus dat in de tabel namen een veld voorkomt met plaat_id.
en in de tabel plaatsen komt deze natuurlijk ook voor en je voegt iets toe aan je QUERY als:

AND
plaatsen.plaats_id=namen.plaats_id
Volgens mij heb jij niet mijn hele sql:
SELECT *, naam.id as pers_id, plaatsen.naam as plaatsnaam, MID(geboortedatum,7,4) as gjaar FROM naam, plaatsen WHERE achternaam REGEXP '^(achternaam)$' && voornaam like '%' AND naam.plaats = plaatsen.id AND ((MID(geboortedatum,7,4) <= 2000 AND MID(geboortedatum,7,4) >= 1880) OR (MID(geboortedatum,1,4) <= 2000 AND MID(geboortedatum,1,4) >= 1880)) AND geboortedatum != ''
Je hebt gelijk het staat er wel in. Dan blijft alleen de * over
Wat ik gedaan heb is het volgende:

- De achternaam regexp verwijderd, Jelmer zei dat dit een CPU vreter is.
- MID(geboortedatum...) is verwijderd.

Ook heb ik wat 'parse time' testen gedaan. Voor deze aanpassingen was de gemiddelde parse tijd vijf seconden, na deze aanpassingen ligt deze tijd ver onder de één seconde.

[edit]De tijd loopt weer erg voor 8-9 minuten
@Steffan ik zie niet dat Jelmer dat zei LOL
Via IRC op

/server irc.chat4all.org
/join #phphulp

:P:P
Je gebruikt een hele reeks AND's na elkaar met zomaar ineens een OR ertussen. Dat is vragen om moeilijkheden. Een OR tussen een serie AND's zorgt er meestal voor dat de hele expressie altijd TRUE is dus levert altijd het maximale aantal resultaten.

Verder gebruik je de * operator die, zoals gezegd, niet aan te raden is. De MID funktie op een datum loslaten is ook niet slim. Er zijn in MySQL heel handige datumfuncties die je beter kunt gebruiken. Zie de handleiding.
De hele MID functie is verwijderd, dus dat zijn al twee dingen.

De operator * zal ik veranderen.

En wat betreft die datum functies, dat is nu wat lastiger. Dat datums worden namelijk opgeslagen als varchar, maar verander ik nu ook.


Misschien verander ik de hele database-structuur wel, maar daar moet ik eens goed voor gaan zitten. Dat doe ik niet in deze hitte.

Reageren