Moin,
was auch noch einen grossen Unterschied macht ist die Reihenfolge der WHERE-Bedingungen und/oder JOINs. Der
Query-Optimizer kommt da nicht immer ganz gut mit (hab ich z.B. bei
MySQL gemerkt).
Nehmen wir dieses
Query:
SELECT * FROM a, b WHERE a.id = b.id AND a.user = 5
Das ist nicht dasselbe wie das hier:
SELECT * FROM a, b WHERE a.user = 5 AND a.id = b.id
Der Unterschied liegt darin, dass beim ersten
Query zuerst ein Kreuzprodukt erstellt wird. Vor allem in m:n-Beziehungen koennen da viele Datensaetze zusammenkommen. Anschliessend wird die Datenmenge eingeschraenkt. Beim zweiten
Query wird zuerst eingeschraenkt und anschliessend erst das Kreuzprodukt erstellt, das heisst die aufkommende Datenmenge wird kleiner sein. Wenn nun auch b eine user-ID haette (die natuerlich dieselbe ist wie bei a, kann ja sein) dann koennte man auch das noch machen:
SELECT * FROM a, b WHERE a.user = 5 AND b.user = 5 AND a.id = b.id
So werden in beiden Tabellen erstmal die Datensaetze eingeschraenkt, bevor das Kreuzprodukt daherkommt.
Was den * betrifft: Wenn du alle Felder brauchst, dann schreib auch den * rein. Der
Query-Optimizer muss eh jedes Feld durch seinen vollen Namen ersetzen (<datenbank>.<tabelle>.<feld>), da macht das mitm * auch keinen Unterschied. Die meisten Server vertragen den * mittlerweile auch sehr gut. V.a. bei Count-Statements (SELECT COUNT(*) FROM xyz) gehts mitm * immer noch am schnellsten.
Was teilweise einen grossen Unterschied macht ist die Verwendung von DISTINCT oder GROUP BY. Da kann man teilweise auch einiges rausholen.
Im Grunde genommen kann man keine allgemeingueltigen Regeln aufstellen. Manchmal muss man einfach damit leben, dass ein
Query langsam laeuft (z.B. wenn ich Daten aus drei Tabellen hole, in denen jeweils mehr als 1 Million Datensaetze drin sind). Die Optimierung geschieht dabei meistens auf
Query-Basis, d.h. guck dir das
Query mit EXPLAIN an, versuch rauszufinden was du dran aendern kannst, usw. Teilweise reicht es ja auch, das Schema geringfuegig zu aendern. Um kurz ein Beispiel zu nennen:
Wir haben eine Seite in der Artikel stehn. Diese Artikel stehen in verschiedenen Kategorien. Auf der Uebersichtsseite will ich natuerlich die Kategorien zusammen mit Infos zum letzten Artikel anzeigen. Wie wuerde man das machen, wenns streng nach Protokoll geht (
MySQL):
SELECT * FROM categories ORDER BY category_order
Und zum Rausholen der Artikel in der Anzeigeschleife:
SELECT * FROM articles WHERE category_id = <id> ORDER BY article_time DESC LIMIT 1
Das ist schon nicht schlecht. Wenn ich nun aber die ID des letzten Beitrags der Kategorie im Datensatz der Kategorie hinterlege, hab ich zwar eine Redundanz in der
DB und Normalform-Fetischisten wuerden gleich wieder Zeter und Mordio bruellen, aber dafuer geht sowas:
SELECT c.*, a.id, a.time FROM categories c LEFT JOIN articles a ON c.last_article = a.id ORDER BY category_order
Und schon wars das. Dann noch ein Index auf c.last_article und c.category_order, a.id als Primary und der Datenbankserver wird dir zum Dank ein Kuesschen mit jedem
Query-Ergebnis mitschicken *g*
Mein Tipp: teste verschiedene Varianten eines Queries rum und guck dir an, was der Optimizer daraus macht. In
MySQL kannst du das sehn in dem du zuerst das
Query mit EXPLAIN ausfuehrst:
EXPLAIN EXTENDED SELECT .....
und dir anschliessend die Warnungen anzeigen laesst:
SHOW WARNINGS;
Dann zeigt dir
MySQL das
Query an, wie es dann tatsaechlich ausgefuehrt wurde. Da kann man auch schon Engpaesse sehn. In den meisten Faellen reicht es jedoch, folgendes zu machen:
EXPLAIN SELECT .....
Das gibt dir Informationen ueber das
Query und die Abarbeitungsreihenfolge. Da lassen sich die Engpaesse mit etwas Erfahrung auch gut sehen
Greetz
alcaeus