mmofacts.com

Tbl sperren für user während aufrufzeit

gepostet vor 18 Jahre, 8 Monate von None
hi,

ich wollte mal fragen, ob es notwendig ist, die tabellen so zu sperren, dass nur 1 user gleichzeitig den inhalt der php datei berechnen lassen kann.

also z.b. so:

$r=mysql_query("select * from sperre where gesperrt=1");

while(mysql_num_rows($r)){
usleep(10000);
$r=mysql_query("select * from sperre where gesperrt=1");
}

mysql_query("update sperre set gesperrt=1");

//PHP Kram

mysql_query("update sperre set gesperrt=0");

erst gugckt, man, das gesperrt auf wirklich = 0 ist, man die seite also aufrufen kann.
dann sperrt man die seite, damit niemand anderes aufrufen kann, dann führt man alles aus und am ende gibt man alles wieder frei...

somit ist gesichert, dass 2 seitenaufrufe sich nicht überschneiden und somit fehler verursachen..

aber da die ausführzeit ja im millisekunden bereich liegt.. ist das wirklich notwendig??
gepostet vor 18 Jahre, 8 Monate von Klaus
Ja das ist eigentlich notwendig, weil ein Überschneiden immer passieren kann, obwohl das Risiko gering ist. Wenns dann aber doch passiert gehen die Konsequenzen von kleinen Anzeigefehlern bis große Struktur-Fehler in deiner Datenbank.

Es gibt noch die Möglichkeit mit dem Table Lock. Ich würde gerne wissen was passiert wenn ein Thread einen Write Lock auf eine Tabelle setzt und der andere Thread dann schreiben will. Gibt das einen MySQL Fehler?
gepostet vor 18 Jahre, 8 Monate von BLUESCREEN
Original von ilk
ist das wirklich notwendig??

Ja ist es, aber nicht so, wie du den Code gepostet hast!
Der ist nämlich auch nicht vor Überschneidungen geschützt...

Stattdessen solltest du z.B. Transaktionen oder Locking verwenden.

Original von Klaus

Ich würde gerne wissen was passiert wenn ein Thread einen Write Lock auf eine Tabelle setzt und der andere Thread dann schreiben will. Gibt das einen MySQL Fehler?
Nein, MySQL lässt den anderen Thread dann warten, bis die Tabelle wieder freigegeben ist.
gepostet vor 18 Jahre, 8 Monate von dan kirpan
jup, solche looking-fehler habe ich mich auch sehr lange rumgeschlagen... Aber bis jetzt hab ich nur 1 (ein) einziges "Pseudo"-Locking.

Lade Daten
Sperre Daten
Verarbeite Daten
Speicher Daten
Entsperre Daten
Ende

Das ganze in einem Cronjob, der immer nur 1x laufen kann.

Wie verhindere ich solche Fehler jetzt ganz simpel ohne Classen (von denen hab ich gar keine Ahnung), damit folgendes richtig klappt, also ein Parralelles Abarbeiten nicht möglich ist:

A: Lade Daten
B: Lade Daten
A: Sperre Daten
B: Sperre Daten (Daten bereits gesperrt, aber also nichts geändert)
A & B: Verarbeite Daten
A & B: Speicher Daten (doppelt)
A & B: Entsperren
A & B: Ende mit Fehler...
gepostet vor 18 Jahre, 8 Monate von Amun Ra
Transaktionen nur unter InnoDB oder BDB...
Hat jemand mal Erfahrung damit gesammelt bezüglich der Performance ?
MyISAM ist ja schneller aber wieviel ?
gepostet vor 18 Jahre, 8 Monate von Kallisti
Reduziert, ohne Fehlerabfragen usw...:

 

mysql_query("LOCK TABLES auktionshaus WRITE, user WRITE;");

"SELECT gebot, verkaeufer_id, kategorie, pos_x, pos_y, hoechstbietender_id, gebuehren FROM auktionshaus WHERE id=".$bieten

"SELECT credits FROM user WHERE id=".$_SESSION['user_id']

