Ik heb een table waarin prijzen staan met meerdere artikelnummers (ean codes).
Als dit artiekel 1 keer voorkomt, wil ik de rijen verwidjeren, dus ik doe:
$deld = mysqli_query($DBD->conn(),"SELECT *, count(ean) as TEL FROM `pro_pr_spec` group by ean HAVING count(*) = 1") or die (mysqli_error($DBD->conn()));
while ($ppp = mysqli_fetch_array($deld))
{
$th = mysqli_query($DBD->conn(),"DELETE FROM pro_pr_spec WHERE pid = '".$ppp['pid']."'") or die (mysqli_error($DBD->conn()));
}
Dit werkt wel, maar gewoon veels te langzaam, terwijl ik de kolommen geindexeert heb.
Heb je al eens een EXPLAIN op beide queries gedaan, zodat je precies kunt bepalen wat er zoveel tijd kost? Mogelijk is het de count(*)? Waarom gebruik je dat? Je hoeft ook niet alles te selecteren, enkel een id is genoeg? Je zou dus beter COUNT(<id_veld>) AS aantal kunnen gebruiken? En vervolgens simpelweg HAVING aantal = 1 kunnen gebruiken.
En dit zou je vervolgens in een subquery kunnen stoppen, zodat je maar 1 query nodig hebt, in plaats van een loop. Maar ook dat moet je op de juiste manier doen. Mogelijk kun je de volgende constructie gebruiken.
Als er een loop in je code staan waarbinnen queries worden uitgevoerd, dan is dit in ieder geval vaak een indicatie dat er iets mis is.
Queries zijn relatief dure operaties. Dus hoe minder hoe beter.
Op het moment dat code een loop bevat met daarin een query-aanroep, dan heeft dat het potentiële gevaar dat op den duur het totaal aantal queries (explosief) oploopt als de loop -om wat voor reden dan ook- langer wordt. Dit kan vervolgens weer een sneeuwbaleffect veroorzaken op het moment dat meerdere gebruikers een pagina met een dergelijke aanpak opvragen. Deze constructie is dus niet goed schaalbaar. Daarom zou je dit te allen tijde moeten vermijden en zou er een alarmbel moeten gaan rinkelen als je dit ergens tegenkomt.
En uiteraard kosten minder queries altijd (per definitie :p) minder tijd. Dit neemt niet weg dat je queries altijd op efficiëntie zou moeten testen. Er hoeft namelijk maar één brakke query tussen te zitten en dat maakt dan alles traag.
Misschien is het voor de kijkers thuis ook interessant om te vertellen welke query hier uiteindelijk is uitgerold, met misschien een kanttekening over eventueel toegevoegde indexes of andere structuurwijzigingen die je hebt aangebracht.
ten eerste denk ik dat de query niet helemaal klopt:
Dat zou iets moeten zijn als
SELECT ean
FROM pro_pr_spec
GROUP BY ean
HAVING COUNT(1) = 1
>> alle kolommen die niet in de aggregatie functie(s) staan, horen in GROUP BY genoemd te worden. "SELECT *" in combi met GROUP BY is vrijwel altijd fout. Al klaagt Mysql pas als je hem wat strikter dan default instelt.
Ten tweede:
dit zou ook in 1 query kunnen.
Bijvoorbeeld:
DELETE FROM pro_pr_spec
WHERE ean IN (
SELECT ean
FROM pro_pr_spec
GROUP BY ean
HAVING COUNT(1) = 1
)
Al ben ik geen fan van deze constructie: veel waarden in het stukje "in (subquery)" maakt het traag.
bovendien wil mysql dat in tegenstelling tot andere databases niet doen, omdat gelijktijdig geselecteerd en aangepast wordt op 1 query. Een Temp table zou dan uitkomt brengen.
Mooiste is echter een join:
DELETE pro_pr_spec FROM pro_pr_spec
JOIN (SELECT ean
FROM pro_pr_spec GROUP BY ean HAVING COUNT(1) = 1) AS magweg
ON pro_pr_spec .ean = magweg.ean