¿Hay alguna forma de hacer que una variable TSQL sea constante?
sql-server
tsql
TheEmirOfGroofunkistan
fuente
fuente
WITH SCHEMABINDING
debería convertir esto en una constante 'real' (un requisito para que una UDF se considere determinista en SQL). Es decir, debería aterrizar en caché. Aún así, +1.WITH SCHEMABINDING
en laCREATE FUNCTION
declaración (en lugar de en un procedimiento almacenado que podría estar llamando a la función), ¿es así?Una solución que ofrece Jared Ko es utilizar pseudoconstantes .
Como se explica en SQL Server: ¿variables, parámetros o literales? ¿O… constantes? :
fuente
Mi solución a las constantes faltantes es dar pistas sobre el valor del optimizador.
DECLARE @Constant INT = 123; SELECT * FROM [some_relation] WHERE [some_attribute] = @Constant OPTION( OPTIMIZE FOR (@Constant = 123))
Esto le dice al compilador de consultas que trate la variable como si fuera una constante al crear el plan de ejecución. La desventaja es que tienes que definir el valor dos veces.
fuente
No, pero se deben usar las buenas convenciones de nomenclatura.
declare @MY_VALUE as int
fuente
FN_CONSTANT()
. De esa forma queda claro lo que está haciendo.No hay soporte integrado para constantes en T-SQL. Puede usar el enfoque de SQLMenace para simularlo (aunque nunca puede estar seguro de si alguien más ha sobrescrito la función para devolver algo más ...), o posiblemente escribir una tabla que contenga constantes, como se sugiere aquí . ¿Quizás escribir un disparador que revierte cualquier cambio en la
ConstantValue
columna?fuente
Antes de utilizar una función de SQL, ejecute el siguiente script para ver las diferencias en el rendimiento:
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
fuente
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'
y lo mismo... 'C201'
donde code_values es una tabla de diccionario con 250 vars, todos estaban en SQL-Server 2016Si está interesado en obtener un plan de ejecución óptimo para un valor en la variable, puede usar un código SQL dinámico. Hace que la variable sea constante.
DECLARE @var varchar(100) = 'some text' DECLARE @sql varchar(MAX) SET @sql = 'SELECT * FROM table WHERE col = '''+@var+'''' EXEC (@sql)
fuente
Para enumeraciones o constantes simples, una vista con una sola fila tiene un gran rendimiento y control de tiempo de compilación / seguimiento de dependencia (porque es un nombre de columna)
Consulte la publicación del blog de Jared Ko https://blogs.msdn.microsoft.com/sql_server_appendix_z/2013/09/16/sql-server-variables-parameters-or-literals-or-constants/
crear la vista
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]
usa la vista
SELECT h.* FROM Sales.SalesOrderHeader WHERE ShipMethodID = ( select [OVERNIGHT J-FAST] from ShipMethods )
fuente
Esta bien, veamos
Las constantes son valores inmutables que se conocen en el momento de la compilación y no cambian durante la vida del programa.
eso significa que nunca puede tener una constante en SQL Server
declare @myvalue as int set @myvalue = 5 set @myvalue = 10--oops we just changed it
el valor acaba de cambiar
fuente
Dado que no hay soporte integrado para constantes, mi solución es muy simple.
Dado que esto no es compatible:
Declare Constant @supplement int = 240 SELECT price + @supplement FROM what_does_it_cost
Simplemente lo convertiría a
SELECT price + 240/*CONSTANT:supplement*/ FROM what_does_it_cost
Obviamente, esto se basa en que todo (el valor sin espacio final y el comentario) sea único. Cambiarlo es posible con una búsqueda y reemplazo global.
fuente
No existe tal cosa como "crear una constante" en la literatura de bases de datos. Las constantes existen tal como son y, a menudo, se las llama valores. Se puede declarar una variable y asignarle un valor (constante). Desde un punto de vista escolástico:
DECLARE @two INT SET @two = 2
Aquí @two es una variable y 2 es un valor / constante.
fuente
2
se traduce a un valor binario cuando se asigna en el "tiempo de compilación". El valor real codificado depende del tipo de datos al que se está asignando (int, char, ...).La mejor respuesta es de SQLMenace de acuerdo con el requisito si se trata de crear una constante temporal para su uso dentro de los scripts, es decir, en múltiples sentencias / lotes de GO.
Simplemente cree el procedimiento en tempdb, entonces no tendrá ningún impacto en la base de datos de destino.
Un ejemplo práctico de esto es un script de creación de base de datos que escribe un valor de control al final del script que contiene la versión del esquema lógico. En la parte superior del archivo hay algunos comentarios con el historial de cambios, etc. Pero en la práctica, la mayoría de los desarrolladores se olvidarán de desplazarse hacia abajo y actualizar la versión del esquema en la parte inferior del archivo.
El uso del código anterior permite definir una constante de versión de esquema visible en la parte superior antes de que el script de la base de datos (copiado de la función de generar scripts de SSMS) cree la base de datos pero se use al final. Esto está justo en la cara del desarrollador junto al historial de cambios y otros comentarios, por lo que es muy probable que lo actualicen.
Por ejemplo:
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
fuente