Quelle est la méthode la plus efficace pour effectuer le test FIZZBUZZ dans SQL Server?

28

Ce n'est peut-être pas complètement sur le sujet, mais c'est une journée lente ici.

Existe-t-il une méthode plus efficace pour obtenir une liste de nombres de 1 à 49 avec une colonne contenant les mots FIZZlorsque le nombre peut être divisé également par 3, BUZZlorsque le nombre peut être divisé également par 5, et FIZZBUZZlorsque le nombre peut être divisé également par les deux 3 et 5?

Mes tentatives sont (ATTENTION, cela videra le cache de votre procédure, alors NE COUREZ PAS SUR UNE BOÎTE DE PRODUCTION):

DBCC FREEPROCCACHE
GO
/*VARIANT1*/
;WITH t AS (
    SELECT RowNum = ROW_NUMBER() OVER (ORDER BY o.object_id)
    FROM sys.objects o
)
SELECT t.RowNum
    , CASE WHEN ((t.RowNum % 3) + (t.RowNum % 5)) = 0  THEN 'FIZZBUZZ' 
    ELSE 
        CASE WHEN t.RowNum % 3 = 0 THEN 'FIZZ' 
        ELSE 
            CASE WHEN t.RowNum % 5 = 0 THEN 'BUZZ' 
            ELSE '' 
            END 
        END 
    END
FROM t
WHERE t.RowNum < 50;
GO 100

/*VARIANT2*/
DECLARE @t TABLE
(
    Num INT NOT NULL PRIMARY KEY CLUSTERED
);
INSERT INTO @t (Num)
SELECT ROW_NUMBER() OVER (ORDER BY o.object_id)
FROM sys.objects o;

SELECT t.Num
    , CASE WHEN ((t.Num % 3) + (t.Num % 5)) = 0  THEN 'FIZZBUZZ' 
    ELSE 
        CASE WHEN t.Num % 3 = 0 THEN 'FIZZ' 
        ELSE 
            CASE WHEN t.Num % 5 = 0 THEN 'BUZZ' 
            ELSE '' 
            END 
        END 
    END
FROM @t t
WHERE t.Num < 50;
GO 100

SELECT CASE WHEN dest.text LIKE '%/*VARIANT1*/%' THEN 'VARIANT1' ELSE 'VARIANT2' END
    , MAX(deqs.execution_count)
    , SUM(deqs.total_worker_time)
    , AvgWorkerTime = SUM(deqs.total_worker_time) / MAX(deqs.execution_count)
FROM sys.dm_exec_query_stats deqs
CROSS APPLY sys.dm_exec_sql_text(deqs.sql_handle) dest
WHERE (dest.text LIKE '%/*VARIANT1*/%'
    OR dest.text LIKE '%/*VARIANT2*/%')
    AND dest.text NOT LIKE '%/*NOT_ME!*/%'
GROUP BY CASE WHEN dest.text LIKE '%/*VARIANT1*/%' THEN 'VARIANT1' ELSE 'VARIANT2' END
ORDER BY CASE WHEN dest.text LIKE '%/*VARIANT1*/%' THEN 'VARIANT1' ELSE 'VARIANT2' END
/*NOT_ME!*/;

Comme conseillé par @AaronBertrand, j'ai modifié mes tentatives pour exécuter chaque ensemble d'instructions 100 fois chacune, puis afficher les heures enregistrées par SQL Server sys.dm_exec_query_stats.

Les resultats:

            Runs    total_time      average time
VARIANT1    100     42533           425
VARIANT2    100     138677          1386
Max Vernon
la source

Réponses:

3

Vous trouverez ci-dessous une solution T-SQL qui écrit le premier million de nombres dans une table temporaire. Cela prend environ 84 ms sur ma machine. Les goulots d'étranglement clés attendent sur le verrou NESTING_TRANSACTION_FULL et CXPACKET, tous deux que je ne sais pas comment résoudre, à part changer MAXDOP. Je voulais un plan de requête qui puisse tirer parti des boucles imbriquées parallèles et du parallélisme basé sur la demande, ce que j'ai réussi à obtenir:

entrez la description de l'image ici

Le code est un peu long. En bref, je réunis deux tables dérivées de 246 lignes et 271 lignes pour un total de 66666 lignes. Ces lignes sont jointes à une table dérivée de 15 lignes qui tire parti du fait que le modèle FIZZBUZZ est répété pour toutes les 15 lignes. Les dix dernières lignes sont ajoutées avec un UNION ALL.

DROP TABLE IF EXISTS #t;

SELECT res.fizzbuzz INTO #t
FROM
(
VALUES
(0),
(15),
(30),
(45),
(60),
(75),
(90),
(105),
(120),
(135),
(150),
(165),
(180),
(195),
(210),
(225),
(240),
(255),
(270),
(285),
(300),
(315),
(330),
(345),
(360),
(375),
(390),
(405),
(420),
(435),
(450),
(465),
(480),
(495),
(510),
(525),
(540),
(555),
(570),
(585),
(600),
(615),
(630),
(645),
(660),
(675),
(690),
(705),
(720),
(735),
(750),
(765),
(780),
(795),
(810),
(825),
(840),
(855),
(870),
(885),
(900),
(915),
(930),
(945),
(960),
(975),
(990),
(1005),
(1020),
(1035),
(1050),
(1065),
(1080),
(1095),
(1110),
(1125),
(1140),
(1155),
(1170),
(1185),
(1200),
(1215),
(1230),
(1245),
(1260),
(1275),
(1290),
(1305),
(1320),
(1335),
(1350),
(1365),
(1380),
(1395),
(1410),
(1425),
(1440),
(1455),
(1470),
(1485),
(1500),
(1515),
(1530),
(1545),
(1560),
(1575),
(1590),
(1605),
(1620),
(1635),
(1650),
(1665),
(1680),
(1695),
(1710),
(1725),
(1740),
(1755),
(1770),
(1785),
(1800),
(1815),
(1830),
(1845),
(1860),
(1875),
(1890),
(1905),
(1920),
(1935),
(1950),
(1965),
(1980),
(1995),
(2010),
(2025),
(2040),
(2055),
(2070),
(2085),
(2100),
(2115),
(2130),
(2145),
(2160),
(2175),
(2190),
(2205),
(2220),
(2235),
(2250),
(2265),
(2280),
(2295),
(2310),
(2325),
(2340),
(2355),
(2370),
(2385),
(2400),
(2415),
(2430),
(2445),
(2460),
(2475),
(2490),
(2505),
(2520),
(2535),
(2550),
(2565),
(2580),
(2595),
(2610),
(2625),
(2640),
(2655),
(2670),
(2685),
(2700),
(2715),
(2730),
(2745),
(2760),
(2775),
(2790),
(2805),
(2820),
(2835),
(2850),
(2865),
(2880),
(2895),
(2910),
(2925),
(2940),
(2955),
(2970),
(2985),
(3000),
(3015),
(3030),
(3045),
(3060),
(3075),
(3090),
(3105),
(3120),
(3135),
(3150),
(3165),
(3180),
(3195),
(3210),
(3225),
(3240),
(3255),
(3270),
(3285),
(3300),
(3315),
(3330),
(3345),
(3360),
(3375),
(3390),
(3405),
(3420),
(3435),
(3450),
(3465),
(3480),
(3495),
(3510),
(3525),
(3540),
(3555),
(3570),
(3585),
(3600),
(3615),
(3630),
(3645),
(3660),
(3675)
) v246 (n)
CROSS JOIN 
(
VALUES
(0),
(15),
(30),
(45),
(60),
(75),
(90),
(105),
(120),
(135),
(150),
(165),
(180),
(195),
(210),
(225),
(240),
(255),
(270),
(285),
(300),
(315),
(330),
(345),
(360),
(375),
(390),
(405),
(420),
(435),
(450),
(465),
(480),
(495),
(510),
(525),
(540),
(555),
(570),
(585),
(600),
(615),
(630),
(645),
(660),
(675),
(690),
(705),
(720),
(735),
(750),
(765),
(780),
(795),
(810),
(825),
(840),
(855),
(870),
(885),
(900),
(915),
(930),
(945),
(960),
(975),
(990),
(1005),
(1020),
(1035),
(1050),
(1065),
(1080),
(1095),
(1110),
(1125),
(1140),
(1155),
(1170),
(1185),
(1200),
(1215),
(1230),
(1245),
(1260),
(1275),
(1290),
(1305),
(1320),
(1335),
(1350),
(1365),
(1380),
(1395),
(1410),
(1425),
(1440),
(1455),
(1470),
(1485),
(1500),
(1515),
(1530),
(1545),
(1560),
(1575),
(1590),
(1605),
(1620),
(1635),
(1650),
(1665),
(1680),
(1695),
(1710),
(1725),
(1740),
(1755),
(1770),
(1785),
(1800),
(1815),
(1830),
(1845),
(1860),
(1875),
(1890),
(1905),
(1920),
(1935),
(1950),
(1965),
(1980),
(1995),
(2010),
(2025),
(2040),
(2055),
(2070),
(2085),
(2100),
(2115),
(2130),
(2145),
(2160),
(2175),
(2190),
(2205),
(2220),
(2235),
(2250),
(2265),
(2280),
(2295),
(2310),
(2325),
(2340),
(2355),
(2370),
(2385),
(2400),
(2415),
(2430),
(2445),
(2460),
(2475),
(2490),
(2505),
(2520),
(2535),
(2550),
(2565),
(2580),
(2595),
(2610),
(2625),
(2640),
(2655),
(2670),
(2685),
(2700),
(2715),
(2730),
(2745),
(2760),
(2775),
(2790),
(2805),
(2820),
(2835),
(2850),
(2865),
(2880),
(2895),
(2910),
(2925),
(2940),
(2955),
(2970),
(2985),
(3000),
(3015),
(3030),
(3045),
(3060),
(3075),
(3090),
(3105),
(3120),
(3135),
(3150),
(3165),
(3180),
(3195),
(3210),
(3225),
(3240),
(3255),
(3270),
(3285),
(3300),
(3315),
(3330),
(3345),
(3360),
(3375),
(3390),
(3405),
(3420),
(3435),
(3450),
(3465),
(3480),
(3495),
(3510),
(3525),
(3540),
(3555),
(3570),
(3585),
(3600),
(3615),
(3630),
(3645),
(3660),
(3675),
(3690),
(3705),
(3720),
(3735),
(3750),
(3765),
(3780),
(3795),
(3810),
(3825),
(3840),
(3855),
(3870),
(3885),
(3900),
(3915),
(3930),
(3945),
(3960),
(3975),
(3990),
(4005),
(4020),
(4035),
(4050)
) v271 (n)
CROSS APPLY
(
VALUES
(CAST(v246.n * 271 + v271.n + 1 AS CHAR(8))),
(CAST(v246.n * 271 + v271.n + 2 AS CHAR(8))),
(CAST('FIZZ' AS CHAR(8))),
(CAST(v246.n * 271 + v271.n + 4 AS CHAR(8))),
(CAST('BUZZ' AS CHAR(8))),
(CAST('FIZZ' AS CHAR(8))),
(CAST(v246.n * 271 + v271.n + 7 AS CHAR(8))),
(CAST(v246.n * 271 + v271.n + 8 AS CHAR(8))),
(CAST('FIZZ' AS CHAR(8))),
(CAST('BUZZ' AS CHAR(8))),
(CAST(v246.n * 271 + v271.n + 11 AS CHAR(8))),
(CAST('FIZZ' AS CHAR(8))),
(CAST(v246.n * 271 + v271.n + 13 AS CHAR(8))),
(CAST(v246.n * 271 + v271.n + 14 AS CHAR(8))),
(CAST('FIZZBUZZ' AS CHAR(8)))
) res (fizzbuzz)

