通用 TVP 权衡?

Dan*_*zzi 6 sql-server table-valued-parameters

是否有针对 TVP 中使用的表类型的最佳实践或策略?例如,鉴于以下情况:

CREATE TABLE dbo.Colors (
    Id int identity PRIMARY KEY,
    Name nvarchar(100),
);

CREATE TABLE dbo.Shapes (
    Id int identity PRIMARY KEY,
    Name nvarchar(100),
);

CREATE TABLE dbo.Materials (
    Id int identity PRIMARY KEY,
    Name nvarchar(100),
);

CREATE TABLE dbo.Items (
    Id int identity PRIMARY KEY,
    Name nvarchar(100),
    ColorId int FOREIGN KEY REFERENCES dbo.Colors (ID),
    ShapeId int FOREIGN KEY REFERENCES dbo.Shapes (ID),
    MaterialId int FOREIGN KEY REFERENCES dbo.Materials (ID),
);
Run Code Online (Sandbox Code Playgroud)

如果您实现了一个存储过程来搜索需要支持通过 TVP 选择多种颜色、多种形状和多种材料的项目(想想 UI 中的复选框列表),您会创建三种单独的表格类型,一种用于每个 TVP,还是创建一个类型以在所有三个中使用它?

换句话说,这:

CREATE TYPE dbo.ColorIds AS TABLE (Id int);
CREATE TYPE dbo.ShapeIds AS TABLE (Id int);
CREATE TYPE dbo.MaterialIds AS TABLE (Id int);
GO

CREATE PROCEDURE dbo.SearchItems
    @ColorIds ColorIds READONLY,
    @ShapeIds ShapeIds READONLY,
    @MaterialIds MaterialIds READONLY
AS
BEGIN
    PRINT 'Do something here'
END
GO
Run Code Online (Sandbox Code Playgroud)

与此相反:

CREATE TYPE dbo.Ids AS TABLE (Id int);
GO

CREATE PROCEDURE dbo.SearchItems
    @ColorIds Ids READONLY,
    @ShapeIds Ids READONLY,
    @MaterialIds Ids READONLY
AS
BEGIN
    PRINT 'Do something here'
END
GO
Run Code Online (Sandbox Code Playgroud)

样本是故意设计的;真正的用例由更多的表组成,这些表虽然有不同的列,但都有一个ID int主键。因此,我个人倾向于做后者。它的开销要少得多,但我很想知道这样做是否有任何我应该注意的缺点。这当然适用于 TVP 和 TVP (我永远不会在真实表或任何其他更持久的结构中混合不同的实体。)

在此期间,您命名表类型和 TVP 的命名约定是什么?

Wor*_*DBA 7

我个人在我的系统中使用后者,更通用的版本。我有两个我能想到的表:UniqueIntegerTable而且UniqueStringTable- 你可以想象,它们的定义如下:

CREATE TYPE Utils.UniqueIntegerTable AS TABLE (
    [Value] INT NOT NULL PRIMARY KEY
);
CREATE TYPE Utils.UniqueStringTable AS TABLE (
    [Value] NVARCHAR(50) NOT NULL PRIMARY KEY
);
Run Code Online (Sandbox Code Playgroud)

我更喜欢使用通用 TVP,这样我就不会用基本相同的多种类型阻塞我的模式。性能与您在第一个示例中定义的显式类型完全相同,它的好处是它为我创建的代码更少,需要维护。

我知道我之前听到的关于使用绑定到表的显式类型的一个论点是更容易理解它们的用法。我个人不同意这一点。没有什么可以阻止我使用错误的类型定义存储过程(但具有满足我需要的正确形状)。相反,我可以给变量一个好名字来推断用法和表的内容:

CREATE PROCEDURE dbo.UpdateEmployees (
    @employeeIds Utils.UniqueIntegerTable READONLY
)
BEGIN
SET NOCOUNT ON;

-- Use table as needed.

END
GO
Run Code Online (Sandbox Code Playgroud)

在命名约定方面,我不知道任何官方标准,但我使用的标准是附加Table到类型名称的末尾。我知道这与给事物添加前缀并没有什么不同,tbl但在这种情况下我可以接受。与所有命名约定一样,请选择您认为易于使用的命名约定 - 但一旦完成,请坚持下去。命名约定仅在您保持一致时才有用。

  • 完全同意没有什么可以阻止您使用错误的类型部分。事实上,就在发布问题之前,我正在检查表类型是否有类似 FK 约束的东西。没有找到任何东西。如果有一个论点促使我倾向于支持特定类型,那就是它了。我很高兴事实并非如此! (2认同)