sql-server - CLR 表如何对函数 'streaming' 进行赋值?

标签 sql-server f# sqlclr

MSDN Docs on table-valued Sql Clr functions状态:

Transact-SQL table-valued functions materialize the results of calling the function into an intermediate table. ... In contrast, CLR table-valued functions represent a streaming alternative. There is no requirement that the entire set of results be materialized in a single table. The IEnumerable object returned by the managed function is directly called by the execution plan of the query that calls the table-valued function, and the results are consumed in an incremental manner. ... It is also a better alternative if you have very large numbers of rows returned, because they do not have to be materialized in memory as a whole.

Then I find out that no data access is allowed in the 'Fill row' method 。这意味着您仍然必须在 init 方法中执行所有数据访问并将其保存在内存中,等待调用“Fill row”。我是不是误会了什么? 如果我不将结果强制放入数组或列表中,则会收到错误:“ExecuteReader 需要一个打开且可用的连接。”连接的当前状态已关闭。'

代码示例:

[<SqlFunction(DataAccess = DataAccessKind.Read, FillRowMethodName = "Example8Row")>]
static member InitExample8() : System.Collections.IEnumerable = 
   let c = cn() // opens a context connection
   // I'd like to avoid forcing enumeration here:
   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))
   ()

我在这里处理几百万行。有什么办法可以懒惰地做到这一点吗?

最佳答案

我假设您使用的是 SQL Server 2008。正如 Microsoft 员工在 this page 上提到的那样,2008 年要求使用 DataAccessKind.Read 标记的方法比 2005 年更加频繁。其中一个时间是 TVF 参与事务时(当我测试时,情况似乎总是如此)。解决方案是在连接字符串中指定 enlist=false,可惜它不能与 context connection=true 结合使用。这意味着您的连接字符串需要采用典型的客户端格式:Data Source=.;Initial Catalog=MyDb;Integrated Security=sspi;Enlist=false 并且您的程序集必须使用 permission_set= 创建external_access,至少。作品如下:

using System;
using System.Collections;
using System.Data.SqlClient;
using System.Data.SqlTypes;
using Microsoft.SqlServer.Server;

namespace SqlClrTest {
    public static class Test {
        [SqlFunction(
            DataAccess = DataAccessKind.Read,
            SystemDataAccess = SystemDataAccessKind.Read,
            TableDefinition = "RowNumber int",
            FillRowMethodName = "FillRow"
            )]
        public static IEnumerable MyTest(SqlInt32 databaseID) {
            using (var con = new SqlConnection("data source=.;initial catalog=TEST;integrated security=sspi;enlist=false")) {
                con.Open();
                using (var cmd = new SqlCommand("select top (100) RowNumber from SSP1 where DatabaseID = @DatabaseID", con)) {
                    cmd.Parameters.AddWithValue("@DatabaseID", databaseID.IsNull ? (object)DBNull.Value : databaseID.Value);
                    using (var reader = cmd.ExecuteReader()) {
                        while (reader.Read())
                            yield return reader.GetInt32(0);
                    }
                }
            }
        }
        public static void FillRow(object obj, out SqlInt32 rowNumber) {
            rowNumber = (int)obj;
        }
    }
}

F# 中也有同样的事情:

namespace SqlClrTest

module Test =

    open System
    open System.Data
    open System.Data.SqlClient
    open System.Data.SqlTypes
    open Microsoft.SqlServer.Server

    [<SqlFunction(
        DataAccess = DataAccessKind.Read,
        SystemDataAccess = SystemDataAccessKind.Read,
        TableDefinition = "RowNumber int",
        FillRowMethodName = "FillRow"
        )>]
    let MyTest (databaseID:SqlInt32) =
        seq {
            use con = new SqlConnection("data source=.;initial catalog=TEST;integrated security=sspi;enlist=false")
            con.Open()
            use cmd = new SqlCommand("select top (100) RowNumber from SSP1 where DatabaseID = @DatabaseID", con)
            cmd.Parameters.AddWithValue("@DatabaseID", if databaseID.IsNull then box DBNull.Value else box databaseID.Value) |> ignore
            use reader = cmd.ExecuteReader()
            while reader.Read() do
                yield reader.GetInt32(0)
        } :> System.Collections.IEnumerable

    let FillRow (obj:obj) (rowNumber:SqlInt32 byref) =
        rowNumber <- SqlInt32(unbox obj)

好消息是:Microsoft considers this a bug .

关于sql-server - CLR 表如何对函数 'streaming' 进行赋值?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5653963/

相关文章:

.net - 在 Linux 上使用 z3 .NET 绑定(bind)时的警告 ("unknown parameter ' model_completion'")

c# - CLR 函数中的反序列化失败

sql - 使用 T-SQL/MS-SQL 将字符串附加到现有表格单元格的最简单方法是什么?

sql - 当 WHERE 条件不满足时,如何选择至少 1 行?

sql-server - SQL Server 文件和文件组

sql-server - 仅连接到 SQL Server 2005 数据库时,SQL Management Studio 2008 有什么好处?

.net - MailboxProcessor 在 Finalize 期间崩溃

f# - F#的统计功能(或.NET库)

c# - 我们如何从 SQL Server CLR 调用 SSL Web 服务?

entity-framework - Code first Entity Framework 6.1 自定义聚合函数