Partilhar via


Estudo de Áreas Iniciais em In-Memory OLTP

Aplica-se a:SQL ServerBanco de Dados SQL do AzureInstância Gerenciada SQL do Azure

Este artigo é para o desenvolvedor que está com pressa para aprender os conceitos básicos dos recursos de desempenho OLTP In-Memory do Microsoft SQL Server e do Banco de Dados SQL do Azure.

Para In-Memory OLTP, este artigo fornece o seguinte:

  • Explicações rápidas dos recursos.
  • Exemplos de código principal que implementam os recursos.

O SQL Server e o Banco de dados SQL têm apenas pequenas variações em seu suporte a tecnologias In-Memory.

Na natureza, alguns blogueiros se referem ao OLTP In-Memory como Hekaton.

Benefícios dos recursos In-Memory

O SQL Server fornece recursos In-Memory que podem melhorar consideravelmente o desempenho de muitos sistemas de aplicativos. As considerações mais diretas são descritas nesta seção.

Recursos para OLTP (Online Transactional Processing)

Sistemas que devem processar um grande número de SQL INSERTs simultaneamente são excelentes candidatos para os recursos OLTP.

  • Nossos benchmarks mostram que melhorias de velocidade de 5 a 20 vezes mais rápidas são alcançáveis pela adoção dos recursos In-Memory.

Sistemas que processam cálculos pesados em Transact-SQL são excelentes candidatos.

  • Um procedimento armazenado dedicado a cálculos pesados pode ser executado até 99 vezes mais rápido.

Mais tarde, você pode visitar os seguintes artigos que oferecem demonstrações de ganhos de desempenho de In-Memory OLTP:

Recursos para análise operacional

In-Memory Analytics refere-se a SQL SELECTs que agregam dados transacionais, normalmente pela inclusão de uma cláusula GROUP BY. O tipo de índice chamado columnstore é central para a análise operacional.

Existem dois cenários principais:

  • do Batch Operational Analytics refere-se a processos de agregação que são executados após o horário comercial ou em hardware secundário que tem cópias dos dados transacionais.
  • de Análise Operacional em Tempo Real refere-se a processos de agregação executados durante o horário comercial e no hardware principal usado para cargas de trabalho transacionais.

O presente artigo se concentra no OLTP, e não no Analytics. Para obter informações sobre como os índices columnstore trazem o Analytics para o SQL, consulte:

Columnstore

Uma sequência de excelentes artigos de blog explica elegantemente os índices columnstore a partir de várias perspetivas. A maioria dos posts descreve ainda mais o conceito de análise operacional em tempo real, que a columnstore suporta. Esses posts foram criados por Sunil Agarwal, gerente de programas da Microsoft, em março de 2016.

Análise operacional em tempo real

  1. Real-Time Análise Operacional Usando a Tecnologia In-Memory
  2. Real-Time Operational Analytics - Visão geral do índice de columnstore não agrupado (NCCI)
  3. Real-Time Analytics Operacionais: exemplo simples usando o índice columnstore não clusterizado (NCCI) no SQL Server 2016
  4. Real-Time Operational Analytics: operações DML e índice columnstore não clusterizado (NCCI) no SQL Server 2016
  5. Real-Time Operational Analytics: Índice de columnstore não clusterizado (NCCI) filtrado
  6. Real-Time Análise Operacional: Opção de Atraso de Compressão para índice columnstore não clusterizado (NCCI)
  7. Real-Time Análise Operacional: Opção de Atraso de Compressão com NCCI e desempenho
  8. Real-Time Operational Analytics: Memory-Optimized Tabelas e columnstore index

Desfragmentar um índice de armazenamento em coluna

  1. Desfragmentação do índice Columnstore usando o comando REORGANIZE
  2. Política de mesclagem de índice Columnstore para reorganizar

Importação em massa de dados

  1. Armazenamento de Colunas Clusterizadas: Carga em Massa
  2. Clustered columnstore index: Otimizações de carga de dados - Registo em Log Mínimo
  3. Clustered columnstore index: Otimização da carga de dados - Importação paralela em massa

Características de In-Memory OLTP

Vejamos as principais características do In-Memory OLTP.

Tabelas com otimização de memória

A palavra-chave T-SQL MEMORY_OPTIMIZED, na instrução CREATE TABLE, é como uma tabela é criada para existir na memória ativa, em vez de no disco.

