Есть ли способ сделать переменную TSQL постоянной?
sql-server
tsql
TheEmirOfGroofunkistan
источник
источник
WITH SCHEMABINDING
должен превратить это в «реальную» константу (требование, чтобы UDF рассматривалась как детерминированная в SQL). Т.е. он должен попасть в кеш. Тем не менее, +1.WITH SCHEMABINDING
вCREATE FUNCTION
операторе (в отличие от хранимой процедуры, которая может вызывать функцию) - это правильно?Одним из решений, предложенных Джаредом Ко, является использование псевдоконстант .
Как объяснено в SQL Server: переменные, параметры или литералы? Или… константы? :
источник
Мой обходной путь к отсутствию констант - дать подсказку о значении оптимизатору.
DECLARE @Constant INT = 123; SELECT * FROM [some_relation] WHERE [some_attribute] = @Constant OPTION( OPTIMIZE FOR (@Constant = 123))
Это указывает компилятору запроса обрабатывать переменную, как если бы она была константой при создании плана выполнения. Обратной стороной является то, что вам нужно определить значение дважды.
источник
Нет, но следует использовать старые добрые соглашения об именах.
declare @MY_VALUE as int
источник
FN_CONSTANT()
. Так понятно, что он делает.В T-SQL нет встроенной поддержки констант. Вы можете использовать подход SQLMenace для его моделирования (хотя вы никогда не можете быть уверены, что кто-то перезаписал функцию, чтобы вернуть что-то еще…), или, возможно, написать таблицу, содержащую константы, как предлагается здесь . Может быть, написать триггер, который откатывает любые изменения в
ConstantValue
столбце?источник
Перед использованием функции 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
источник
2760ms elapsed, using function
|2300ms elapsed, using local variable
|2286ms elapsed, using hard coded values
|5570 elapsed, using function
|406 elapsed, using local variable
|383 elapsed, using hard coded values
|3893 elapsed, using function without schemabinding
select top 1 @m = cv_val from code_values where cv_id = 'C101'
и такие же,... 'C201'
где code_values - таблица словаря с 250 варами, все они были на SQL-Server 2016Если вы заинтересованы в получении оптимального плана выполнения для значения в переменной, вы можете использовать динамический код sql. Это делает переменную постоянной.
DECLARE @var varchar(100) = 'some text' DECLARE @sql varchar(MAX) SET @sql = 'SELECT * FROM table WHERE col = '''+@var+'''' EXEC (@sql)
источник
Для перечислений или простых констант представление с одной строкой имеет отличную производительность и проверку времени компиляции / отслеживание зависимостей (потому что это имя столбца)
См. Сообщение в блоге Джареда Ко 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]
использовать вид
SELECT h.* FROM Sales.SalesOrderHeader WHERE ShipMethodID = ( select [OVERNIGHT J-FAST] from ShipMethods )
источник
Хорошо, давай посмотрим
Константы - это неизменяемые значения, которые известны во время компиляции и не меняются в течение жизни программы.
это означает, что у вас никогда не может быть константы в SQL Server
declare @myvalue as int set @myvalue = 5 set @myvalue = 10--oops we just changed it
значение только что изменилось
источник
Поскольку в нем нет встроенной поддержки констант, мое решение очень простое.
Поскольку это не поддерживается:
Declare Constant @supplement int = 240 SELECT price + @supplement FROM what_does_it_cost
Я бы просто преобразовал его в
SELECT price + 240/*CONSTANT:supplement*/ FROM what_does_it_cost
Очевидно, это зависит от уникальности всего (значение без конечного пробела и комментария). Изменить его можно с помощью глобального поиска и замены.
источник
В литературе по базам данных нет такого понятия, как «создание константы». Константы существуют как есть и часто называются значениями. Можно объявить переменную и присвоить ей значение (константу). Со схоластической точки зрения:
DECLARE @two INT SET @two = 2
Здесь @two - переменная, а 2 - значение / константа.
источник
2
преобразуется в двоичное значение при назначении "во время компиляции". Фактическое закодированное значение зависит от типа данных, которому оно присваивается (int, char, ...).Наилучший ответ от SQLMenace в соответствии с требованием, если он должен создать временную константу для использования в сценариях, то есть в нескольких операторах / пакетах GO.
Просто создайте процедуру в базе данных tempdb, тогда вы не окажете никакого влияния на целевую базу данных.
Одним из практических примеров этого является сценарий создания базы данных, который записывает контрольное значение в конце сценария, содержащего версию логической схемы. Вверху файла есть комментарии с историей изменений и т. Д. Но на практике большинство разработчиков забывают прокрутить вниз и обновить версию схемы внизу файла.
Использование приведенного выше кода позволяет определить видимую константу версии схемы вверху до того, как сценарий базы данных (скопированный из функции создания сценариев SSMS) создаст базу данных, но будет использоваться в конце. Это видно разработчикам рядом с историей изменений и другими комментариями, поэтому они, скорее всего, обновят ее.
Например:
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
источник