Posts mit dem Label Sql werden angezeigt. Alle Posts anzeigen
Posts mit dem Label Sql werden angezeigt. Alle Posts anzeigen

Sonntag, Dezember 12, 2010

Query Performance–Open Source, Reflection und “Java”-Tools

Wie  üblich bei den meisten Applikationsentwicklungen ging es bei uns in den letzten Wochen u. a. um das Thema Performance. Die aktuelle Anwendung nutzt verschiedene Open Source Komponenten zum Verarbeiten der Daten. Die Komponenten sind convertierte Java-Entwicklungen, teilweise mit langem Hintergrund.

Zum einen muss ich sagen, dass man wirklich extrem Differenzieren muss zwischen den einzelnen Projekten. Teilweise sollte man vor dem Einsatz noch ein Code-Review und Analyse einschieben. Eine Open Source Komponente nutze Exceptions exzessiv zur Flusssteuerung, was schlechtes Design ist und u. U. Performance kostet. Leider nutzen wir auch eine Datenzugriffskomponente, die eigentlich fast keine Arbeit abnimmt, da damit nur Objektzuweisung durchgeführt werden. Ein OR-Mapper, der Arbeit abnimmt, würde eine wesentlich bessere und einfachere Entkopplung ermöglichen.

Die Datenzugriffskomponente, ich weigere mich OR-Mapper zu sagen, arbeitet intern heftig mit Reflection um die Properties zu setzen. Leider ist gerade bei Massenoperationen Reflection keine gute Wahl. Reflection ist ein zentraler Bestandteil im .NET Framework, dennoch kostet jede Operation dennoch einige Millisekunden, die wenigen Millisekunden potenzieren sich dann bei mehreren Tausend Objekten zu einigen Sekunden, im schlimmsten Fall zu Minuten. Allgemein sollte vor dem Einsatz eines OR-Mapper immer geprüft werden, ob es sich um Massenoperationen handelt, diese sollten ggf. mit klassischen ADO-Mitteln abgehandelt werden. Um unsere Roundtrips zur DB zu reduzieren, haben wir die verschiedenen Statements zu einem "großen" Statement zusammengefügt. Leider wurde dadurch das resultierende Objekt größer und die Property Zuweisungen haben sich auch vervielfacht. Aufgrund der Eltern-Kind-Beziehung in den Statements benötigten die Abfragen anschließend 40s (5s beim Ausführen in der DB). Grundsätzlich kann durch Joins die Abfragegeschwindigkeit gesteigert werden, OR-Mapper wie Lind2SQL oder NHibernate machen diese Optimierungen durchaus auch. Wir haben unsere Zugriffe durch Aufsplitten unserer Joins um das 10-fache beschleunigt. Die Joins wurden eingeführt, um einige DB-Roundtrips zu sparen, leider wurden unserer Datensätze dadurch aber auch ver-100-facht. 100-fache Datenmenge und viel Reflection haben sich so massiv ausgewirkt, dass wir bis zu 40s für einfache Selects benötigt haben. Somit wurden also 2 Statements abgesetzt, 1 die Elterndaten und die 2. Abfrage mit den Kinderdaten, in beiden Statements wurde die gleiche Bedingung benutzt. Wir haben die Zuordnung der Kinder zu Ihren Elternelementen im Code realisiert, da dies sehr einfach war und wir nicht ggf. 100te Roundtrips produzieren. Würde man zu jedem Customer (Beispiel) die entsprechenden Orders über den PK laden, wären dass ggf. sehr viele Operationen. Um das ganze weiter zu optimieren, kann man bei einigen Datenbankprovidern mehrere SQL-Operationen in einem Rutsch absenden, so dass die Weitere Zeit kaum ins Gewicht fällt.

Hier ein sehr abstraktes und einfaches Beispiel:

1 select * from Customers c 2 INNER JOIN Orders o ON c.ID=o.customerID 3 WHERE o.orderdate>@DATE; 4 /* Splittet into 2 Statements */ 5 select c.* from Customers c 6 INNER JOIN Orders o ON c.ID=o.customerID 7 WHERE o.orderdate>@DATE; 8 select o.* from Customers c 9 INNER JOIN Orders o ON c.ID=o.customerID 10 WHERE o.orderdate>@DATE;

Dies soll kein Post gegen Open Source oder konvertierte Java-Componente sein. Jedoch finde ich es falsch, einfach anzunehmen, dass gut funktionierende Java-Componenten, auch gut in .NET funktionieren. Es sollte immer der Anwendungsfall im Vordergrund stehen. Componenten/Frameworks sind nur Unterstützer zu diesem Weg. Nebenbei bin ich sehr  gespannt, wie es mit JAVA weiter geht http://goo.gl/rUAHG.

Vielleicht bekomme ich es doch noch mal hin, dass ich diese Jahr noch einen weiteren Post erstelle. Ich wollte seit Wochen mal was zu NDepend schreiben, aber …

Montag, Mai 03, 2010

Oracle Batch Operation

Ich hatte mich letzte Woche bei einer Anwendung mit der Geschwindigkeit bei Datenbankoperationen beschäftigt. Die Anwendung schreibt etwa 100 Datensätze in einer große Tabelle mit ca. 60 Mio Datensätzen. Beim einfügen der Daten musste ich leider 20s warten, was für mein Verständnis für Datenbankzugriffe einfach nichz akzeptabel ist. Demzufolge habe ich die Gründe untersucht.

  1. Werden alle Daten in einer Transaktion geschrieben. In dem Thema verbirgt sich eine etwas heßliche Problemstellung. Die Oracle-Clientversion ist so eine seltsame Version, dass ich kein ODP.NET Treiber bekomme, der ohne Client-Neuinstallation arbeitet. Ich habe keine Möglichkeit die Ora-Client-Installation auf den Zielsystemen zu verändern. Um meine Absichten deutlich zu machen, habe ich trotz des Bewußtseins, dass es nicht funktioniert den TransactionScope benutzt. Im Anschluss die manuelle “old-style” Transaction geöffnet, IDbConnection.BeginTransaction.
  2. Trigger auf der Tabelle prüfen. Trigger verlangsamen die Ausführung der Änderungsoptionen und könnten schon einen negativen Effekt erklären.
  3. Indizes beeinflußen die Geschwindigkeit von Änderungsoperationen ebenso, so dass diese auch geprüft werden sollten.
  4. Andere Abhängige Datenbankobjekte prüfen, z. B. Materialized views (Snapshots).

Nunja, da ich mich mit der Anwendungsprogrammierung deutlich besser auskenne als in der DB-Programmierung, habe ich mich mit dem ersten Punkt beschäftigt. Meine Transaktionen waren vorhanden, aber die Geschwindigkeit war immer noch nicht befriedigend. Also die Idee eines Kollegen aufgegriffen, einen PL/SQL aus meinen Operationen zu erstellen. Bei der Ausführung eines PL/SQL-statements wird dieses durch die DB optimiert und als ein Block  übergeben, evtl. greifen auch einige zusätzliche Optimierungen. PL/SQL-Blöcke beginnen mit “BEGIN” und Enden mit “END”. Um den Befehl aus dem .NET-Framework über den ODP-Provider zu übergeben, müssen alle Anweisungen in einer Zeile aufgeführt werden. Zum Beispiel: BEGIN Stmt1; Stmt2; … END; Nach all der Mühe war ich von dem Ergebnis enttäucht. Es gab eine Verbesserung, allerdings nur maginal. Es gab auch nix an Triggern, die ich hätte verantwortlich machen können.

Allerdings gabe es 3 Indizes, 1 PK und 2 Indizes, bei einer 4 Spalten-Tabelle. Die Wahrscheinlichkeit ist sehr hoch, dass bei den Abfragen die definierten Indizes genutzt werden, so dass ich mich nicht daran zu schaffen machen wollte. Ein Kollege meinte zu dem, dass die Berechnung der Indizes nicht die Operation merklich beeinflußt.