UNION ALL

SELECT v.fizzbuzz
FROM (
VALUES 
('999991'),
('999992'),
('FIZZ'),
('999994'),
('BUZZ'),
('FIZZ'),
('999997'),
('999998'),
('FIZZ'),
('BUZZ')
) v (fizzbuzz)

OPTION (MAXDOP 6, NO_PERFORMANCE_SPOOL);
Joe Obbish
la source
C'est un peu une triche que la solution ne fasse aucun calcul, mais ce n'était pas une exigence déclarée. Cette solution utilise un système de réflexion prêt à l'emploi ™ qui est un signe de grandeur. Je voudrais le voir avec deux colonnes dans la sortie, afin que la sortie puisse être plus facilement confirmée comme correcte.
Max Vernon
@MaxVernon Fair point, étant donné que les lignes ne sont pas ordonnées, il n'est pas vraiment raisonnable de ne pas inclure le nombre de toutes les lignes. N'hésitez pas à le modifier.
Joe Obbish
15

Utilisation d'une table optimisée en mémoire pour SQL Server 2014 et d'une procédure compilée en mode natif:

-- Setup
CREATE DATABASE InMem;
GO
ALTER DATABASE InMem
ADD FILEGROUP FG1
CONTAINS MEMORY_OPTIMIZED_DATA;
GO
ALTER DATABASE InMem
ADD FILE 
(
    NAME = 'FN1', 
    -- Change to suit your system
    FILENAME = 'C:\Program Files\Microsoft SQL Server\MSSQL12.SQL2014\MSSQL\DATA\FN1.mod'
)
TO FILEGROUP FG1;
GO
USE InMem;
GO
CREATE TYPE dbo.FizzBuzzTableType AS TABLE 
(
    n integer NOT NULL INDEX i,
    FizzBuzz varchar(8) NOT NULL
) WITH (MEMORY_OPTIMIZED = ON);
GO

