Abaixo está uma solução T-SQL que grava o primeiro milhão de números em uma tabela temporária. Demora cerca de 84 ms na minha máquina. Os principais gargalos estão aguardando a trava NESTING_TRANSACTION_FULL e CXPACKET
, os quais não sei como resolver além de mudar MAXDOP
. Eu queria um plano de consulta que pudesse tirar proveito de loops aninhados paralelos e paralelismo baseado em demanda, que foi o que consegui obter:
O código é um pouco longo. Em resumo, uno duas tabelas derivadas de 246 linhas e 271 linhas, para um total de 66666 linhas. Essas linhas são unidas a uma tabela derivada de 15 linhas, que aproveita o fato de o padrão FIZZBUZZ ser repetido para cada 15 linhas. As dez linhas finais são adicionadas com a 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);
Usando uma tabela otimizada de memória do SQL Server 2014 e um procedimento compilado nativamente:
Procedimento nativo:
Teste:
Resultados típicos:
Isso grava a saída do procedimento em uma variável da tabela na memória, porque, caso contrário, estamos apenas testando a velocidade de exibição dos resultados no SSMS.
Um milhão de linhas
O procedimento nativo acima leva cerca de 12 segundos para executar em 1.000.000 de números. Existem todos os tipos de maneiras mais rápidas de fazer a mesma coisa no T-SQL. Um que eu escrevi antes segue. Ele roda em cerca de 500 ms no meu laptop em um milhão de linhas quando o plano paralelo pretendido é alcançado:
fonte
Este funciona da mesma forma na minha máquina que o seu primeiro (0 ms). Não tenho certeza se escalaria mais rápido ou não.
fonte
A melhor versão que eu criei é executada em 30ms na minha máquina:
fonte
De acordo com sqlfiddle.com, são necessários 7 ms:
Não usa tabelas, procs armazenados ou CTEs.
fonte
Eu obtive uma versão razoável do proc armazenado nativamente compilado, trabalhando por 1 milhão de linhas em ~ 500-800ms. Esta é uma conversão T-SQL que fiz do algoritmo bit a bit daqui com uma pequena ajuda do blog de Adam Machanic sobre operações bit a bit aqui .
Estou (espero) seguindo as mesmas regras do processo de 500ms / 1 milhão de linhas da @ PaulWhite, ou seja, gerando os resultados, mas não exibindo-os / não transmitindo-os como parte do tempo. Tem que haver índices de hash nas tabelas na memória para tamanhos de velocidade e de balde de 4.194.304 ou 8.388.608 pareceu ser o ponto ideal para mim, embora obviamente isso ofereça contagens altas de baldes vazios.
fonte
Eu encontrei e joguei com este único sub-select sem CTE. max_elapsed_time nas estatísticas da consulta mostra 1036
fonte
Não aceito o código conforme escrito, só queria ver quanto tempo levaria
UM BILHÃO DE LINHAS!
A resposta é: cerca de 10 minutos.
fonte
PostgreSQL
O PostgreSQL fornece
generate_series
uma função de valor de tabela (função de retorno de conjunto) que torna isso substancialmente mais simples. Eu estou supondo que você não quer nada de saída quando o número nem 3, nem 5 entra nele.fonte