Blieb nur noch der Punkt 4., es gibt 4 MVs, 2 werden OnDemand aktualisiert, 2 werden OnCommit (fast) aktualisiert. Also der Versuch alle Views mittels Demand von Operationen auf der Tabelle abzuklemmen. Oh Wunder, von 20s auf unter 1s, dass sind schon Zahlen, die ich für 100 einfüge Operationen in eine große Tabelle erträglich finde. Das Aktualisieren der Views wird durch einen seperaten Aufruf am Ende der Verarbeitung angetriggert und dauert einige Sekunden, allerdings weniger, als 100 Inserts mit Daueraktualisierng. MVs haben viele Vorteile, gerade beim Abfragen der Daten und könen die Performance von Abfragen um ein vielfaches Steigern. Wie aber auch geschehen, können andere Operationen verlangsamt werden.

Sonntag, April 25, 2010

ASP.NET SQL Membership database schema

AAAAAhhhh!!!

Mir war mal wieder nach Fluchen, als ich eine ASP.NET DB mit dem SQL-Express als File DB angelegt hatte. Ich konnte das Schema mit “ASPNET_REGSQL” nicht anlegen. Irgendwie ist es doof gemacht, dass das Tool nicht die Möglichkeit bietet auf eine File-DB zu zugreifen. Zugriff über das im SQL Server (Express) gemountet File ist eigentlich auch nicht so schwer, wenn manweiß wie, aber…

Ich habe den Weg direkt über ASPNET_REGSQL versucht und auch über SQL Server Management Studio und dann AttachDB. Beide Wege führten zu einem “Unable to attach physical file …” Operation System Error 5 --- WAS? Eigentlich könnte man den Fehler mit keine/zu wenig Rechte auf der Datei. Ich glaube, man muss auf dem Verzeichnis “Full Control” für den Dienst Nutzer vergeben. Ich habe es noch einfach gemacht, einfach “Everyone” auf FullControl für mein Projektverzeichnis.

Anschließend ASPNET_REGSQL starten. Auf der 2. Seite als Server “.\SQLEXPRESS” eingeben und den kompletten Pfad zum MDF-File.

image Anschließend nur noch warten und das Schema ist erstellt. Schade, dass es nicht aus dem Studio einfach durch einen klick auf die DB geht. (auch in VS 2010 nicht)

Auf jeden Fall habe ich nun mein Datenbank-Schema und kann mich weiter mit OpenID beschäftigen, denn ich will gar kein SqlMembership. ;) Ich bin der Meinung, dass Passwortverwaltung auf der eigenen Website gestern war. Dazu kommt bestimmt demnächst auch mehr.

SQL Server 2008 R2 Released? – Office 2010

Laut Microsoft Newsletter gibt es das neue Release des SQL Servers, also ab zu Technet/MSDN. Nur leider war ich sehr enttäucht, dass es nur CTPs für den R2 gab. Komisch aber am 21.4. war das Launch-Event. Dann muss ich leider noch warten, bis ich das neue Release installieren kann, Express, Management Studio.

Als Alternative gab es dafür bereits für Technet/MSDN Abbonennten Office 2010 zum Download. Den download habe ich dann natürlich sofort angeschmissen. Anschließend habe ich 1-2h überlegt, ob ich es installieren sollte. Wie sich die meisten denken können, ich habe das neue Office installiert. Ich muss sagen, dass es schon schick, anders aussieht. Ich freue mich jetzt schon auf die Conversation-View im Outlook, ich bin die Anzeige in Threads schon so aus Google gewöhnt, dass ich es dieses Feature im Outlook vermisst habe. Bei allen Office-Applikationen hat sich mal wieder das Ribbon verändert.

imageAls Entwickler ist das schon …. Zum einen fand ich diesen Buuble oben-links sehr ansprechend, zum anderen hat es bei der Entwicklung etwas genervt.

Dann hoffe ich mal auf den baldigen SQL Server Download.

Freitag, Februar 13, 2009

SQL Server 2008 Setup issue Vista x64

