the*_*bit 6 sql vb.net sql-server stored-procedures
上下文
我们目前正在清理SQL数据库,我们遇到了大量的存储过程,它们之间只有细微的差别.我们希望将它们整合到一个单一的过程中,以便于维护.
问题
下面只是我们尝试合并的那种存储过程的两个例子(请注意,这些是简化版本,而不是实际的过程).
存储过程 - 当前预订
ALTER PROCEDURE [dbo].[SelectCurrentBookings]
@client_FK INT, @startDate DATETIME, @endDate DATETIME
AS
BEGIN
SELECT ROW_NUMBER() OVER (ORDER BY [Booking].[bookingDateTime]) [RowNumber],
[Booking].[booking_PK] [Booking ID],
[Booking].[bookingDateTime] [Booking Date],
[Booking].[bookingDuration] [Duration],
[Booking].[client] [Client Name],
CASE WHEN [Booking].[bookingStatusCode_FK] IN (4,8,9,7,16) THEN 1 ELSE 0 END [Unserviced],
FROM [Booking]
WHERE [client_FK] = @client_FK
AND [Booking].[bookingStatusCode_FK] IN (1,2,14,17)
AND [Booking].[bookingDateTime] >= @startDate
AND [Booking].[bookingDateTime] < DATEADD(d,1,@endDate)
AND [Booking].[deleted] = 0
END
Run Code Online (Sandbox Code Playgroud)
存储过程 - 存档预订
ALTER PROCEDURE [dbo].[SelectArchivedBookings]
@client_FK INT, @startDate DATETIME, @endDate DATETIME
AS
BEGIN
SELECT ROW_NUMBER() OVER (ORDER BY [Booking].[bookingDateTime]) [RowNumber],
[Booking].[booking_PK] [Booking ID],
[Booking].[bookingDateTime] [Booking Date],
[Booking].[bookingDuration] [Duration],
[Booking].[client] [Client Name],
CASE WHEN [Booking].[bookingStatusCode_FK] IN (4,8,9,7,16) THEN 1 ELSE 0 END [Unserviced],
FROM [Booking]
WHERE [client_FK] = @client_FK
AND [Booking].[bookingStatusCode_FK] IN (1,2,14,4,9,7,16,13)
AND [Booking].[bookingDateTime] >= @startDate
AND [Booking].[bookingDateTime] < DATEADD(d,1,@endDate)
AND [Booking].[deleted] = 0
END
Run Code Online (Sandbox Code Playgroud)
调用存储过程的代码在VB.NET中
Dim Command As DbCommand = _db.GetStoredProcCommand("SelectCurrentBookings")
_db.AddInParameter(Command, "client_FK", DbType.Int32, ClientID)
_db.AddInParameter(Command, "startDate", DbType.DateTime, StartDate)
_db.AddInParameter(Command, "endDate", DbType.DateTime, EndDate)
Return _db.ExecuteDataSet(Command)
Run Code Online (Sandbox Code Playgroud)
如您所见,上述存储过程之间的唯一区别是提供给WHERE IN的值.
有没有办法让我们修改它并通过参数或变量提供值列表?
如果目标是减少维护工作,我会谦虚地建议将数据值移出数据层并将它们硬编码到逻辑层中(也许在几个地方),这可能无助于实现这一目标。
从查询中删除这些显式值将删除优化器可用于创建计划的信息。请小心将其替换为更好的东西,否则查询性能可能会受到影响。我认为这些 SP 是精确分离的,因此每个 SP 都存在独特的计划,特别是当查询比显示的复杂得多时。将当前的计划与其他计划以及最终的结果进行比较,以确保您没有倒退。
一种选择可能是创建一个新的“列表”表:
ListName StatusCode
current 1
current 2
...
current 17
archive 1
archive 2
archive 4
...
archive 16
Run Code Online (Sandbox Code Playgroud)
连接到该表而不是使用 IN 子句。通过 ListName 限定连接,该名称作为参数传递。(ListName, StatusCode) 上的唯一聚集索引会很好。您可以考虑为每个 ListName 创建一个过滤统计数据。如果您拥有状态值的主列表,请创建外键约束。
存储过程则变为
ALTER PROCEDURE [dbo].[SelectCurrentBookings]
@client_FK INT, @startDate DATETIME, @endDate DATETIME,
@ListName char(10)
AS
BEGIN
SELECT ROW_NUMBER() OVER (ORDER BY [Booking].[bookingDateTime]) [RowNumber],
...
FROM [Booking]
INNER JOIN dbo.List as l
ON [Booking].[bookingStatusCode_FK] = l.StatusCode
AND l.ListName = @ListName
WHERE [client_FK] = @client_FK
AND [Booking].[bookingDateTime] >= @startDate
AND [Booking].[bookingDateTime] < DATEADD(d,1,@endDate)
AND [Booking].[deleted] = 0
END
Run Code Online (Sandbox Code Playgroud)
调用代码获得一个参数
Dim Command As DbCommand = _db.GetStoredProcCommand("SelectCurrentBookings")
_db.AddInParameter(Command, "client_FK", DbType.Int32, ClientID)
_db.AddInParameter(Command, "startDate", DbType.DateTime, StartDate)
_db.AddInParameter(Command, "endDate", DbType.DateTime, EndDate)
_db.AddInParameter(Command, "ListName", DbType.String, "current") //correct type needed
Return _db.ExecuteDataSet(Command)
Run Code Online (Sandbox Code Playgroud)
通过这种方式,状态代码的含义被记录在一个地方,并且优化器可以获得良好的统计数据。这是否比当前的实现更快,只有测试才能知道。
| 归档时间: |
|
| 查看次数: |
172 次 |
| 最近记录: |