Uma tabela otimizada para memória tem uma representação de si mesma na memória ativa e uma cópia secundária no disco.

  • A cópia de disco é para recuperação de rotina após um desligamento e reinicialização do servidor ou banco de dados. Essa dualidade memória-mais-disco está completamente escondida de você e do seu código.

Módulos compilados nativamente

A palavra-chave T-SQL NATIVE_COMPILATION, na instrução CREATE PROCEDURE, é como um procedimento armazenado compilado nativamente é criado. As instruções T-SQL são compiladas para código de máquina no primeiro uso do procedimento nativo cada vez que o banco de dados é colocado online. As instruções do T-SQL não suportam mais uma interpretação lenta de todas as instruções.

  • Vimos a compilação nativa resultar em durações que são 1/100 da duração interpretada.

Um módulo nativo pode fazer referência apenas a tabelas com otimização de memória e não pode fazer referência a tabelas baseadas em disco.

Existem três tipos de módulos compilados nativamente:

Disponibilidade no Banco de Dados SQL do Azure

In-Memory OLTP e Columnstore estão disponíveis no Banco de Dados SQL do Azure. Para obter detalhes, consulte Otimizar o desempenho usando tecnologias In-Memory no Banco de dados SQL.

1. Garanta o nível de compatibilidade >= 130

Esta seção inicia uma sequência de seções numeradas que, juntas, demonstram a sintaxe Transact-SQL que você pode usar para implementar In-Memory recursos OLTP.

Primeiro, é importante que seu banco de dados seja definido para um nível de compatibilidade de pelo menos 130. Em seguida, está o código T-SQL para exibir o nível de compatibilidade atual para o qual seu banco de dados atual está definido.

SELECT d.compatibility_level
    FROM sys.databases as d
    WHERE d.name = Db_Name();

Em seguida, está o código T-SQL para atualizar o nível, se necessário.

ALTER DATABASE CURRENT
    SET COMPATIBILITY_LEVEL = 130;

2. Eleve para SNAPSHOT

Quando uma transação envolve uma tabela baseada em disco e uma tabela com otimização de memória, chamamos isso de transação entre contêineres. Nessa transação, é essencial que a parte otimizada para memória da transação opere no nível de isolamento da transação chamado SNAPSHOT.

Para aplicar de forma fiável este nível para tabelas otimizadas para memória numa transação entre contêineres, altere as definições da base de dados executando o seguinte comando T-SQL.

ALTER DATABASE CURRENT
    SET MEMORY_OPTIMIZED_ELEVATE_TO_SNAPSHOT = ON;

3. Crie um FILEGROUP otimizado (conjunto de ficheiros)

No Microsoft SQL Server, antes de criar uma tabela com otimização de memória, você deve primeiro criar um FILEGROUP que você declara CONTÉM MEMORY_OPTIMIZED_DATA. O FILEGROUP é atribuído ao seu banco de dados. Para mais pormenores, consultar:

No Banco de Dados SQL do Azure, você não precisa e não pode criar esse FILEGROUP.

O script T-SQL de exemplo a seguir habilita um banco de dados para In-Memory OLTP e define todas as configurações recomendadas. Funciona com o SQL Server e a Base de Dados SQL do Azure: enable-in-memory-oltp.sql.

Observe que nem todos os recursos do SQL Server têm suporte para bancos de dados com um grupo de arquivos MEMORY_OPTIMIZED_DATA. Para obter detalhes sobre limitações, consulte: Recursos do SQL Server sem suporte para In-Memory OLTP

4. Crie uma tabela com otimização de memória

A palavra-chave crucial Transact-SQL é MEMORY_OPTIMIZED.

CREATE TABLE dbo.SalesOrder
    (
        SalesOrderId   integer   not null   IDENTITY
            PRIMARY KEY NONCLUSTERED,
        CustomerId   integer    not null,
        OrderDate    datetime   not null
    )
        WITH
            (MEMORY_OPTIMIZED = ON,
            DURABILITY = SCHEMA_AND_DATA);

Transact-SQL instruções INSERT e SELECT em uma tabela com otimização de memória são as mesmas de uma tabela normal.

ALTER TABLE para tabelas Memory-Optimized

ALTER TABELA... ADD/DROP pode adicionar ou remover uma coluna de uma tabela otimizada para memória, ou de um índice.

  • CREATE INDEX e DROP INDEX não podem ser executados em uma tabela com otimização de memória, use ALTER TABLE ... ADD/DROP INDEX em vez disso.
  • Para obter detalhes, consulte Alteração de Memory-Optimized Tabelas.

