有没有办法使TSQLvariables不变?
有没有办法使TSQLvariables不变?
不,但是你可以创build一个函数并在那里硬编码并使用它。
这里是一个例子:
CREATE FUNCTION fnConstant() RETURNS INT AS BEGIN RETURN 2 END GO SELECT dbo.fnConstant()
缺less常量的解决方法是提供有关优化器的值的提示。
DECLARE @Constant INT = 123; SELECT * FROM [some_relation] WHERE [some_attribute] = @Constant OPTION( OPTIMIZE FOR (@Constant = 123))
这就告诉查询编译器在创build执行计划时将这个variables看作是一个常量。 不利的一面是你必须定义两次这个值。
使用伪常量: http : //blogs.msdn.com/b/sql_server_appendix_z/archive/2013/09/16/sql-server-variables-parameters-or-literals-or-constants.aspx
伪常量不是variables或参数。 相反,它们只是一行视图,并且有足够的列来支持你的常量。 有了这些简单的规则,SQL引擎完全忽略了视图的价值,但仍然根据其值创build执行计划。 执行计划甚至不显示join视图!
T-SQL中没有对常量的内置支持。 你可以使用SQLMenace的方法来模拟它(尽pipe你永远无法确定别人是否覆盖函数返回其他东西…),或者可能编写一个包含常量的表, 正如在这里build议的 。 也许写一个触发器,将任何更改回滚到ConstantValue
列?
不,但应使用古老的命名惯例。
declare @MY_VALUE as int
在使用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
如果您有兴趣为variables中的值获取最佳执行计划,则可以使用dynamicSQL代码。 它使variables不变。
DECLARE @var varchar(100) = 'some text' DECLARE @sql varchar(MAX) SET @sql = 'SELECT * FROM table WHERE col = '''+@var+'''' EXEC (@sql)
好的,让我们看看
常量是编译时已知的不变值,不会改变程序的生命周期
这意味着你永远不能在SQL Server中有一个常量
declare @myvalue as int set @myvalue = 5 set @myvalue = 10--oops we just changed it
价值刚刚改变
在数据库文献中没有“创造一个不变”的东西。 常量按原样存在,通常称为值。 我们可以声明一个variables并为其赋值(常量)。 从学术angular度看:
DECLARE @two INT SET @two = 2
这里@two是一个variables,2是一个值/常量。
最好的答案是根据需要从SQLMenace中创build一个在脚本中使用的临时常量,即在多个GO语句/批处理中使用。
只需在tempdb中创build过程,就不会对目标数据库产生任何影响。
一个实际的例子就是数据库创build脚本,它在包含逻辑模式版本的脚本末尾写入一个控制值。 在文件的顶部是一些评论与变化的历史等…但实际上大多数开发人员会忘记向下滚动并更新文件底部的架构版本。
使用上面的代码允许在数据库脚本(从SSMS的生成脚本特性中复制)创build数据库之前在顶部定义一个可见的模式版本常量,但在最后使用。 面对更改历史和其他评论旁边的开发者,这是正确的,所以他们很可能会更新它。
例如:
use tempdb go create function dbo.MySchemaVersion() returns int as begin return 123 end go use master go -- Big long database create script with multiple batches... print 'Creating database schema version ' + CAST(tempdb.dbo.MySchemaVersion() as NVARCHAR) + '...' go -- ... go -- ... go use MyDatabase go -- Update schema version with constant at end (not normally possible as GO puts -- local @variables out of scope) insert MyConfigTable values ('SchemaVersion', tempdb.dbo.MySchemaVersion()) go -- Clean-up use tempdb drop function MySchemaVersion go
不幸的是,这是一个错误的答案,已被选为正确的在这里…
正确答案是由上面的mbobka / Pixelated给出的: 使用(伪)常量视图
即使使用与模式绑定的函数也不会使编译器明白它是一个常量!