Die MSDN-Dokumente zu tabellenwertigen Sql Clr-Funktionen besagen:
Transact-SQL-Tabellenwertige Funktionen materialisieren die Ergebnisse des Funktionsaufrufs in eine Zwischentabelle. ... Im Gegensatz dazu stellen CLR-Tabellenwertige Funktionen eine alternative Streaming-Möglichkeit dar. Es besteht keine Anforderung, dass der gesamte Ergebnissatz in einer einzelnen Tabelle materialisiert wird. Das von der verwalteten Funktion zurückgegebene IEnumerable-Objekt wird direkt vom Ausführungsplan der Abfrage aufgerufen, die die tabellenwertige Funktion aufruft, und die Ergebnisse werden inkrementell verarbeitet. ... Es ist auch eine bessere Alternative, wenn sehr viele Zeilen zurückgegeben werden, weil sie nicht als Ganzes im Speicher materialisiert werden müssen.
Dann finde ich heraus, dass kein Datenzugriff in der 'Fill row'-Methode erlaubt ist. Das bedeutet, dass Sie immer noch all Ihren Datenzugriff in der Init-Methode erledigen müssen und ihn im Speicher behalten müssen, bis 'Fill row' aufgerufen wird. Habe ich etwas missverstanden? Wenn ich meine Ergebnisse nicht in ein Array oder eine Liste zwingen, erhalte ich einen Fehler: 'ExecuteReader erfordert eine offene und verfügbare Verbindung. Der aktuelle Zustand der Verbindung ist geschlossen.'
Codebeispiel:
[]
static member InitExample8() : System.Collections.IEnumerable =
let c = cn() // öffnet eine Kontextverbindung
// Ich möchte hier das Erzwingen einer Enumeration vermeiden:
let data = getData c |> Array.ofSeq
data :> System.Collections.IEnumerable
static member Example8Row ((obj : Object),(ssn: SqlChars byref)) =
do ssn <- new SqlChars(new SqlString(obj :?> string))
()
Ich habe hier mit mehreren Millionen Zeilen zu tun. Gibt es eine Möglichkeit, dies faul zu machen?
0 Stimmen
Die Art und Weise, wie ich die Dokumentation lese, scheint zu implizieren, dass bei einer tabellenwertigen Funktion der gesamte Ergebnissatz generiert und irgendwo abgelegt wird - wahrscheinlich im Speicher, wenn er klein ist, und andernfalls in tempdb -, bevor die Ergebnisse an den Client zurückgegeben werden. Mit CLR kann der Ergebnissatz direkt aus einem Speicherpuffer an den Client zurückgegeben werden, sobald einige Datensätze verfügbar sind. Ich weiß nicht, ob Sie sich diesbezüglich explizit Sorgen machen müssen. Ich glaube, MSDN erläutert einfach die internen Arbeitsweisen beider Arten von Tabellenfunktionen. Es sei denn, ich habe den Artikel falsch verstanden.
0 Stimmen
Ich glaube, dass
yield return
in C# funktioniert. Ich würde erwarten, dassseq { }
ähnlich funktioniert. Nicht wahr?2 Stimmen
@Daniel - Das habe ich versucht. Ich möchte '|> Array.ofSeq' entfernen und stattdessen yield return verwenden, aber das führt zu diesem Fehler. Darum geht es bei dieser Frage. Beim Yielding wird der Datenzugriff in der Example8Row-Funktion durchgeführt, was anscheinend nicht erlaubt ist.
0 Stimmen
@Yuck und Robert: Ja, der "Streaming"-Teil bezieht sich auf die Möglichkeit,
yield return
zu verwenden, um Ergebnisse zurückzusenden, bevor die Methode endet. Dies ist eine Option, die du verwenden könntest, oder du kannst die Sammlung aufbauen und sie am Ende der Methode komplett zurücksenden. Für T-SQL-Mehrere-Anweisungen-TVF gibt es keine Wahl. Alles, was sie tun können, ist die Ergebnisse in einer Tabellenvariable aufzubauen, die nur am Ende der Funktion zurückgegeben werden kann.