Sqlserver
 sql >> Base de Dados >  >> RDS >> Sqlserver

Tutorial de particionamento e partições de tabela do SQL Server

Problema


Neste artigo, vamos nos concentrar na demonstração do particionamento de tabelas. A explicação mais simples do particionamento de tabelas pode ser chamada de divisão de tabelas grandes em pequenas. Este tópico fornece escalabilidade e gerenciamento.

O que é particionamento de tabela no SQL Server?


Suponha que temos uma mesa e ela cresce dia a dia. Neste caso, a tabela pode causar alguns problemas que precisam ser resolvidos pelos passos definidos abaixo:
  • Mantenha esta tabela. Levará muito tempo e consumirá mais recursos (CPU, IO etc.).
  • Faça backup.
  • Bloqueie problemas.

Devido aos motivos mencionados acima, precisamos de um particionamento de tabela. Essa abordagem tem os seguintes benefícios:
  • Capacidade de gerenciamento:Se separarmos a tabela, podemos gerenciar cada partição da tabela. Por exemplo, podemos fazer apenas uma partição da tabela.
  • Recurso de arquivamento:algumas partições da tabela são usadas apenas por esse motivo. Não precisamos fazer backup dessa partição da tabela. Podemos usar um backup de grupo de arquivos e fazer backup apenas alterando uma partição da tabela.
  • Desempenho de consulta:o otimizador de consulta do SQL Server decide usar a eliminação de partição. Isso significa que o SQL Server não faz nenhuma pesquisa pela partição não relacionada da tabela.

Particionamento de tabela vertical e horizontal no SQL Server


O particionamento de tabela é um conceito geral. Existem vários tipos de particionamento que funcionam para casos específicos. As mais essenciais e amplamente utilizadas são as duas abordagens:particionamento vertical e particionamento horizontal.

A especificidade de cada tipo reflete a essência de uma tabela como uma estrutura composta por colunas e linhas:

• O Particionamento Vertical divide a tabela em colunas.
• O particionamento horizontal divide a tabela em linhas.

O exemplo mais típico de particionamento de tabela vertical é uma tabela de funcionários com seus detalhes – nomes, e-mails, números de telefone, endereços, aniversários, ocupações, salários e todas as outras informações que possam ser necessárias. Uma parte desses dados é confidencial. Além disso, na maioria dos casos, os operadores precisam apenas de alguns dados básicos, como nomes e endereços de e-mail.

O particionamento vertical cria várias tabelas “mais estreitas” com os dados necessários à mão. As consultas visam apenas uma parte específica. Dessa forma, as empresas reduzem a carga, aceleram as tarefas e garantem que dados confidenciais não sejam revelados.

O particionamento de tabela horizontal resulta na divisão de uma tabela geral em várias menores, onde cada tabela de partículas tem o mesmo número de colunas, mas o número de linhas é menor. É uma abordagem padrão para tabelas excessivas com dados cronológicos.

Por exemplo, uma tabela com os dados para todo o ano pode ser dividida em seções menores para cada mês ou semana. Então, a consulta se referirá apenas a uma tabela menor específica. O particionamento horizontal melhora a escalabilidade dos volumes de dados com seu crescimento. As tabelas particionadas permanecerão menores e fáceis de processar.

Qualquer particionamento de tabela no SQL Server deve ser considerado com cuidado. Às vezes, você precisa solicitar os dados de várias tabelas particionadas de uma só vez e, em seguida, precisará de JOINs nas consultas. Além disso, o particionamento vertical ainda pode resultar em tabelas grandes e você terá que dividi-las mais. Em seu trabalho, você deve confiar nas decisões para seus propósitos comerciais específicos.

Agora que esclarecemos o conceito de particionamento de tabelas no SQL Server, é hora de prosseguir para a demonstração.

Vamos evitar qualquer script T-SQL e lidar com todas as etapas de partição de tabela com o assistente de particionamento do SQL Server.

O que você precisa para fazer partições de banco de dados SQL?

  • Banco de dados de amostra WideWorldImporters
  • SQL Server 2017 Developer Edition