Die Woche habe ich mich nach einigen Erzählungen von einem Kollegen dazu entschlossen, die SQL Server 2008 Management Tools zu nutzen. Nach der Entscheidung gleich zu MSDN-Seite und das ISO (Dev-Version) gezogen, leider braucht das bei 4GB einiges an Zeit, wenn man nicht gerade am Deutschen Forschungsnetz hängt.

Den nächsten Tag habe ich dann mit der Installation los gelegt, alte Version der Management Tools deinstalliert, noch relativ Problemlos. Allerdings haben mich die ganzen verbleibenden “Leichen” und Reste etwas verwundert. Ich frage mich immer noch, was weiter zu deinstallieren ist. Anschließend das DVD-Image gemounted und die Installation gestartet. Überraschung, wieder eine neue Installer-Version, dabei fand ich die alte gar nicht schlecht, aber wie auch immer, mutig durch. Dann ging es los!

“Attribute do not match … “-Error nach der Auswahl der Komponenten. Der Fehler bezog sich auf das Zielverzeichnis des SQL Servers. Ok, so überrascht war ich allerdings von dem Fehler nicht, da ich den gleichen Fehler bereits von der SQL Server 2005 Installation kenne. Es ist nicht möglich den Server in komprimierten Verzeichnissen zu installieren. Also ohne Bedenken das Verzeichnis von der Komprimierung ausgenommen und erneut versucht. AH, immer noch der Fehler. Bei meinem 2. Versuch mit etwas verzogener Miene habe ich auf meinen gesamten “Program Files”-Verzeichnis die Komprimierung entfernt, wehe einer hat eine zu kleine Platte. Aber auch der Versuch scheitert. Installation neu gestartet, allerdings keine Besserung. Anschließend habe ich die Installation den Tag über nicht mehr angefasst und sie stand noch im gleichen Zustand. Abend mal so mögliche Optionen überlegt, auch Google bemüht (ich weiß, eigentlich hätte ich Live-Search verwenden müssen), allerdings waren die Texte nicht sehr hilfreich. Dann habe ich etwas probiert, was ich bei einer Microsoft Installation von einer x64-Software nicht erwartet hätte, es funktionierte. Die Lösung war einfach die Attribute vom “Program Files (x86)”-Verzeichnis zu löschen. Aber wo zur Hölle steht denn dieser Tipp!

Nach wenigen Minuten war die Installation abgeschlossen und die Tools ready. So, welchen Server migriere ich nach 2008? ….

Sonntag, Juni 22, 2008

Kämpfen mit ASP.NET MVC

Ich habe mir dieses Wochenende mal wieder etwas Zeit für ein Projekt genommen, in dem das ASP.NET MVC-Framework zum Einsatz kommt. Das Arbeiten mit dem MVC-Framework macht mir richtig Spass. Aber dennoch gibt es einige Hacken, die einem den nerv rauben.

MVC Routing Trouble

Allgemein ist es wichtig, dass Routen nach der Reihenfolge des hinzufügen ausgewertet werden. Meistens sollte dass auch mit der Lesereihenfolge in der Global.asax übereinstimmen.

Meine erste Baustelle war das Routing bzw. die Übergaben von Parametern. Mir ist noch nicht klar, warum die Standardwerte in der Global.asax nicht weitergegeben werden. Meine Nullable-Parameters haben erhalten nicht den Wert. Für das Problem habe ich 2 mögliche Lösungsszenarien, zum einen kann man die Parameter nicht Nullable machen oder innerhalb der Methode ggf. den Standardwert setzen.

Bei einer meiner Routen wurden einer der 1. Parameter nur ab und zu gesetzt. Zur besseren Darstellung mal ein Beispiel:

Die Route:

new Route("Projects/Results/{client}/{customerName}/{projectName}/{page}/{pageSize}/{order}", new MvcRouteHandler())
{
    Defaults = new RouteValueDictionary(new { controller = "Projects", action = "Results", client = ClientEnum.SDC, customerName = "", projectName = "", page = 1, pageSize = 20, order = "Default" }),
}