Procédure native:

CREATE PROCEDURE dbo.FizzBuzz
WITH 
    NATIVE_COMPILATION, 
    SCHEMABINDING, 
    EXECUTE AS OWNER
AS
BEGIN ATOMIC 
WITH 
(
    TRANSACTION ISOLATION LEVEL = SNAPSHOT, 
    LANGUAGE = N'english'
)   
    DECLARE @n AS dbo.FizzBuzzTableType;

    DECLARE @i integer = 1;
    WHILE @i < 50
    BEGIN
        IF @i % 15 = 0
        BEGIN
            INSERT @n (n, FizzBuzz) 
            VALUES (@i, 'FizzBuzz')
        END
        ELSE 
        BEGIN
            IF @i % 3 = 0
            BEGIN
                INSERT @n (n, FizzBuzz)
                VALUES (@i, 'Fizz')
            END
            ELSE 
            BEGIN
                IF @i % 5 = 0
                BEGIN
                    INSERT @n (n, FizzBuzz) 
                    VALUES (@i, 'Buzz')
                END
                ELSE
                BEGIN
                    INSERT @n (n, FizzBuzz) 
                    VALUES (@i, CONVERT(varchar(8), @i));
                END;
            END;
        END;

        SET @i += 1;
    END;

    SELECT
        N.n, 
        N.FizzBuzz
    FROM @n AS N
    ORDER BY
        N.n;
END;

Tester:

SET NOCOUNT ON;
PRINT SYSUTCDATETIME();
GO
DECLARE @T AS dbo.FizzBuzzTableType;

INSERT @T (n, FizzBuzz)
EXECUTE dbo.FizzBuzz;
GO 100

PRINT SYSUTCDATETIME();

Résultats typiques:

-- 95ms for 100 iterations, < 1ms each
2014-12-31 10:07:13.7993355
Beginning execution loop
Batch execution completed 100 times.
2014-12-31 10:07:13.8943409

Cela écrit la sortie de la procédure dans une variable de table en mémoire, car sinon nous testons simplement la vitesse d'affichage des résultats dans SSMS.

Un million de lignes

La procédure native ci-dessus prend environ 12 secondes pour s'exécuter sur 1 000 000 de numéros. Il existe toutes sortes de moyens plus rapides de faire la même chose dans T-SQL. Un que j'ai écrit avant suit. Il s'exécute en environ 500 ms sur mon ordinateur portable sur un million de lignes lorsque le plan parallèle prévu est atteint:

IF  OBJECT_ID(N'tempdb..#Result', N'U') IS NOT NULL
    DROP TABLE #Result;

IF  OBJECT_ID(N'tempdb..#Thousand', N'U') IS NOT NULL
    DROP TABLE #Thousand;

SET NOCOUNT ON;
DECLARE @start datetime2(7) = SYSUTCDATETIME();

CREATE TABLE #Thousand 
(
    n integer NOT NULL,

    CONSTRAINT PK_#Thousand
    PRIMARY KEY CLUSTERED (n)
);

-- Add 1,000 rows numbered 0-999 to #Thousand
WITH 
    L1 (n) AS
(
    SELECT  V.n
    FROM    
    (
        VALUES  (0), (1), (2), (3), (4),
                (5), (6), (7), (8), (9)
    ) AS V (n)
),
    Thousand AS
(
    SELECT  n = 
        CONVERT
        (
            integer,
            ROW_NUMBER() OVER (
            ORDER BY (SELECT NULL))
            - 1
        )
    FROM L1
    CROSS JOIN L1 AS L2
    CROSS JOIN L1 AS L3
)
INSERT #Thousand (n)
SELECT n
FROM Thousand;

-- To hold the Fizz Buzz output
CREATE TABLE #Result 
(
    n integer NOT NULL, 
    result varchar(8) NOT NULL
);

INSERT #Result
SELECT 
    Million.n, 
    Million.result
FROM
(
    -- Modulo operation to encourage few outer rows parallelism
    SELECT  n
    FROM    #Thousand
    WHERE   n % 1 = 0
) AS T1
-- Outer Apply to keep the Compute Scalar parallel
OUTER APPLY
(
    SELECT
        F2.n, 
        F2.result
    FROM #Thousand AS T2
    CROSS APPLY
    (
        -- Row numbers 1 to 1,000,000
        SELECT  (T1.n * 1000) + T2.n + 1
    ) AS F1 (n)
    CROSS APPLY
    (
        -- The Fizz Buzz bit
        SELECT
            F1.n,
            result =
                CASE 
                    WHEN F1.n % 15 = 0 THEN 'FizzBuzz'
                    WHEN F1.n % 3 = 0 THEN 'Buzz'
                    WHEN F1.n % 5 = 0 THEN 'Fizz'
                    ELSE CONVERT(varchar(8), F1.n)
                END
    ) AS F2
) AS Million
OPTION  (MAXDOP 4, QUERYTRACEON 9481);

PRINT DATEDIFF(MILLISECOND, @start, SYSUTCDATETIME());
Paul White dit GoFundMonica
la source
1
Vous avez dit "Outer Apply to keep the Compute Scalar parallel" - pouvez-vous me signaler quelque chose à ce sujet?
Max Vernon
3
Nan. Il se trouve que l'application externe peut parfois empêcher les scalaires de calcul de sortir de la zone parallèle. Complètement sans papiers, pourrait changer n'importe quel jour etc.
Paul White dit GoFundMonica
11

Celui-ci fonctionne de la même manière sur ma machine que la première (0 ms). Je ne sais pas si elle évoluerait plus rapidement ou non.

