16. april 2013 - 11:01Der er
11 kommentarer og 1 løsning
Problemer når script kaldes samtidig - kan tabel reserves
Hejsa. Jeg har et script som har en afviklingstid på 4-5 sekunder. Der sker følgende: 1. Tjek MySQL, hvornår der sidst er gemt en post. 2. Er der sidst gemt for mere end 10 minutter siden, så hent nogle målerværdier fra ekstern site. Denne del tager ca. 4-5 sekunder 3. Skriv værdierne ned i tabellen.
Mit problem er, at mit script kan blive kaldt flere gange inden for afviklingstiden på 4-5 sekunder, og så afvikles punkt 2 og 3 dobbelt eller 3-dobbelt.
Er det muligt under punkt 1, at "reservere" tabellen og frigive den igen under punkt 3.
Min forespørgsel under punkt 1, ser sådan her ud:
if ($stmt = $mysqli->prepare('SELECT COUNT(*) as `antal` FROM `maalere` WHERE DATE_ADD(`datetime`, INTERVAL 10 MINUTE) >= NOW() AND `server` = ?')) {
Jeg bruger PHP og er blevet inspireret af oleboles guide til MySQLi. Scriptet ligger på et alm. webhotel, Wannafind.
Interessant, men er det INSERT INTO, der blot venter eller er det også min SELECT under punkt 1. Løsningen skal gerne være, at SELECT også afventer opdateringen af den første programafvikling, således SELECT i 2. kørsel fanger, at der lige er gemt en post.
Man skal normalt ikke bruge LOCK TABLES, men jeg synes at kunne læse, at du har et par processer, der kommer regelmæssigt, men kan risikere at ramme oven i hinanden. Så går det nok.
Jeg er ret sikker på at Facebook ikke låser tabellerne, når der kommer een opdatering ...
Tak for din gode tips. Jeg kan jo også vælge, at lave et trin 2½, hvor jeg laver samme tjek som i trin1, da dette kald tager millisekunder.
Men jeg har lige et spørgsmål til trin3, som måske også kan løse det.
Når jeg skriver til tabellen med INSERT INTO, kan jeg så på en eller anden måde få "WHERE DATE_ADD(`datetime`, INTERVAL 10 MINUTE) >= NOW()" med, så der kun indsættes, hvis sidste post er mere end 10 minutter gammelt?
Umiddelbart lyder en write låsning af tabellen som en udmærket ide til at sikre, at andre sessions ikke kan ændre i tabellen i fremfindings-tidsrummet.
Men det vil også betyde, at tabellen samtidig ikke kan læses til andre formål. Jeg ved selvfølgelig ikke, om det er relevant, men det kunne jo være, at du f.eks. havde en side, hvor du godt ville kunne vise indholdet af tabellen selv om der var en insert undervejs.
Et forslag kunne være at indføre en slags semafor tabel med 1 row og 1 boolean felt, hvor man opdaterer med opdateringsstatus. Denne opdateringsstatus skal så tjekkes for at se, om andre sessioner allerede er i gang med at opdatere/tilføje målinger. Det vil så betyde, at forløbet skal ændres lidt:
1) SELECT mus.updating FROM maalerupdatestatus mus WHERE mus.updating=0 AND NOT EXISTS (SELECT * FROM maalere WHERE DATE_ADD(datetime, INTERVAL 10 MINUTE) >= NOW() AND server = ?) 2) Hvis selecten returnerer en record/row, så skal der: 2a) UPDATE maalerupdatestatus SET updating = 1 2b) Hent ny måling 2c) INSERT INTO maalere 2d) UPDATE maalerupdatestatus SET updating = 0
Indrømmet, der er flere steps og umiddelbart vil det måske synes lidt omstændeligt, men det har også sine fordele.
Du har i din select også et kriterie på et felt der hedder server. Hvis det betyder, at der kan være flere servere der skal hentes data fra, så skal du nok også have det samme felt inkluderet i semafor-tabellen og så have en row for hver server i denne. Det vi så også ændre ovenstående lidt:
1) SELECT mus.updating FROM maalerupdatestatus mus WHERE mus.updating=0 AND server = ? AND NOT EXISTS (SELECT * FROM maalere WHERE DATE_ADD(datetime, INTERVAL 10 MINUTE) >= NOW() AND server = mus.server) 2) Hvis selecten returnerer en record/row, så skal der: 2a) UPDATE maalerupdatestatus SET updating = 1 WHERE server = ? 2b) Hent ny måling 2c) INSERT INTO maalere .... 2d) UPDATE maalerupdatestatus SET updating = 0 WHERE server = ?
Vær også opmærksom på, at hvis der sker et nedbrud mellem punkt 2a og 2d, vil det kunne forhindre yderligere indsætning. Den risiko vil dog kunne elimineres ved at køre punkterne 2a - 2d som en transaktion, således at ændringer maalerupdatestatus mv. bliver rullet tilbage ved fejl.
Disclaimer: Jeg har ikke testet noget af dette. Det er alene tanker som du selv kan arbejde videre med. Mit kendskab til mySQL er desuden begrænset, så der kan sagtens være ting jeg overser.
Hvis ikke SELECT er i samme transaktion som resten og transaction isolation level >= repeatable read og InnoDB tabel, saa blokerer den logik ikke noedvendigvis for samtidige opdateringer.
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.