"UPDATE auktionshaus SET gebot = ".$neues_gebot.", hoechstbietender_id = ".$_SESSION['user_id'].", gebuehren = ".$lieferkosten." WHERE id=".$bieten

"UPDATE user SET credits = credits + ".$auktion['gebot']." + ".$auktion['gebuehren']." WHERE id=".$auktion['hoechstbietender_id']
"UPDATE user SET credits = credits - ".$neues_gebot." - ".$lieferkosten." WHERE id=".$_SESSION['user_id']

mysql_query("UNLOCK TABLES;");
gepostet vor 18 Jahre, 8 Monate von None
d.h. nicht so wie ichs gemacht hab, sondern via mysql LOCK ?

hab davon (noch) keine ahnung, sollte das in etwa so aussehen:

mysql_query("LOCK TABLES tbl1 WRITE, tbl2 WRITE, tbl3 WRITE, ...");

mysql_query("SELECT ...");
mysql_query("UPDATE ...");
mysql_query("UPDATE ...");
mysql_query("UNLOCK TABLES tbl1,tbl2,tbl3,...");

oder lieber

mysql_query("SELECT ...");

mysql_query("LOCK TABLES tbl1 WRITE, tbl2 WRITE, tbl3 WRITE, ...");
mysql_query("UPDATE ...");
mysql_query("UNLOCK TABLES tbl1,tbl2,tbl3,...");
mysql_query("LOCK TABLES tbl1 WRITE, tbl2 WRITE, tbl3 WRITE, ...");
mysql_query("UPDATE ...");
mysql_query("UNLOCK TABLES tbl1,tbl2,tbl3,...");

also immer vor und nach dem query... ?

und was passiert jetzt, wenn ne andere abfrage drauf zugreifen (schreiben) will, während die gelockt iust? kommt die ganze php datei dann zum stehen, bis die wieder unlocked ist, oder rechnet die weiter und führt das query später aus (was ja auch schwachsinn wäre) ?
gepostet vor 18 Jahre, 8 Monate von woodworker
mhh frage: locke ich lieber einmal mache EIN query und unlokc ewieder und locke dann wieder?

oder locke ich einmal führe meine querys aus und unlocke wiedeR?


so eine frage schon zu stellen ist ja ne ohrfeige wert ;p
gepostet vor 18 Jahre, 8 Monate von Kallisti
Locken, alles machen was zu race conditions fuehren koennte, unlocken.

Das Select also erst _nach_ dem Lock, sonst koennten sich ja die Inhalte noch aendern, mit denen du weiterarbeitest.

Fuer ein einzelnes Query locked mysql die Tabelle sowieso von allein...

Ja, alle andern Zugriffe muessen dann bis zum unlock warten, sonst waere es ja auch Unsinn. Da es sicher meist um Millisekunden handelt, ist das ziemlich egal.
gepostet vor 18 Jahre, 8 Monate von dan kirpan
Danke erstmal für die schnelle Hilfe...

Und wenn eine table gelockt ist, und ein anderer locken will, dann wartet der eine auf den anderen?

Die gesamte Tabelle zu locken ist vielleicht ein wenig zu krass, wenn nur 1 Datensatz betroffen ist. Kann man nicht nur 1 Datensatz sperren?
gepostet vor 18 Jahre, 8 Monate von Kallisti
Jedes normale SELECT oder UPDATE lockt auch alles bis es fertig ist...

Das ist vollkommen normal, man muss es eben richtig einsetzen und nicht am Anfang eines Scripts locken und am ende unlocken, sondern die Berechnungen vorher durchfuehren und dann zentral die abhaengigen Anfragen hintereinander schalten.
gepostet vor 18 Jahre, 8 Monate von Drezil
locking auf zeilenebene geht in mysql nur mit InnoDB.
gepostet vor 18 Jahre, 8 Monate von None
aber, hm, wenn ich nen update machen will, darf ich die tabelle ja nicht vorher locken...

also angenommen ich hab nen selct und dnan nen update
select
update

muss dass dann zu
lock
select
update
unlock