;WITH t AS (
    SELECT RowNum = ROW_NUMBER() OVER (ORDER BY o.object_id)
    FROM sys.objects o
)
SELECT t.RowNum
    , Cxa.Fizz + CxB.Buzz
FROM t
CROSS APPLY (SELECT CASE WHEN t.RowNum % 3 = 0 THEN 'FIZZ' ELSE '' END) CxA(Fizz)
CROSS APPLY (SELECT CASE WHEN t.RowNum % 5 = 0 THEN 'BUZZ' ELSE '' END) CxB(Buzz)
WHERE t.RowNum < 50;
JNK
la source
10

La meilleure version que j'ai trouvée fonctionne en 30 ms sur ma machine:

WITH t AS (
    SELECT 1 As RowNum
    Union ALL
    Select RowNum + 1
    From t
    Where RowNum < 49
)
SELECT t.RowNum
, SubString('FIZZ', (t.RowNum % 3)*10, 5) + SubString('BUZZ', (t.RowNum % 5)*10, 5)
FROM t;
Robert L Davis
la source
6

Selon sqlfiddle.com, cela prend 7 ms:

select coalesce(fizz + buzz, fizz, buzz, cast(n as varchar)) as FizzBuzz
  from (
    select n0 + 3 * n3 + 9 * n9 + 27 * n27 + 81 * n81 as n
        from
            (select 0 as n0  union all select 1 union all select 2 as n0)  as n0,
            (select 0 as n3  union all select 1 union all select 2 as n3)  as n3,
            (select 0 as n9  union all select 1 union all select 2 as n9)  as n9,
            (select 0 as n27 union all select 1 union all select 2 as n27) as n27,
            (select 0 as n81 union all select 1                    as n81) as n81
  ) as stupidalias1
  left outer join
    (select 3 as fizzstep, 'Fizz' as fizz) as stupidalias2 on n % fizzstep = 0
  left outer join
    (select 5 as buzzstep, 'Buzz' as buzz) as stupidalias3 on n % buzzstep = 0
  where n between 1 and 100
  order by n;

N'utilise aucune table, proc stocké ou CTE.


la source
6

J'ai obtenu une version raisonnable du proc stocké compilé en mode natif fonctionnant pour 1 million de lignes en ~ 500-800 ms. C'est une conversion T-SQL que j'ai faite de l'algorithme au niveau du bit d' ici avec un peu d'aide du blog d'Adam Machanic sur les opérations au niveau du bit ici .

J'espère (je l'espère) suivre les mêmes règles que le proc de 500ms / 1 million de lignes de @ PaulWhite, c'est-à-dire générer les résultats mais ne pas les afficher / ne pas les faire circuler dans le cadre du timing. Il doit s'agir d'index de hachage sur les tables en mémoire pour des tailles de vitesse et de godet de 4194304 ou 8388608, ce qui m'a semblé être le point idéal, bien que cela donne évidemment un nombre élevé de compartiments vides.

USE hekatondb
GO

--NB: SQLCMD script, Enable via: Query menu > SQLCMD Mode
:setvar bucketCount 4194304
--:setvar bucketCount 8388608

IF OBJECT_ID('dbo.usp_hekatonFizzBuzz') IS NOT NULL
DROP PROC dbo.usp_hekatonFizzBuzz 
GO
IF OBJECT_ID('dbo.FizzBuzz') IS NOT NULL
DROP TABLE dbo.FizzBuzz
GO


IF OBJECT_ID('dbo.FizzBuzz') IS NULL
CREATE TABLE dbo.FizzBuzz (
    Number      INT NOT NULL,
    Result      VARCHAR(8) NULL,

    CONSTRAINT PK_FizzBuzz PRIMARY KEY NONCLUSTERED HASH ( Number ) WITH ( BUCKET_COUNT = $(bucketCount) )

) WITH ( MEMORY_OPTIMIZED = ON, DURABILITY = SCHEMA_ONLY )
GO


