小编Wil*_*Cau的帖子

如何避免在 WHERE 子句中使用变量

给定一个(简化的)存储过程,例如:

CREATE PROCEDURE WeeklyProc(@endDate DATE)
AS
BEGIN
  DECLARE @startDate DATE = DATEADD(DAY, -6, @endDate)
  SELECT
    -- Stuff
  FROM Sale
  WHERE SaleDate BETWEEN @startDate AND @endDate
END
Run Code Online (Sandbox Code Playgroud)

如果Sale表很大,SELECT可能需要很长时间才能执行,显然是因为优化器由于局部变量而无法优化。我们测试运行SELECT带有变量的部件,然后硬编码日期,执行时间从约 9 分钟变为约 1 秒。

我们有许多基于“固定”日期范围(周、月、8 周等)进行查询的存储过程,因此输入参数只是 @endDate,@startDate 是在过程中计算的。

问题是,在 WHERE 子句中避免变量以免损害优化器的最佳做法是什么?

我们提出的可能性如下所示。是否有任何这些最佳实践,或者还有其他方法吗?

使用包装程序将变量转换为参数。

参数不会像局部变量那样影响优化器。

CREATE PROCEDURE WeeklyProc(@endDate DATE)
AS
BEGIN
   DECLARE @startDate DATE = DATEADD(DAY, -6, @endDate)
   EXECUTE DateRangeProc @startDate, @endDate
END

CREATE PROCEDURE DateRangeProc(@startDate DATE, @endDate DATE)
AS
BEGIN
  SELECT
    -- Stuff
  FROM Sale
  WHERE SaleDate …
Run Code Online (Sandbox Code Playgroud)

sql-server-2008 sql-server

16
推荐指数
1
解决办法
3万
查看次数

如何从表中选择而不包含重复的列值?

在上一个问题中如何合并数据集而不包括冗余行?我询问了在导入过程中过滤冗余历史数据的问题,但@DavidSpillett 正确回答说我无法做我想做的事情。

我现在不想在导入过程中过滤表,而是想在表上创建一个视图,该视图仅返回价格发生变化的记录。

这是为解决这个问题而改写的原始场景:

我们有一个物品的历史价格表。该表包含多个日期记录相同价格的行。我想在此数据上创建一个视图,该视图仅显示价格随时间的变化,因此如果价格从 A 更改为 BI 想要查看它,但如果它从 B“更改”为 B 那么我不想看到它.

例子:如果昨天的价格是$1,今天的价格是$1,并且没有其他价格变化,那么今天的价格可以从昨天的价格推断出来,所以我只需要昨天的记录。

示例(http://sqlfiddle.com/#!3/c95ff/1):

Table data:

Effective            Product  Kind  Price
2013-04-23T00:23:00  1234     1     1.00
2013-04-24T00:24:00  1234     1     1.00 -- redundant, implied by record 1
2013-04-25T00:25:00  1234     1     1.50
2013-04-26T00:26:00  1234     1     2.00
2013-04-27T00:27:00  1234     1     2.00 -- redundant, implied by record 4
2013-04-28T00:28:00  1234     1     1.00 -- not redundant, price changed back to 1.00

Expected view data:

Effective            Product  Kind  Price
2013-04-23T00:23:00  1234     1 …
Run Code Online (Sandbox Code Playgroud)

sql-server-2008

5
推荐指数
2
解决办法
9688
查看次数

是否存在跨多个数据库使用通用数据和过程的标准方法?

我们有几个独立的数据库,它们的数据和代码是相同的,不是在数据库之间访问,而是在每个数据库中数据意味着相同的事情,代码做同样的事情。

例子是:

  • 配置设置(例如错误代码 50xxx、公司名称的样板文本等)。
  • 执行常见任务的过程和函数(例如,将 CSV 字符串转换为表格、记录错误、根据错误代码格式化错误消息)。
  • 表结构(例如数据库版本历史表、记录错误表)。除了列、约束和触发器之外,还有读/写数据的通用过程和函数。
  • 查找表(例如,包含 2000-2100 年之间日期的日期查找表)。这些类似于表结构,但通常数据库中的数据是相同的。对于日期表,开始和结束日期是配置设置,由函数读取,然后由程序生成日期数据。所有这些操作在数据库之间都是通用的。
  • 用户定义的类型(例如用于将表传递给函数的类型)。

出于维护和支持的原因,我认为对于错误代码、过程、函数和类型之类的东西来说,在所有数据库中拥有一个“单一事实点”是有意义的,而不是每个数据库中都有一个不同的事实。

目前,每个数据库都有自己的所有副本,包括源存储库,我们独立维护它们。这很不理想,因为在 A 中修复一个过程而忘记将它放在 B 中太容易了,或者在 A 中添加错误代码而在 B 中添加相同的错误代码但它们意味着不同的东西,等等。

数据库不会同时更新,它们不一定驻留在相同的硬件上。在某些情况下,它们可以相互读取数据(如果存在另一个)。

是否有一种标准方法可以为跨多个数据库使用的数据/代码提供单一事实点?

sql-server-2008 sql-server

3
推荐指数
1
解决办法
1465
查看次数

如何从使用 sp_executesql 执行的存储过程中获取返回值

我需要调用另一个数据库中的存储过程并检查返回值。其他数据库的名称可能会有所不同,因此我尝试使用 sp_executesql,但我一直无法找到如何从该过程中获取返回值。

这是我所拥有的简化版本:

DECLARE @errorLogId INT
DECLARE @otherDbName NVARCHAR(MAX) = 'Foo' -- Get the database name from somewhere
DECLARE @sql NVARCHAR(MAX)

SET @sql = @otherDbName + '.dbo.SomeProc'

-- I want @errorLogId to be the return value from SomeProc, this didn't work.    
EXECUTE @errorLogId = sp_executesql @sql

IF @errorLogId <> 0
   RAISERROR('SomeProc failed, ErrorLogId = %d.', 16, 1, @errorLogId) WITH SETERROR
Run Code Online (Sandbox Code Playgroud)

如果 SomeProc 中发生错误,它会被捕获并将条目写入错误表(在另一个数据库中),然后 SomeProc 返回所写入记录的错误表 ID(标识)。否则 SomeProc 返回 0。

我知道 SomeProc 失败,因为错误被写入另一个数据库中的错误日志,但在本地数据库中 @errorLogId 为 0,这被视为成功。我认为返回值会“通过”sp_executesql,但我认为返回值实际上来自 sp_executesql 而不是 SomeProc(即,无论 SomeProc 成功还是失败,sp_executesql …

sql-server sql-server-2008-r2

1
推荐指数
1
解决办法
3万
查看次数