J'ai eu une discussion intéressante avec un collègue aujourd'hui sur l'optimisation des déclarations de cas et s'il est préférable de laisser une déclaration de cas qui a des critères qui se chevauchent en tant que clauses when individuelles, ou de faire une déclaration de cas imbriquée pour chacune des déclarations qui se chevauchent.
Par exemple, disons que nous avions une table avec 2 champs entiers, la colonne a et la colonne b. Laquelle des deux requêtes serait plus conviviale pour le processeur? Puisque nous évaluons uniquement si a = 1 ou a = 0 une fois en utilisant les instructions imbriquées, cela serait-il plus efficace pour le processeur, ou la création d'une instruction imbriquée grugerait-elle cette optimisation?
Plusieurs critères pour l'énoncé de cas:
Select
case
when a=1 and b=0 THEN 'True'
when a=1 and b=1 then 'Trueish'
when a=0 and b=0 then 'False'
when a=0 and b=1 then 'Falseish'
else null
end AS Result
FROM tableName
Déclarations de cas de nidification:
Select
case
when a=1 then
case
when b=0 then 'True'
when b=1 then 'Trueish'
end
When a=0 then
case
when b=0 then 'False'
when b=1 then 'Falseish'
end
else null
end AS Result
FROM tablename
Quelqu'un peut venir et creuser dans les détails de la façon dont ces opérations sont réellement traitées sur les CPU, ou quelles instructions sont générées différemment entre ces deux requêtes. Mais d'un point de vue pratique, il semble qu'il n'y ait pas de différence significative.
Cela charge une table avec 10 millions de lignes de colonnes à deux bits, avec une distribution quelque peu arbitraire des valeurs 1 et 0.
CREATE DATABASE [239583];
GO
USE [239583];
GO
SELECT TOP 10000000
CASE WHEN v.number % 2 = 0 THEN CAST(1 AS bit) ELSE CAST(0 AS bit) END AS a,
CASE WHEN v.number % 2 = 1 THEN CAST(1 AS bit) ELSE CAST(0 AS bit) END AS b
INTO dbo.TableName
FROM master.dbo.spt_values v
CROSS JOIN master.dbo.spt_values v2
CROSS JOIN master.dbo.spt_values v3;
J'ai ensuite dit à SSMS de supprimer les résultats après exécution (Requête -> Options de requête -> Grille -> Supprimer les résultats après exécution), car je n'ai pas le temps d'attendre sur SSMS pour bloquer le chargement des lignes de 20 mm de 1 et de 0.
Puis a exécuté ce code:
SET STATISTICS IO, TIME ON;
Select
case
when a=1 and b=0 THEN 'True'
when a=1 and b=1 then 'Trueish'
when a=0 and b=0 then 'False'
when a=0 and b=1 then 'Falseish'
else null
end
FROM tableName;
Select
case
when a=1 then
case
when b=0 then 'True'
when b=1 then 'Trueish'
end
When a=0 then
case
when b=0 then 'False'
when b=1 then 'Falseish'
end
else null
end
FROM tablename;
Je lance généralement une sortie CPU comme celle-ci sur ma machine:
Query 1: CPU time = 2141 ms, elapsed time = 2191 ms.
Query 2: CPU time = 2359 ms, elapsed time = 2461 ms.
Parfois, ils sont légèrement plus proches de l'égal, ou la deuxième requête est légèrement plus rapide, mais je pense que ce ne sont que les variations habituelles des processeurs de mon ordinateur portable faisant autre chose que d'exécuter cette requête.