No SQL Server, como o paralelismo altera as concessões de memória?

9

Ouvi coisas conflitantes sobre concessões de memória para consultas de seleção paralela:

  • As concessões de memória são multiplicadas pelo DOP
  • As concessões de memória são divididas pelo DOP

Qual é?

Erik Darling
fonte

Respostas:

10

Sup?

Para consultas do SQL Server que requerem memória adicional, as concessões são derivadas para planos seriais. Se um plano paralelo for explorado e escolhido, a memória será dividida igualmente entre os threads.

As estimativas de concessão de memória são baseadas em:

  • Número de linhas (cardinalidade)
  • Tamanho das linhas (tamanho dos dados)
  • Número de operadores que consomem memória simultaneamente

Se um plano paralelo for escolhido, haverá alguma sobrecarga de memória para processar trocas paralelas (distribuir, redistribuir e reunir fluxos), no entanto, suas necessidades de memória ainda não são calculadas da mesma maneira.

Operadores que consomem memória

Os operadores mais comuns que solicitam memória são

  • Classifica
  • Hashes (junções, agregados)
  • Loops aninhados otimizados

Operadores menos comuns que requerem memória são inserções nos índices de armazenamento de coluna. Eles também diferem porque as concessões de memória são atualmente multiplicadas pelo DOP para elas.

As necessidades de memória para Classificações geralmente são muito maiores do que para hashes. As classificações solicitarão pelo menos o tamanho estimado dos dados para uma concessão de memória, pois precisam classificar todas as colunas de resultados pelo (s) elemento (s) de pedido. Hashes precisam de memória para criar uma tabela de hash, que não inclui todas as colunas selecionadas.

Exemplos

Se eu executar esta consulta, intencionalmente sugerida para o DOP 1, ela solicitará 166 MB de memória.

SELECT *
FROM 
     (  
        SELECT TOP (1000) 
               u.Id 
        FROM dbo.Users AS u
        ORDER BY u.Reputation
     ) AS u
OPTION(MAXDOP 1);

NUTS

Se eu executar esta consulta (novamente, DOP 1), o plano mudará e a concessão de memória aumentará um pouco.

SELECT *
FROM (  
        SELECT TOP (1000) 
               u.Id
        FROM dbo.Users AS u
        ORDER BY u.Reputation
     ) AS u
JOIN (
        SELECT TOP (1000) 
               u.Id
        FROM dbo.Users AS u
        ORDER BY u.Reputation
     ) AS u2
ON u.Id = u2.Id
OPTION(MAXDOP 1);

NUTS

Existem dois tipos, e agora um Hash Join. A concessão de memória aumenta um pouco para acomodar a compilação de hash, mas não dobra porque os operadores de classificação não podem ser executados simultaneamente.

Se eu alterar a consulta para forçar uma junção de loops aninhados, a concessão dobrará para lidar com as classificações simultâneas.

SELECT *
FROM (  
        SELECT TOP (1000) 
               u.Id
        FROM dbo.Users AS u
        ORDER BY u.Reputation
     ) AS u
INNER LOOP JOIN ( --Force the loop join
        SELECT TOP (1000) 
               u.Id
        FROM dbo.Users AS u
        ORDER BY u.Reputation
     ) AS u2
ON u.Id = u2.Id
OPTION(MAXDOP 1);

NUTS

A concessão de memória dobra porque o Nested Loop não é um operador de bloqueio e o Hash Join é.

Tamanho dos assuntos de dados

Esta consulta seleciona dados de sequência de combinações diferentes. Dependendo das colunas que eu selecionar, o tamanho da concessão de memória aumentará.

A maneira como o tamanho dos dados é calculado para dados variáveis ​​da sequência é de linhas * 50% do comprimento declarado da coluna. Isso vale para VARCHAR e NVARCHAR, embora as colunas NVARCHAR sejam duplicadas, pois armazenam caracteres de byte duplo. Isso muda em alguns casos com o novo CE, mas os detalhes não são documentados.

O tamanho dos dados também é importante para operações de hash, mas não no mesmo grau que para as Classificações.

SELECT *
FROM 
     (  
        SELECT TOP (1000) 
                 u.Id          -- 166MB (INT)
               , u.DisplayName -- 300MB (NVARCHAR 40)
               , u.WebsiteUrl  -- 900MB (NVARCHAR 200)
               , u.Location    -- 1.2GB (NVARCHAR 100)
               , u.AboutMe     -- 9GB   (NVARCHAR MAX)
        FROM dbo.Users AS u
        ORDER BY u.Reputation
     ) AS u
OPTION(MAXDOP 1);

Mas e o paralelismo?

Se eu executar essa consulta em diferentes DOPs, a concessão de memória não será multiplicada pelo DOP.

SELECT *
FROM (  
        SELECT TOP (1000) 
               u.Id
        FROM dbo.Users AS u
        ORDER BY u.Reputation
     ) AS u
INNER HASH JOIN (
        SELECT TOP (1000) 
               u.Id
        FROM dbo.Users AS u
        ORDER BY u.Reputation
     ) AS u2
ON u.Id = u2.Id
ORDER BY u.Id, u2.Id -- Add an ORDER BY
OPTION(MAXDOP ?);

NUTS

Existem pequenos aumentos para lidar com mais buffers paralelos por operador de câmbio, e talvez haja razões internas para que as compilações Sort e Hash exijam memória extra para lidar com DOP mais alto, mas claramente não é um fator multiplicador.

Erik Darling
fonte