A imagem abaixo nos mostra como projetar uma partição de tabela. Faremos uma partição de tabela por anos e localizaremos diferentes grupos de arquivos.

Nesta etapa, criaremos dois grupos de arquivos (FG_2013, FG_2014). Clique com o botão direito do mouse em um banco de dados e clique na guia Grupos de arquivos.

Agora, vamos conectar os grupos de arquivos aos novos arquivos pdf.

Nossa estrutura de armazenamento de banco de dados está pronta para particionamento de tabelas. Vamos localizar a tabela que queremos particionar e iniciar o assistente Criar Partição.

Na captura de tela abaixo, selecionaremos uma coluna na qual queremos aplicar a função de partição. A coluna selecionada é "InvoiceDate".

Nas próximas duas telas, nomearemos uma função de partição e um esquema de partição.

Uma função de partição definirá como particionar as linhas [Vendas].[Faturas] com base na coluna InvoiceDate.

Um esquema de partição definirá mapas para as linhas Sales.Invoices para grupos de arquivos.

Atribua as partições aos grupos de arquivos e defina os limites.

Limite Esquerdo/Direito define o lado de cada intervalo de valor de limite que pode ser esquerdo ou direito. Vamos definir limites como este e clicar em Estimar armazenamento. Esta opção nos fornece as informações sobre o número de linhas a serem localizadas nos limites.

E, finalmente, selecionaremos Executar imediatamente e clique em Avançar.

Quando a operação for bem-sucedida, clique em Fechar.

Como você pode ver, nossa tabela Sales.Invoices foi particionada. Esta consulta mostrará os detalhes da tabela particionada.
SELECT
  OBJECT_SCHEMA_NAME(pstats.object_id) AS SchemaName
  ,OBJECT_NAME(pstats.object_id) AS TableName
  ,ps.name AS PartitionSchemeName
  ,ds.name AS PartitionFilegroupName
  ,pf.name AS PartitionFunctionName
  ,CASE pf.boundary_value_on_right WHEN 0 THEN 'Range Left' ELSE 'Range Right' END AS PartitionFunctionRange
  ,CASE pf.boundary_value_on_right WHEN 0 THEN 'Upper Boundary' ELSE 'Lower Boundary' END AS PartitionBoundary
  ,prv.value AS PartitionBoundaryValue
  ,c.name AS PartitionKey
  ,CASE 
    WHEN pf.boundary_value_on_right = 0 
    THEN c.name + ' > ' + CAST(ISNULL(LAG(prv.value) OVER(PARTITION BY pstats.object_id ORDER BY pstats.object_id, pstats.partition_number), 'Infinity') AS VARCHAR(100)) + ' and ' + c.name + ' <= ' + CAST(ISNULL(prv.value, 'Infinity') AS VARCHAR(100)) 
    ELSE c.name + ' >= ' + CAST(ISNULL(prv.value, 'Infinity') AS VARCHAR(100))  + ' and ' + c.name + ' < ' + CAST(ISNULL(LEAD(prv.value) OVER(PARTITION BY pstats.object_id ORDER BY pstats.object_id, pstats.partition_number), 'Infinity') AS VARCHAR(100))
  END AS PartitionRange
  ,pstats.partition_number AS PartitionNumber
  ,pstats.row_count AS PartitionRowCount
  ,p.data_compression_desc AS DataCompression
FROM sys.dm_db_partition_stats AS pstats
INNER JOIN sys.partitions AS p ON pstats.partition_id = p.partition_id
INNER JOIN sys.destination_data_spaces AS dds ON pstats.partition_number = dds.destination_id
INNER JOIN sys.data_spaces AS ds ON dds.data_space_id = ds.data_space_id
INNER JOIN sys.partition_schemes AS ps ON dds.partition_scheme_id = ps.data_space_id
INNER JOIN sys.partition_functions AS pf ON ps.function_id = pf.function_id
INNER JOIN sys.indexes AS i ON pstats.object_id = i.object_id AND pstats.index_id = i.index_id AND dds.partition_scheme_id = i.data_space_id AND i.type <= 1 /* Heap or Clustered Index */
INNER JOIN sys.index_columns AS ic ON i.index_id = ic.index_id AND i.object_id = ic.object_id AND ic.partition_ordinal > 0
INNER JOIN sys.columns AS c ON pstats.object_id = c.object_id AND ic.column_id = c.column_id
LEFT JOIN sys.partition_range_values AS prv ON pf.function_id = prv.function_id AND pstats.partition_number = (CASE pf.boundary_value_on_right WHEN 0 THEN prv.boundary_id ELSE (prv.boundary_id+1) END)
WHERE pstats.object_id = OBJECT_ID('Sales.Invoices')
ORDER BY TableName, PartitionNumber;

EM Desempenho de particionamento do SQL Server


Compararemos o desempenho da tabela particionada e não particionada para a mesma tabela. Para fazer isso, use a consulta abaixo e ative Incluir Plano de Execução Real.
DECLARE @Dt as date  = '20131231'
SELECT COUNT(InvoiceDate)
  FROM [Sales].[Invoices]
  where InvoiceDate < @Dt

Quando examinamos o plano de execução, descobrimos que ele inclui as propriedades “Partitioned”, “Actual Partition Count” e “Actual Partitioned Accessed”.

A propriedade particionada indica que esta tabela está habilitada para partição.

A Contagem Real de Partições propriedade é o número total de partições que são lidas pelo mecanismo do SQL Server.

O Acessado Particionado Real propriedade são os números de partição avaliados pelo mecanismo do SQL Server. O SQL Server elimina o acesso para outras partições, pois é chamado de eliminação de partição e obtém uma vantagem no desempenho da consulta.

Agora, observe o plano de execução da tabela não particionada.

A principal diferença entre esses dois planos de execução é o Número de linhas lidas porque esta propriedade indica quantas linhas são lidas para esta consulta. Como você pode ver no gráfico de compactação abaixo, os valores da tabela particionada são muito baixos. Por esse motivo, ele consumirá um IO baixo.

Em seguida, execute a consulta e examine o plano de execução.
DECLARE @DtBeg as date  = '20140502'
DECLARE @DtEnd as date  = '20140701'

SELECT COUNT(InvoiceDate)
  FROM [Sales].[Invoices]
  where InvoiceDate between @DtBeg and @DtEnd

Escalonamento de bloqueio em nível de partição


O escalonamento de bloqueio é um mecanismo usado pelo SQL Server Lock Manager. Ele organiza para bloquear um nível de objetos. Quando o número de linhas a serem bloqueadas aumenta, o gerenciador de bloqueio altera um objeto de bloqueio. Este é o nível de hierarquia de escalonamento de bloqueio “Linha -> Página -> Tabela -> Banco de Dados”. Mas, na tabela particionada, podemos bloquear uma partição à medida que aumenta a simultaneidade e o desempenho. O nível padrão de escalonamento de bloqueio é “TABLE” no SQL Server.

Execute a consulta usando a instrução UPDATE abaixo.
BEGIN TRAN
DECLARE @Dt as date  = '20131221'
UPDATE [Sales].[Invoices] SET CreditNoteReason = 'xxx'   where InvoiceDate < @Dt
SP_LOCK

A caixa vermelha define um bloqueio exclusivo que garante que várias atualizações não possam ser feitas no mesmo recurso ao mesmo tempo. Ocorre na tabela Faturas.

Agora, definiremos o modo de escalonamento da tabela Sales.Invoices para automatizá-lo e executar novamente a consulta.
ALTER TABLE Sales.Invoices SET (LOCK_ESCALATION = AUTO)

Agora, a caixa vermelha define o bloqueio exclusivo de recuo que protege bloqueios exclusivos solicitados ou adquiridos em alguns recursos inferiores na hierarquia. Em breve, este nível de bloqueio nos permite atualizar ou excluir outra partição de tabelas. Isso significa que podemos iniciar outra atualização ou inserir outra partição da tabela.

Em postagens anteriores, também exploramos a questão de alternar entre particionamento de tabela e fornecemos o passo a passo. Esta informação pode ser útil para você se você lidar com esses casos. Consulte o artigo para obter mais informações.

Referências

  1. Modos de bloqueio
  2. Tabelas e índices particionados