verwendetes Datenbanksystem: <SQL Express 2008>
VS 2008 C# mit LINQ to SQL
Hallo,
ich habe folgendes Problem.
Mein Programm besteht aus einem UI und einem Background Thread.
Der Background schreibt kontinuierlich Messdaten in die Datenbank (Messdaten Tabelle) (Dies habe ich über eine Transaction gelößt).
Auf der UI hat der User die Möglichkeit sich die Messdaten anzeigen zu lassen.
Allerdings kann er die Daten nicht anzeigen während die Transaction offen ist.
Ich hätte gerne, dass aus der MessdatenTabelle alle Daten angezeigt werden, die nicht von der Transaction betroffen sind.
Wenn ich aber die Tabelle abfrage laufe ich nur in ein Timeout...
Gibts eine Möglichkeit in der LINQ Abfrage zu sagen, er soll nur nicht gesperrte Daten ausgeben?
Dank für alle Hilfe
Alexander
Brot kann schimmeln - ich kann nichts!
Hallo Alexander
Standardmäßig werden nur die Zeilen gelockt die neu geschrieben oder aktualisiert werden. Wenn deine Abfrage diese Daten nicht beinhaltet sollte normalerweise ein Ergebnis zurückgeliefert werden. Ausnahme ist hierbei jedoch Lock Escalation. Hier ein Artikel von Adam Machanic zu dem Thema:
SQL Server 2008: Lock Escalation, INSERTs, and a Potential Bug
Ansonsten gäbe es theoretisch(!!!) die Möglichkeit mit SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
zu arbeiten. Davon rate ich aber dringendst ab!
Der einfache korrekte Ansatz wäre hier einfach den Background Thread nicht die ganze Zeit mit der gleichen Transaktion arbeiten zu lassen sondern diese alle paar Sekunden zu comitten. Damit kann das parallel abgesetzte SELECT zurückgeliefert werden und alles ist valide.
Ein anderer Weg wäre den Background Thread in eine Staging-Tabelle statt in die eigentliche Zieltabelle schreiben zu lassen und die Daten erst am Ende über eine Bulk-Operation in die Zieltabelle zu übertragen.
Frage:
Welche Datenmengen importiert der Background Thread denn, dass der so lange braucht?
Grüße
Flo
Blog: Things about Software Architecture, .NET development and SQL Server
Twitter
Google+
Je mehr ich weiß, desto mehr weiß ich was ich noch nicht weiß.
...die Daten kommen von einer Messmaschine, wobei an dieser nicht exakt die Dauer einer Messfahrt definiert ist.
Eigentlich wollte ich die Transaction nutzen, damit nicht vor dem Ende der Messung auf die zugehöirgen Daten zugegriffen werden kann.
Wonach könnte ich die Abfrage filtern, damit nicht die Daten, die momentan geschrieben werden (gesperrt sind), Teil der Abfrage sind.
Ich weiss ja nicht auf welche Datensätze geschrieben wird...
Grüsse
Alexander
Brot kann schimmeln - ich kann nichts!
Hallo Alexander
Kommt drauf an. Wie schon gesagt, vielleicht einfach mit einer Staging-Tabelle arbeiten.
Je nach Menge der Daten kannst du die in dem Worker-Thread puffern und über eine Bulk-Operation auf einmal in die Tabellen schreiben. Die Performance bei Bulk-Operationen ist dabei so hoch dass es den Client nicht stören sollte. Hierzu kannst du die Daten entweder die SqlBulkCopy
Klasse verwenden welche auf BCP aufsetzt, oder Table-Valued Parameter (TVPs) verwenden. Zu TVPs habe ich vor ein paar Monaten einige Tests gemacht und komme dabei mit 400.000 Datensätzen auf eine Laufzeit von 7 Sekunden. Siehe:
Table-Valued Parameters - A Performance Comparison
Zuletzt kannst du noch mit TRANSACTION LEVEL SNAPSHOT arbeiten. Das erfordert in deiner aktuellen Implementierung keine Anpassungen, ist aber teuer für den SQL Server da er alle Requests kopieren muss. Dazu muss über ALTER DATABASE Sandbox SET ALLOW_SNAPSHOT_ISOLATION OFF
erstmal Snapshot auf der Datenbank erlaubt werden und danach über SET TRANSACTION ISOLATION LEVEL SNAPSHOT;
die entsprechende Transaktion in den Snapshot-Modus versetzt werden. Allerdings kann ich dir hier jetzt nicht sagen wie du das in deinem O/R-Mapper aktivieren kannst.
Grüße
Flo
Blog: Things about Software Architecture, .NET development and SQL Server
Twitter
Google+
Je mehr ich weiß, desto mehr weiß ich was ich noch nicht weiß.
Hallo,
hab die TVPs mal überflogen, klingt echt vielversprechend (leider keine Linq 2 SQL Unterstützung).
Gibt es eine Möglichkeit, dass mir beim Lesen nur aller Daten der Tabelle nur die angezeigt werden, welche "commited" sind und die anderen weggelassen werden?
so siehts im Moment aus
li_messungen = (from m in rohdatendc.Messungen
where (m.FKTypNummerPK == iPK)
select
new T_Messungen(m.PK, m.UNI, m.Timestamp, ....).ToList();
...
ich möchte, dass mir nur die angezeigt werden, die commited sind
(die halbfertigen soll er nicht anzeigen)
Gruß alex
Brot kann schimmeln - ich kann nichts!
Nur weil's LINQ2SQL nicht kann heißt das ja nicht dass man's nicht machen kann...
Anyway...
Wie schon gesagt, du musst das Transaction-Level auf Snapshot stellen oder stagen.
Grüße
Flo
Blog: Things about Software Architecture, .NET development and SQL Server
Twitter
Google+
Je mehr ich weiß, desto mehr weiß ich was ich noch nicht weiß.