PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : [MySQL]: Abfrage optimieren?


mf_2
2008-03-30, 06:01:31
Hallo,

ich will die Existenz eines Eintrages überprüfen. Der Eintrag existiert, wenn das Feld eins dem Wert 1 und das Feld zwei dem Wert 2 entspricht.

Ich habe folgende Abfrage dafür gemacht (in PHP):


if(mysql_fetch_row(mysql_query("SELECT * FROM table WHERE eins='1' AND zwei='2'"))==FALSE)


aber das ist äußerst lahm. Gibt es einen Ausdruck in der MySQL Sprache um die Existenz zu überprüfen? Oder eine andere Möglichkeit um das zu beschleunigen?
Die Performance meines Scripts ist gerade ins Bodenlose gesunken. Es soll eine Zeile nur in die MySQL Tabelle schreiben, wenn diese vorher nicht schon existiert. Wenn ich also das mit dieser Abfrage überprüfe, schafft das Script ca. 5-8 Inserts pro Sekunde. Bei ca. 170.000 Einträgen ist das extrem blöd. Vorher (also ohne die Existenzabfrage) hat das Script über 1.000 Einträge pro Sekunde geschafft.

Gruß,
mf_2

The_Invisible
2008-03-30, 08:30:01
versuch mal "select count(*) ..."

mfg

Gast
2008-03-30, 09:26:30
SELECT * ...

Grässlich, niemals, nichtmal wenn die Hölle gefriert!

mf_2
2008-03-30, 12:38:13
Ok, danke! Das count(*) scheint ein wenig schneller zu sein!

ethrandil
2008-03-30, 12:45:45
CREATE UNIQUE INDEX index_name
HASH
ON tabelle (eins, zwei)


?

gereggter Gast
2008-03-30, 13:05:40
Hallo!

Jede einzelne Abfrage an die Datenbank ist sehr zeitintensiv. Darum würde ich prüfen, ob man die Checks nicht einzeln, sondern irgendwie in einem Bulk (zehntausender Schritte?) zusammenfassen kann. Dann geht man die zehntausend Ergebnisse durch und führt die inserts an den entsprechenden Stellen aus - oder eben nicht.

Außerdem gäbe es noch die Möglichkeit von conditional inserts. Das wäre dann in etwa so:
INSERT INTO table VALUES ('foo','bar') WHERE NOT EXISTS (SELECT * FROM table WHERE eins='1' AND zwei='2')
So kann man sich die If-Bedingung in php sparen sparen und verringert gleichzeitig die Requests an die Datenbank.

Berni
2008-03-30, 13:18:15
Wie ethrandil schon sagte einfach einen UNIQUE-Index (oder Primary Index wenn das geht) auf die Spalten setzen und dann mit "Insert Ignore Into..." einfügen. Der UNIQUE-Index stellt sicher, dass kein Eintrag doppelt bestehen darf und wenn der Insert fehlschlägt wird das durch das "Ignore" einfach übergangen und normal weitergearbeitet. Und dann kannst du auch einfach alle Befehle als einen einzigen Insert-Befehl zusammenfassen und nicht als 1000 Einzelabfragen was zusätzlich ein Maximum an Performance bringt:
Insert Ignore into table (eins, zwei, Zusatzinfo) VALUES ('1','2','test1'),('3','4','test2') usw.
Damit wird dann alles eingetragen was noch nicht im Index besteht, die restlichen Inserts werden verworfen. Du kannst auch mehr Spaltenwerte natürlich noch einbauen.

LordZed
2008-03-31, 11:01:44
Ich bin mir nicht sicher, aber könnte es nicht sogar noch was performanter werden, wenn man anstatt COUNT(*) sich einfach eine Spalte ausgeben lässt? Angenommen du hast ne laufende Nummer "ID" dann versuch doch mal
if(mysql_fetch_row(mysql_query("SELECT id FROM table WHERE eins='1' AND zwei='2'"))==FALSE)
könnte mir vorstellen, dass es u.A. so lahm ist weil es vllt. ne Tabelle mit vielen Spalten ist (ist dem so?). Das COUNT(*) ist da ja definitiv schon eine Verbesserung, aber denke mit einem gezielten SELECT auf eine Spalte (reicht ja!) könnte es vllt. noch performanter sein!

Nur eine Vermutung! Sicher bin ich mir da nicht! Probieren geht über studieren ;)

Berni
2008-03-31, 13:42:10
Count(*) ist in der Regel genauso schnell wie die Abfrage eines Tabellenwertes. Wenn alle WHERE-Einschränkungen aus einem Index kommen ist es minimal schneller, weil dann die gesamte Abfrage aus dem Index bedient werden kann.