Signatur:

public void List(ClientEnum client, long page, long pageSize, string order)
{
    this.Results(client, null, null, page, pageSize, order);
}

Die Url:

http://localhost/Projects/search/customerPart/myProjectPart

In meinen Routen soll eigentlich die nicht mehr die Default.aspx aufgerufen werden, hierfür habe ich noch nicht die Lösung gefunden. Das Verhalten muss ich mir noch mal zu Gemüte führen und die Videos dazu anschauen, Vielleicht schon morgen im Zug.

SQL Paging Trouble

In der Anwendung greife ich auf einen Sql Server oder Sql Server Express mittels Paging zu, leider ist es kompliziert eine ordentliche Abfrage dafür zu erstellen. Normalerweise soll man für Paging-Abfragen RowNumber oder Rank benutzen, alternativ wird oft über Temp-Tables das Select erstellt. Allerdings ist das mit dem Sql Express nicht möglich, in dem Fall ist ein anderer Weg notwendig. Ich bin auf eine recht einfache Lösung im Internet gestoßen, dabei wird Top verwendet um die Ergebnismengen zu reduzieren. Das Grundprinzip für die Abfrae verwendet TOP mit unter Queries und könnte so aussehen:

SELECT top(ANZAHL) * 
FROM (
    SELECT top(OFFSET + ANZAHL) * 
    FROM MyTable
    ORDER BY xyz ASC
) as maxLimit 
ORDER BY xyz DESC

SETUP

Wer das MVC unter IIS6 benutzen will, sollte mal in die Blog-Einträge How to enable pretty urls with Asp.Net MVC and IIS6 oder Using ASP.NET MVC on IIS 6 without the .MVC Extension schauen. Besser kann man das nicht mehr beschreiben. Bei beiden Techniken wird Url-Rewriting eingesetzt. Ich würde aber den IIS7 empfehlen, da sind solche Umwege nicht mehr notwendig.

Samstag, Februar 23, 2008

Sql Server Reporting Service Multivalue und die Integration in SharePoint

Am Wochende habe ich mich intensiv mit dem Sql Server Reporting Service beschäftigt, ich muss sagen, dass ich mir mal endlich richtig Zeit genommen habe und auch einige Tricky-Sachen gelöst habe. (Natürlich durch googlen) Letztendlich wollte ich dem Kunden ermöglichen in unserer Datenbank nach Einlieferungsnummern zu suchen, um so simple Fragen „Was ist mit meinen Daten passiert?“ selbst zu lösen. Der erste Schritt war das überfliegen eines Tutorials zu dem Thema. Das Beste was ich kenne, sind diese: Beginning SQL Server 2005 Reporting Services Part 1 - Building and deploying basic reports , Beginning SQL Server 2005 Reporting Services Part 2 , Beginning SQL Server 2005 Reporting Services Part 3 - The Chart Control und Beginning SQL Server Reporting Services Part 4 alle Artikel sind von Steve Joubert . Ich kann jedem diese Artikel nur Empfehlen.

Nun aber zu den eigentlichen Problemstellungen. Ich bin nun nicht gerade der beste zum Schreiben von Sql Statements, einige meiner Kollegen werden noch mit erschrecken zurückdenken. … Immer wenn ich an eine Prozedur in der DB ran wollte, weil es mir zu langsam ging, haben die Kollegen das Priorisiert gemacht, quasi gleich, denn immer nachdem ich an der DB war musste alles aufgeräumt werden … Die Statements gingen recht leicht, hätte ich gar nicht gedacht, ich hatte mir allerdings die Woche auch einige Tricks für die Erstellung und das zusammen setzen von komplexen Statements von einem Kollegen geholt. Für die Reporting Services sind die Datenquellen das wichtigste bei der Realisierung. Gerade bei der Realisierung von Online-Statements sollte man auf schnelle Ausfrührung und möglichst limitierte Daten achten. Gerade bei großen Ergebnismengen ist die Aufbereitung problematisch und zeitintensiv.