oder
lock
select
unlock
update
gepostet vor 18 Jahre, 8 Monate von woodworker
du lockst ja nur für andere verbindungen
nur du hast ja dann zugriff

das ist doch bei jedme lock so
gepostet vor 18 Jahre, 8 Monate von Kallisti
Natuerlich darfst du sie locken, der lock gilt nur fuer andere Verbindungen, die aktive Verbindung darf zugreifen (sonst waere es ja Unsinn).

Also:

lock
select
update
unlock


Ansonsten koennte ja jemand anderes die Daten aendern, bevor du hereinschreibst...

Ist das so schwer verstaendlich? O_o
gepostet vor 18 Jahre, 8 Monate von Chojin
Mal eine etwas eigenwillige Frage, nachdem das Thema nun schon so hitzig diskuttiert worden ist.

Reicht das automatische Table bzw. Zeilen locking in den entsprechenden Datenbank modulen nicht für den normalen Gebrauch aus?

Ich dachte man muss das beschriebene Verfahren (Table locking) nur anwenden, wenn man z.b. zwei Webserver hat die auf den gleichen Datenbestand auf einem DB Server zugreifen (und auch nur dann, wenn mehrere Querys und Datensätze zu einem Ereigniss abgearbeitet werden müssen).

reg4rds
chojin
gepostet vor 18 Jahre, 8 Monate von TheUndeadable
Lies mal das von mir hier gepostete Dokument durch, dort findest du Hinweise, warum es nicht IMMER funktionieren kann.

Es brauchen ja nur 2 Requests gleichzeitig stattfinden. Es macht da keinen Unterschied, ob die auf 2 Servern oder auf einem Server stattfinden.
gepostet vor 18 Jahre, 8 Monate von dan kirpan
Original von Kallisti
Jedes normale SELECT oder UPDATE lockt auch alles bis es fertig ist...

Das ist vollkommen normal, man muss es eben richtig einsetzen und nicht am Anfang eines Scripts locken und am ende unlocken, sondern die Berechnungen vorher durchfuehren und dann zentral die abhaengigen Anfragen hintereinander schalten.


> nutzt mir aber nichts, weil die daten geupdatet werden können, während ich sie mit php verarbeite und dann abspeichere.

Also würde ein einfaches Lock all tables am anfang eines Scriptes reichen und ein unlock am ende... dann gehts... und wenn 2 user gleichzeitig zugreifen möchten, muss der eine auf den anderen warten.

Wird davon die Scriptlaufzeit von PHP beeinflusst? Ich meine, ist klar, wenn mysql warten muss, wartet auch php ;-)

Aber: 30 Scriptlaufzeit für PHP danach ein kill vom server. Zählen die 5 Sekunden warten auch zu den 30 Sekunden Scriptlaufzeit?

Ausserdem ist die "einfach alles locken"-methode doch sehr unwirtschaftlich, weil auch datensätze / Tabellen gelockt werden, die überhaupt nicht benötigt werden...

Ich muss mir das echt mal durch den Kopf gehen lassen... weil wichtig wäre sowas auf jeden fall!
gepostet vor 18 Jahre, 8 Monate von Kallisti
Du sollst ja auch nicht alles locken, sondern nur was du brauchst und nur Stellen an denen auch Race Conditions auftreten koennen.

Oft reicht es auch, die Abfragelogik ins SQL zu verpacken.

Beispiel:

SELECT ressourcen FORM user WHERE id = 123

if(ressource > lalelu...)
INSERT xyz
UPDATE user SET ressourcen = ... WHERE id = 123


Stattdessen besser:
UPDATE user SET ressourcen = IF(ressourcen>lalelu,ressourcen-lalelu,ressourcen) WHERE id = 123 (oder hier die Einschraenkung im where clause...).
affected rows ueberpruefen
je nach Resultat INSERT oder error message

-> Das "IF" und "SWITCH CASE" im (my)SQL kann sehr praktisch sein (glaube IF ist proprietaeres mysql, SWITCH ist Standard SQL)


Ansonste eben moeglichst alle Abfragen und Updates (zeitlich) "nah beeinander" positionieren, so dass es nicht mehr viel zu berechnen gibt und die Locks keine anderen Scripte aufhalten.

