有没有办法让TSQL变量保持不变?

The*_*tan 82 t-sql sql-server

有没有办法让TSQL变量保持不变?

SQL*_*ace 53

不,但你可以在那里创建一个函数并对其进行硬编码并使用它.

这是一个例子:

CREATE FUNCTION fnConstant()
RETURNS INT
AS
BEGIN
    RETURN 2
END
GO

SELECT dbo.fnConstant()
Run Code Online (Sandbox Code Playgroud)

  • `WITH SCHEMABINDING`**应该**将它转换为'实数'常量(要求UDF在SQL中被视为确定性).即它应该被缓存.仍然是+1. (11认同)
  • 是的,在函数中。WITH SCHEMABINDING 允许 SQL 内联“内联表值函数” - 因此它*也*需要采用以下形式:https://gist.github.com/jcdickinson/61a38dedb84b35251da301b128535ceb。查询分析器不会内联任何没有 SCHEMABINDING 或任何带有 BEGIN 的内容。 (2认同)

Joh*_*son 19

我对缺少常量的解决方法是给优化器提供有关值的提示.

DECLARE @Constant INT = 123;

SELECT * 
FROM [some_relation] 
WHERE [some_attribute] = @Constant
OPTION( OPTIMIZE FOR (@Constant = 123))
Run Code Online (Sandbox Code Playgroud)

这告诉查询编译器在创建执行计划时将变量视为常量.缺点是你必须定义两次值.

  • 它有帮助,但也违背了单一定义的目的。 (4认同)

小智 19

使用伪常量:http://blogs.msdn.com/b/sql_server_appendix_z/archive/2013/09/16/sql-server-variables-parameters-or-literals-or-constants.aspx

伪常数不是变量或参数.相反,它们只是一行的视图,以及足够的列来支持您的常量.使用这些简单的规则,SQL引擎完全忽略视图的值,但仍然根据其值构建执行计划.执行计划甚至没有显示视图的连接!


jas*_*ldo 9

不,但应使用良好的旧命名约定.

declare @MY_VALUE as int
Run Code Online (Sandbox Code Playgroud)


Sör*_*lau 7

T-SQL中没有对常量的内置支持.您可以使用SQLMenace的方法来模拟它(尽管您永远无法确定其他人是否已覆盖该函数以返回其他内容...),或者可能会编写一个包含常量的表,如此处所示.也许写一个触发器来回滚ConstantValue列的任何更改?


小智 7

在使用SQL函数之前,请运行以下脚本以查看性能差异:

IF OBJECT_ID('fnFalse') IS NOT NULL
DROP FUNCTION fnFalse
GO

IF OBJECT_ID('fnTrue') IS NOT NULL
DROP FUNCTION fnTrue
GO

CREATE FUNCTION fnTrue() RETURNS INT WITH SCHEMABINDING
AS
BEGIN
RETURN 1
END
GO

CREATE FUNCTION fnFalse() RETURNS INT WITH SCHEMABINDING
AS
BEGIN
RETURN ~ dbo.fnTrue()
END
GO

DECLARE @TimeStart DATETIME = GETDATE()
DECLARE @Count INT = 100000
WHILE @Count > 0 BEGIN
SET @Count -= 1

DECLARE @Value BIT
SELECT @Value = dbo.fnTrue()
IF @Value = 1
    SELECT @Value = dbo.fnFalse()
END
DECLARE @TimeEnd DATETIME = GETDATE()
PRINT CAST(DATEDIFF(ms, @TimeStart, @TimeEnd) AS VARCHAR) + ' elapsed, using function'
GO

DECLARE @TimeStart DATETIME = GETDATE()
DECLARE @Count INT = 100000
DECLARE @FALSE AS BIT = 0
DECLARE @TRUE AS BIT = ~ @FALSE

WHILE @Count > 0 BEGIN
SET @Count -= 1

DECLARE @Value BIT
SELECT @Value = @TRUE
IF @Value = 1
    SELECT @Value = @FALSE
END
DECLARE @TimeEnd DATETIME = GETDATE()
PRINT CAST(DATEDIFF(ms, @TimeStart, @TimeEnd) AS VARCHAR) + ' elapsed, using local variable'
GO

DECLARE @TimeStart DATETIME = GETDATE()
DECLARE @Count INT = 100000

WHILE @Count > 0 BEGIN
SET @Count -= 1

DECLARE @Value BIT
SELECT @Value = 1
IF @Value = 1
    SELECT @Value = 0
END
DECLARE @TimeEnd DATETIME = GETDATE()
PRINT CAST(DATEDIFF(ms, @TimeStart, @TimeEnd) AS VARCHAR) + ' elapsed, using hard coded values'
GO
Run Code Online (Sandbox Code Playgroud)

  • 这是相当古老的,但在这里参考是在我的服务器上执行的结果:| `2760ms过去了,使用函数`| `2300ms过去了,使用局部变量`| `经过2286ms,使用硬编码值| (4认同)
  • 在开发型笔记本电脑上,具有两个没有模式绑定的附加功能。使用功能5过去了5570 使用本地变量,“ 406已逝去” 使用硬编码值,“ 383已逝去” 使用了没有模式绑定的函数,3893过去了 (2认同)

小智 5

如果您有兴趣为变量中的值获取最佳执行计划,则可以使用动态sql代码.它使变量保持不变.

DECLARE @var varchar(100) = 'some text'
DECLARE @sql varchar(MAX)
SET @sql = 'SELECT * FROM table WHERE col = '''+@var+''''
EXEC (@sql)
Run Code Online (Sandbox Code Playgroud)


use*_*606 5

对于枚举或简单常量,具有单行的视图具有出色的性能和编译时检查/依赖性跟踪(导致其列名)

请参阅Jared Ko的博客文章https://blogs.msdn.microsoft.com/sql_server_appendix_z/2013/09/16/sql-server-variables-parameters-or-literals-or-constants/

创建视图

 CREATE VIEW ShipMethods AS
 SELECT CAST(1 AS INT) AS [XRQ - TRUCK GROUND]
   ,CAST(2 AS INT) AS [ZY - EXPRESS]
   ,CAST(3 AS INT) AS [OVERSEAS - DELUXE]
  , CAST(4 AS INT) AS [OVERNIGHT J-FAST]
   ,CAST(5 AS INT) AS [CARGO TRANSPORT 5]
Run Code Online (Sandbox Code Playgroud)

使用视图

SELECT h.*
FROM Sales.SalesOrderHeader 
WHERE ShipMethodID = ( select [OVERNIGHT J-FAST] from ShipMethods  )
Run Code Online (Sandbox Code Playgroud)