Donnerstag, 17. Dezember 2009

"Timeout abgelaufen" bei Abfrage des Verbindungsservers

Kürzlich hatte ich das Problem, dass alle meine Abfragen gegen einen Verbindungsserver auf ein Timeout liefen. Es hat sich hierbei um einen Datenabgleich zwischen zwei Datenbanken auf unterschiedlichen Servern gehandelt. Den einen Server (S2) habe ich zuvor als Verbindungsserver auf dem anderen (S1) eingerichtet. Danach habe ich auf dem Server S1 folgendes SQL-Statement ausgeführt.

Statement:
INSERT INTO dbo.NeueTabelle
SELECT * FROM [Server2].[DatenbankAlt].[dbo].AlteTabelle
WHERE ID NOT IN (SELECT ID FROM dbo.NeueTabelle)
AND Imei IN (SELECT Imei FROM dbo.VertragsTabelle)
AND Erstellungsdatum > '29.11.2009 00:00:00'

Datenmengen:
Quelltabelle (AlteTabelle) = 60 Mio.
Zieltabelle (NeueTabelle) = 55 Mio.

Nach kurzer Zeit des Wartens wurde mir dann folgende Fehlermeldung ausgeworfen:
Der OLE DB-Anbieter 'SQLNCLI10' für den Verbindungsserver 'Server2' hat die Meldung 'Abfragetimeout abgelaufen' zurückgeben.
Meldung 7399, Ebene 16, Status 1, Zeile 4
Der OLE DB-Anbieter 'SQLNCLI10' für den Verbindungsserver 'Server2' hat einen Fehler gemeldet. Die Ausführung wurde vom Anbieter beendet, da ein Ressourcenlimit erreicht wurde.
Meldung 7421, Ebene 16, Status 2, Zeile 4
Das Rowset kann nicht vom OLE DB-Anbieter 'SQLNCLI10' für den Verbindungsserver 'Server2' abgerufen werden.

Abhilfe:
Da bei mir sichergestellt ist, dass das Statement nur einmalig läuft und nach Beendigung das Timeout wieder gesetzt werden kann, habe ich dieses kurzfirstig wie folgt deaktiviert bzw. auf unbegrenzt gesetzt.

Remote Login Timeout mithilfe dieses Codes auf 30 Sekunden festlegen:
sp_configure 'remote login timeout', 30
go
reconfigure with override
go

Remote Query Timeout auf 0 (unbegrenztes Warten) mithilfe dieser Code festgelegt wird:
sp_configure 'remote query timeout', 0
go
reconfigure with override
go

Donnerstag, 3. Dezember 2009

SQL-Statements blockweise verarbeiten und somit Tablelocks verhindern

Wenn man mit großen Datenmengen arbeiten muss und Abfragen viel Last erzeugen oder sogar komplette Tabellen sperren, so kann man dieses umgehen indem man die Daten blockweise verarbeitet. Hierzu gibt es einen einfachen Trick.

1. SET ROWCOUNT 500
2. insert_more:
3. INSERT INTO dbo.TabelleZiel
4. SELECT * FROM [TestDB].[dbo].TabelleQuelle
5. WHERE ID NOT IN (SELECT ID FROM dbo.TabelleZiel)
6. AND ErstellDatum > '29.11.2009 00:00:00'
7. IF @@ROWCOUNT > 0 GOTO insert_more
8. SET ROWCOUNT 0

Mit dem Befehl RowCount legt man die pro Block zu verarbeitende Anzahl an Datensätzen fest.
Hier ist es wichtig einen geeigneten Wert zu finden. Sollte man die Blöcke zu groß einstellen, so wird doch wieder die komplette Tabelle gesperrt. 500 Datensätze ist hier schon ein gängiger Wert, welcher eigentlich immer verwendet werden kann.

Im Beispiel sieht man eine Goto-Schleife zwischen Zeile 2 und 7.
zwischen diesen Zeilen kann man dann das auszuführende Statement eintagen.
Das Beispiel zeigt ein umfangreicheres Insert. Hier könnte genauso gut ein einfaches Delete stehen.