CREATE PROC dbo.usp_hekatonFizzBuzz 

    @limit  INT

WITH
    NATIVE_COMPILATION, 
    SCHEMABINDING, 
    EXECUTE AS OWNER
AS
BEGIN ATOMIC
WITH
(
    TRANSACTION ISOLATION LEVEL = SNAPSHOT, 
    LANGUAGE = N'english'
)   

    DECLARE @acc INT = 810092048    -- 11 00 00 01 00 10 01 00 00 01 10 00 01 00 00
    DECLARE @i INT = 1
    DECLARE @c INT

    WHILE @i <= @limit
    BEGIN 

        SELECT
            @c = @acc & 3,
            @acc = ( @acc / 4 ) | ( @c * 268435456 )

        INSERT dbo.FizzBuzz ( Number, Result )
        SELECT @i, SUBSTRING( '       Fizz    Buzz    FizzBuzz', @c * 8, @c * 4 )

        SET @i += 1

    END

END
GO

DELETE dbo.FizzBuzz
DECLARE @startDate DATETIME2 = SYSUTCDATETIME();

EXEC dbo.usp_hekatonFizzBuzz 1000000

SELECT DATEDIFF( millisecond, @startDate, SYSUTCDATETIME() ) diff
GO 10
wBob
la source
5

J'ai trouvé et joué avec ce seul sous-sélecteur sans CTE. max_elapsed_time dans les statistiques de requête affiche 1036

 SELECT num,
        CASE    WHEN mod3 + mod5 = 0 THEN 'FizzBuzz'
                WHEN mod5 = 0 THEN 'Buzz'
                WHEN mod3 = 0 THEN 'Fizz'
                ELSE CONVERT(VARCHAR(8), num)
        END
 FROM 
 (
    SELECT  number as num,
            number % 3 AS mod3,
            number % 5 AS mod5
    FROM    master.dbo.spt_values
    WHERE   name IS NULL
            AND number BETWEEN 1 AND 101
 ) AS numbers;
James Anderson
la source
3

Je ne prends aucun crédit pour le code écrit, je voulais juste voir combien de temps cela prendrait

UN MILLIARD DE RANGS!

;WITH T(N) AS (SELECT N FROM (VALUES (NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL)) AS X(N))
    ,NUMS(N) AS (SELECT TOP(1000000000) ROW_NUMBER() OVER (ORDER BY (SELECT NULL))  AS N FROM T T1,T T2,T T3,T T4,T T5,T T6,T T7,T T8,T T9, T T10)
    SELECT  n, ca.fb
    INTO #fizzywizzy
    FROM    NUMS n
            CROSS APPLY ( SELECT    CASE WHEN n.N % 15 = 0 THEN 'FizzBuzz'
                                         WHEN n.N % 3 = 0 THEN 'Fizz'
                                         WHEN n.N % 5 = 0 THEN 'Buzz'
                                         ELSE CAST(n AS VARCHAR)
                                    END AS [fb]
                        ) ca

La réponse est: environ 10 minutes.

SQL Server parse and compile time: 
   CPU time = 13 ms, elapsed time = 13 ms.

 SQL Server Execution Times:
   CPU time = 648625 ms,  elapsed time = 618025 ms.
Erik Darling
la source
-2

PostgreSQL

PostgreSQL fournit generate_seriesune fonction Table-Value (Set-Returning Function) qui rend cela beaucoup plus simple. Je suppose que vous ne voulez rien que ce soit lorsque le nombre ni 3, ni 5 n'y entre.

SELECT x, str
FROM generate_series(1,49) AS gs(x)
CROSS JOIN LATERAL (VALUES (CASE
  WHEN x % 15 =0 THEN 'Fizzbuzz'
  WHEN x % 3  =0 THEN 'Fizz'
  WHEN x % 5  =0 THEN 'Buzz'
END)) AS c(str)
WHERE str IS NOT NULL;
Evan Carroll
la source