Existe-t-il un moyen de rendre constante une variable TSQL?
sql-server
tsql
TheEmirOfGroofunkistan
la source
la source
WITH SCHEMABINDING
devrait transformer cela en une constante «réelle» (une exigence pour qu'un UDF soit considéré comme déterministe en SQL). Ie il devrait atterrir en cache. Pourtant, +1.WITH SCHEMABINDING
dans l'CREATE FUNCTION
instruction (par opposition à une procédure stockée qui pourrait appeler la fonction) - est-ce exact?Une solution proposée par Jared Ko est d'utiliser des pseudo-constantes .
Comme expliqué dans SQL Server: variables, paramètres ou littéraux? Ou… des constantes? :
la source
Ma solution de contournement aux constans manquants est de donner des conseils sur la valeur à l'optimiseur.
DECLARE @Constant INT = 123; SELECT * FROM [some_relation] WHERE [some_attribute] = @Constant OPTION( OPTIMIZE FOR (@Constant = 123))
Cela indique au compilateur de requêtes de traiter la variable comme s'il s'agissait d'une constante lors de la création du plan d'exécution. L'inconvénient est que vous devez définir la valeur deux fois.
la source
Non, mais de bonnes vieilles conventions de dénomination devraient être utilisées.
declare @MY_VALUE as int
la source
FN_CONSTANT()
. De cette façon, ce qu'il fait est clair.Il n'y a pas de prise en charge intégrée des constantes dans T-SQL. Vous pouvez utiliser l'approche de SQLMenace pour le simuler (bien que vous ne puissiez jamais être sûr si quelqu'un d'autre a écrasé la fonction pour renvoyer quelque chose d'autre…), ou éventuellement écrire une table contenant des constantes, comme suggéré ici . Peut-être écrire un déclencheur qui annule les modifications apportées à la
ConstantValue
colonne?la source
Avant d'utiliser une fonction SQL, exécutez le script suivant pour voir les différences de performances:
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
la source
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'
et même... 'C201'
où code_values est une table de dictionnaire avec 250 vars, il y en avait tous sur SQL-Server 2016Si vous souhaitez obtenir un plan d'exécution optimal pour une valeur de la variable, vous pouvez utiliser un code SQL dynamique. Cela rend la variable constante.
DECLARE @var varchar(100) = 'some text' DECLARE @sql varchar(MAX) SET @sql = 'SELECT * FROM table WHERE col = '''+@var+'''' EXEC (@sql)
la source
Pour les énumérations ou les constantes simples, une vue avec une seule ligne a d'excellentes performances et la vérification du temps de compilation / le suivi des dépendances (cause son nom de colonne)
Voir l'article de blog de Jared Ko https://blogs.msdn.microsoft.com/sql_server_appendix_z/2013/09/16/sql-server-variables-parameters-or-literals-or-constants/
créer la vue
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]
utiliser la vue
SELECT h.* FROM Sales.SalesOrderHeader WHERE ShipMethodID = ( select [OVERNIGHT J-FAST] from ShipMethods )
la source
D'accord, voyons voir
Les constantes sont des valeurs immuables qui sont connues au moment de la compilation et qui ne changent pas pendant la durée de vie du programme
cela signifie que vous ne pouvez jamais avoir de constante dans SQL Server
declare @myvalue as int set @myvalue = 5 set @myvalue = 10--oops we just changed it
la valeur vient de changer
la source
Puisqu'il n'y a pas de support intégré pour les constantes, ma solution est très simple.
Puisque cela n'est pas pris en charge:
Declare Constant @supplement int = 240 SELECT price + @supplement FROM what_does_it_cost
Je le convertirais simplement en
SELECT price + 240/*CONSTANT:supplement*/ FROM what_does_it_cost
Évidemment, cela repose sur le fait que l'ensemble (la valeur sans espace de fin et le commentaire) soit unique. Le changer est possible avec une recherche globale et un remplacement.
la source
Il n'existe pas de "création d'une constante" dans la littérature des bases de données. Les constantes existent telles qu'elles sont et sont souvent appelées valeurs. On peut déclarer une variable et lui attribuer une valeur (constante). D'un point de vue scolaire:
DECLARE @two INT SET @two = 2
Ici, @two est une variable et 2 est une valeur / constante.
la source
2
est traduit en valeur binaire lorsqu'il est attribué au "moment de la compilation". La valeur réelle encodée dépend du type de données auquel elle est affectée (int, char, ...).La meilleure réponse vient de SQLMenace selon l'exigence de créer une constante temporaire à utiliser dans les scripts, c'est-à-dire sur plusieurs instructions / lots GO.
Créez simplement la procédure dans tempdb, vous n'aurez aucun impact sur la base de données cible.
Un exemple pratique de ceci est un script de création de base de données qui écrit une valeur de contrôle à la fin du script contenant la version du schéma logique. En haut du fichier se trouvent des commentaires avec l'historique des modifications, etc ... Mais en pratique, la plupart des développeurs oublieront de faire défiler vers le bas et de mettre à jour la version du schéma en bas du fichier.
L'utilisation du code ci-dessus permet de définir une constante de version de schéma visible en haut avant que le script de base de données (copié à partir de la fonction de génération de scripts de SSMS) ne crée la base de données mais utilisé à la fin. C'est juste en face du développeur à côté de l'historique des modifications et d'autres commentaires, il est donc très susceptible de le mettre à jour.
Par exemple:
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
la source