Natuerlich zaehlt die lockzeit zur gesamten Laufzeit eines Scripts, aber wenn du mehr als wenige Millisekunden warten musst, solltet du sowieso dein Konzept / deinen Code / deine Server ueberpruefen...
gepostet vor 18 Jahre, 8 Monate von BLUESCREEN
Original von ilk
und was passiert jetzt, wenn ne andere abfrage drauf zugreifen (schreiben) will, während die gelockt iust?

Original von dan kirpan

Und wenn eine table gelockt ist, und ein anderer locken will, dann wartet der eine auf den anderen?
Steht doch schon in meinem ersten Post...

Original von Amun Ra

Transaktionen (...)
Hat jemand mal Erfahrung damit gesammelt bezüglich der Performance ?
MyISAM ist ja schneller aber wieviel ?
Würde mich auch mal interessieren.

Original von dan kirpan

Ausserdem ist die "einfach alles locken"-methode doch sehr unwirtschaftlich, weil auch datensätze / Tabellen gelockt werden, die überhaupt nicht benötigt werden...
Hier hat ja auch niemand empfohlen, immer alles zu sperren.
gepostet vor 18 Jahre, 8 Monate von Teonas
Vergleichswerte für MySQL 5 würden mich auch interessieren - für die 4er Version hab ich ein paar Quellen, aber das interessiert ja heute keinen mehr ;-)
gepostet vor 18 Jahre, 8 Monate von dan kirpan
Original von BLUESCREEN
Original von dan kirpan
Ausserdem ist die "einfach alles locken"-methode doch sehr unwirtschaftlich, weil auch datensätze / Tabellen gelockt werden, die überhaupt nicht benötigt werden...

Hier hat ja auch niemand empfohlen, immer alles zu sperren. Ist schon klar, dass das hier niemand empfohlen hat, aber mich würde ein System/Hinweise/Tipps interessieren, welches mir sagt, welche Tabellen ich sperren muss. Ich hab jetzt einfach mal für jeden Aufruf alle Tabellen, bei denen schon Doppelberechnungen aufgetretten sind, bzw. auftretten können, gesperrt... das game läuft seit dem schneller... zumindest empfinde ich es so!
gepostet vor 18 Jahre, 8 Monate von Kallisti
Du sollst alle sperren in denen Race Conditions auftreten _koennen_. Das haengt von der Logik deiner SQL Statements ab, da kann dir keiner etwas vorschreiben oder so.

Eine Beschleunigung kann durchaus eintreten, wenn es die richtigen Tabellen trifft, da dann einige Scripts schneller abgearbeitet werden und nicht andere sich "dazwischenschieben". Musst nur aufpassen, dass du nicht in zu vielen Locks endest bzw. am Ende alle Prozesse nur noch warten.

Table locks immediate 931903

Table locks waited 640
(Hatte vorgestern wegen USV Defekt bei Hetzner Zwangsreboot... GRUMPF 150 Tage uptime im Arsch).

D.h. also 640 locks mussten warten, 931903 erfolgten sofort.
3,610,515 Queries insgesamt, der Rest kam aus dem QCache.

Ist aus der mysql runtime info, kannst du dir z.B. bequem in phpmyadmin ansehen.
gepostet vor 18 Jahre, 8 Monate von dan kirpan
jup, ich hab nur die gelockt, wo race conditions auftreten _können_...

Ich arbeite eigentlich nur mit einfachen db-abfragen, also mit max 1 Tabelle und maximal einer verschachtelten Where-Abfrage, aber sonst alles nur 0 8 15 krams... also dürfte sich durch das locken nichts negativ auswirken oder?
gepostet vor 18 Jahre, 6 Monate von General Crime
Ich bekomme bei meinem Scvript manchmal einen Fehler oder Hinweis:
"Table xyz was not locket with mysql lock" oder so

ist das nun ein Fehler oder ist das nur ein Hinweis das ich die Tabelle auch locken sollte!???

Auf diese Diskussion antworten