web-dev-qa-db-fra.com

Déclarations de cas imbriquées vs déclarations de cas à critères multiples

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
1
Sean K.

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.

6
Josh Darnell