Wichtig ist auch, dass nach der Verarbeitung die Blockverarbeitung wieder deaktiviert wird.
Dieses geschieht in Zeile 8. Der Wert 0 steht für eine unbegranzte Menge an Datensätzen.

Die Blockverarbeitung ist etwas langsamer als die direkte Komplettverarbeitung. Jedoch ist sie Ressourcen schonender und erzeugt keine Table-Locks.

Freitag, 11. September 2009

Zuweisen von Werten aus einem Enum an eine DropDownList

Wenn man auf einfache Art und Weise eine DropDownList (ggf. ein anderes Control) mit den Werten eines Enumarables füllen möchte,
so kann man dieses per DataBind machen.

Definition des Enums

///
/// Position
///
public enum Position
{
Tor = 0,
Abwehr = 1,
Mittelfeld = 2,
Sturm = 3
}

Zuweisung der Werte des Enums and eine DropDownListe

///
/// Zuweisung der Position
///
protected void BindPosition()
{
// Bestehende Liste leeren
ddlPositions.Items.Clear();

// Werte eines Enums an DropDownListe binden
ddlPositions.DataSource = Enum.GetValues(typeof(Position));
ddlPositions.DataBind();
}

Auslesen des selektierten Wertes der DropDownListe

Position pos = (Position)Enum.Parse(typeof(Position), ddlPositions.SelectedValue);

Freitag, 19. Juni 2009

FileUpload innerhalb eines UpdatePanels

Wenn man innerhalb eines Update-Panels einen FileUpload verwenden will, so muss man einen so genannten PostBackTrigger einbinden.

Ohne den Trigger kann die Datei nicht auf den Server hochgeladen werden. Der Grund hierfür ist, dass das Update-Panel ein Postback verhindert. Setzt man jedoch für den Upload-Button (der Button, auf dem die eigentliche Upload-Funktion liegt) einen Trigger, so wird ein Postback ausgeführt und die gewünschte Datei hochgeladen.

Beispiel:



Freitag, 12. Juni 2009

Ungültiges Datum in SQL-Abfrage

Als ich gerade eine SQL-Abfrage im SQL-Server 2008 ausführen wollte, bin ich auf einen Fehler gestoßen, bei dem ich doch einen Moment lang nach der Fehlerursache suchen musste.

Abfrage:
select * from dbo.Testtabelle
where SpalteVomTypDateTime between '01.09.2008 00:00:00' and '31.09.2008 00:00:00'

Fehlermeldung:
Meldung 242, Ebene 16, Status 3, Zeile 1
Bei der Konvertierung eines char-Datentyps in einen datetime-Datentyp liegt der datetime-Wert außerhalb des gültigen Bereichs.

Ursache:
Normalerweise hätte ich jetzt vermutet, dass ich mich irgendwo vertippt oder mich in der SQL-Syntax vertan habe. Dieses Mal jedoch hat der Fehler nichts mit der Syntax oder mit Schreibfehlern zu tun. Die Ursache für den Abbruch ist ganz einfach. Bei einem Blick auf den Kalender musste ich leider feststellen, dass es den 31. September 2008 gar nicht gibt.

Somit kann natürlich auch kein korrektes Datum erstellt werden.

Zukünftig frage ich wohl besser nur noch Daten ab, die es auch wirklich gibt ;-)

Freitag, 5. Juni 2009

Blog veröffentlicht

Endlich ist es soweit. Nach langer Zeit habe ich nun doch die Zeit gefunden und mir einen Blog erstellt. Hätte ich gewusst, wie einfach es doch ist und vor allem wie schnell es doch geht, einen neuen Blog bei Google zu erstellen, dann hätte ich dieses wahrscheinlich schon viel früher gemacht.
Im Großen und Ganzen soll dieses eigentlich ein Blog über Softwareentwicklung im speziellen ASP.Net, C# sowie SQL werden. Wahrscheinlich wird auch das ein oder andere mal hoffentlich interessante Beiträge zu diversen anderen Themen erscheinen. Aber da lasse ich mich selbst mal überraschen ;-)

So, nun hoffe ich auf viele Leser.

Viele Grüße
Florian