为什么我们需要 table 值参数
Why do we need table value parameter
我们可以访问存储过程中的实际 table。那么需要通过参数传递table什么呢?有什么特别的优势吗?
Table 值参数对于以 "safe" 的方式将表格数据传递给存储过程或函数是必需的,尤其是从客户端代码(例如 SqlCommand
和 SqlParameter
).
主要的替代技术是在调用存储过程之前先创建 INSERT
并将其放入 #temporaryTable
,但是临时 table 并不完全是临时的,它们存在于 tempdb
引入了命名空间和并发问题。您还必须使用 Dynamic SQL,因为您无法参数化 table 名称。对于非临时 table,同样的问题也适用。
另外,如果你想将数据传递给一个 FUNCTION
然后你想扔掉然后你不能使用临时 table 因为 FUNCTION
代码是严格的只读:它不能删除临时 table 当它完成时,而 table 值的参数在超出范围后神奇地消失。
如果 FUNCTION
出于相同的只读原因想要将表格数据传递给另一个函数,这也是绝对必需的:该函数不允许创建 #temporarytable
,但它可以创建并填充一个 table 值参数。
打个比方,这就像在堆栈上传递变量与在堆上传递变量一样 - 使用堆栈意味着您可以获得自动生命周期管理和所有权语义,而不必担心并发性 - 而使用堆则引入了一个整体大量问题。
一个例子
假设您的应用程序代码需要将元组列表(或主键列表)传递给存储过程或 FUNCTION
- 或者如果现有存储过程或函数需要将数据传递给另一个功能。
使用临时 tables 你的代码必须这样做:
- 创建并打开
SqlConnection
.
- 创建并开始
TRANSACTION
。
- 新建一个
#temporarytable
- 临时 table 的范围限于当前数据库会话。这对于大多数用途来说是可以的,但这意味着您不能在同一会话中对该临时 table 执行多个并发数据库操作。
LOCK
任何正常的 table 如有必要,您将使用,因为您的操作将跨越多次 SqlCommand
执行。
- 从客户端或原始存储过程,执行
INSERT
语句来填充临时 table。如果您从客户端应用程序插入数据,您可能还需要多次执行单行 INSERT
操作 - 这是非常低效的,尤其是在高延迟连接环境中,因为 [=84 使用的 TDS 协议=] 服务器非常健谈(具有讽刺意味的是,您可以使用 SqlCommand
执行单个多行 INSERT
操作,但您必须使用 Table 值参数来包含多行数据).
- 调用将使用临时 table.
的存储过程或 FUNCTION
- 如果您要让会话保持活动状态,请拆除
#temporaryTable
,或者立即结束会话以防止浪费内存。
但是如果你使用一个 Table 值的参数就简单多了:
- 创建并打开
SqlConnection
.
- 创建并开始
TRANSACTION
。
- 创建将调用存储过程或
FUNCTION
的 SqlCommand
对象,但您可以直接使用 Table-Valued Parameter 并一次性从客户端填充它.然后,客户端软件通过一次操作将 table 数据流推送到服务器,效率更高。
- 存储过程随后运行。无需拆卸或结束会话。
我们可以访问存储过程中的实际 table。那么需要通过参数传递table什么呢?有什么特别的优势吗?
Table 值参数对于以 "safe" 的方式将表格数据传递给存储过程或函数是必需的,尤其是从客户端代码(例如 SqlCommand
和 SqlParameter
).
主要的替代技术是在调用存储过程之前先创建 INSERT
并将其放入 #temporaryTable
,但是临时 table 并不完全是临时的,它们存在于 tempdb
引入了命名空间和并发问题。您还必须使用 Dynamic SQL,因为您无法参数化 table 名称。对于非临时 table,同样的问题也适用。
另外,如果你想将数据传递给一个 FUNCTION
然后你想扔掉然后你不能使用临时 table 因为 FUNCTION
代码是严格的只读:它不能删除临时 table 当它完成时,而 table 值的参数在超出范围后神奇地消失。
如果 FUNCTION
出于相同的只读原因想要将表格数据传递给另一个函数,这也是绝对必需的:该函数不允许创建 #temporarytable
,但它可以创建并填充一个 table 值参数。
打个比方,这就像在堆栈上传递变量与在堆上传递变量一样 - 使用堆栈意味着您可以获得自动生命周期管理和所有权语义,而不必担心并发性 - 而使用堆则引入了一个整体大量问题。
一个例子
假设您的应用程序代码需要将元组列表(或主键列表)传递给存储过程或 FUNCTION
- 或者如果现有存储过程或函数需要将数据传递给另一个功能。
使用临时 tables 你的代码必须这样做:
- 创建并打开
SqlConnection
. - 创建并开始
TRANSACTION
。 - 新建一个
#temporarytable
- 临时 table 的范围限于当前数据库会话。这对于大多数用途来说是可以的,但这意味着您不能在同一会话中对该临时 table 执行多个并发数据库操作。
LOCK
任何正常的 table 如有必要,您将使用,因为您的操作将跨越多次SqlCommand
执行。- 从客户端或原始存储过程,执行
INSERT
语句来填充临时 table。如果您从客户端应用程序插入数据,您可能还需要多次执行单行INSERT
操作 - 这是非常低效的,尤其是在高延迟连接环境中,因为 [=84 使用的 TDS 协议=] 服务器非常健谈(具有讽刺意味的是,您可以使用SqlCommand
执行单个多行INSERT
操作,但您必须使用 Table 值参数来包含多行数据). - 调用将使用临时 table. 的存储过程或
- 如果您要让会话保持活动状态,请拆除
#temporaryTable
,或者立即结束会话以防止浪费内存。
FUNCTION
但是如果你使用一个 Table 值的参数就简单多了:
- 创建并打开
SqlConnection
. - 创建并开始
TRANSACTION
。 - 创建将调用存储过程或
FUNCTION
的SqlCommand
对象,但您可以直接使用 Table-Valued Parameter 并一次性从客户端填充它.然后,客户端软件通过一次操作将 table 数据流推送到服务器,效率更高。 - 存储过程随后运行。无需拆卸或结束会话。