Planeje suas tabelas e índices com otimização de memória

5. Crie um procedimento armazenado compilado nativamente (proc nativo)

A palavra-chave crucial é NATIVE_COMPILATION.

CREATE PROCEDURE ncspRetrieveLatestSalesOrderIdForCustomerId  
        @_CustomerId   INT  
        WITH  
            NATIVE_COMPILATION,  
            SCHEMABINDING  
    AS  
    BEGIN ATOMIC  
        WITH  
            (TRANSACTION ISOLATION LEVEL = SNAPSHOT,
            LANGUAGE = N'us_english')  
      
        DECLARE @SalesOrderId int, @OrderDate datetime;
      
        SELECT TOP 1  
                @SalesOrderId = s.SalesOrderId,  
                @OrderDate    = s.OrderDate  
            FROM dbo.SalesOrder AS s  
            WHERE s.CustomerId = @_CustomerId  
            ORDER BY s.OrderDate DESC;  
      
        RETURN @SalesOrderId;  
    END;  

A palavra-chave SCHEMABINDING significa que as tabelas referenciadas no proc nativo não podem ser descartadas, a menos que o proc nativo seja descartado primeiro. Para obter detalhes, consulte Criando procedimentos armazenados compilados nativamente.

Observe que você não precisa criar um procedimento armazenado compilado nativamente para acessar uma tabela com otimização de memória. Você também pode referenciar tabelas com otimização de memória a partir de procedimentos armazenados tradicionais e pacotes ad hoc.

6. Execute o procedimento nativo

Preencha a tabela com duas linhas de dados.

INSERT into dbo.SalesOrder  
        ( CustomerId, OrderDate )  
    VALUES  
        ( 42, '2013-01-13 03:35:59' ),
        ( 42, '2015-01-15 15:35:59' );

Segue-se uma chamada EXECUTE para o procedimento armazenado compilado nativamente.

DECLARE @LatestSalesOrderId int, @mesg nvarchar(128);
      
EXECUTE @LatestSalesOrderId =  
    ncspRetrieveLatestSalesOrderIdForCustomerId 42;
      
SET @mesg = CONCAT(@LatestSalesOrderId,  
    ' = Latest SalesOrderId, for CustomerId = ', 42);
PRINT @mesg;  

Aqui está a real saída de impressão:

-- 2 = Latest SalesOrderId, for CustomerId = 42  

Guia para a documentação e próximas etapas

Os exemplos simples anteriores fornecem uma base para aprender os recursos mais avançados do In-Memory OLTP. As seções a seguir são um guia para as considerações especiais que você pode precisar saber e para onde você pode ver os detalhes sobre cada uma delas.

Como as funcionalidades In-Memory OLTP funcionam muito mais rapidamente

As subseções a seguir descrevem brevemente como os recursos In-Memory OLTP funcionam internamente para fornecer melhor desempenho.

Como as tabelas com otimização de memória têm um desempenho mais rápido

Natureza dupla: Uma tabela otimizada para memória tem uma natureza dupla: uma representação na memória ativa e outra no disco rígido. Cada transação é comprometida com ambas as representações da tabela. As transações operam contra a representação de memória ativa, que é muito mais rápida. As tabelas com otimização de memória se beneficiam da maior velocidade da memória ativa em relação ao disco. Além disso, a maior flexibilidade da memória ativa possibilita uma estrutura de tabela mais avançada que é otimizada para velocidade. A estrutura avançada também é sem paginação, evitando desta forma a sobrecarga e a contenção de travas e bloqueios ativos.

Sem bloqueios: A tabela otimizada para memória depende de uma abordagem otimista para os objetivos concorrentes de integridade de dados versus simultaneidade e alta taxa de transferência. Durante a transação, a tabela não coloca bloqueios em nenhuma versão das linhas de dados atualizadas. Isso pode reduzir muito a disputa em alguns sistemas de alto volume.

Versões de linha: Em vez de bloqueios, a tabela com otimização de memória adiciona uma nova versão de uma linha atualizada na própria tabela, não em tempdb. A linha original é mantida até que a transação seja confirmada. Durante a transação, outros processos podem ler a versão original da linha.

  • Quando várias versões de uma linha são criadas para uma tabela baseada em disco, as versões de linha são armazenadas temporariamente em tempdb.

