{"id":506,"date":"2007-08-12T12:20:44","date_gmt":"2007-08-12T10:20:44","guid":{"rendered":"http:\/\/www.glorf.it\/blog\/2007\/08\/12\/sql-talk\/performance\/beliebte-performance-fallen"},"modified":"2007-08-12T18:51:58","modified_gmt":"2007-08-12T16:51:58","slug":"beliebte-performance-fallen","status":"publish","type":"post","link":"http:\/\/www.glorf.it\/blog\/2007\/08\/12\/sql-talk\/performance\/beliebte-performance-fallen","title":{"rendered":"beliebte Performance-Fallen"},"content":{"rendered":"<p>Einer meiner Jobs ist die Analyse von Performanceproblemen bei unseren Anwendungen. Deswegen habe ich hier einfach mal ein paar typische Performance-Fallen bei datenbanknutzenden Anwendungen geschrieben. Nat&#252;rlich ist es schwierig pauschale Ratschl&#228;ge abzugeben. Es besteht immer die Gefahr platt oder arrogant zu wirken. So ist es nicht gemeint.<br \/>\nDas alles l&#228;uft unter dem Motto: Gefahren, die man kennt, kann man umschiffen&#8230;<\/p>\n<p>* Nur die wirklich notwendigen Datens&#228;tze anfordern<br \/>\nWerden in der Anwendung beispielsweise Cursor verwendet (gerne bei ODBC oder MFC), dann werden oft nur die ersten 30 Datens&#228;tze lesen (mehr passt nicht auf den Bildschirm, der Rest wird dann nur im Bedarfsfalls gelesen (z.B. in einem virtuellen List-Control). Je nachdem welchen Cursor-Typ man verwendet und wie komplex das Statement ist, muss der SQL-Server aber dennoch alle vom Datensatz betroffenen Datens&#228;tze lesen, z.B. 10000, obwohl in der Regel nur die aktuellesten 20 tats&#228;chlich von Kunden tats&#228;chlich werden. Das gilt h&#228;ufig dann, wenn der SQL-Server die Datens&#228;tze sortiert liefern soll, aber kein entsprechender Index da ist.<\/p>\n<p>* Immer alle ben&#246;tigen Daten auf einen Schlag anfordern<br \/>\nIch sehe immer wieder, dass eine Reihe von Datens&#228;tzen aus einer Tabelle gelesen wird. Sagen wir mal die Daten einer Rechnung. Dann wird pro Rechnung nachgelesen wie der verantwortliche Sachbearbeiter &#8211; von dem ja nur die ID in dem Datensatz steckt &#8211; hei&#223;t. Dann wird der Name des Kunden (aus dem Gleichen Grund) pro Rechnung nachgelesen. Das sollte man bitte auf keinen Fall machen. Damit belegt man nur, dass der Chef das Geld oder die Zeit f&#252;r eine SQL-Schulung nicht ausgeben wollte. Und kauft damit eine schlechte Performance ein.<br \/>\nStatt dessen verwendet man einen Join, um die beiden Namen zusammen mit den Rechnungsinformationen zu lesen. Das ist einfach und effizient.<\/p>\n<p>* die Objektorientierung nicht um seiner selbst Willen durchziehen<br \/>\nLeider passiert es sonst regelm&#228;&#223;ig, dass die aufgerufene Klasse, die ja meist nicht wei&#223; in welchem Kontext sie gerufen wird, sich unsinnig verh&#228;lt.<br \/>\nBeispielsweise soll der Status von allen Bestellungen eines Kunden auf &quot;fakturiert&quot; gesetzt werden, wenn die Rechnung daf&#252;r raus ging. Die beste Performance bekommt man wenn man nur ein einziges UPDATE daf&#252;r absetzt. Wenn man aber (vermeintlich) &quot;objektorientiert&quot; vorgeht, dann werden in einer Schleife alle Bestellungen durch genudelt, und pro Bestellung ein UPDATE abgesetzt. Das kostet unglaublich Performance und ist so als ob man jede Morgen f&#252;r jedes einzelne Br&#246;tchen wieder einzeln zum B&#228;cker f&#228;hrt. Dabei k&#246;nnte man doch mit einer Fuhre alle 10 Br&#246;tchen mitbringen.<\/p>\n<p>* Schleifen<br \/>\nDas gilt nat&#252;rlich nicht nur f&#252;r die objekt-orientierte Vorgehensweise: Das gilt f&#252;r alle Programmiersprachen und Architekturen. Deswegen nenne ich es noch als eigenen Punkt: Jede Schleife kostet unn&#246;tig Zeit. Mehr Zeit als man denkt.<\/p>\n<p>* keine oder unsinnige Clustered-Indexe<br \/>\nDen Prim&#228;rschl&#252;ssel zum Clustered-Index zu machen ist nach meiner Erfahrung meistens suboptimal und lohnt sich nur bei zusammengesetzten Prim&#228;rschl&#252;sseln. Wenn man eine ID verwendet, dann sollte man Clustered-Index lieber auf ein oder mehrere fachliche Felder legen, die unter Umst&#228;nden sogar Fremdschl&#252;ssel irgendwohin sind. Dadurch erreicht man, dass fachlich zusammengeh&#246;rige Felder auf der gleichen oder wenigstens auf benachbarten Datenseiten liegen.<br \/>\nDer Clustered-Index sollte &#252;brigens nicht zu &quot;breit&quot; sein, weil am SQL-Server-2005 die anderen Index nicht mehr auf die Datenseiten verweisen, sondern auf den Eintrag im Clustered-Index&#8230;<\/p>\n<p>Fr&#252;her hatte ich auch noch eine ganze Palette an Tricks zur Mikro-Optimierung auf Lager. Aber der Optimizer des SQL-Servers ist jetzt so clever geworden, dass die meisten zum alten Eisen geh&#246;ren. Au&#223;erdem habe ich echt die Erfahrung gemacht, dass die dicken Brocken so viel Zeit verschlingen, dass sich die Mikrogeschichten (wie z.B. Parametrisierung) erst sehr sp&#228;t rentieren&#8230;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Einer meiner Jobs ist die Analyse von Performanceproblemen bei unseren Anwendungen. Deswegen habe ich hier einfach mal ein paar typische Performance-Fallen bei datenbanknutzenden Anwendungen geschrieben. Nat&#252;rlich ist es schwierig pauschale Ratschl&#228;ge abzugeben. Es besteht immer die Gefahr platt oder arrogant zu wirken. So ist es nicht gemeint. Das alles l&#228;uft unter dem Motto: Gefahren, die [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[18],"tags":[],"_links":{"self":[{"href":"http:\/\/www.glorf.it\/blog\/wp-json\/wp\/v2\/posts\/506"}],"collection":[{"href":"http:\/\/www.glorf.it\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/www.glorf.it\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/www.glorf.it\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/www.glorf.it\/blog\/wp-json\/wp\/v2\/comments?post=506"}],"version-history":[{"count":0,"href":"http:\/\/www.glorf.it\/blog\/wp-json\/wp\/v2\/posts\/506\/revisions"}],"wp:attachment":[{"href":"http:\/\/www.glorf.it\/blog\/wp-json\/wp\/v2\/media?parent=506"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/www.glorf.it\/blog\/wp-json\/wp\/v2\/categories?post=506"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/www.glorf.it\/blog\/wp-json\/wp\/v2\/tags?post=506"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}