Für die Darstellung habe ich anschließend ein Drill Down Report gewählt, der über 4 Ebene/Gruppen geht, so wird die Anzeige kompakt und doch informativ.

Die Anforderung das MultiValue-Feld zu realisieren, war zunächst extrem schwierig umzusetzen. Den besten Tipp habe ich auf dem Blog RDA Corp – BI and Sql Server gefunden. Man benötigt für die Verwendung des Parameters die Prozedur um die Werte zurück zubekommen.

Parameter Expression: Join(Parameters!Param.Value, ",")

Statement:
[tableSynonym].[KeyColumn] IN
(
SELECT [columniID]
FROM [schema].[table] tb, [dbo].[Split](@ItemList, ',') tmp
WHERE patindex('%' + tmp.Item + '%', tb.[KeyColumn]) > 0
)

Prozedur: ( RDA Corp – BI and Sql Server )
CREATE FUNCTION [dbo].[Split]
(
@ItemList NVARCHAR(8000 ),
@delimiter CHAR(1 )
)
RETURNS @IDTable TABLE (Item VARCHAR(200 ))
AS
BEGIN
DECLARE @tempItemList NVARCHAR(8000 )
SET @tempItemList = @ItemList
 
DECLARE @i INT
DECLARE @Item NVARCHAR(8000 )
SET @tempItemList = REPLACE (@tempItemList, @delimiter + ' ', @delimiter )
SET @i = CHARINDEX(@delimiter, @tempItemList )
WHILE (LEN(@tempItemList) > 0 )
BEGIN
IF @i = 0
SET @Item = @tempItemList
ELSE
SET @Item = LEFT(@tempItemList, @i - 1 )
INSERT INTO @IDTable(Item) VALUES(@Item )
IF @i = 0
SET @tempItemList = ''
ELSE
SET @tempItemList = RIGHT(@tempItemList, LEN(@tempItemList) - @i )
SET @i = CHARINDEX(@delimiter, @tempItemList )
END
RETURN
END

Nach dem der Report so richtig gut funktionierte, war es Zeit die Integration in den Sharepoint durchzuführen. Es gibt von MS ein Report Service WebPart für Sharepoint, außerdem hat man die Möglichkeit mit dem .NET FX2 das ReportViewer Webpart zu nutzen. Ich hatte zu erst versucht das fertige WebPart zu nutzen, bin dabei allerdings gescheitert, außerdem habe ich damit nicht die Möglichkeit kleinere Modifikationen durchzuführen. Also einen kleinen Wrapper für erstellt, der Connections-Akzeptiert, Parameter von einer anderen Quelle empfangen kann und über ein Parameter-Mapping verfügt. Man kann im Viewer-Control sehr schön die Ansichten modifizieren, so sind bei uns die Parameter nicht vorhanden, da diese durch ein anderes WebPart geliefert werden. Bisschen Probleme hat mir die Anzeige gemacht, da die Scrollbalken immer störten, leider konnte ich nicht einfach die gesamte Seitenhöhe verwenden, hier kann evtl. ein JavaScript helfen, aber es gibt wichtigeres.

Nach dem auch der Schritt erledigt war, hat ein Kollege sich den Report noch mal vorgenommen und versucht die Abfragen zu optimieren (ohne den Plan zu nutzen). Außerdem wurde das zugehörige DataWarehouse angepasst, um Datenstrukturen bereite optimiert vorzuhalten.

Man muss einfach sagen, dass die Reportings Services so viele extrem schöne Feature mitliefern, dass man diese einfach viel mehr nutzen sollte. Die Exportformate sehen sehr schick aus, richtig Klasse finde ich die Excel-Version des Reports. Man sollte bei der exzessiven Nutzung aber unbedingt die Serverresourcen im Auge behalten. Reporting kann sehr Rechenintensiv sein! Sorry, dass ich kein Bild vom Report einfüge, aber leider sind sehr viele vertrauliche Daten enthalten.

Hier noch eine weitere Webseite http://www.gotreportviewer.com/ mit vielen Tipps und Tutorials.