Menos registro: As versões antes e depois das linhas atualizadas são mantidas na tabela com otimização de memória. O par de linhas fornece muitas das informações que são tradicionalmente gravadas no arquivo de log. Isso permite que o sistema escreva menos informações, e com menos frequência, no log. No entanto, a integridade transacional é assegurada.

Como os procs nativos funcionam mais rapidamente

A conversão de um procedimento armazenado interpretado regular em um procedimento armazenado compilado nativamente reduz consideravelmente o número de instruções a serem executadas durante o tempo de execução.

Concessões das funcionalidades In-Memory

Como é comum na ciência da computação, os ganhos de desempenho proporcionados pelos recursos In-Memory são uma compensação. Os melhores recursos trazem benefícios que são mais valiosos do que os custos extras do recurso. Você pode encontrar orientações abrangentes sobre as trocas em:

O restante desta seção lista algumas das principais considerações de planejamento e compensação.

Compensações de tabelas com otimização de memória

Estimar memória: Você deve estimar a quantidade de memória ativa que sua tabela otimizada para memória consumirá. O sistema do computador deve ter capacidade de memória adequada para hospedar uma tabela com otimização de memória. Para mais pormenores, consultar:

Particione sua tabela grande: Uma maneira de atender à demanda por muita memória ativa é particionar sua tabela grande em partes na memória que armazenam linhas de dados de recentes quentes em comparação com outras partes no disco que armazenam linhas de legadas frias (como ordens de venda que foram totalmente enviadas e concluídas). Este particionamento é um processo manual de design e implementação. Veja:

Compromissos em processos nativos

  • Um procedimento armazenado compilado nativamente não pode acessar uma tabela baseada em disco. Um proc nativo pode acessar apenas tabelas com otimização de memória.
  • Quando um proc nativo é executado pela primeira vez depois que o servidor ou banco de dados foi colocado online novamente recentemente, o proc nativo deve ser recompilado uma vez. Isso causa um atraso antes que o proc nativo comece a ser executado.

Considerações avançadas para tabelas com otimização de memória

Índices para Memory-Optimized Tabelas diferem em alguns aspetos dos índices em tabelas tradicionais armazenadas em disco. Os índices de hash estão disponíveis apenas em tabelas com otimização de memória.

Você deve planejar para garantir que haverá memória ativa suficiente para sua tabela planejada com otimização de memória e seus índices. Veja:

Uma tabela com otimização de memória pode ser declarada com DURABILIDADE = SCHEMA_ONLY:

  • Essa sintaxe informa ao sistema para descartar todos os dados da tabela com otimização de memória quando o banco de dados é colocado offline. Apenas a definição da tabela é persistente.
  • Quando o banco de dados é colocado online novamente, a tabela com otimização de memória é carregada de volta na memória ativa, vazia de dados.
  • SCHEMA_ONLY tabelas podem ser uma alternativa superior às tabelas #temporary em tempdb, quando muitos milhares de linhas estão envolvidas.

As variáveis de tabela também podem ser declaradas como otimizadas para memória. Veja:

Considerações avançadas para módulos compilados nativamente

Os tipos de módulos compilados nativamente disponíveis através Transact-SQL são:

Uma função definida pelo usuário (UDF) compilada nativamente é executada mais rápido do que uma UDF interpretada. Aqui estão algumas coisas a considerar com UDFs:

  • Quando um T-SQL SELECT usa um UDF, o UDF é sempre chamado uma vez por linha retornada.
    • As UDFs nunca são executadas em linha e, em vez disso, são sempre chamadas.
    • A distinção compilada é menos significativa do que a sobrecarga de chamadas repetidas que é inerente a todas as UDFs.
    • Ainda assim, a sobrecarga das chamadas UDF é muitas vezes aceitável a nível prático.

Para obter dados de teste e explicação sobre o desempenho de UDFs nativas, consulte:

Guia de documentação para tabelas com otimização de memória

Consulte estes outros artigos que discutem considerações especiais para tabelas com otimização de memória:

Guia de documentação para procs nativos

O artigo a seguir e os seus subartigos no índice explicam os detalhes sobre procedimentos armazenados compilados de forma nativa.

Aqui estão os artigos que oferecem código para demonstrar os ganhos de desempenho que você pode obter usando In-Memory OLTP: