#26 – Para que serve

Olá, pessoal, bom dia.

Como vocês estão? Já fazem alguns meses que não nos encontramos nesta sessão em meu blog, fico feliz em te encontrar novamente. Seja bem-vindo a mais um post da sessão Para que Serve, post de número 26, em mais um dia de muitas atividades, afazeres e compromissos profissionais, domésticos (sim, eu adoro ajudar a minha esposa, cuidar da nossa casa…..) e claro acadêmicos.

Neste post quero destacar uma parte de um dos recursos mais importantes, impactantes e tradicionais do Microsoft SQL Server existente deste sua primeira versão, o qual esta totalmente relacionamento com o comportamento de nossas transações, querys e processamentos que possam estar sendo realizados neste momento em nossos servidores ou instâncias.

Sendo direto e reto no assunto, você que esta neste momento lendo este post e trabalhando com seus dados, tabelas e bancos no SQL Server esta fazendo uso dele sem talvez saber que ele exista, me refiro ao tradicionais Níveis de Isolamento de Transações ou Transaction Isolation Levels.

Você se lembra da existência deste recurso e o quanto ele é importante? Pois bem, caso não se lembra, a partir deste post e provavelmente os próximos 2 ou 3 futuros serão dedicados nesta sessão a apresentar de forma simples, prática e muito didática como podemos fazer uso deste recurso em nossas transações, seus comportamentos, vantagens e desvantagens (isso se elas existirem) e principalmente os riscos ao fazer uso talvez de uma forma não muito indicada.

Sendo assim, chegou a hora de conhecer um pouco mais sobre o post de número 25 da sessão Para que serve. Mas uma vez, bem vindo ao #26 – Para que serve – Apresentando os nível de isolamento Read Uncommitted.

Espero que você esteja animado para conhecer um pouco mais sobre este recurso, caso já conheça, continue lendo este post, sempre podemos aprender algo novo….

Introdução

Durante o processamento de nossas querys, transações e processos internos executados pelo Microsoft SQL Server, estamos sem saber fazendo uso de um dos mais importantes e inevitáveis recursos, conhecidos como Níveis de Isolamento. Os níveis de isolamento tem a finalidade de gerenciar, controlar e manter todo controle de simultaniedade, em nossas querys e transações, afim de garantir e evitar que possíveis efeitos colaterais indesejáveis possam ocorrer.
A partir do momento que uma transação é executado, a mesma internamente especifica ou informa através do Query Processor qual será o seu grau de transação, o qual tem a finalidade de ajudar o SQL Server a estabelecer uma camada de isolamento dentro da transações, procurando proteger nova query contra modificações de recursos ou dados que possam estar sendo processados ou encontram-se na fila de processamento de outras querys ou transações.
Você pode estar se perguntando:
  1. Como um nível de isolamento se comporta?
  2. O que ele controla?
Vou tentar de uma forma bastante simples responder esta e possíveis outras perguntas, vamos avançar mais um pouco.

Os Níveis de Isolamento

Ao fazer uso de um nível de isolamento, estamos procurando maneiras de garantir a atomicidade e consistência em seu banco de dados, garantindo a integridade transacional.

Este recurso tem o objetivo de tentar (e praticamente ele faz isso muito bem), evitar bloqueios, ou garantir problemas como atualizações perdidas ou leituras sujas não venham a ocorrer, ou de outra forma garantir a qualidade dos seus dados.

O isolamento transacional é um assunto muito específico, um pouco complexo, mas tenho a certeza que entender um pouco mais sobre ele, será ideal para suas necessidades.

Existem cinco níveis de isolamento no Microsoft SQL Server:

  1. Read Uncommitted;
  2. Read Committed;
  3. Repeatable Read;
  4. Snapshot; e
  5. Serializable.

Todos devem de forma direta e obrigatória controlar nossas transações da seguinte forma:

  1. Estabelecer bloqueios quando os dados estão sendo lidos, informando internamente qual tipo de bloqueio deverá ser solicitado e aplicado;
  2. Definir por quanto tempo um bloqueio relacionado a leitura de daods deverá ser mantido em funcionamento; e
  3. Identificar a ocorrência ou possível existência de alterações de linhas, na qual se sua referência estiver sendo envolvida em uma operação de leitura que possa estar sendo modificada por outra transação, aplicando assim:- Um bloqueio exclusivo sobre esta linha, o mesmo só será encerrado após o termino da transação que deseja usar esta linha;- Identificar e recuperar as versão de controle de linha, conhecida como versão confirmada, a qual existia até seu momento em que a instrução que deseja utilizar esta linha tenha sido inicidada; e

    – Realizar a leitura da modicação dos dados que ainda não encontra-se confirmados.

Mas cada um trabalha de uma forma diferente, apresentando comportamento e formas de uso únicas e específicas de acordo com todo cenário transacional que encontra-se naquele devido momento em execução.

Para que possamos saber qual nível vamos usar ou esta sendo utilizado, precisamos entender um pouco sobre a escolha deste recurso por nós ou pelo próprio SQL Server, vamos então avançar mais um pouco na nossa caminhada, e conhecer sobre a escolha do nível.

A escolha do nível de isolamento

Quando o Microsoft SQL Server realiza a escolha de um nível, o mesmo por padrão não afeta os atuais níveis de bloqueio já aplicados para proteger toda as possíveis modificações de dados, a partir do momento que uma transação estabelece um bloqueio exclusivo sobre nossos dados, os mesmos estão “colocados” dentro de uma camada de proteção, como se fosse um escudo existente para aquele conjunto de dados, permitindo assim que este bloqueio possa permitir que toda e qualquer alteração de um ou mais dados venha a ser feito de forma satisfatória.
O encerramento e termino deste bloqueio exclusivo vai ocorrer assim que a transação se encerrar, independente do nível de isolamento que foi adquirido ou escolhido para ela ou por ela.
Ao se fazer uma escolha de um nível de isolamento para uma transação, nossa mecanismo de banco de dados (Database Engine) poderá trabalhar de forma tranquila, sendo de existência destes escudos protetores, ainda mais em transações que envolvem a leitura e modificações de dados (algo que é feito a todo momento em nossos ambientes), esta camada protetora também é aplicada de acordo com o nível de modificação dos dados afim de evitar impacto em outras transações.
Mas como diria meu irmão, nem tudo são flores em nossas vidas, imagine então em um Sistema Gerenciador de banco de dados, isso deve ser pior ainda, escolher ou definir um nível de isolamento que possa ser inadequado pode acarretar em diversos risco ou problemas.
Avançando mais ainda, vamos conhecer um pouco de um conceito chamado efeitos colaterais da simultaniedade (nome bonito esse kkkkk….)

Os efeitos colaterais de simultaniedade

Ao se escolher um nível de isolamento, tanto nós como principalmente o Microsoft SQL Server esta estabelecendo uma escala de simultaniedade de acesso aos dados para nossos usuários, ou seja, estamos aumentando ou diminuindo de forma direta, única e exclusiva como o mesmo dado poderá ser acesso por diversos usuários e suas transações ao mesmo tempo.
Os níveis de isolamento internamento possuem uma escala, a qual pode ser entendida como: Baixa, Média ou Alta, quanto mais baixa for esta escala, maior será a capacidade de diversos usuários acessarem um determinado dado ou conjunto de dados ao mesmo tempo, isso pode parecer bom, mas nem sempre, pois sem perceber estaremos aumentando a possibilidade de ocorrência dos efeitos colaterais de simultaniedade, os quais podem permitir: a leitura de de dados fantasmas, dados sujos ou desatualizados, a ocorrência de atualizações já processadas que podem ser chamadas de atualizações perdidas, afetando um ou mais usuários.
Por outro lado, temos uma contrapartida, ou seja, quando maior for o nível de isolamento, menor será o risco da ocorrência ou presença dos nossos efeitos colaterais de simultaniedade, o que vai exigir por parte de nossos sistemas, um controle transacional muito maior, o que vai provocar a possibilidade de bloqueios entre transações, conhecido como Deadlock (abraço da morte).
Até aqui tudo tranquilo…. por enquanto estamos conhecendo um pouco mais sobre estes conceitos, algo muito importante.
Tenho a certeza que ao acaber de ler o parágrafo anterior você ficou com uma pulga atrás da sua orelha, e se questionou: Qual seria o nível de isolamento mais alto e também o mais baixo? Calma, calma, tenha muita calma nessa hora que a resposta se encontra logo abaixo.

Dentre os cinco níveis de isolamento existentes, o Serializable (Serializável) é o mais alto, o qual garante que uma transação recupere todos os dados sempre exatamente da forma que se encontrava, todas as vezes que se repetir uma operação de leitura daquele referido dado, o que ao se fazer uso deste nível de isolamento estaremos impossibilitando o acesso ao mesmo dado por parte de outros usuários, isso em um sistema monousuário seria o mais indicado, mas em sistemas modernos conhecidos como multiusuário não seria indicado.
O nível de isolamento mais baixo é conhecido como Read Uncommited (Leitura não confirmada), o qual permite realizar a recuperação de dados modificados mas que ainda não estão totalmente confirmados, possibilitando que outras transações tenham acesso, permitindo então a ocorrência da leitura de dados sujos ou fantasmas, sendo assim, todos os possíveis efeitos colaterais existentes por parte dos níveis de isolamento poderam ocorrer a partir do momento em que o Read Uncommitted encontra-se em uso, deixando de lado qualquer tipo de bloqueio de leitura ou alteração de dados, descartando totalmente o chamado controle de versão de linha (Row Versioning).
Agora que já sabemos um pouco mais sobre os níveis de isolamento, a escolha do nível e seus efeitos, vamos começar nossa brincadeira, vamos colocar a mão em nossos teclados e conhecer de forma prática o nível de isolamento Read Uncommitted.
Mas antes de praticarmos, gostaria de indicar a leitura de outro post existente aqui no meu blog, que vai justamente complementar um conceito importante relacionado aos níveis de isolamento, a propriedades e características de todo e qualquer dado, conhecidas como AVIAO (autoria deste que vos escreve).

Caminhando mais um pouco, nosso primeiro passo será criar como de costume um pequeno ambiente para trabalharmos, composto pelos seguintes elementos:

  • Database: BancoDeDadosNiveldeIsolamento; e
  • Table: Empregados.

Utilizaremos o Bloco de Código 1 apresentado abaixo para realizar a criação deste ambiente:

 

— Bloco de Código 1 — Criando o ambiente —

— Criando o Banco de Dados —
Create Database BancoDeDadosNiveldeIsolamento
Go
— Acessando —
Use BancoDeDadosNiveldeIsolamento
Go
— Criando a Tabela Empregados —
Create Table Empregados
(CodigoEmpregado Int Identity(1,1),
NomeEmpregado Varchar(100),
SalarioEmpregado Money,
Constraint PK_CodigoEmpregado PRIMARY KEY(CodigoEmpregado) )
Go
— Inserindo os dados, populando a tabela Empregados —
Insert Into Empregados (NomeEmpregado, SalarioEmpregado)
Values  (‘Pedro Galvão’, 2100),
(‘Fernanda Galvão’, 2200),
(‘Eduardo Galvão’, 4000),
(‘João Pedro Galvão’, 1950),
(‘Maria Luíza Galvão’, 6500)
Go
Acredito que você tenha executado este bloco de código e obtido sucesso em sua execução, nossa tabela esta criada e populada. Por enquanto tudo tranquilo, e assim será os demais passos, nosso que o nosso próximo será identificar qual é o atual nível de isolamento que estamos utilizando em nossa query, para tal vamos executar o Bloco de Código 2 a seguir:
— Bloco de Código 2 — Identificando o nível de isolamento atual —
Select Case transaction_isolation_level
When 0 Then ‘Unspecified’
When 1 Then ‘Read Uncommitted’
When 2 Then ‘Read Committed’ — nível padrão.
When 3 Then ‘Repeatable’
When 4 Then ‘Serializable’
When 5 Then ‘Snapshot’
End As ‘Nível de Isolamento’
FROM sys.dm_exec_sessions
Where session_id = @@SPID
Go
Ao executar o bloco de Código 2 apresentado acima, provavelmente o Microsoft SQL Server deverá ter retornado em sua query o valor de Read Committed, sendo este o nível de isolamento padrão de toda e qualquer query ou transação processada em nossos servidores ou instâncias.
Note que estamos fazendo uso da Visão de Gerenciamento Dinâmica sys.dm_exec_sessions em conjunto com a variável de Sistema @@SPID, para que possamos identificar o nível de isolamento em nossa query, caso você queira saber os níveis que possam estar sendo utilizados nas outras transações, basta remover a cláusula Where.
Legal, lega, vamos para nosso próximo passo, que será justamente fazer uso do nível de isolamento Read Uncommitted, para que seja possível demonstrar teremos a necessidade de abrir três novas querys, sendo que na primeira vamos copiar o colar o Bloco de Código 3 e na segunda o Bloco de Código 4 e na terceira o Bloco de Código 5, ambos apresentados respectivamente abaixo:
— Bloco de Código 3 — Realizando o Update de dados —
Begin Transaction
Update Empregados
Set SalarioEmpregado = 5000
Where   CodigoEmpregado = 5
Go
— Bloco de Código 4 — Alterando o nível de isolamento para Read Uncommitted —
Set Transaction Isolation Level Read Uncommitted
Set NoCount On
Go
Select CodigoEmpregado, NomeEmpregado, SalarioEmpregado
From Empregados
Where CodigoEmpregado = 5
Go
— Bloco de Código 5 — Identificando os bloqueios e seus tipos —
SELECT es.login_name,
es.session_id,
tl.resource_type,
tl.resource_associated_entity_id,
tl.request_mode,
tl.request_status
FROM  sys.dm_tran_locks tl INNER JOIN  sys.dm_exec_sessions es
On tl.request_session_id = es.session_id
WHERE es.login_name = SUSER_SNAME()
AND tl.resource_associated_entity_id <> 0
Go
E ai você esta vivo? Eu acredito que sim, pois não executamos nada até o presente momento!
Vamos então começar a ver o que acontece, executando o Bloco de Código 3 na primeira query apresentado acima. Podemos notar que aparentemente nossa query foi processada e a alteração da coluna salário do nosso funcionário de Código 5 foi completada.
Ai eu lhe pergunto, será que isso aconteceu mesmo? Vai depender de como vamos tentar obter esta comprovação, se você se manter na mesma query utilizada para processar o Bloco de Código 3 e executar um comando Select, com certeza terá o seguinte retorno em tela conforme ilustra a Figura 1 a seguir:
Figura 1 – O funcionário com Código 5 teve aparentemente seu salário atualizado.
Bom, se trocamos de query e executarmos e executarmos o seguinte Bloco de Código 6 começaremos a entender que não é bem assim:
— Bloco de Código 6 — Tentando consultar os dados da tabela Empregados —
Select CodigoEmpregado, NomeEmpregado, SalarioEmpregado
From Empregados
Where CodigoEmpregado = 5
Go
Você vai observar que nossa query começa a ser processada e o resultado na aparece em tela, ou seja, o Update realizado no Bloco de Código 3 encontra-se na fila de confirmação, ou seja, a mesma ainda não foi confirmada ou desfeita, justamente porque abrir uma transação única e exclusive para sua execução através do comando Begin Transaction.
A Figura 2 apresentada abaixo, ilustra o processamento da query, mas sem retorno de dados em tela:
Figura 2 – Select tentando ser executado.
Se você observou ainda não executamos os Blocos de Código 4 e 5, vou deixar para o final a execução do bloco de Código 4, o qual vai nos ajudar a entender o que acontece quando utilizamos o nível de isolamento Read Uncommitted.
Então, vamos voltar um pouco no tempo, e executar o Bloco de Código 5 e identificar com base na execução do bloco de código 3 quais os bloqueios estão aplicados pelo Microsoft SQL Server em nossa query, tabela e dados, tendo um possível resultado similar ao apresentado pela Figura 3 abaixo:
Figura 3 – Relação de bloqueios aplicados neste momento, com base, nas sessões, usuários, objetos e dados.
Se observarmos a figura acima, Podemos identificar a existência de três bloqueios do tipo IX conhecido como Intent Exclusive (“O qual possui intenção de colocar bloqueios X (exclusivos) em algum recurso subordinado na hierarquia de bloqueio.”) na coluna Request_Mode (modo de requisição do bloqueio).
Neste momento temos um bloqueio de forma hierárquica aplicada nas páginas de dados, na chave primária de acesso e propriamente a tabela Empregados.
Não vou abordar neste post os bloqueios e seus tipos, este não é o objetivo de hoje, caso queira saber mais acesse a documentação oficial Microsoft: Guia de Controle de Versão de Linha e Bloqueio de Transações.
Para finalizarmos e entendermos os efeitos colaterais que podem ocorrer a partir do momento em que utilizamos um determinado nível de isolamento, vamos executar o Bloco de Código 4, o qual vai comprovar a ocorrência de leituras sujas ou dados fantasmas em nosso ambiente.
A Figura 4 ilustra o resultado apresentada em tela:
Para nossa surpresa conseguimos obter o retorno dos dados em tela, mesmo com todos os bloqueios aplicados, fica claro observar que neste momento o Salário da funcionária Maria Luíza Galvão foi alterado para 5.000, mas este dado ainda não esta confirmado, pois só estamos conseguindo obter este valor e realizar o acesso e leitura destes dados devido a estarmos utilizando a instrução Set Transaction Isolation Level Read Uncommitted, a qual em tempo de execução alterou o nível de isolamento de nossa sessão para Read Uncommitted (Leitura não confirmada).
Para comprovar mais ainda, você pode executar novamente os blocos de Código 5 e 6 que apresentaram ao mesmo comportamento já destacado aqui.
Isso não é fantástico, sensacional esta mudança de comportamento e ao mesmo tempo perigosa.
Vou deixar em suas mãos confirmar ou não esta atualização do salário da funcionária Maria Luíza Galvão, caso você queira dar este direto a ela, utilize a instrução Commit Transaction, caso contrário Rollback Transaction.
Logo após isso, execute novamente o Bloco de Código 5 e observe que todos os bloqueios serão removidos, ou seja, agora sim nossa query e suas respectivos transações foram encerradas.

Sem mais delongas, chegamos ao final, foi muito legal poder apresentar um pouco sobre os níveis de isolamento existentes no Microsoft SQL Server.

Claro de que um pouco de trabalho este post, mas já estou acostumado, mesmo assim sempre vale a pena poder compartilhar um pouco de conhecimento e experiências adquiridas ao longo dos anos de trabalho como DBA e Professor.

Espero que você tenha gostado, eu posso dizer que sim, mas sua opinião é muito importante.


Referências

https://docs.microsoft.com/en-us/sql/relational-databases/system-dynamic-management-views/sys-dm-tran-locks-transact-sql

https://www.mssqltips.com/sqlservertip/2977/demonstrations-of-transaction-isolation-levels-in-sql-server/

https://docs.microsoft.com/en-us/sql/connect/jdbc/understanding-isolation-levels?view=sql-server-2017

https://docs.microsoft.com/pt-br/sql/connect/jdbc/understanding-isolation-levels?view=sql-server-2017

http://msdn.microsoft.com/en-us/library/ms189122(v=sql.105).aspxhttps://www.mssqltips.com/sqlservertip/1081/snapshot-isolation-in-sql-server-2005/

https://www.mssqltips.com/sqlservertip/1081/snapshot-isolation-in-sql-server-2005/

https://www.mssqltips.com/sqlservertip/2250/sql-server-serializable-isolation-level-and-duplicate-key-insertion-attempts/

https://docs.microsoft.com/en-us/sql/relational-databases/sql-server-transaction-locking-and-row-versioning-guide

https://docs.microsoft.com/pt-br/sql/relational-databases/sql-server-transaction-locking-and-row-versioning-guide?view=sql-server-2017

https://docs.microsoft.com/en-us/sql/relational-databases/system-dynamic-management-views/sys-dm-tran-locks-transact-sql?view=sql-server-2017

Links

Caso você ainda não tenha acessado os posts anteriores desta sessão, fique tranquilo é fácil e rápido, basta selecionar um dos links apresentados a seguir:

https://pedrogalvaojunior.wordpress.com/2019/05/07/25-para-que-serve/

https://pedrogalvaojunior.wordpress.com/2019/02/23/24-para-que-serve/

https://pedrogalvaojunior.wordpress.com/2018/12/21/23-para-que-serve/

https://pedrogalvaojunior.wordpress.com/2018/08/22/22-para-que-serve/

https://pedrogalvaojunior.wordpress.com/2018/05/28/21-para-que-serve/

 

Conclusão

Mais uma vez podemos observar como o Microsoft SQL Server apresenta um conjunto grandioso de funcionalidades, recursos e principalmente comportamentos únicos e específicos aplicados de formas diferentes para cenários simulares.

Neste post podemos conhecer, aprender e enteder um pouco sobre os níveis de isolamento, sua forma de escolha, seus efeitos colaterais e comportamentos. Tivemos a possibilidade de conhecer um pouco sobre bloqueios, quando eles podem ocorrer e como já identificados, além disso, utilizamos o nível de isolamento Read Uncommitted para similar a ocorrência de leitura suja, dados fantasmas e acesso a tabelas mesmo encontrando-se em bloqueios.

Os níveis de isolamento são recursos de extrema importância, desempenhando um papel primordial no acesso, compartilhamento e proteção de nossas dados, tabelas e páginas de dados, estabelecendo um comportamento integro e confiável para que o Database Engine, Storage Engine e Query Processor possam realizar suas atividades normalmente.

Este é o fantástico Microsoft SQL Server, que desde suas primeiras versões nos apresenta inúmeras possibilidades de se aprender, possibilitando usar o passado como fonte de inspiração para construção de um futuro melhor, por isso que a cada dia eu me apaixono ainda mais por este produto…

Vai SQL Server, Vai SQL Server….

Agradecimentos

Mais uma vez obrigado por sua ilustre visita, sinto-me honrado com sua presença, espero que este conteúdo possa lhe ajudar e ser útil em suas atividades profissionais e acadêmicas.

Um forte abraço, até o próximo post da sessão Para que serve a ser publicado no mês novembro de 2019.

Um grande abraço e uma ótima semana.