Prévia do material em texto
UNIDADE III Projetos de Banco de Dados Everton Gomede Gerenciamento de Transações Imagine o acesso simultâneo a um mesmo dado; por exemplo: a compra de uma passagem aérea. Caso não tenhamos uma forma de controlar esse acesso, podemos vender 2 vezes a mesma poltrona. Para lidar com esse cenário, utilizamos as transações. Ao �nal desta aula, você será capaz de: Aprender o conceito de transação; Entender sobre atomicidade de transação e durabilidade; Aprender sobre Isolamento de transações. Aula 01 Introdução 2 Visão geral O termo transação refere-se a uma coleção de operações que formam uma única unidade de trabalho. Por exemplo, a transferência de dinheiro de uma conta para outra é uma transação composta por duas atualizações, uma para cada conta. É importante que todas as ações sejam executadas completamente, uma vez que, em caso de falha, os efeitos parciais de cada transação incompleta serão desfeitos. Essa propriedade é chamada atomicidade. Além disso, uma vez que uma transação é bem- sucedida, seus efeitos devem persistir no banco de dados. Essa propriedade é chamada de durabilidade. Em um sistema de banco de dados no qual várias transações estão sendo executadas simultaneamente, se as atualizações dos dados compartilhados não forem controladas, haverá potencial para que transações vejam estados intermediários inconsistentes criados por atualizações de outras transações. Tal situação pode resultar em atualizações erradas nos dados armazenados no banco de dados. Frente a isso, os sistemas de banco de dados devem fornecer mecanismos para isolar transações, bem como os efeitos de outras transações em execução simultaneamente. Essa propriedade é chamada isolamento (ELMASRI; NAVATHE, 2016). 3 Muitas vezes, uma coleção de várias operações no banco de dados parece ser uma única unidade do ponto de vista do seu usuário. Por exemplo, uma transferência de fundos de uma conta corrente para uma conta poupança é uma única operação do ponto de vista do cliente; dentro do sistema de banco de dados, no entanto, consiste em várias operações. Claramente, é essencial que todas essas operações ocorram ou, em caso de falha, que nenhuma se dê. Seria inaceitável se a conta corrente fosse debitada e a conta poupança não creditada (SILBERSCHATZ et al., 2019). SAIBA MAIS Isolamento de transação é um dos aspectos mais importante no gerenciamento de transação para manter o desempenho do servidor do banco de dados. Em cenários de alta concorrência, essa propriedade deve ser considerada com cuidado. Fonte: Silberschatz (2019) 4 Coleções de operações que formam uma única unidade lógica de trabalho são chamadas transações. Um sistema de banco de dados deve garantir a execução adequada de transações apesar das falhas — a transação inteira deve ser executada ou nenhuma delas deve ser processada. Além disso, ele deve gerenciar a execução simultânea de transações de uma maneira que evite a introdução de inconsistência. Em nosso exemplo de transferência de fundos, uma transação que calcula o saldo do cliente pode ser visualizada por outra transação, antes mesmo de ocorrer o débito pela transação de transferência de fundos, logo, o resultado se dá incorreto (SILBERSCHATZ et al., 2019). Conceito de Transação Uma transação é uma unidade de execução do programa que acessa e possivelmente atualiza vários itens de dados. Normalmente, uma transação é iniciada por um Figura 1 - Transação em dispositivos móveis Fonte: prykhodov / 123RF. 5 programa de usuário escrito em uma linguagem de manipulação de dados de alto nível (normalmente SQL) ou linguagem de programação (por exemplo, C ++ ou Java) com acesso ao banco de dados embutido no JDBC ou ODBC. Uma transação é delimitada por instruções (ou chamadas de função) de iniciar transação e �nalizar transação. A transação consiste em todas as operações executadas entre a operação inicial e �nal (SILBERSCHATZ et al., 2019). Essa coleção de etapas deve aparecer para o usuário como uma unidade única e indivisível. Como uma transação é indivisível, ou ela é executada integralmente ou não é. Portanto, se uma transação começar a ser executada, mas falhar por qualquer motivo, qualquer alteração no banco de dados que a transação possa ter feito deve ser desfeita. Esse requisito se mantém independentemente de a transação ter falhado (por exemplo, se ela pôr zero), o sistema operacional ter caído ou o próprio computador ter parado de funcionar. Figura 2 - Uma transação em um ATM FATOS E DADOS Na prática, uma transação consiste em executar todos os passos ou não executar nenhum, caso algum deles apresente erro. Por exemplo, quando realizamos a transferência de uma conta para outra, se o crédito na conta não for feito, o débito não deve ser realizado. 6 Fonte: prykhodov / 123RF. Como veremos, garantir que esse requisito seja atendido é difícil, já que as alterações no banco de dados ainda podem ser armazenadas apenas nas variáveis da memória principal da transação, enquanto outros podem ter sido gravados no banco de dados e armazenados no disco. Essa propriedade “tudo ou nada” é chamada de atomicidade. Além disso, como uma transação é uma única unidade, suas ações não podem parecer ser separadas por outras operações de banco de dados que não fazem parte da transação. Enquanto nós desejamos apresentar essa impressão de transações no nível do usuário, sabemos que a realidade é bem diferente. Mesmo uma única instrução SQL envolve muitos acessos separados para o banco de dados, e uma transação pode consistir em várias instruções SQL. Assim sendo, o sistema de banco de dados deve tomar ações especiais para garantir que as transações operem corretamente, sem interferência da execução simultânea das instruções do banco de dados. Essa propriedade é referida como isolamento. Mesmo que o sistema garanta a execução correta de uma transação, se o sistema subsequentemente falhar, como resultado, o sistema “esquece” a transação. Assim, as ações de uma transação devem persistir em todas as falhas. Essa propriedade é referida como durabilidade (SILBERSCHATZ et al., 2019). Por causa das três propriedades acima, as transações são uma maneira ideal de estruturar interações com um banco de dados. Isso nos leva a impor um requisito sobre transações em si. Uma transação deve preservar a consistência do banco de dados – se a transação é executada de forma automática em isolamento a partir de um banco de dados consistente, o banco de dados deve ser novamente consistente no �nal da transação (SILBERSCHATZ et al., 2019). Essa consistência vai além das restrições de integridade de dados (como restrições de chave primária, integridade referencial, restrições de veri�cação e similares). Em vez disso, espera-se que as transações vão além disso para garantir a preservação de restrições de consistência dependentes do aplicativo, que são muito complexas para o estado que usam as construções SQL para integridade de dados (HOFFER et al., 2019). Como isso é feito é responsabilidade do programador que codi�ca uma transação. Essa propriedade é referida como consistência. Para reforçar a informação acima de forma mais concisa, exigimos que o sistema de banco de dados mantenha as seguintes propriedades das transações (SILBERSCHATZ et al., 2019): Atomicidade. Todas as operações da transação são re�etidas adequadamente no banco de dados. 7 Consistência. A execução de uma transação isoladamente (ou seja, sem outra transação executando simultaneamente) preserva a consistência do banco de dados. Isolamento. Mesmo que várias transações sejam executadas simultaneamente, há a garantia de que, para cada par de transações Ti e Tj, uma comece a execução antes que a outra termine ou que uma termine antes que a outra comece. Assim, cada transação não tem conhecimento de outras transações em execução simultânea no sistema. Durabilidade. Depois que uma transação for concluída com sucesso, as alterações feitas no banco de dados devem persistir, mesmo se houver falhas no sistema. SAIBA MAISO isolamento é uma das propriedades mais importantes do modelo ACID. Dessa forma, entenda bem como ele pode ser utilizado para ajustar questões de desempenho. Fonte: Silberschatz et al. (2019). 8 Essas propriedades são chamadas de propriedades ACID; a sigla é derivada da primeira letra de cada uma das quatro propriedades. Como veremos mais adiante, garantir a propriedade de isolamento pode ter efeito adverso no desempenho do sistema. Por essa razão, algumas aplicações comprometem a propriedade de isolamento. Um modelo Simples de Transação Figura 3 - Transação vista pelo usuário Fonte: David Molina / 123RF. Como o SQL é uma linguagem poderosa e complexa, iniciamos nosso estudo de transações com uma linguagem de banco de dados simples que se concentra no momento em que os dados são movidos de disco para a memória principal, bem como SAIBA MAIS O modelo ACID não é o único para o gerenciamento de transações. Existe um outro, mais comumente empregado nos bancos de dados NoSQL, chamado de BASE (Basically Available, Soft State, Eventual consistency) Fonte: Chandra (2015). 9 da memória principal para o disco. Vamos ilustrar o conceito de transação usando um simples aplicativo bancário que consiste em várias contas e um conjunto de transações que acessam e atualizam essas contas (SILBERSCHATZ et al., 2019). As transações acessam dados usando duas operações: read (X), que transfere o item de dados X do banco de dados para uma variável, também chamado X, em um buffer na memória principal pertencente à transação que executou a operação de leitura. write (X), que transfere o valor na variável X na memória principal buffer da transação que executou a gravação no item de dados X na base de dados. É importante saber se uma alteração em um item de dados aparece apenas na memória principal ou se foi gravada no banco de dados no disco. Em um sistema de banco de dados real, a operação de gravação não resulta necessariamente na atualização imediata dos dados no disco; a operação de gravação pode ser temporariamente armazenada em outro lugar e executada no disco depois. Por enquanto, vamos supor que a operação de gravação atualiza o banco de dados imediatamente. Deixe que Ti seja uma transação que transfere $ 50 da conta A para a conta B. A transação pode ser de�nida como: Ti: leia (A); A: = A - 50; escreva (A); leia (B); B: = B + 50; escreva (B). Vamos, agora, considerar cada uma das propriedades do ACID. (Para facilitar o entendimento, vamos apresentar uma ordem diferente da A-C-I-D). Consistência: O requisito de consistência aqui é que a soma de A e B permanece inalterado pela execução da transação. Sem a consistência, o dinheiro poderia ser criado ou destruído pela transação! Pode ser veri�cado facilmente que, se a base de dados for consistente antes de uma execução de transação, o banco de 10 dados permanecerá consistente após a execução da transação (SILBERSCHATZ et al., 2019). Atomicidade: Suponha que, pouco antes da execução da transação Ti, os valores das contas A e B eram $ 1000 e $ 2000, respectivamente. Agora, suponha que, durante a execução da transação Ti, ocorreu uma falha que impediu o Ti de concluir sua execução com sucesso. Além disso, suponha que a falha aconteceu após a operação de gravação (A), mas antes da operação de gravação (B). Nesse caso, os valores das contas A e B re�etidos no banco de dados são $ 950 e $ 2000. O sistema destruiu $ 50 como resultado dessa falha. Em particular, notamos que a soma A + B não é mais preservada. Assim, devido à falha, o estado do sistema não re�ete mais um estado real do mundo que o banco de dados deve capturar. Tal estado é um estado inconsistente. Devemos assegurar que tais inconsistências não sejam visíveis em um sistema de banco de dados. Note, no entanto, que o sistema deve, em algum ponto, estar em um estado inconsistente. Mesmo se a transação Ti for executada para conclusão, existe um ponto em que o valor da conta A é $ 950 e o valor da conta B é $ 2000, o que é claramente um estado inconsistente. Esse estado, no entanto, é eventualmente substituído pelo estado consistente em que o valor da conta A é de $ 950 e o valor da conta B é $ 2050. Assim, se a transação nunca começou ou foi garantida a sua conclusão, um estado tão inconsistente não será visível, exceto durante a execução da transação. Essa é a razão para o requisito de atomicidade: se a propriedade de atomicidade estiver presente, todas as ações da transação serão re�etidas no banco de dados ou nenhuma será. A ideia básica por trás de garantir a atomicidade é esta: o sistema de banco de dados acompanha (em disco) os valores antigos de quaisquer dados nos quais uma transação executa uma gravação. Essa informação é gravada em um arquivo chamado log. Se a transação não completa sua execução, o sistema de banco de dados restaura valores antigos do log para fazer parecer que a transação nunca foi executada. Garantir a atomicidade é de responsabilidade do sistema de banco de dados; especi�camente, é tratada por um componente do banco de dados chamado de sistema de recuperação (SILBERSCHATZ et al., 2019). Durabilidade: Uma vez que a execução da transação seja concluída com sucesso, e o usuário que iniciou a transação foi noti�cado de que a transferência de fundos foi feita, os dados alterados devem permanecer. A propriedade de durabilidade garante que, uma vez concluída a transação, todas as atualizações que a execução no banco de dados persistir, mesmo se houver uma falha no 11 sistema após a conclusão da transação. Presumimos, por enquanto, que uma falha do sistema de computador pode resultar em perda de dados na memória principal, mas os dados gravados no disco nunca são perdidos (SILBERSCHATZ et al., 2019). Isolamento: Mesmo que as propriedades de consistência e atomicidade sejam asseguradas a cada transação, se várias transações forem executadas simultaneamente, suas operações podem intercalar de alguma forma indesejável, resultando em uma inconsistência. Por exemplo, como vimos anteriormente, o banco de dados está temporariamente inconsistente enquanto a transação para transferir fundos de A para B está sendo executada, com o total deduzido de A e o total aumentado para B. Se uma segunda transação executada simultaneamente lê A e B neste ponto intermediário e computa A + B, será observado, então, um valor inconsistente. Além disso, se essa segunda transação, em seguida, executa atualizações em A e B com base nos valores inconsistentes que lê, o banco de dados pode ser deixado inconsistente, mesmo depois de ambas as transações terem sido concluídas. Uma maneira de evitar o problema de executar transações simultaneamente é executar transações em série - ou seja, uma após a outra. No entanto, concorrentes execuções de transações proporcionam benefícios signi�cativos de desempenho. A propriedade de isolamento de uma transação garante que a concorrente execução de transações resulte em um estado do sistema que é equivalente para um estado que poderia ter sido obtido se essas transações fossem executadas uma de cada vez (SILBERSCHATZ, et al., 2019). Estruturas de Armazenamento Para entender como garantir as propriedades de atomicidade e durabilidade de uma transação, precisamos entender melhor como os vários itens de dados no banco de dados podem ser armazenados e acessados. A mídia de armazenamento pode ser distinguida por sua velocidade, capacidade e resiliência, e classi�cada como armazenamento volátil ou não-volátil (SILBERSCHATZ et al., 2019). Vamos entender esses termos e introduzir outra classe de armazenamento, chamado de armazenamento estável. Armazenamento volátil. As informações que residem no armazenamento volátil geralmente não sobrevivem a falhas do sistema. Exemplos desse armazenamento são a memória principal e memória cache. O acesso ao 12 armazenamento volátil é extremamente rápido, tanto por causa da velocidade do acesso à memória em si, como porque é possível acessar qualqueritem de dados no armazenamento volátil diretamente (SILBERSCHATZ et al., 2019). Armazenamento não volátil. As informações que residem no armazenamento não volátil sobrevivem a falhas no sistema. Exemplos de armazenamento não volátil incluem armazenamento secundário, como disco magnético, armazenamento �ash, usados para armazenamento online, e dispositivos de armazenamento terciário, como mídia ótica, e �tas magnéticas usadas para armazenamento arquivístico. No estado atual da tecnologia, o armazenamento não volátil é mais lento que o armazenamento volátil, particularmente para acesso aleatório. Tanto o armazenamento secundário como os dispositivos de armazenamento terciário, no entanto, são suscetíveis a falhas que podem resultar na perda de informação (SILBERSCHATZ et al., 2019). Armazenamento estável. A informação que reside no armazenamento estável nunca é perdida. Apesar de o armazenamento estável ser, teoricamente, impossível de ser obtido, pode ser aproximado por técnicas que tornam a perda de dados improvável. Para implementar o armazenamento estável, replicamos as informações em várias mídias não-voláteis (geralmente disco) com modos de falha independentes (SILBERSCHATZ et al., 2019). As distinções entre os vários tipos de armazenamento podem ser menos claras na prática do que na nossa apresentação. Por exemplo, algumas controladoras de RAID fornecem backup de bateria para que dados na memória principal possam sobreviver a falhas no sistema e a falhas de energia. Para uma transação ser durável, suas alterações precisam ser gravadas no armazenamento estável. Da mesma forma, para uma transação ser atômica, os registros de log precisam ser gravados em armazenamento estável antes que qualquer alteração seja feita no banco de dados no disco. Em alguns casos, uma única cópia no disco é considerada su�ciente, mas aplicações cujos dados são altamente valiosos e as transações são altamente importantes exigem várias cópias ou, em outras palavras, uma aproximação do conceito idealizado de armazenamento estável (VANIER et al., 2019). 13 Atomicidade de Transação e Durabilidade Como observamos anteriormente, uma transação nem sempre conclui sua execução com êxito. Tal transação é denominada abortada. Se quisermos garantir a propriedade atomicidade, uma transação abortada não deve ter efeito sobre o estado do banco de dados. Assim, quaisquer mudanças que a transação abortada �zer no banco de dados devem ser desfeitas. Depois que as alterações causadas por uma transação abortada forem desfeitas, dizemos que a transação foi revertida. Faz parte da responsabilidade de um esquema de recuperação gerenciar insucessos de SAIBA MAIS Na prática, o armazenamento estável apresenta uma certa complexidade em sua implementação, no entanto, é uma meta a ser alcançada. isso melhora a qualidade da solução �nal. 14 transação. Isso é feito tipicamente mantendo um registro. Cada modi�cação do banco de dados feita por uma transação é registrada pela primeira vez no registro. Registramos o identi�cador da transação que está executando a modi�cação, o identi�cador do item de dados que está sendo modi�cado, o valor antigo (antes de modi�cação) e o novo valor (após modi�cação) do item de dados. Manter um registro possibilita refazer uma modi�cação e garantir a atomicidade e a durabilidade, bem como a possibilidade de desfazer uma modi�cação e garantir a atomicidade em caso de falha durante execução da transação (Hoffer et al., 2019). Uma transação que conclui sua execução com sucesso é considerada commited (ou con�rmada). A transação concluída, que realizou atualizações, transforma o banco de dados em um novo estado consistente, que deve persistir mesmo se houver uma falha no sistema. Uma vez que uma transação tenha sido efetivada, não podemos desfazer seus efeitos abortando isso. A única maneira de desfazer os efeitos de uma transação efetivada é executar uma transação compensadora. Por exemplo, se uma transação adicionou $ 20 a uma conta, a transação de compensação subtrairia $ 20 da conta. No entanto nem sempre é possível criar uma transação de compensação, portanto, a responsabilidade de escrever e executar uma transação de compensação do usuário não é tratado pelo sistema de banco de dados (HOFFER et al., 2019). Precisamos ser mais precisos sobre o que entendemos por conclusão bem-sucedida de uma transação. Portanto, estabelecemos um modelo simples de transação abstrata. Uma transação deve estar em um dos seguintes estados: O estado inicial ativo: a transação permanece nesse estado enquanto está sendo executada. Parcialmente efetivado: após a declaração �nal ter sido executada. Falha: após a descoberta de que a execução normal não pode continuar. Abortado: após a transação ter sido revertida e o banco de dados ter sido restaurado ao seu estado de antes do início da transação. Efetivado: após a conclusão bem-sucedida. O diagrama de estado correspondente a uma transação aparece na Figura 1. Nós dizemos que uma transação foi con�rmada somente se ela entrou no estado efetivado. 15 Da mesma forma, dizemos que uma transação foi anulada apenas se tiver entrado no estado abortado. A transação é terminada se tiver sido con�rmada ou abortada. Uma transação começa no estado ativo. Quando termina sua declaração �nal, entra no estado parcialmente efetivado. Nesse ponto, a transação concluiu sua execução, mas ainda é possível que seja abortada, uma vez que a saída ainda pode estar temporariamente residindo na memória principal, e, portanto, uma falha de hardware pode impedir sua conclusão bem-sucedida. O sistema de banco de dados, então, grava informações su�cientes no disco. Mesmo em caso de falha, as atualizações realizadas pela transação podem ser recriadas quando o sistema for reiniciado. Quando a última dessas informações é escrita, a transação entra no estado efetivada. Como mencionado anteriormente, assumimos por enquanto que as falhas não resultam em perda de dados no disco (SILBERSCHATZ et al., 2019). Uma transação entra no estado falho após o sistema determinar que a transação não pode mais prosseguir com sua execução normal (por exemplo, por conta de hardware ou erros lógicos). Essa transação, por sua vez, deve ser revertida; então, entra no estado abortado. Nesse ponto, o sistema tem duas opções: Figura 4 - Estados de uma transação Fonte: adaptada de Elmasri e Navathe (2016). 16 Pode reiniciar a transação, mas somente se a transação foi abortada como resultado de algum erro de hardware ou software que não foi criado por meio da lógica interna da transação. Uma transação reiniciada é considerada uma nova transação. Pode matar a transação. Geralmente isso ocorre por causa de algum erro de lógica interna que pode ser corrigido apenas reescrevendo o programa aplicativo ou porque a entrada foi ruim ou porque os dados desejados não foram encontrados na base de dados. Devemos ser cautelosos ao lidar com gravações externas observáveis. Uma vez que tal gravação tenha ocorrido, não pode ser apagada, pois pode ter sido vista externamente ao sistema de banco de dados. Isolamento de Transações A maioria dos sistemas permite que tais escritas ocorram somente após a transação ter entrado no estado efetivado. Isso signi�ca que somente ao �nal de uma transação (com sucesso ou falha) os dados podem ser acessados por demais transações. Se o sistema falhar após a transação ter entrado no estado efetivado, mas antes que pudesse concluir as gravações externas, o sistema de banco de dados executará as gravações externas (usando os dados no armazenamento não volátil) quando o sistema for reiniciado (SILBERSCHATZ et al., 2019). O tratamento de gravações externas pode ser mais complicado em algumas situações. Por exemplo, suponha que a ação externa seja a de dispensar dinheiro em um caixa eletrônico, e o sistema falha um pouco antes de o dinheiro ser realmente dispensado (suponha que o dinheiro pode ser dispensado atomicamente). Não faz sentido dispensar dinheiro quando o sistema é reiniciado,desde que o usuário tenha deixado a máquina. Nesse caso, uma transação de compensação, como depositar o dinheiro de volta na conta do usuário, precisa ser executada quando o sistema for reiniciado (SILBERSCHATZ et al., 2019). Como outro exemplo, considere um usuário fazer uma reserva pela Web. É possível que o sistema de banco de dados ou o servidor de aplicativo trave logo após a transação de reserva con�rmada. Também é possível que a conexão de rede para o usuário seja perdida logo após o commit da transação de reserva. Em ambos os casos, embora a transação tenha sido con�rmada, a gravação externa não ocorreu. 17 Para lidar com tais situações, o aplicativo deve ser projetado de tal forma que, ao conectar-se ao aplicativo da Web novamente, o usuário possa ver se a transação teve sucesso ou não. Para certas aplicações, deseja-se permitir transações ativas para a exibição de dados aos usuários, especialmente para transações de longa duração, que são executadas em minutos ou horas. Infelizmente, não podemos permitir essa saída de dados observáveis, a menos que estejamos dispostos a comprometer a atomicidade das transações (SILBERSCHATZ et al., 2019). Os sistemas de processamento de transações geralmente permitem que várias transações sejam executadas simultaneamente, podendo causar várias complicações na consistência dos dados, como vimos anteriormente. Assegurar a consistência, apesar da execução simultânea de transações, requer trabalho extra; é muito mais fácil insistir que as transações sejam executadas em série, ou seja, uma de cada vez, começando apenas depois que a anterior for concluída. No entanto, existem duas boas razões para permitir a simultaneidade (SILBERSCHATZ et al., 2019): Melhor taxa de transferência e utilização de recursos. Uma transação consiste em muitos passos. Alguns envolvem atividade de E/S; outros envolvem a atividade da CPU. A CPU e os discos em um sistema de computador podem operar em paralelo. Portanto, E/S atividade pode ser feita em paralelo com o processamento na CPU. O paralelismo da CPU e do sistema de E/S pode, portanto, ser explorado para executar múltiplas transações em paralelo. Enquanto uma leitura ou gravação em nome de uma transação está em andamento em um disco, outra transação pode estar sendo executada na CPU, enquanto outro disco pode estar executando uma leitura ou gravação em nome de uma terceira transação. Tudo isso aumenta o rendimento do sistema, isto é, o número de transações executadas em um determinado período. Correspondentemente, o processador e a utilização de disco também aumentam; em outras palavras, o processador e o disco gastam menos tempo ocioso ou não executam nenhum trabalho útil. Tempo de espera reduzido. Pode haver uma mistura de transações em execução em um sistema, algumas curtas e algumas longas. Se as transações forem executadas em série, uma transação curta pode ter que esperar por uma transação longa anterior para concluir, o que pode provocar atrasos imprevisíveis na execução de uma transação. Se as transações estão operando em diferentes partes do banco de dados, é melhor deixá-las rodar ao mesmo tempo, compartilhando os ciclos da CPU e os acessos ao disco entre eles. Além 18 disso, também reduz o tempo médio de resposta: o tempo médio de transação a ser concluída depois de ter sido enviada. A motivação para usar a execução concorrente em um banco de dados é essencialmente a mesma que a motivação para usar multiprogramação em um sistema operacional. Quando várias transações são executadas simultaneamente, a propriedade de isolamento pode ser violada, resultando na consistência da base de dados, sendo destruída apesar da correção de cada transação individual. Serialização Serialização é um conceito útil porque permite que os programadores ignorem os problemas relacionados à concorrência quando eles codi�cam transações. Se toda transação tiver a propriedade que mantém a consistência do banco de dados se executada sozinha é considerada como sequencial; além disso, serialização garante que as execuções simultâneas mantenham a consistência. No entanto, os protocolos necessários para se garantir a serialização podem permitir pouca concorrência para certas aplicações. Nesses casos, níveis mais fracos de consistência são usados, impondo cargas adicionais aos programadores para garantir a correção do banco de dados (ELMASRI; NAVATHE, 2016). Níveis de isolamento de transação O padrão SQL também permite que uma transação especi�que que ela pode ser executada de tal forma que se torne não serializável em relação a outras transações. Por exemplo, uma transação pode operar no nível de isolamento de read uncommitted, que permite que a transação leia um item de dados, mesmo que tenha sido escrito por uma transação que não foi con�rmada. O SQL fornece esses recursos para o benefício de transações longas cujos resultados não precisam ser precisos. Se essas transações fossem executadas de forma serializável, elas poderiam interferir em outras transações, fazendo com que a execução delas fosse adiada. Os níveis de isolamento especi�cados pelo padrão SQL são os seguintes (ELMASRI; NAVATHE, 2016): Serializável garante execução sequencial. No entanto, alguns sistemas de banco de dados implementam esse nível de isolamento de uma maneira que podem, em certos casos, permitir execuções não serializáveis. Leitura repetível permite que apenas os dados efetivados sejam lidos ou que dentro da mesma transação sejam consistentes. No entanto, a transação pode 19 não ser serializável em relação a outras transações. Por exemplo, quando se está pesquisando dados, satisfazendo algumas condições, uma transação pode encontrar alguns dos dados inseridos por uma transação con�rmada, mas não pode encontrar outros dados inseridos pela mesma transação. Leitura efetivada permite que apenas dados con�rmados sejam lidos, mas não requer leituras repetitivas. Por exemplo, entre duas leituras de um item de dados pela transação, outra transação pode ter atualizado o item de dados e con�rmado. Leitura não efetivada permite que dados não con�rmados sejam lidos. É o menor nível de isolamento permitido pelo SQL. Todos os níveis de isolamento acima também impedem gravações sujas, isto é, um item de dados que já foi gravado por outra transação que ainda não foi efetivada ou abortada. Muitos sistemas de banco de dados são executados, por padrão, no nível de isolamento de leitura con�rmada. No SQL, é possível de�nir o nível de isolamento explicitamente em vez de aceitar a con�guração padrão do sistema. A alteração do nível de isolamento deve ser feita como a primeira declaração de uma transação. Além disso, a con�rmação automática de declarações individuais deve ser desativada se estiver ativada por padrão (ELMASRI; NAVATHE, 2016). 20 Bloqueio Em vez de bloquear todo o banco de dados, uma transação poderia, em vez disso, bloquear apenas itens de dados que ela acessa. Sob essa política, a transação deve conter bloqueios o tempo su�ciente para garantir a serialização, mas por um período curto o su�ciente para não prejudicar o desempenho de modo excessivo; melhorias adicionais no resultado do bloqueio se houver dois tipos de bloqueios: compartilhados e exclusivo. Os bloqueios compartilhados são usados para dados que SAIBA MAIS Níveis de isolamento da transação são uma medida da extensão para qual transação de isolamento é bem-sucedida. Em particular, os níveis de isolamento da transação são de�nidos pela presença ou ausência de fenômenos como Leituras sujas, Leituras não repetíveis e Leituras Fantasmas. Fonte: Níveis (2017, on-line) 21 a transação lê, e bloqueios exclusivos são usados para aqueles que ela escreve. Muitas transações podem conter bloqueios compartilhados no mesmo item de dados ao mesmo tempo, mas uma nova transação é permitida bloqueio exclusivo em um item de dados somente se nenhuma outra transação contiver o bloqueio compartilhado ou exclusivo no item de dados. Esse uso de dois modos debloqueios com bloqueio de duas fases permite a leitura simultânea de dados enquanto, ainda, assegura a serialização (HOFFER et al., 2019). 22 QUESTÃO OBJETIVA Lorem ipsum dolor donec eros lectus consequat vulputate integer ultricies aliquam, in erat tortor augue congue aenean eu non nostra consectetur phasellus, hac a euismod velit ac cursus volutpat curabitur vivamus. est orci odio sodales habitant euismod turpis ligula, accumsan conubia vehicula tempor mattis tortor vulputate potenti, pulvinar vulputate et non tincidunt diam. Essa propriedade é chamada atomicidade. Essa propriedade é chamada durabilidade. Essa propriedade é chamada isolamento. Essa propriedade é chamada consistência. Essa propriedade é chamada longevidade. 23 QUESTÃO OBJETIVA Depois que uma transação é concluída com sucesso, as alterações feitas no banco de dados devem persistir, mesmo se houver falhas no sistema. Como essa propriedade é chamada? Essa propriedade é chamada atomicidade. Essa propriedade é chamada isolamento. Essa propriedade é chamada consistência. Essa propriedade é chamada longevidade. Essa propriedade é chamada durabilidade. 24 Fechamento O maior benefício do gerenciamento de transações é lidar com o acesso simultâneo a um mesmo dado; por exemplo: a compra de uma passagem aérea. Caso não tenhamos uma forma de controlar esse acesso podemos vender 2 vezes a mesma poltrona. Para lidar com esse cenário, utilizamos as transações. Nesta aula, você teve a oportunidade de: Aprender o conceito de transação; Entender sobre atomicidade de transação e durabilidade; Aprender sobre Isolamento de transações. 25 Controle de Concorrência Quando temos um cenário com muitas transações simultâneas que acessam o mesmo dado, temos um ambiente de alta concorrência. O isolamento de transação fornece uma maneira e�caz de lidar com o acesso simultâneo; entretanto, se colocarmos todas as transações em uma sequência, podemos ter um problema de desempenho. Ao �nal desta aula, você será capaz de: Entender o Controle de Concorrência; Entender os Protocolos Baseados em Bloqueio; Utilizar a Concessão de bloqueios. Aula 02 Introdução 26 Controle de Concorrência Uma das propriedades fundamentais de uma transação é isolamento. Quando várias transações são executadas simultaneamente no banco de dados, a propriedade de isolamento pode não ser mais preservada, e para garantir que seja, o sistema deve controlar a interação entre as transações simultâneas; esse controle é obtido por meio de uma variedade de mecanismos chamados controle de simultaneidade (HOFFER et al., 2019). Protocolos Baseados em Bloqueio Uma forma de garantir isolamento é exigir que os itens de dados sejam acessados mutuamente de forma exclusiva; isto é, enquanto uma transação está acessando um item de dados, outra transação pode modi�car esse item. O método mais comum ATENÇÃO O isolamento de transações em um ambiente de alta concorrência pode gerar um baixo desempenho do servidor de banco de dados. Fonte: Silberschatz (2019). 27 usado para implementar esse requisito é permitir que uma transação acesse um item de dados somente se estiver bloqueando esse item (SILBERSCHATZ et al., 2019). Bloqueios Existem vários modos nos quais um item de dados pode ser bloqueado. Nesta seção, vamos restringir nossa atenção a dois modos (SILBERSCHATZ et al., 2019): 1. Compartilhado. Se uma transação Ti obteve um bloqueio de modo compartilhado (denotado por S) no item Q, então, Ti pode ler, mas não pode escrever Q. 2. Exclusivo. Se uma transação Ti tiver obtido um bloqueio de modo exclusivo (denotado por X) no item Q, então, Ti pode ler e escrever Q. Nós exigimos que cada transação solicite um bloqueio em um modo apropriado no item de dados Q, a depender dos tipos de operações que ele executará em P. A transação faz a solicitação para o gerenciador de controle de simultaneidade. A transação pode prosseguir com a operação somente após o controle de simultaneidade conceder o bloqueio para a transação. O uso desses dois modos de bloqueio permite que múltiplas transações leiam um item de dados, mas limita o acesso à gravação a apenas uma transação de cada vez. Figura 1 - Bloqueio compartilhado e exclusivo Fonte: adaptada de Elmasri e Navathe (2016). 28 Para a�rmar isso de forma mais geral, dado um conjunto de modos de bloqueio, podemos de�nir função de compatibilidade da seguinte forma: sendo A e B um bloqueio de modos arbitrários, suponha que uma transação Ti solicite uma trava de modo A no item Q em que a transação Tj (Ti? = Tj) possui um bloqueio de modo B. Se a transação Ti pode ser concedida um bloqueio em Q imediatamente, apesar da presença do modo B bloqueio, então, dizemos que o modo A é compatível com o modo B. Essa função pode ser representada convenientemente por uma matriz. A relação de compatibilidade entre os dois modos de bloqueio aparece na composição da matriz da Figura 1. Um elemento comp (A, B) da matriz tem o valor verdadeiro se e somente se o modo A é compatível com o modo B. Note que sharedmode é compatível com o modo compartilhado, mas não com modo exclusivo. A qualquer momento, vários bloqueios de modo compartilhado podem manter simultaneamente transações diferentes em um item de dados especí�co. Um modo exclusivo SAIBA MAIS Bloqueios exclusivos devem ser utilizados com muito cuidado, pois eles são extremamente restritivos com os objetos que foram bloqueados. Dessa forma, vale a pena entender com profundidade esse tipo de bloqueio antes de utilizá-los. Para saber mais, acesse: http://bit.ly/2YRHVaJ. Fonte: Wilson (2015, on-line) 29 http://bit.ly/2YRHVaJ subsequente à solicitação de bloqueio precisa aguardar até que os bloqueios do modo compartilhado atualmente em espera sejam liberados. Uma transação solicita um bloqueio compartilhado no item de dados Q executando o bloqueio Instrução S (Q). Da mesma forma, uma transação solicita um bloqueio exclusivo por meio da instrução lock-X (Q). Uma transação pode desbloquear um item de dados Q pelo desbloqueio (Q) instrução. Para acessar um item de dados, a transação Ti deve primeiro bloquear esse item. Se o item de dados já foi bloqueado por outra transação em um modo incompatível, o controle de simultaneidade, o gerente não concederá o bloqueio até que todos os bloqueios incompatíveis mantidos por outras transações sejam liberados. Assim, Ti é obrigado a esperar até que todos os bloqueios incompatíveis mantidos por outras transações sejam liberados. Ti transação pode desbloquear um item de dados que havia bloqueado em algum ponto anterior. Observe que uma transação deve conter um bloqueio em um item de dados, desde que ele acesse o item. Além disso, não é necessariamente desejável que uma transação destrave item de dados imediatamente após o seu acesso a ele (SILBERSCHATZ et al., 2019). SAIBA MAIS Tenha cuidado para evitar impasses oriundos de bloqueios. Isso pode levar à degradação da performance do banco de dados. 30 Como ilustração, considere novamente o exemplo bancário. Seja A e B duas contas que são acessadas pelas transações e . A transação transfere $ 50 da conta B para a conta A (Tabela 1). A transação exibe a quantia nas contas A e B - isto é, a soma A + B (Tabela 2). Suponha que os valores das contas A e B sejam de US $ 100 e US $ 200, respectivamente. Se essas duas transações forem executadas em série, na ordem , ou ordem , , então, a transação exibirá o valor $ 300. Se, no entanto, essas transações são executadas simultaneamente, então a situação 1, na Figura 4, é possível. Nesse caso, a transação exibe $ 250, o que é incorreto. A razão para esse erro é que a transação desbloqueou o item de dados B muito cedo, como resultado em que acessou um estado inconsistente. A sequência mostra as ações executadas pelas transações, bem como os pontos nos quais o gerenciador de controle de simultaneidade concede os bloqueios. A transação, ao fazer um pedido de bloqueio, não pode executar sua próxima ação até que o controle de simultaneidadeconceda o bloqueio. Portanto, o bloqueio deve ser T1 T2 T1 T2 T1 T2 T2 T1 T2 T2 T1 T2 ATENÇÃO Estados inconsistentes podem levar o banco de dados a �car dani�cado e, dessa forma, prejudicar a estratégia de backup. Fonte: Silberschatz (2019). 31 concedido no intervalo de tempo entre a operação de solicitação de bloqueio e a ação a seguir da transação. Tabela 1 - Exemplo de transação Fonte: adaptada de Elmasri e Navathe (2016). Suponha, agora, que o desbloqueio seja atrasado até o �nal da transação. Transação T3 corresponde a T1 com desbloqueio atrasado (Tabela 3). Transação T4 T1 T2 Gerenciador lock-X(B) grant-X(B,T1) read(B) B := B - 50 write(B) unlock(B) lock-S(A) grant-S(A,T2) read(A) unlock(A) lock-S(B) grant-S(B,T2) read(B) unlock(B) display(A+B) lock-X(A) grant-X(A,T2) read(A) A := A – 50 write(A) unlock(A) 32 corresponde a T2 com desbloqueio atrasado (Tabela 4). Você deve veri�car se a sequência de leituras e gravações na sequência 1, que leva a um total incorreto de $ 250 sendo exibido, não é mais possível com T3 e T4. T4 não imprime um resultado inconsistente em qualquer um deles; veremos o porquê mais tarde. Infelizmente, o bloqueio pode levar a uma situação indesejável. Considere a sequência parcial da Tabela 4 para T3 e T4. Desde T3 está segurando um bloqueio modo de exclusivo em B e T4 está solicitando um bloqueio de modo compartilhado em B, T4 está esperando por T3 para desbloquear B. Da mesma forma, uma vez que T4 está segurando um bloqueio de modo compartilhado em A e T3 é solicitando um bloqueio de modo exclusivo em A, T3 está esperando por T4 para desbloquear A. Assim, nós chegamos a um estado em que nenhuma dessas transações pode prosseguir com sua execução normal. Essa situação é chamada de deadlock. Quando ocorre um impasse, o sistema deve reverter uma das duas transações. Depois de uma transação ser revertida, os itens de dados bloqueados por essa transação são desbloqueados (SILBERSCHATZ et al., 2019). Esses itens de dados estão disponíveis para a outra transação, que pode continuar com a sua execução. Se não usarmos bloqueio ou se desbloquearmos itens de dados muito cedo depois da leitura, poderemos obter estados inconsistentes. Por outro lado, se não desbloquearmos um item de dados antes de solicitar um bloqueio em outro item de dados, deadlocks podem ocorrer. Existem maneiras de evitar o impasse em algumas situações. No entanto, em geral, os deadlocks são um mal necessário associado com bloqueio se quisermos evitar estados inconsistentes. Os deadlocks são de�nitivamente preferíveis a estados inconsistentes, uma vez que eles podem ser manipulados, gerenciando transações, considerando que estados inconsistentes podem levar a problemas do mundo real que não podem ser manipulados pelo sistema de banco de dados. T3 lock-X(B) read(B) B := B – 50 write(B) lock-X(A) read(A) A := A + 50 write(A) unlock(B) unlock(A) 33 Tabela 2 - Exemplo de bloqueio Fonte: adaptada de Elmasri e Navathe (2016). Exigimos que cada transação no sistema siga um conjunto de regras, chamado protocolo de bloqueio, indicando quando uma transação pode bloquear e desbloquear cada item de dados. Os protocolos de bloqueio restringem o número de agendamentos possíveis. O conjunto de todas essas sequências é um subconjunto apropriado de todos os possíveis agendamentos serializáveis, podem apresentar vários protocolos de bloqueio que permitem somente agendamentos serializáveis por con�itos, e, assim, garantir isolamento. Antes disso, vamos apresentar alguma terminologia. Deixe { } ser um conjunto de transações participando de uma sequência S. Digamos que precede em S, escrito , se existe um item de dados Q tal que manteve o modo de bloqueio A em Q, e realizou o modo de bloqueio B em Q mais tarde, sendo comp (A, B) = falso. Se , então, essa precedência implica que em qualquer equivalente programação em série, deve aparecer antes de . Observe que este grá�co é semelhante ao grá�co de precedência que usamos na Tabela 5 para testar a serializabilidade por con�ito. Con�itos entre as instruções correspondem a não compatibilidade dos modos de bloqueio. Dizemos que um agendamento S é legal sob um determinado protocolo de bloqueio se S é uma programação possível para um conjunto de transações que segue as regras do bloqueio. Dizemos que um protocolo de bloqueio garante a execução sequencial se, e somente se, todas as programações legais forem serializáveis; em outras palavras, para todos os esquemas legais a relação → associada é acíclica. Concessão de bloqueios Quando uma transação solicita um bloqueio em um item de dados em um modo especí�co, e outra transação tem um bloqueio no mesmo item de dados em um modo con�itante, o bloqueio pode ser concedido. No entanto, deve-se ter cuidado para evitar o seguinte cenário. Suponha que uma transação tenha um bloqueio de modo compartilhado em um item de dados e outra transação solicita um bloqueio de modo exclusivo no item de dados. Claramente, tem que aguardar liberar o bloqueio de modo compartilhado. Enquanto isso, uma transação pode solicitar um bloqueio de modo compartilhado no mesmo item de dados. A solicitação de bloqueio é compatível com o bloqueio concedido para ; para , pode ser concedido o bloqueio de modo compartilhado. Neste ponto, pode liberar o bloqueio, mas ainda tem que esperar que termine. Novamente, pode haver uma nova transação, , que solicite um bloqueio de modo compartilhado no mesmo item de dados e , , . . . ,T0 T1 Tn Ti Tj →Ti Tj Ti Tj →Ti Tj Ti Tj T2 T1 T1 T2 T3 T2 T3 T2 T1 T3 T4 34 receba o bloqueio antes de liberá-lo. De fato, é possível que exista uma sequência de transações em que cada uma solicite um bloqueio de modo compartilhado no item de dados, e cada transação libere o bloqueio um pouco depois de ser concedido, mas nunca obtém o bloqueio de modo exclusivo no item de dados. A transação pode nunca progredir, e é dito que está starved (SILBERSCHATZ et al., 2019). Podemos evitar o estado starved das transações concedendo bloqueios nas seguintes maneiras: Quando uma transação Ti solicita um bloqueio em um item de dados Q em um determinado modo M, o gerenciador de controle de concorrência concede o bloqueio, desde que: 1. Não haja outra transação contendo um bloqueio em Q em um modo que con�ita com M. 2. Não haja outra transação que esteja esperando por um bloqueio em Q e que tenha feito seu pedido de bloqueio antes do Ti. Assim, uma solicitação de bloqueio nunca será bloqueada por uma solicitação de bloqueio feita posteriormente. O Protocolo de Bloqueio de Duas Fases Um protocolo que garante a serialização é o protocolo de bloqueio de duas fases. Esse protocolo exige que cada transação emita os pedidos de bloqueio e desbloqueio em duas fases: 1. Fase de crescimento. Uma transação pode obter bloqueios, mas não pode liberar Bloqueio. 2. Fase de encolhimento. Uma transação pode liberar bloqueios, mas não pode obter novos bloqueios. Inicialmente, uma transação está em fase de crescimento. A transação adquire bloqueios quando necessário. Uma vez que a transação libera um bloqueio, ela entra na fase de retração e não pode emitir mais solicitações de bloqueio. Por exemplo, as transações e são de duas fases. Por outro lado, transações e não são de duas fases. Note que as instruções de desbloqueio não precisam aparecer no �nal da T3 T1 T1 T3 T4 T1 T2 35 transação. Por exemplo, no caso da transação , poderíamos mover a instrução de desbloqueio (B) após a instrução lock-X (A) e ainda reter a propriedade de bloqueio de duas fases. Podemos mostrar que o protocolo de bloqueio de duas fases garante a serialização do con�ito. Considere qualquer transação. O ponto na sequência onde a transação obteve o seu bloqueio �nal (o �nal da sua fase de crescimento) é chamado ponto de bloqueio da transação. Agora, as transações podem ser encomendadas de acordo com seus pontos de bloqueio. Essa ordenação é, na verdade, umaordem de serialização para as transações. O bloqueio de duas fases não garante a liberdade do impasse. Observe que as transações e são duas fases, mas na sequência 2 (Tabela 3) elas são deadlocked (ELMASRI; NAVATHE, 2016). A reversão em cascata pode ocorrer sob bloqueio de duas fases. Como ilustração, considere a sequência parcial da Tabela 4. Cada transação observa o protocolo de bloqueio de duas fases, mas a falha de após a leitura (A), o passo leva à reversão em cascata de e . Reversões em cascata podem ser evitadas por uma modi�cação de bloqueio de duas fases chamada protocolo estrito de bloqueio de duas fases. Esse protocolo exige não só o bloqueio de duas fases, mas também que todos os bloqueios de modo exclusivo tomados por uma transação sejam realizados até que a transação seja con�rmada. Esse requisito garante que todos os dados escritos por uma transação não con�rmada sejam bloqueados no modo exclusivo até a con�rmação de transação, impedindo que qualquer outra transação leia os dados. T3 T3 T4 T5 T7 T6 T7 36 Outra variante do bloqueio de duas fases é o protocolo rigoroso de bloqueio de duas fases, que requer que todos os bloqueios sejam mantidos até que a transação seja con�rmada. Podemos facilmente veri�car que, com esse tipo de bloqueio, as transações podem ser serializadas na ordem em que eles se comprometem. Considere as duas transações a seguir, para as quais mostramos apenas das operações signi�cativas de leitura e gravação: Se empregarmos o protocolo de bloqueio de duas fases, então o deve bloquear o em modo. Portanto, qualquer execução simultânea de ambas as transações equivale a execução serial. Observe, no entanto, que o precisa de um bloqueio exclusivo em apenas no �m de sua execução, quando escreve . Assim, se pudesse, inicialmente, bloquear em modo compartilhado e, depois, mudar o bloqueio para o modo exclusivo, poderíamos obter mais concorrência, pois e poderiam acessar e simultaneamente. Essa observação nos leva a um re�namento do protocolo de bloqueio básico de duas fases, no qual as conversões de T8 a1 T8 a1 a1 T8 a1 T8 T9 a1 a2 ATENÇÃO O escalonamento de transações pode ser um fator importante para manter o desempenho do seu servidor de banco de dados. O MySQL pode lidar com o escalonamento e vale a pena entender os re�exos disso no desempenho. Conheça um pouco mais, acesse: http://bit.ly/2XJUZST. 37 http://bit.ly/2XJUZST bloqueio são permitidas. Nós forneceremos um mecanismo para atualizar um bloqueio compartilhado para um bloqueio exclusivo e fazer downgrade a um bloqueio compartilhado. Denotamos a conversão de modos compartilhados para exclusivos e de exclusivo para compartilhado por downgrade. A conversão de bloqueio não pode ser permitida arbitrariamente; pelo contrário, a atualização pode ocorrer apenas na fase de crescimento, considerando que a desclassi�cação pode ocorrer apenas na fase de encolhimento. Tabela 3 - Exemplo de bloqueio compartilhado Fonte: adaptada de Elmasri e Navathe (2016). T5 T6 T7 lock-X(A) read(A) lock-S(B) read(B) write(A) unlock(A) lock-X(A) read(A) write(A) nlock(A) lock-S(A) read(A) T8: read(a1) read(a2) … read(aN) write(a1) T9: read(a1) 38 Tabela 4 - Exemplo de leitura e escrita Fonte: adaptada de Elmasri e Navathe (2016). Tabela 5 - Exemplo de atualização de recursos Fonte: adaptado de Elmasri e Navathe (2016). Voltando ao nosso exemplo, as transações T8 e T9 podem ser executadas simultaneamente sob protocolo re�nado de bloqueio de duas fases, conforme mostrado na sequência da Tabela 5, em que apenas algumas das instruções de bloqueio são mostradas. Observe que uma transação tentando atualizar um bloqueio em um item Q pode ser forçado a esperar. Essa espera forçada ocorre se Q estiver atualmente bloqueado por outra transação no modo compartilhado (Elmasri e Navathe, 2016). Assim como o protocolo básico de bloqueio de duas fases, o bloqueio de duas fases com conversão gera apenas agendamentos serializáveis por con�itos, e as transações podem ser serializadas por seus pontos de bloqueio. Além disso, se os bloqueios exclusivos forem mantidos até o �nal da transação, os horários são em cascata. Para um conjunto de transações, pode haver sequências serializáveis por con�ito que não read(a2) display(a1 + a2) T8 T9 lock-S(a1) lock-S(a1) lock-S(a3) lock-S(a4) unlock(a1) unlock(a2) lock-S(aN) upgrade(a1) 39 podem ser obtidas por meio do protocolo de bloqueio de duas fases. No entanto, para obter agendas serializáveis por con�itos por meio de protocolos de bloqueio não- bifásicos, precisamos ter informações adicionais sobre as transações ou impor alguma estrutura ou ordenação sobre o conjunto de itens de dados no banco de dados. O bloqueio de duas fases estrito e o travamento de duas fases rigoroso (com conversões de bloqueio) são usados extensivamente em sistemas de bancos de dados comerciais. Um esquema simples, mas amplamente usado, gera automaticamente o bloquear e desbloquear de instruções para uma transação com base em ler e escrever solicitações da transação: Quando uma transação Ti emite uma operação de leitura (Q), o sistema emite instrução S (Q) seguida pela instrução read (Q). Quando Ti emite uma operação de gravação (Q), o sistema veri�ca se o Ti já possui um bloqueio compartilhado no Q. Se isso ocorrer, o sistema emitirá uma instrução atualização (Q), seguida pela instrução write (Q). Caso contrário, o sistema emite uma instrução lock-X (Q), seguida pela instrução write (Q). Todos os bloqueios obtidos por uma transação são desbloqueados após essa transação ser con�rmada ou abortada. Implementação do Bloqueio Um gerenciador de bloqueio pode ser implementado como um processo que recebe mensagens de transações e envia mensagens em resposta. O processo do gerenciador de bloqueio responde mensagens de solicitação de bloqueio com mensagens de concessão de bloqueio ou com mensagens solicitando reversão da transação (no caso de deadlocks). Desbloquear mensagens requer apenas uma con�rmação em resposta, mas pode resultar em uma mensagem de concessão para outra transação em espera (SILBERSCHATZ et al., 2019). O gerenciador de bloqueio usa esta estrutura de dados: para cada item de dados que está atualmente bloqueado, ele mantém uma lista de registros vinculados, um para cada solicitação, na ordem em que os pedidos chegaram. Ele usa uma tabela de hash, 40 indexada no nome de um dado item, para encontrar a lista encadeada (se houver) para um item de dados; esta tabela é chamada de bloqueio mesa. Cada registro da lista vinculada de um item de dados registra qual transação e o modo de bloqueio solicitados. O registro também observa se o pedido foi atualmente concedido. A Tabela 5 mostra um exemplo de uma tabela de bloqueios. A tabela contém bloqueios para cinco itens de dados diferentes, I4, I7, I23, I44 e I912. A tabela de bloqueio usa �uxo de encadeamento, portanto, há uma lista encadeada de itens de dados para cada entrada na tabela de bloqueios. Há também uma lista de transações que receberam bloqueios ou estão aguardando bloqueios para cada um dos itens de dados. Bloqueios concedidos são os retângulos preenchidos em um tom mais escuro, enquanto os que esperam pedidos são os retângulos preenchidos em um tom mais claro. Omitimos o modo de bloqueio para manter a �gura simples. Pode-se ver, por exemplo, que o T23 recebeu bloqueios em I912 e I7 e está aguardando um bloqueio no I4. Embora não mostre, a tabela de bloqueio também deve manter identi�cadores de transação para que seja possível determinar com e�ciência o conjunto de bloqueios mantidos por uma determinada transação (SILBERSCHATZ et al., 2019). O gerenciador de bloqueio processa solicitações desta maneira: Quando chega uma mensagem de solicitação de bloqueio, ele adiciona um registro ao �nal da lista para o item de dados se a lista vinculada estiver presente. Caso contrário, cria uma lista vinculada, contendo apenas o registro dasolicitação. · Ele sempre concede uma solicitação de bloqueio em um item de dados que não está bloqueado no momento, mas se a transação solicitar um bloqueio em um item no qual um bloqueio está atualmente mantido, o gerenciador de bloqueio concede a solicitação somente se for compatível com as travas que estão atualmente em espera e todas as solicitações anteriores já terem sido concedidas. Caso contrário, o pedido deve aguardar. Quando o gerenciador de bloqueio recebe uma mensagem de desbloqueio de uma transação, exclui o registro desse item de dados na lista vinculada correspondente a essa transação. Ele testa o registro seguinte, se houver, para ver se esse pedido pode, então, ser concedido. Se puder, o gerenciador de bloqueio concede essa solicitação e processa o registro que segue, se houver, da mesma forma, e assim por diante. Se uma transação for anulada, o gerenciador de bloqueio excluirá qualquer solicitação em espera feita pela transação. Uma vez que o sistema de banco de 41 dados tenha tomado as ações apropriadas para desfazer a transação, ele libera todos os bloqueios da transação abortada. Esse algoritmo garante os pedidos de bloqueio, uma vez que uma solicitação nunca pode ser concedida enquanto uma solicitação recebida anteriormente está aguardando para ser concedida. Protocolos baseados em grafos Se quisermos desenvolver protocolos que não sejam bifásicos, precisamos de informações adicionais sobre como cada transação acessa o banco de dados. Existem vários modelos que podem nos fornecer informações adicionais, cada um diferindo na quantidade de informações fornecidas. O modelo mais simples requer que tenhamos conhecimento prévio sobre a ordem em que os itens do banco de dados Figura 2 - Algoritmo para o gerenciamento de bloqueios Fonte: adaptada de Elmasri e Navathe (2016). 42 serão acessados. Dada essa informação, é possível construir protocolos de bloqueio que não são duas fases, mas que, no entanto, garantem a serialização do con�ito. Para adquirir tal conhecimento prévio, impomos uma ordenação parcial → no set D = { } de todos os itens de dados. Se , qualquer transação de acesso a e deve acessar antes de acessar . Essa ordenação parcial pode ser o resultado da organização lógica ou física dos dados ou pode ser imposta unicamente para �ns de controle de concorrência. A ordenação parcial revela que o conjunto D pode agora ser visto como um grafo acíclico, chamado grafo de banco de dados. Nesta seção, por uma questão de simplicidade, vamos restringir nossa atenção apenas aos grafos que são do tipo árvores. Nós devemos apresentar um protocolo simples, chamado protocolo de árvore, que é restrito a empregar bloqueios exclusivos (SILBERSCHATZ et al., 2019). No protocolo de árvore, a única instrução de bloqueio permitida é lock-X. Cada transação Ti pode bloquear um item de dados, no máximo, uma vez e deve observar o seguinte regras: 1. O primeiro bloqueio por Ti pode estar em qualquer item de dados. 2. Posteriormente, um item de dados Q poderá ser bloqueado pela Ti somente se o pai de Q for atualmente bloqueado pela Ti. 3. Itens de dados podem ser desbloqueados a qualquer momento. 4. Um item de dados que tenha sido bloqueado e desbloqueado pela Ti não pode ser bloqueado por Ti. Todos os planejamentos que são legais sob o protocolo de árvore são serializáveis por con�ito. Para ilustrar esse protocolo, considere o grafo do banco de dados da Figura 3. Após quatro transações, siga o protocolo de árvore neste grafo, considerando as instruções de bloqueio e desbloqueio: , , . . . ,d1 d2 dh →di dj di dj di dj 43 T10: bloqueio-X (B); lock-X (E); lock-X (D); desbloqueio (B); desbloqueio (E); bloqueio-X (G); desbloqueio (D); desbloqueio (G). T11: lock-X (D); bloqueio-X (H); desbloqueio (D); desbloqueio (H). T12: trava-X (B); lock-X (E); desbloqueio (E); desbloqueio (B). T13: lock-X (D); bloqueio-X (H); desbloqueio (D); desbloqueio (H). Para garantir a recuperabilidade e a ausência de cascata, o protocolo pode ser modi�cado para não permitir a liberação de bloqueios exclusivos até o �nal da transação. Manter bloqueios exclusivos até o �nal da transação reduz a simultaneidade. Aqui está uma alternativa que melhora a simultaneidade, mas garante apenas recuperabilidade: Para cada item de dados com uma gravação não con�rmada, registramos qual transação executou a última gravação no item de dados. Sempre que uma transação Ti executa uma leitura de um item de dados não con�rmado, registramos uma dependência de commit do Ti no transação que executou a última gravação no item de dados. Transação Ti é então não autorizada a Figura 3 - Protocolo baseado em grafo Fonte: adaptada de Elmasri e Navathe (2016). 44 efetivar até o commit de todas as transações. Se alguma dessas transações for cancelada, Ti também deve ser abortado. Tabela 6 - Exemplo de bloqueio e desbloqueio Fonte: adaptada de Elmasri e Navathe (2016). O protocolo de bloqueio de árvore tem uma vantagem sobre o protocolo de bloqueio de duas fases em que, ao contrário do bloqueio de duas fases, é livre de impasse, T10 T11 T12 T13 lock-X(B) lock-X(D) lock-X(H) unlock(D) lock-X(E) lock-X(D) unlock(B) unlock(E) lock-X(B) lock-X(E) unlock(H) lock-X(G) unlock(D) lock-X(D) lock-X(H) unlock(D) unlock(H) unlock(E) unlock(B) unlock(G) 45 portanto, não há reversões requeridas. O protocolo de bloqueio de árvore tem outra vantagem sobre as duas fases do protocolo de bloqueio em que o desbloqueio pode ocorrer mais cedo. O desbloqueio antecipado pode provocar tempos de espera mais curtos e um aumento na simultaneidade. No entanto, o protocolo tem a desvantagem de, em alguns casos, levar uma transação a bloquear itens de dados que ele não acessa. Por exemplo, uma transação que precisa acessar os itens de dados A e J no grafo do banco de dados da Tabela 6 deve bloquear não apenas A e J, mas também os itens de dados B, D e H. Esses resultados adicionais de bloqueio geram um aumento da sobrecarga de bloqueio e a possibilidade de tempo de espera adicional além da redução potencial na concorrência. Além disso, sem conhecimento prévio de quais dados os itens precisarão ser bloqueados, as transações terão que bloquear a raiz da árvore, e isso pode reduzir muito a concorrência. Para um conjunto de transações, pode haver sequências serializáveis por con�ito que não pode ser obtido por meio do protocolo de árvore. De fato, existem agendamentos possíveis sob o protocolo de bloqueio de duas fases que não são possíveis sob o protocolo de árvore, e vice-versa (SILBERSCHATZ et al., 2019). 46 SAIBA MAIS Deadlock ou impasses é uma situação em que uma transação �ca esperando por outra para assumir o bloqueio de um recurso. Esse é o pior cenário em ambientes de alta concorrência em um banco de dado. Para evitar isso, tenha um bom modelo de banco de dados para fornecer as consultas de forma a evitar concorrência. Fonte: Silberschatz (2019). 47 QUESTÃO OBJETIVA Quando uma transação solicita um bloqueio em um item de dados em um modo especí�co e outra transação tem um bloqueio no mesmo item de dados em um modo con�itante, qual o resultado? O bloqueio pode ser encerrado. O bloqueio pode ser comprometido. O bloqueio pode ser concedido. O bloqueio pode ser negado. O bloqueio pode ser escalonado. 48 QUESTÃO OBJETIVA Um protocolo que garante a serialização é o protocolo de bloqueio de duas fases. Esse protocolo exige que cada transação emita os pedidos de bloqueio e desbloqueio em duas fases. Quais fases são essas? Crescimento e Estabilidade. Crescimento e Encolhimento. Encolhimento e Expansão. Ligado e Desligado. 0 e 1 49 Fechamento Um dos benefícios do entendimento correto do controle de concorrência é ter um ambiente com alto desempenho. Quando temos um cenário com muitas transações simultâneas e que acessam o mesmo dado, temos um ambiente de alta concorrência. O isolamento de transação forneceuma maneira e�caz de lidar com o acesso simultâneo. Entretanto, se colocarmos todas as transações em uma sequência, podemos ter um problema de desempenho. Nesta aula, você teve a oportunidade de: Entender o Controle de Concorrência; Entender os Protocolos Baseados em Bloqueio; Utilizar a Concessão de bloqueios. 50 Backup e Recuperação de Dados Realizar cópias de segurança do banco de dados é uma prática para garantir a continuidade do negócio em cenários de desastres. Para isso, temos que avaliar as estratégias disponíveis e adequar a melhor para a nossa situação. Ao �nal desta aula, você será capaz de: Entender os Backups full, incremental e diferencial; Entender os Restores full, incremental e diferencial; Realizar Agendamentos. Você sofre um ataque em seu servidor de banco de dados ou ele apresenta problemas técnicos. Para esses cenários, você deve ter backups que permitam que você coloque rapidamente um servidor em funcionamento com os dados mais Aula 03 Introdução 51 atualizados possível. A maneira mais simples de criar backups é copiar todo o banco de dados em uma mídia externa. Claramente, ao realizarmos uma cópia de segurança, temos um problema de tempo de cópia x quantidade de dados que estamos dispostos a perder. Vamos explorar esse problema ao longo deste estudo, explicando abordagens alternativas para se fazer backup e restaurar Bancos de dados com o MySQL, bem como con�gurar backups automáticos regulares. Nós também explicaremos como veri�car e reparar tabelas de banco de dados dani�cadas. Finalmente, mostraremos como você pode recriar um banco de dados MySQL dani�cado (ELMASRI; NAVATHE, 2016). Backup SAIBA MAIS Recuperação de desastres faz parte de uma área da governança de TI conhecida como gerenciamento de continuidade. Em outras palavras, está relacionada à conservação do negócio mesmo depois de eventos catastró�cos. Uma das publicações mais conhecidas que trata do assunto é a ITIL (The Information Technology Infrastructure Library (OgC)). Para saber mais, acesse: http://bit.ly/2JHhHRN. 52 http://bit.ly/2JHhHRN Os bancos de dados, em geral, possuem algumas estratégias de backup. A escolha da estratégia correta pode ser a diferença entre conseguir recuperar um cenário catastró�co de forma satisfatória ou perder muitos dados. Geralmente, quando nos perguntamos sobre backup devemos ter em mente o quanto de dados estamos dispostos a perder. Obviamente, a primeira resposta a essa pergunta é “nenhum dado”. No entanto, na prática, essa resposta não é muito fácil de ser obtida. Essas estratégias são conhecidas como backup full, incremental e diferencial. Vamos estudar com detalhes cada uma delas e as possíveis combinações para reduzirmos o tempo de backup e a perda de dados em eventuais cenários de desastres (VANIER et al., 2019). Backup Full Essa estratégia é uma das mais simples e, a depender do tamanho do banco de dados e sua frequência de atualização, umas das mais e�cientes. Essa estratégia consiste em criar uma cópia completa do banco de dados em seu estado atual. Dessa forma, podemos criar uma cópia sempre que for necessário, para eventuais falhas, e que seja a mais atualizada possível. A Figura 1 mostra um exemplo de backup full ao longo do tempo. Figura 1 - Exemplo de backup full Fonte: adaptada de Elmasri e Navathe (2016). 53 Assim, temos os backups 1, 2 e N. Podemos de�nir que a frequência das cópias será diária, digamos que às 23:00, para compreender todas as transações do dia. Nesse cenário, caso um desastre aconteça às 23:01 no primeiro dia, perderíamos somente 1 minuto de transações. Se nosso banco for atualizado com pouca frequência, provavelmente não teríamos nenhuma transação entre a cópia e o estado atual no momento do desastre (VANIER et al., 2019). Essa cópia pode ser feita no MySQL, via linha de comando, com a seguinte linha: mysqldump -u <usuario> -p<senha> mysql > bkp1.sql Embora essa estratégia seja muito simples, tanto para a cópia quanto para a recuperação, para bancos de dados atualizados com maior frequência ou com um tamanho muito grande (por exemplo, 1 terabyte) ela pode não ser a mais adequada. Vamos ver outras possibilidades na sequência. Backup Incremental ATENÇÃO O backup full é uma solução simples de cópia. Pense em quais situações ele deve ser utilizado para se ter a menor perda de dados possíveis em situações de emergência. 54 Vamos imaginar, que no exemplo anterior, nosso banco de dados era atualizado com uma maior frequência. Realizar backups completos com tanta frequência pode ser inviável, pois o tempo desse tipo de cópia tende a ser maior, o espaço consumido em disco também é maior, sobretudo em eventuais transferências pela rede. Nesse caso, podemos lançar mão da estratégia de backup incremental, que nada mais é do que uma cópia completa (backup full) dessa cópia completa com uma frequência menor. A Figura 2 mostra um exemplo disso. O primeiro backup é um backup completo. Depois disso, a cada período um backup com os dados que foram incrementados desde o último backup full ou incremental. Um possível cenário de utilização desse tipo de backup seria quando você faz um backup full no início da semana e faz os incrementais, por exemplo, uma vez por dia (SILBERSCHATZ et al., 2019). Dessa forma, poderíamos ter um backup full no domingo, os incrementais na segunda, terça, etc. A forma de realizar o backup incremental no MySQL pode ser realizado via comando abaixo: mysqlbackup --defaults-�le=/home/dbadmin/my.cnf --incremental \ --start-lsn=2654255716 \ --with-timestamp \ Figura 2 - Exemplo de backup incremental Fonte: adaptada de Elmasri e Navathe (2016). 55 --incremental-backup-dir=/incr-tmp \ --backup-image=/incr-backup/incremental_image.bi backup-to-image Backup Diferencial O backup diferencial é uma estratégia para cenários onde os bancos de dados são atualizados com uma frequência maior, o que inviabiliza as cópias completas ou incrementais. Dessa forma, podemos utilizar a estratégia de backups diferenciais. Esse tipo de backup, ao contrário do backup incremental, traz somente a diferença entre o último backup, seja ele um completo, incremental ou diferencial. A Figura 3 mostra esse tipo de backup. Um cenário de utilização dessa estratégia de backup é quando temos um banco de dados atualizado frequentemente. Com isso, podemos gerar um backup full uma vez ao dia, por exemplo, às 23:00, e vários backups diferenciais ao longo do dia, sendo executados de hora em hora. Dessa maneira, teríamos um backup full e mais 23 diferenciais. Para realizar um backup diferencial no MySQL, primeiramente, Figura 3 - Exemplo de backup diferencial Fonte: adaptado de Elmasri e Navathe (2016). 56 precisamos realizar um backup full. Depois disso, podemos realizar os backups diferenciais por meio do log binário (SILBERSCHATZ et al., 2019). O Log binário O log binário é um arquivo que armazena todas as consultas realizadas pelo banco de dados que altera ou cria registros. O log binário é usado na replicação de banco de dados para manter os servidores escravos em sincronia com o servidor mestre. Logs binários também podem ser usados como métodos de backup para seu banco de dados, sendo mais frequentes e mais rápidos do que a execução de grandes backups em um agendamento. Há também um arquivo de índice usado para acompanhar os logs binários necessários para a replicação do banco de dados. O arquivo de índice rastreia quais logs binários existem. Servidores slaves usam os índices dos logs para saberem por onde a sincronização de dados deve começar. Con�gurando o Log Binário ATENÇÃO O backup diferencial pode ser uma boa estratégia para reduzir a probabilidade de perda de dados, entretanto, ele gera muitos arquivos, dependendo da frequência do backup, e, dessa forma, pode ser complicado para o gerenciamento e o restore. 57 Para começar a usar o log binário, você precisa modi�car ou adicionar algumas linhas à sua con�guração do MySQL. O local de con�guração do MySQL pode variar com basena distribuição, mas você geralmente pode encontrá-los nos seguintes locais. Esses arquivos também podem importar outros arquivos e diretórios de con�guração. /etc/my.cnf /etc/mysql/my.cnf ~/.my.cnf Encontre o arquivo de con�guração ou crie um que será incluído pelos arquivos de con�guração principais e adicione as seguintes linhas. Essas linhas devem estar dentro da seção [mysqld]. O server_id provavelmente já estará de�nido pelo arquivo de con�guração. Você precisa reiniciar seu servidor MySQL antes que as mudanças tenham efeito. [mysqld] server_id = 1 log_bin = /var/log/mysql/mysql-bin.log max_binlog_size = 100M Backup Inicial É importante criar um backup inicial do banco de dados e, em seguida, liberar os logs para ter início o registro binário após o backup, a �m evitar o backup dos mesmos dados duas vezes. Você pode escolher o método usado para o backup inicial, como realizar um backup físico ou usar o mysqldump para criar um backup lógico. Em geral, o mysqldump é mais seguro, mais fácil, mas ao custo de ser mais lento (SILBERSCHATZ et al., 2019). $ mysqldump --�ush-logs --lock-all-tables --all-databases > backup.sql O argumento passado de --lock-all-tables terá o efeito de descarregar o banco de dados e liberar os logs no mesmo momento. Isso impede que o log binário tenha consultas que já estão presentes no dump. A opção --�ush-logs limpa os logs do banco de dados antes (ou ao mesmo tempo) do dump. Limpar os logs do banco de 58 dados é importante para iniciar um novo log com o dump do banco de dados mais recente. Backup do Log binário Uma vez que o banco de dados tenha sido con�gurado com a opção log_bin, o log binário será armazenado por padrão em seu diretório de dados (em algum lugar próximo a / var / lib / mysql) a menos que você especi�que um caminho absoluto; Nesse caso, você sabe onde o log binário está localizado. Toda vez que o servidor MySQL descarregar os logs do servidor (eventos cronometrados, tamanhos de log ou manualmente), um novo log binário será criado com uma extensão com um inteiro maior. SAIBA MAIS O log binário do MySQL pode ser utilizado para cenários de replicação de dados. Um dos cenários possíveis é a utilização de arquiteturas como CQRS, que signi�ca Command Query Responsibility Segregation. Isso, em outras palavras, consiste em separar os bancos de leitura e escrita. Para saber mais, acesse: http://bit.ly/2xNNmvg. 59 http://bit.ly/2xNNmvg Para fazer o backup do log binário, você deve salvar todos os logs binários gerados. O comando cp é bom para copiar arquivos de log binários, excluindo o log binário ativo. É importante manter os arquivos na mesma ordem, já que eles são armazenados sequencialmente e devem ser restaurados sequencialmente. Você pode forçar o MySQL a iniciar um novo log binário executando o comando FLUSH BINARY LOGS. Um novo log binário será criado e o último poderá ser copiado e adicionado ao seu backup. Excluindo antigos logs A exclusão de logs binários pode se tornar complicada se você tiver replicação de banco de dados con�gurada. Se você não tiver a replicação do banco de dados con�gurada, poderá excluir com segurança os logs binários antigos, de preferência com o comando mysqlbinlogpurge (disponível no pacote mysql-utilities). Se você tem replicação de banco de dados e servidores slaves, é necessário garantir que todos os servidores slaves (on-line e off-line) estejam atualizados ou você terá que gastar mais tempo sincronizando os servidores escravos com os backups (SILBERSCHATZ et al., 2019). Agendamento Manter um cronograma de backup regular é uma medida importante para evitar perda de dados para o seu servidor MySQL. Esta seção discute alguns meios simples para con�gurar um cronograma para executar o MySQL Enterprise Backup. Para Linux e outras plataformas semelhantes à Unix: você pode con�gurar uma tarefa cron em seu sistema para backups agendados. Existem dois tipos de tarefas agendadas. Para con�gurar uma tarefa cron do usuário, que é de propriedade e executada por um usuário especí�co, faça o seguinte: faça o logon como o usuário que executa o MySQL Enterprise Backup e use o seguinte comando para invocar um editor para criar (ou modi�car) um crontab: shell> crontab -e No editor, inclua uma entrada semelhante a seguinte no crontab e salve suas alterações: @daily /path-to-mysqlbackup/mysqlbackup -uroot --backup-dir=/path-to-backup- folder/cronbackups --with-timestamp backup &>/dev/null Essa entrada crontab invoca o mysqlbackup para criar um backup no diretório cronbackups às 00:00:00 todos os dias. As saídas dos �uxos stderr e stdout serão redirecionadas para / dev / null /, portanto, elas não invocarão outras ações na parte 60 do servidor Cron (por exemplo, noti�cações de email para o usuário). Para con�gurar uma tarefa cron do sistema, que é de propriedade e executada pelo root, crie um arquivo sob a pasta /etc/cron.d e insira nela uma entrada crontab semelhante à que foi mencionada acima, incluindo o usuário (root no exemplo a seguir ) antes do comando mysqlbackup: @daily root /path-to-mysqlbackup/mysqlbackup -uroot --backup-dir=/path-to- backup-folder/cronbackups --with-timestamp backup &>/dev/null Veri�que a documentação da sua plataforma para obter mais detalhes sobre as diferentes formas de con�gurar tarefas agendadas para vários tipos de agendas. Para plataformas Windows: use o Agendador de Tarefas para essa �nalidade. Veri�que a documentação da sua plataforma Windows para obter instruções. SAIBA MAIS No Windows, você pode usar a ferramenta Agendador de tarefas no painel de controle para agendar tarefas. Você também pode agendar tarefas manualmente. Para saber mais, acesse: http://bit.ly/2XH0SAv. 61 http://bit.ly/2XH0SAv Recovery O objetivo �nal dos dados de backup é ajudar na recuperação de um problema de banco de dados ou criar um clone do banco de dados original em outro local (normalmente, para executar consultas de relatório ou criar um slave de replicação). Esta seção descreve os procedimentos para lidar com esses cenários. Após um grave problema no banco de dados, talvez seja necessário executar uma recuperação sob pressão de tempo (SILBERSCHATZ et al., 2019). É fundamental con�rmar antecipadamente: Quanto tempo a recuperação levará, incluindo as etapas para transferir, descompactar e processar os dados. Se você praticou e documentou todas as etapas do processo de recuperação para que possa fazer isso corretamente em uma tentativa. Se um problema de hardware exigir a restauração dos dados em um servidor diferente, veri�que, com antecedência, todos os privilégios, a capacidade de armazenamento, etc., desse servidor. Veri�que periodicamente a exatidão e a integridade dos dados de backup para que o sistema funcione logo após ser recuperado. Recovery Full Imediatamente após a conclusão da tarefa de backup, os arquivos de backup podem não estar em um estado consistente, porque os dados podem ser inseridos, atualizados ou excluídos enquanto o backup estiver em execução. Esses arquivos de backup iniciais são conhecidos como backup bruto. Você deve atualizar os arquivos de backup para que eles re�itam o estado do banco de dados correspondente a um número de sequência de logs especí�co do InnoDB (o mesmo tipo de operação ocorre durante uma recuperação de falha). Quando essa etapa é concluída, esses arquivos �nais são conhecidos como backup preparado. 62 Durante o backup, o mysqlbackup copia o log do InnoDB acumulado para um arquivo chamado ibbackup_log�le. Esse arquivo de log é usado para “avançar” os arquivos de dados de backup, a �m de que cada página nos arquivos de dados corresponda ao mesmo número de sequência de log do log do InnoDB. Essa fase também cria ib_log�les que correspondem aos arquivos de dados. A opção mysqlbackup para transformar um backup bruto em um backup preparado é apply-log. Você pode executar essa etapa no mesmo servidor de banco de dados no qual fez o backup ou transferir primeiro os arquivos de backup brutos para um sistema diferente, a �mde limitar a sobrecarga de CPU e o armazenamento no servidor de banco de dados. Para backups de diretório simples (que não são compactados e incrementais), é possível combinar as etapas de backup inicial e apply-log usando o comando backup- and-apply-log. Você também pode executar log de aplicação e cópia de backup (que restaura o backup preparado) com um único comando copy-back-and-apply-log. ATENÇÃO O momento do recovery geralmente vem acompanhado de muita tensão. Dessa forma, manter a racionalidade e executar o método que foi de�nido previamente podem fazer a diferença a um restore de sucesso. 63 Os comandos mysqlbackup para executar uma operação de restauração são o copy- back-and-apply-log e copy-back. Normalmente, o processo de restauração requer que o servidor de banco de dados já esteja desligado (ou, pelo menos, não esteja operando no diretório para o qual você está restaurando os dados), exceto para restaurações de backups criados com a opção --use-tts. O processo copia os arquivos de dados, logs e outros arquivos de backup, do diretório de backup nos seus locais originais, bem como executa o pós-processamento necessário neles. mysqladmin --user=root --password shutdown mysqlbackup --defaults-�le=/usr/local/mysql/my.cnf \ --backup-dir=/export/backups/full \ copy-back Ao executar uma restauração, certi�que-se de que os diretórios de destino dos dados de restauração estejam limpos, sem arquivos de dados antigos ou indesejados (isso pode exigir a remoção manual de arquivos nos locais especi�cados por --datadir, -- innodb_data_home_dir, --innodb_log_group_home_dir, e opções -- innodb_undo_directory). A mesma limpeza não é necessária para restaurar backups criados com a opção - use-tts. Antes de restaurar um backup de diretório ativo usando o comando copy-back, o backup deve ser preparado e tornado consistente por meio do comando apply-log. Você pode combinar o log de aplicação e as operações de cópia de backup (bem como várias outras operações, dependendo do tipo de backup que você está restaurando) em uma única etapa usando a opção de cópia de retorno e aplicação em vez de: mysqlbackup --defaults-�le=<my.cnf> \ --backup-dir=/export/backups/full \ copy-back-and-apply-log Recovery Incremental Existem diferentes maneiras de usar backups incrementais para restaurar um banco de dados em diferentes cenários. O método preferido é primeiro restaurar o backup completo e torná-lo atualizado para o momento em que o backup completo for executado, usando o comando copy-back-and-apply-log; em seguida, usar copy-back- 64 and-apply-log novamente para restaurar a imagem de backup incremental sobre o backup completo que acabou de ser restaurado: mysqlbackup --defaults-�le=<my.cnf> -uroot --backup-image=<inc_image_name> \ --incremental-backup-dir=<incBackupTmpDir> --datadir=<restoreDir> -- incremental \ copy-back-and-apply-log Neste exemplo, a imagem de backup incremental denominada <inc_image_name> é restaurada para <restoreDir> no servidor (em que o backup completo, no qual imagem de backup incremental foi baseada, já foi restaurado). A opção -- incremental-backup-dir é usada para especi�car o diretório temporário no qual a saída temporária, os arquivos de status e os metadados de backup são salvos (você pode usar --backup-dir para o mesmo propósito). Repita a etapa com outras imagens de backup incrementais que você tenha, até que os dados tenham sido restaurados para um momento desejado. Como alternativa, você pode atualizar seu backup completo com seu backup incremental (SILBERSCHATZ et al., 2019). Primeiro, aplique ao backup completo todas as alterações ocorridas enquanto o backup estava em execução: $ mysqlbackup --backup-dir=/full-backup/2010-12-08_17-14-11 apply-log ..many lines of output... 101208 17:15:10 mysqlbackup: Full backup prepared for recovery successfully! 101208 17:15:10 mysqlbackup: mysqlbackup completed OK! Em seguida, aplicamos as alterações do backup incremental: Agora, os arquivos de dados no diretório de backup completo estão totalmente atualizados, a partir do momento do último backup incremental. Você pode continuar atualizando-o com mais backups incrementais, para que ele esteja pronto para ser restaurado a qualquer momento. Quando um backup incremental está sendo restaurado por meio do comando copy-back-and-apply-log ou apply-incremental- backup, o log binário (e o log de retransmissão, no caso de um servidor escravo), se incluído no backup incremental, também é restaurado para o servidor de destino por padrão. Esse comportamento padrão é substituído quando: (1) a opção --skip-binlog (ou a opção --skip-relaylog para o log de retransmissão) é usada com o comando restore ou (2), se o backup completo do backup incremental foi com base em 65 qualquer backup incremental anterior que tenha entrado entre o backup completo e este backup incremental sem o log binário (ou log de retransmissão). Recovery Diferencial Você pode restaurar seu banco de dados para seu estado em um momento arbitrário usando os arquivos de log binários incluídos nos backups. O processo pressupõe que a seguinte condição seja atendida: o servidor MySQL com backup já teve seu log binário ativado. Para veri�car se essa condição foi satisfeita, execute esta consulta no servidor: mysql> SHOW VARIABLES LIKE 'log_bin'; +---------------+-------+ | Variable_name | Value | +---------------+-------+ | log_bin | ON | +---------------+-------+ 1 row in set (0.00 sec) Se o valor de log_bin for OFF, o registro binário não foi ativado. Veja o log binário sobre como habilitar o log binário para o servidor. Uma série de backups, consistindo normalmente de um backup completo seguido por uma série de backups incrementais, foi criada para o servidor. O último backup da série abrange o momento desejado para a recuperação. O exemplo abaixo ilustra um caso típico. O último backup na série de backup que você tirou inclui, em si, os arquivos de log binários relevantes. (Para garantir que esse requisito seja satisfeito, não use nenhuma das seguintes opções do MySQL Enterprise Backup ao criar o backup: -- skip-binlog, --use-tts, --no-locking ou --start-lsn.). Estas são as etapas para uma recuperação pontual: Restaure a série de backups no servidor, com exceção do último backup incremental da série (que abrange o ponto de destino para a recuperação). Quando terminar, observe a posição do log binário para a qual você restaurou o servidor. As informações estão disponíveis no arquivo backup_variables.txt no diretório de dados restaurados do servidor: procure o valor da entrada 66 binlog_position no arquivo. Por exemplo: o binlog_position=binlog.000012:426 Isso signi�ca que, após a restauração da série de backup, o servidor está agora na posição de log 426, localizada no arquivo de log binário binlog.000012 (você precisará da informação mais tarde). Embora a última posição de log binário recuperada também seja exibida pelo InnoDB após a restauração, isso não é um meio con�ável para obter a posição de log �nal de sua restauração, pois podem ter ocorrido eventos DDL e alterações não-InnoDB após o tempo re�etido pela posição exibida. Extraia o log binário do último backup incremental na série de backup (isto é, o backup que cobre o ponto de destino no tempo para recuperação) descompactando a imagem de backup incremental em um diretório de backup por meio do comando image-to-backup-dir; por exemplo: mysqlbackup --backup-dir=incr-backup-dir2 --backup-image=incremental_image2.bi image-to-backup-dir Em seguida, vá para o diretório de backup resultante (incr-backup-dir2, neste exemplo) e, no diretório de dados, localize o arquivo de log binário. Procure no banco de dados seu estado no ponto de destino no tempo para recuperação, identi�cado como tR neste exemplo, usando o arquivo de log binário extraído na última etapa. Então, usando o utilitário mysqlbinlog, repita para o servidor as atividades SQL gravadas no arquivo de log binário [s] a partir da posição do log em que o servidorfoi restaurado na Etapa 1 acima (que é 426 no nosso exemplo) até tempo tR. Especi�que o intervalo de eventos de log binário para reproduzir usando a opção -start-position e a opção -stop-position (que indica a posição do log binário correspondente para tR) e canalize a saída para o cliente mysql: mysqlbinlog --start-position="binary-log-position-at-the-end-of-backup-restores" \ --stop-position="binary-log-position-corresponding-to-tR" \ binary-log-�lename | mysql -uadmin -p 67 Você também pode descarregar toda a saída do mysqlbinlog para um único arquivo primeiro e, depois, canalizar ou reproduzir o arquivo para o cliente mysql. Para obter mais explicações sobre como usar o log binário para recuperação pontual, consulte Recuperação pontual (incremental) usando o log binário. Veri�que se o servidor foi restaurado para o ponto desejado no tempo (SILBERSCHATZ et al., 2019). Figura 4 - Exemplo de log binário Fonte: elaborada pelo autor. 68 QUESTÃO OBJETIVA Essa estratégia é uma das mais simples e, dependendo do tamanho do banco de dados e sua frequência de atualização, umas das mais e�cientes. Ela consiste em criar uma cópia completa do banco de dados em seu estado atual. Essa estratégia é conhecida como? Backup Full. Backup Incremental. Backup Diferencial. Backup Log. Backup Alternativo. 69 QUESTÃO OBJETIVA O backup é uma estratégia para cenários onde os bancos de dados são atualizados com uma frequência maior, sendo que isso inviabiliza as cópias completas ou incrementais. Esse backup é chamado de Backup Incremental. Backup Diferencial. Backup Full. Backup Log. Backup Alternativo. 70 Fechamento O maior benefício de manter uma estratégia de backup e ter a menor perda possível de dados em situações problemáticas. Realizar cópias de segurança do banco de dados é uma prática para garantir a continuidade do negócio em cenários de desastres. Para isso, temos que avaliar as estratégias disponíveis e adequar a melhor para nossa situação. Nesta aula, você teve a oportunidade de: Entender os Backups full, incremental e diferencial; Entender os Restores full, incremental e diferencial; Realizar Agendamentos. 71 Segurança Imagine o seguinte cenário: você criou o projeto de banco de dados com todas as boas práticas e técnicas que você aprendeu, mas por algum motivo, deixou de lado as questões de segurança. Com isso, você deixou seu banco de dados exposto a eventuais ataques mal-intencionados. Ao �nal desta aula, você será capaz de: Entender sobre Injeção de SQL; Entender sobre Script de Site e Falsi�cação de Solicitação; Entender sobre Vazamento de senha; Entender sobre Autenticação da Aplicação. Aula 04 Introdução 72 Segurança de Aplicativos Problemas de segurança. Nem todo usuário do sistema de banco de dados deve acessar todos os dados. Por exemplo, em uma universidade, o pessoal da folha de pagamento precisa ver apenas a parte do banco de dados que possui informações �nanceiras; eles não precisam de acesso a informações sobre registros acadêmicos; no entanto, desde a aplicação, programas são adicionados ao sistema de processamento de arquivos de maneira ad hoc, e impor essas restrições de segurança é difícil. A segurança do aplicativo precisa lidar com várias ameaças e vários problemas além daqueles manipulados por autorização de SQL. O primeiro ponto em que a segurança deve ser aplicada está no aplicativo. Façam assim, os aplicativos devem autenticar os usuários e garantir que eles tenham permissão para realizarem tarefas autorizadas. A segurança de um aplicativo pode ser comprometida de várias maneiras, mesmo que o próprio sistema de banco de dados seja seguro, devido a códigos de aplicativos mal escritos. Nesta seção, primeiro descreveremos várias brechas de segurança que podem permitir hackers de realizar ações que ignoram a autenticação e autorização, veri�cações realizadas pelo aplicativo, e explicaremos como evitar tais brechas. Mais adiante, na seção, descreveremos técnicas para autenticação segura e para �ns de autorização. Em seguida, descreveremos as trilhas de auditoria que podem ajudar na recuperação de acesso não autorizado e de atualizações erradas. Nós concluiremos a seção descrevendo problemas na privacidade de dados (SILBERSCHATZ et al., 2019). 73 Injeção de SQL Nos ataques de injeção SQL, o invasor consegue obter um aplicativo para executar uma Consulta SQL criada pelo atacante. Como um exemplo de vulnerabilidade de injeção de SQL, considere o texto de origem do formulário mostrado na Figura 4. Suponha que o correspondente servlet cria uma string de consulta SQL usando o seguinte Java expressão: String query = “select * from student where name like ’%” + name + “%’” em que name é uma variável que contém a string inserida pelo usuário e, em seguida, executa a consulta no banco de dados. Um atacante mal-intencionado usando o formulário da Web pode, então, digitar uma sequência de caracteres como “'; <alguma instrução SQL>; −− ”, em que <alguma instrução SQL> denota qualquer SAIBA MAIS Segurança de aplicativos é uma área muito abrangente. Vale a pena estudar isso e aplicar tais conceitos sempre que possível. Geralmente, essa área é negligenciada até o momento em que um problema acontece. Para saber mais, acesse: http://bit.ly/30riBsm. 74 http://bit.ly/30riBsm declaração SQL que o invasor deseja no lugar de um nome válido de aluno. O servlet então executaria a seguinte string. select * from student where name like ’ ’; <some SQL statement>; −− ’ O comando inserido pelo atacante fecha a string, o ponto-e-vírgula a seguir termina a consulta, e o seguinte texto inserido pelo invasor é interpretado como uma segunda consulta SQL enquanto a cotação de fechamento foi comentada. Então, o usuário mal-intencionado conseguiu inserir uma instrução SQL arbitrária executada pelo aplicativo. A declaração pode causar danos signi�cativos, uma vez que pode executar qualquer ação no banco de dados, ignorando todas as medidas de segurança implementadas no código do aplicativo (SILBERSCHATZ et al., 2019). Para evitar esses ataques, é melhor usar instruções para executar consultas SQL. Ao de�nir um parâmetro de uma consulta preparada, O JDBC adiciona, automaticamente, caracteres de escape para que a cotação fornecida pelo usuário ATENÇÃO Injeção de SQL consiste em colocar algum código malicioso nas instruções SQL (select, delete, update, insert) em um banco de dados. Esse código pode conter comandos para revelar dados sigilosos, modi�car dados ou até mesmo modi�car a estrutura do banco de dados. 75 não possa mais terminar a sequência. Equivalente, uma função que adiciona tais caracteres de escape pode ser aplicada em strings de entrada antes de serem concatenados com a consulta SQL em vez de usar instruções preparadas. Outra fonte de risco de injeção de SQL vem de aplicativos que criam consultas dinamicamente, com base nas condições de seleção e nos atributos de pedido especi�cados em um formulário. Por exemplo, um aplicativo pode permitir que um usuário especi�que que atributo deve ser usado para classi�car os resultados de uma consulta. Um SQL consulta apropriado é construído com base no atributo especi�cado. Suponha que o aplicativo pega o nome do atributo de um formulário na variável orderAttribute e cria uma sequência de consulta, como a seguinte: String query = “select * from takes order by ” + orderAttribute; Um usuário mal-intencionado pode enviar uma string arbitrária no lugar de um orderAttribute de signi�cativo valor, mesmo se o formulário HTML usado para obter a entrada tentar restringir os valores permitidos, fornecendo um menu. Para evitar esse tipo de injeção de SQL, o aplicativo deve garantir que o valor da variável orderAttribute seja um dos valores permitidos (no nosso exemplo, nomes de atributos) antes de anexá-los. Script de Site e Falsi�cação de Solicitação Figura 1 - SQL Injection Fonte: Muslumstock / 123 RF 76 Uma página Web que permite aos usuários inserir texto, como umcomentário ou um nome, e depois armazena-o e o exibe para outros usuários é, potencialmente, vulnerável a um tipo de ataque chamado ataque cross-site scripting (XSS). Em tal ataque, um usuário mal-intencionado insere código escrito em uma linguagem de script do lado do cliente, como JavaScript ou Flash em vez de digitar um nome ou comentário válido (ELMASRI; NAVATHE, 2016). Quando um usuário diferente visualiza o texto digitado, o navegador executa o script, que pode executar ações como o envio de informações privadas de cookies para o usuário mal-intencionado ou executar uma ação em um servidor Web diferente no qual o usuário possa estar logado. Por exemplo, suponha que o usuário esteja logado em sua conta bancária enquanto o script é executado. O script pode enviar informações sobre cookies relacionadas ao login da conta bancária de volta para o usuário malicioso, que pode usar as informações para se conectar ao servidor Web do banco, enganando-o, fazendo-o acreditar que a conexão é do usuário original. Ou, ainda, o script pode acessar as páginas apropriadas no banco Web site, com parâmetros adequadamente de�nidos, para executar uma transferência de dinheiro (SILBERSCHATZ et al., 2019). De fato, esse problema, em particular, pode ocorrer mesmo sem script, simplesmente usando uma linha de código como: <img src= "http://mybank.com/transfermoney?amount=1000&toaccount=14523"> assumindo que a URL mybank.com/transfermoney aceita os parâmetros especi�cados e realiza uma transferência de dinheiro. Esse último tipo de vulnerabilidade é também chamado falsi�cação de solicitação entre sites ou XSRF (às vezes também chamado de CSRF). O XSS pode ser feito de outras maneiras, como atrair um usuário para visitar um site que tem scripts maliciosos incorporados em suas páginas. Existem outros mais complexos, tipos de ataques XSS e XSRF, que não devemos entrar aqui. Para a proteção contra esses ataques, duas coisas precisam ser feitas: Impeça que o seu site seja usado para iniciar ataques XSS ou XSRF. A técnica mais simples é proibir qualquer tag HTML que esteja na entrada de texto pelos usuários. Existem funções que detectam ou retiram todas essas tags. Essas funções podem ser usadas para evitar tags HTML e, como resultado, quaisquer scripts exibidos para outros usuários. Em alguns casos, a formatação HTML é útil; nesse caso, funções que analisam o texto e permitem construções HTML limitadas, mas não permitem que outras construções perigosas possam ser usadas; estes devem ser projetados com cuidado, já que algo tão inócuo quanto 77 uma imagem pode representar perigo se houver um bug no software de exibição de imagens que pode ser explorado. Proteja seu site de ataques XSS ou XSRF iniciados em outros sites. Se o usuário faizer logon no seu site e visitar um site diferente vulnerável ao XSS, o código malicioso que está sendo executado no navegador do usuário executará ações no seu site ou passará informações da sessão relacionada ao seu Web site de volta para o usuário mal-intencionado, que pode tentar explorá-lo. Isso não pode ser evitado completamente, mas você pode dar alguns passos para minimizar o risco (SILBERSCHATZ et al., 2019). O protocolo HTTP permite que um servidor veri�que o referenciador de um acesso à página, é o URL da página que tinha o link em que o usuário clicou para iniciar o acesso à página. Ao veri�car se o referenciador é válido, por exemplo, se o referer URL é uma página no mesmo site, ataques XSS originados em uma página da Web diferente, acessada pelo usuário, podem ser evitados. Em vez de usar apenas o cookie para identi�car uma sessão, a sessão também poderia ser restrita ao endereço IP do qual foi originalmente autenticado. Como resultado, mesmo que um usuário mal-intencionado receba um cookie, ele talvez não consiga fazer o login de um computador diferente. Nunca use um método GET para executar atualizações. Isso evita ataques usando <img src ..> como o que vimos anteriormente. Na verdade, o padrão HTTP recomenda que os métodos GET nunca executem atualizações, por outras razões, como uma atualização de página, repetindo uma ação que deve acontecer apenas uma vez. 78 ATENÇÃO Ataques de Cross-Site são comuns. Existem várias formas de realizar isso. Quando criamos um aplicativo, o mesmo deve ser projetado contra esse tipo de ataque. É comum a captura de dados quanto à comunicação não criptografada, à injeção de scripts com o objetivo de fraudes, etc. 79 Vazamento de senha Outro problema que os desenvolvedores de aplicativos devem lidar é armazenar senhas em texto plano no código do aplicativo. Por exemplo, programas como scripts JSP geralmente contêm senhas em texto não criptografado. Se tais scripts estiverem armazenados em um diretório acessível por um servidor Web, um usuário externo pode acessar a fonte, o código do script, e obter acesso à senha da conta de banco de dados usada pelo aplicativo. Para evitar tais problemas, muitos servidores de aplicativos pensaram em mecanismos para armazenar senhas em formato criptografado, que o servidor descriptografa antes de passá-lo para o banco de dados. Tal recurso elimina a necessidade de armazenamento, senhas como texto não criptografado em programas aplicativos. No entanto, se a chave de descriptogra�a também é vulnerável ao ser exposta, essa abordagem não é totalmente e�caz (SILBERSCHATZ et al., 2019). Como outra medida contra senhas de banco de dados, muitos sistemas permitem que o acesso ao banco de dados seja restrito a um determinado conjunto de endereços, normalmente, as máquinas que executam os servidores de aplicativos. Tentativas de conectar-se ao banco de dados de outros endereços da Internet são rejeitadas. Assim, a menos que o usuário mal-intencionado seja capaz de entrar no servidor de aplicativos, ela não pode fazer danos, mesmo que ela ganhe acesso à senha do banco de dados. Figura 2 - Script Injection Fonte: Paolo de Gasperis / 123 RF 80 ATENÇÃO Vazamento de senha, em outras palavras, refere-se à prática de colocar as senhas de acesso, por exemplo, a senha de acesso ao banco de dados, dentro da aplicação em texto plano. Isso pode ser utilizado como uma técnica de invasão dos aplicativos. Fonte: Silberschatz (2019). 81 Autenticação da Aplicação Autenticação refere-se à tarefa de veri�car a identidade de uma pessoa / software conectando-se a um aplicativo. A forma mais simples de autenticação consiste em uma senha secreta que deve ser apresentada quando um usuário se conecta ao aplicativo. Infelizmente, as senhas são facilmente comprometidas, adivinhadas, por exemplo, por snif�ng de pacotes na rede, se as senhas não forem enviadas criptografadas. Esquemas mais robustos são necessários para aplicações críticas, como contas. A criptogra�a é a base para esquemas de autenticação mais robustos. Muitos aplicativos usam autenticação de dois fatores, em que dois fatores (isto é, partes de informações ou processos) são usados para identi�car um usuário. Os dois fatores não devem compartilhar uma vulnerabilidade comum; por exemplo, se um sistema meramente exigia duas senhas, ambas poderiam ser vulneráveis a vazamentos na mesma maneira (por snif�ng de rede ou por um vírus no computador usado pelo usuário, por exemplo). Embora a biometria, como impressões digitais ou scanners de íris, possa ser usada em situações cujo usuário esteja �sicamente presente no ponto de autenticação, ela não é muito signi�cativa em uma rede (SILBERSCHATZ et al., 2019). As senhas são usadas como o primeiro fator na maioria dessas autenticações de dois fatores esquemas. Cartões inteligentes ou outros dispositivos de criptogra�a conectados por meio do USB interface, que pode ser usado para autenticação baseada em técnicas de criptogra�a, são amplamente utilizados como segundo fator. Dispositivos de senha única, que geram um novo número pseudo aleatório (digamos) a cada minuto, também são amplamente usados como segundo fator. A cada usuário é dado um desses dispositivos, e ele deve digitaro número exibido pelo dispositivo em o momento da autenticação com a senha para se autenticar. Cada dispositivo gera uma sequência diferente de números pseudoaleatórios. O servidor de aplicativos pode gerar a mesma sequência de números pseudoaleatórios como o dispositivo dado ao usuário, parando no número que seria exibido no momento da autenticação, e veri�car se os números correspondem. Esse esquema Figura 3 - Vazamento de senha Fonte: Rawpixel / 123 RF. 82 requer que o relógio no dispositivo e no servidor estejam razoavelmente sincronizados de perto. Outra abordagem de segundo fator é enviar um SMS com uma (gerado aleatoriamente) senha única para o telefone do usuário (cujo número é registrado anteriormente) sempre que o usuário desejar efetuar login no aplicativo. O usuário deve possuir um phonewith com esse número para receber o SMS e, em seguida, digitar a senha de uso único, com sua senha regular, para ser autenticado. Vale notar que, mesmo com a autenticação de dois fatores, os usuários ainda estão vulneráveis a ataques man-in-the-middle. Em tais ataques, um usuário tentando conectar-se ao aplicativo é desviado para um site falso, que aceita a senha (incluindo as senhas do segundo fator) do usuário e a usa imediatamente para autenticar no aplicativo original. O protocolo HTTPS é usado para autenticar o site para o usuário (para que o usuário não se conecte a um site falso acreditando ser o site pretendido). O protocolo HTTPS também criptografa dados e evita ataques man-in-the-middle (SILBERSCHATZ et al., 2019). Quando o usuário acessa vários sites, muitas vezes é incômodo para ele ter que autenticar-se em cada um, muitas vezes com senhas distintas em cada local. Existem sistemas que permitem que o usuário se autentique em um serviço de autenticação central, e outros sites e aplicativos da Web podem autenticar o usuário por meio desse serviço; a mesma senha pode, então, ser usada para acessar vários sites. O protocolo LDAP é amplamente usado para implementar tal ponto central de autenticação; organizações implementam um servidor LDAP contendo nomes de usuário e informações de senha, e os aplicativos usam o LDAP servidor para autenticar usuários. Além de autenticar usuários, um serviço de autenticação central pode fornecer outros serviços, por exemplo, fornecer informações sobre o usuário, como nome, e- mail e endereço, para o aplicativo. Isso elimina a necessidade da inserir essas informações separadamente em cada aplicativo. LDAP pode ser usado para essa tarefa. Outros sistemas de diretório, como o da Microsoft Diretórios Ativos, também fornecem mecanismos para autenticar usuários, bem como fornecer informações ao usuário (SILBERSCHATZ et al., 2019). 83 Um sistema de logon único permite que o usuário seja autenticado uma só vez, e vários aplicativos podem, então, veri�car a identidade do usuário por meio de um serviço de autenticação sem exigir uma nova autenticação. Em outras palavras, uma vez que um usuário está logado em um site, ele não tem que digitar seu nome de usuário e senha em outros sites que usam o mesmo serviço de logon único. Esses mecanismos de logon único, há muito tempo, são usados em protocolos de autenticação de rede, como o Kerberos, e , agora, implementações estão disponíveis para aplicativos da Web. ATENÇÃO O conceito de single sign-on pode ser aplicado aos softwares para evitar várias autenticações em um ambiente corporativo. Além disso, gera outros benefícios como um gerenciamento uni�cado de usuários. Para saber mais, acesse: http://bit.ly/2NVBmmn. 84 http://bit.ly/2NVBmmn O SAML (Security Assertion Markup Language) é um padrão para troca de autenticação e autorização de informações entre diferentes domínios de segurança para fornecer logon único entre organizações. Por exemplo, suponha que um aplicativo precisa fornecer acesso a todos os alunos de uma determinada universidade, por exemplo UEL. A universidade pode con�gurar um serviço baseado na Web que realiza autenticação (SILBERSCHATZ et al., 2019). Suponha que um usuário se conecte ao aplicativo como "joao@uel.edu". O aplicativo, em vez de autenticá-lo diretamente, desvia-o ao serviço de autenticação da Universidade de Yale, que autentica o usuário e, em seguida, informa: o aplicativo, que usuário é, bem como pode fornecer algumas informações adicionais, como a categoria do usuário (aluno ou instrutor) ou outros em formação. A senha do usuário e outros fatores de autenticação nunca são revelados ao aplicativo, e o usuário não precisa se registrar explicitamente com a aplicação, no entanto, o aplicativo deve con�ar no serviço de autenticação da universidade. O padrão OpenID é uma alternativa para o logon único em organizações, e tem-se visto crescente aceitação nos últimos anos. Web sites populares, como Google, Microsoft, Yahoo!, entre muitos outros, atuam como OpenID provedores de autenticação. Qualquer aplicativo que atue como um cliente OpenID pode usar qualquer um desses provedores para autenticar um usuário; por exemplo, um usuário Figura 4 - Autenticação Fonte: Ktsdesign / 123 RF. 85 que tenha uma conta Yahoo! pode escolher o Yahoo! como o provedor de autenticação. O usuário é redirecionado para o Yahoo! para autenticação, e. na autenticação bem-sucedida, é redirecionado de volta para o aplicativo, e pode continuar usando a aplicação (SILBERSCHATZ et al., 2019). Autorização em nível de aplicativo Embora o padrão SQL suporte um sistema bastante �exível de autorização com base em funções (descritas na Seção 4.6), o modelo de autorização SQL desempenha um papel muito limitado no gerenciamento de autorizações de usuários em um aplicativo típico. Por exemplo, suponha que você quer que todos os alunos possam ver suas próprias notas, mas não as notas de outros. Tal autorização não pode ser especi�cada em SQL por, pelo menos, duas razões: 1. Falta de informações do usuário �nal. Com o crescimento da Web, os acessos ao banco de dados vêm principalmente de servidores de aplicativos da Web. Os usuários �nais normalmente não têm identi�cadores de usuário individuais no próprio banco de dados, e, de fato, pode haver apenas um identi�cador de usuário no banco de dados correspondente a todos os usuários de um servidor de aplicativos. Assim, a especi�cação de autorização em SQL não pode ser usado no cenário acima. É possível que um servidor de aplicativos autentique usuários �nais e, em seguida, passe as informações de autenticação para o banco de dados. Nesta seção, vamos assumir que a função syscontext.user id () retorna o identi�cador do usuário do aplicativo em cujo nome uma consulta está sendo executada.5 Falta de autorização re�nada. A autorização deve estar no nível de tuplas individuais se quisermos autorizar os alunos a verem apenas as suas próprias notas. Tal autorização não é possível no atual padrão SQL, que permite a autorização somente em uma relação ou visão inteira ou, ainda, em atributos de relações ou visões. Poderíamos tentar contornar essa limitação criando, para cada aluno, uma visão sobre a relação de tomadas que mostra apenas as notas desse aluno. Enquanto isso funcionaria em princípio, seria extremamente complicado, já que teria que criar uma visão para cada aluno matriculado na universidade, o que é completamente impraticável. Uma alternativa é criar uma visão do formulário: create view studentTakes as select * from takes 86 where takes.ID= syscontext.user id() Os usuários recebem, então, autorização para essa visualização.No entanto, as consultas executadas em nome dos alunos devem ser escritas na vew do studentTakes, em vez da reação origem. A tarefa de desenvolver aplicativos se torna mais complexa como resultado. A tarefa de autorização é, hoje, executada inteiramente no aplicativo, ignorando os recursos de autorização do SQL. No nível do aplicativo, os usuários estão autorizados a acessar interfaces especí�cas, que podem ser restritas, ou atualizar apenas alguns itens de dados. Ao executar a autorização no aplicativo, há uma grande quantidade de�exibilidade para desenvolvedores de aplicativos, mas também há problemas (SILBERSCHATZ et al., 2019). O código para veri�car a autorização se mistura com o resto do código da aplicação. Implementar a autorização por meio de código de aplicativo, em vez de especi�car declarativamente em SQL, torna difícil a garantia da ausência de lacunas. Devido a um descuido, um dos programas aplicativos pode não veri�car autorização, permitindo que usuários não autorizados tenham acesso a dados con�denciais. Analisar se todos os aplicativos executam todas as veri�cações de autorização necessárias envolve a leitura de todo o código do servidor de aplicativos, uma tarefa considerável um sistema grande. Em outras palavras, os aplicativos têm uma "área de superfície" muito grande, tornando a tarefa de proteger o aplicativo signi�cativamente mais difícil. E, de fato, brechas de segurança foram encontradas em uma variedade de aplicações da vida real. Por outro lado, se um banco de dados suportasse diretamente uma autorização de baixa granularidade, as políticas de autorização podem ser especi�cadas e aplicadas no nível SQL, que tem uma área de superfície muito menor. Mesmo que algumas das interfaces do aplicativo inadvertidamente omitir as veri�cações de autorização exigidas, a autorização em nível impedirá que ações não autorizadas sejam executadas. Alguns sistemas de banco de dados fornecem mecanismos para autorização de baixa granularidade. 87 Por exemplo, o VPD (Oracle Virtual Private Database) permite que um administrador de sistema associe uma função a uma relação; a função retorna um predicado que deve ser adicionado a qualquer consulta que use a relação (diferentes funções podem ser de�nidas para as relações que estão sendo atualizadas). Por exemplo, usando nossa sintaxe para recuperar identi�cadores de usuários de aplicativos, a função para a relação de retornar um predicado como: ID = sys context.user id () Esse predicado é adicionado à cláusula where de todas as consultas que usam os takes relação. Como resultado (supondo que o programa aplicativo de�ne o valor do id do usuário para o ID do aluno), cada aluno pode ver apenas as tuplas correspondentes aos cursos que ele pegou. Assim, o VPD fornece autorização no nível de tuplas ou linhas especí�cas de uma relação, e, portanto, é visto como um mecanismo de autorização em nível de linha. Uma armadilha potencial com a adição de um predicado como descrito acima é que ele pode mudar o signi�cado de uma consulta de forma signi�cativa. Por exemplo, se um usuário escreveu uma consulta ATENÇÃO Autorização é um dos A da segurança (Autenticação, Autorização e Auditoria). Esses elementos devem ser considerados em aplicações de banco de dados uma vez que o 88 para encontrar a nota média em todos os cursos, ele acabaria recebendo a média dela notas, e não a de todas as notas. Embora o sistema tenha dado a resposta “certa” para a consulta, essa resposta não correspondeu à consulta que o usuário pensou ter se submetido (SILBERSCHATZ et al., 2019). 89 QUESTÃO OBJETIVA Como são conhecidos os ataques nos quais o invasor consegue obter um aplicativo para executar uma Consulta SQL criada pelo atacante e que pode dani�car o banco de dados? SQL Injection. SQL Projection. Script Injection. DDL Injection. DML INJECTION. 90 QUESTÃO OBJETIVA Um problema que os desenvolvedores de aplicativos devem lidar é o armazenamento de senhas em texto plano no código do aplicativo. Por exemplo, programas como scripts JSP geralmente contêm senhas em texto não criptografado. Esse tipo de problema é conhecido como? Vazamento de memória. Criptogra�a. Chave assíncrona. Vazamento de senha. LDAP 91 Fechamento O maior benefício da segurança em banco de dados é manter seus dados íntegros. Imagine o seguinte cenário: você criou um projeto de banco de dados com todas as boas práticas e técnicas que aprendeu, mas por algum motivo, deixou de lado as questões de segurança. Com isso, você deixou seu banco de dados exposto a eventuais ataques mal-intencionados. Nesta aula, você teve a oportunidade de: Entender sobre Injeção de SQL; Entender sobre Script de Site e Falsi�cação de Solicitação; Entender sobre Vazamento de senha; Entender sobre Autenticação da Aplicação. 92 27/01/2020 Aula 05 https://iesb-banco-de-dados.webflow.io/unidade-3/aula-05 1/30 Projetos de Bancos de Dados Ao criarmos projetos de bancos de dados devemos nos preocupar não somente com o modelo E-R, mas também com questões relacionadas a esquemas, domínios e formas normais. Isso faz com que a qualidade do banco de dados aumente, deixando-o mais simples para acomodar eventuais mudanças ao longo do ciclo de vida. Ao final desta aula, você será capaz de: Aprender a Alterna�va de design: esquemas maiores; Entender os Domínios Atômicos e Primeira Forma Normal; Aprender sobre a Decomposição Usando Dependências Funcionais. Aula 05 Introdução 93 27/01/2020 Aula 05 https://iesb-banco-de-dados.webflow.io/unidade-3/aula-05 2/30 Recursos de Bons Projetos Relacionais Neste estudo, consideramos o problema de projetar um esquema para um relacionamento base de dados. Muitas das questões ao fazê-lo são semelhantes às questões de design usando o modelo E-R. Em geral, o obje�vo do projeto de banco de dados relacional é gerar um conjunto de relações esquemas que nos permita armazenar informações sem redundância desnecessária, bem como nos permita recuperar informações facilmente. Isso é conseguido projetando esquemas que estão em uma forma normal apropriada. Para determinar se uma relação esquema está em uma das formas normais desejáveis, precisamos de informações sobre a empresa do mundo real que estamos modelando com o banco de dados. Algumas dessas informações existe em um diagrama E-R bem projetado, mas informações adicionais sobre a empresa podem ser necessárias também. Neste estudo, apresentamos uma abordagem formal ao design de banco de dados relacional com base na noção de dependências funcionais. Nós, então, definimos formas normais em termos de dependências funcionais e outros �pos de dependências de dados. Em primeiro lugar, no entanto, vemos o problema do design relacional do ponto de vista dos esquemas derivados de um determinado design de relacionamento entre en�dades (SILBERSCHATZ et al., 2019). Nosso estudo sobre o design de relacionamento entre en�dades fornece um excelente começo para se criar um design de banco de dados relacional. Obviamente, a qualidade (ou falta dela) do conjunto resultante de esquemas depende, em primeiro lugar, do quão bom foi o design de E-R. Para facilitar a referência, repe�mos os esquemas para o banco de dados da universidade na Figura 1. 94 27/01/2020 Aula 05 https://iesb-banco-de-dados.webflow.io/unidade-3/aula-05 3/30 Figura 1 - Visão geral do modelo de dados Fonte: adaptada de Elmasri e Navathe (2016). 95 27/01/2020 Aula 05 https://iesb-banco-de-dados.webflow.io/unidade-3/aula-05 4/30 Alternativa de Design: Esquemas Maiores Agora, vamos explorar recursos desse design de banco de dados relacional, bem como algumas alterna�vas. Silberschatz et al. 2019, fornecem o seguinte exemplo; suponha que, em vez de ter o professor e o departamento de esquemas, nós temos o esquema: PROFESSOR (ID, NOME, SALARIO_MENSAL, DEPARTAMENTO, ENDERECO) Isso representa o resultado de uma união natural nas relações correspondentes professor e departamento. Essa parece ser uma boa ideia, porque algumas consultas podem ser expressas usando menos junções, até pensarmos cuidadosamente sobre os fatos que levou a Universidade ao nosso modelo E-R. Vamos considerar a instância da relação PROFESSOR mostrada na Figura 1 que temos que repe�r as informações do departamento ("NOME" e "ID") para cada professor do ATENÇÃO Uma relação é um conjunto de atributos. Ela é a base do modelo en�dade- relacionamento E-R. Entender quais são os atributos de uma relação auxilia muito na modelagem de um banco de dados. Fonte: Silberschatz (2019). 96 27/01/2020 Aula 05https://iesb-banco-de-dados.webflow.io/unidade-3/aula-05 5/30 departamento. Por exemplo, as informações sobre o departamento de COMPUTAÇÃO está incluído nas tuplas de professores Pedro e José. É importante que todas essas tuplas concordem quanto ao valor do orçamento, desde que nosso banco de dados seja inconsistente. Em nosso design original, sendo usados professor e departamento, armazenamos o valor de cada orçamento exatamente uma vez. Isso sugere que usar o departamento é uma má ideia, pois armazena os valores do orçamento de forma redundante, e há o risco de que algum usuário possa atualizar o valor do orçamento em uma tupla, mas não todos, criando, assim, uma inconsistência (SILBERSCHATZ et al., 2019). Dessa forma, o que se pretende com essa abordagem é separar os dados do departamento dos dados do professor. Com isso o nome do departamento deixa de exis�r na relação PROFESSOR e uma chave estrangeira DEPARTAMENTO_FK se encarrega de manter o vínculo entre as relações DEPARTAMENTO e PROFESSOR. Esse processo é conhecido como normalização. Agora vamos verificar como realizar isso nas relações para manter a estrutura de banco de dados imune as anomalias de atualização. 97 27/01/2020 Aula 05 https://iesb-banco-de-dados.webflow.io/unidade-3/aula-05 6/30 Mesmo que se tenha decidido viver com o problema da redundância, ainda há outro problema com a relação PROFESSOR. Suponha que estamos criando um departamento na Universidade. No projeto alterna�vo acima, não podemos representar diretamente as informações rela�vas a um departamento (nome do departamento e ID), a menos que o departamento tenha, pelo menos, um professor na universidade. Isso ocorre porque as tuplas da relação PROFESSOR requer valores para ID, nome e salário. Isso significa que não serão registradas informações sobre o departamento recém-criado até o primeiro professor. SAIBA MAIS A atributo ID, presente em quase todas as relações do modelo u�lizado neste estudo, é conhecido como uma chave ar�ficial. Existem vários �pos de chaves. Uma dela é a chave natural, que, em uma pessoa, aqui no Brasil, poderia ser representada pelo CPF. Fonte: Silberschatz et al. (2019). 98 27/01/2020 Aula 05 https://iesb-banco-de-dados.webflow.io/unidade-3/aula-05 7/30 ser contratado para o novo departamento. No design an�go, o departamento de esquema pode lidar com isso, mas sob o design revisado, teríamos que criar uma tupla com um Valor nulo para construção e orçamento. Em alguns casos, valores nulos são problemá�cos, vimos em nosso estudo de SQL. No entanto, se decidirmos que isso não é um problema nesse caso, podemos con�nuar a usar o design revisado. Alternativa de projeto: esquemas menores Suponha novamente que, de alguma forma, nós começamos com o esquema inst dept. Como reconheceríamos que requer repe�ção de informações e deve ser dividido nos dois esquemas professor e departamento? Ao observarmos o conteúdo de relações reais no esquema PROFESSORES, vemos a repe�ção de informações resultantes da necessidade de se listar o professor associado a um departamento. No entanto, esse é um processo não confiável (SILBERSCHATZ et al., 2019). Um banco de dados do mundo real tem muitos esquemas e um número ainda maior de atributos. O número de tuplas pode estar em milhões ou mais. A repe�ção da descoberta seria dispendiosa. Ela não nos permite determinar se a falta de repe�ção é apenas um caso especial “sortudo” ou se é uma manifestação de uma regra. Em nosso exemplo, como saberíamos que em nossa organização universitária, cada departamento (iden�ficado pelo nome do departamento) deve residir em um único Figura 2 - Relação PROFESSOR com seus atributos Fonte: adaptada de Elmasri e Navathe (2016). 99 27/01/2020 Aula 05 https://iesb-banco-de-dados.webflow.io/unidade-3/aula-05 8/30 prédio e deve ter um único valor de orçamento? O fato de o montante do orçamento para o departamento de COMPUTAÇÃO aparecer três vezes com o mesmo valor de orçamento é apenas uma coincidência? Não podemos responder a essas perguntas sem voltarmos à própria empresa e entender suas regras. Em par�cular, precisaríamos descobrir que a universidade exige que cada departamento (iden�ficado por seus nomes do departamento) tenha apenas um prédio e um valor de orçamento. No caso da relação PROFESSOR, nosso processo de criar um design E-R com sucesso evitou a criação desse esquema; no entanto, essa situação fortuita não ocorre sempre, portanto, precisamos permi�r que o designer de banco de dados especifique regras como “cada valor específico para o nome do departamento corresponde a quase um orçamento” nos casos em que o nome do departamento não seja a chave primária do esquema em questão (SILBERSCHATZ et al., 2019). Em outras palavras, precisamos escrever uma regra que diz “se houvesse um esquema ATENÇÃO Decompor um esquema muito grande em menores é uma boa maneira de manter a complexidade de um modelo de dados sob controle. Isso é especialmente ú�l para modelar aplicações do mundo real. 100 27/01/2020 Aula 05 https://iesb-banco-de-dados.webflow.io/unidade-3/aula-05 9/30 (nome do departamento, orçamento), o nome do departamento poderia servir como chave primária.” Essa regra é especificada como uma dependência funcional nome do departamento → id Dada tal regra, agora temos informações suficientes para reconhecer o problema do esquema departamento. Devido ao nome do departamento não poder ser a chave primária para o departamento inst (porque um departamento pode precisar de várias tuplas na relação PROFESSOR), o montante de um orçamento deve ser repe�do. Observações dessas regras (dependências funcionais em par�cular) permitem que o designer de banco de dados reconheça situações em que um esquema deve ser dividido ou decomposto em dois ou mais esquemas. Não é di�cil ver que o caminho certo para se decompor inst departamento está em esquemas professor e departamento como no design original. Encontrar a decomposição correta é muito mais di�cil para esquemas com muitos atributos e várias dependências. Para lidar com isso, vamos nos basear em uma metodologia formal que iremos desenvolver mais adiante neste estudo. Nem todas as decomposições de esquemas são úteis. Considere um caso extremo em que tudo o que �nhamos era esquemas que consis�am em um atributo. Nenhum relacionamento interessante de qualquer �po poderia ser expressado. Agora, considere um caso menos extremo. Nós escolhemos decompor o esquema do empregado: ALUNO (ID , NOME, DATA_NASCIMENTO, CURSO) nos dois esquemas seguintes: CURSO (ID, NOME) ORIENTACAO (PROFESSOR, ALUNO, DATA_INICIO, DATA_ENCERRAMENTO) A falha nessa decomposição surge da possibilidade de que a empresa tenha dois funcionários com o mesmo nome. Isso não é improvável na prá�ca, já que muitas culturas têm certos nomes altamente populares. Claro que cada pessoa teria um ID de funcionário exclusivo, e é por isso que o ID pode servir como chave primária. Como um exemplo, vamos supor que dois professores, ambos chamados João, trabalhem na universidade, e que haja as seguintes tuplas na relação do esquema no design original: (57766, João, Principal, Computação, 7500) 101 27/01/2020 Aula 05 https://iesb-banco-de-dados.webflow.io/unidade-3/aula-05 10/30 (98776, João, Norte, Matemá�ca, 6000) A Figura 3 mostra essas tuplas resultantes por meio de esquemas resultantes a par�r da decomposição, bem como o resultado, se tentássemos regenerar as tuplas originais por meio de uma junção natural. Como vemos na figura, as duas tuplas originais aparecem no resultado junto com duas novas tuplas que misturam incorretamente valores de dados referentes aos dois funcionários chamados João. Embora tenhamos mais tuplas, na verdade, temos menos informações no sen�do a seguir. Podemos indicar que uma certa rua, cidade e um salário pertencem a alguém chamado João, mas não conseguimos dis�nguir a qual dos Joãos. Assim, nossa decomposição é incapaz de representar alguns fatos importantes sobre os funcionários da universidade. Claramente, nós gostaríamosde evitar tais decomposições. Vamos nos referir a tais decomposições como sendo decomposições com perdas, e, inversamente, àquelas que não são tão decomposições como sendo sem perdas. Figura 3 - Relacionamento entre as relações PROFESSOR e ENDERECO Fonte: adaptada de Elmasri e Navathe (2016). 102 27/01/2020 Aula 05 https://iesb-banco-de-dados.webflow.io/unidade-3/aula-05 11/30 Domínios Atômicos e Primeira Forma Normal O modelo E-R permite que conjuntos de en�dades e conjuntos de relacionamentos tenham atributos de algum grau de subestrutura. Especificamente, ele permite atributos de vários valores, como número de telefone e atributos compostos (como um endereço de atributo com atributos de componente rua, cidade, estado e CEP). Quando criamos tabelas de Projetos E-R que contêm esses �pos de atributos, eliminamos essa subestrutura. Para atributos compostos, deixamos cada componente ser um atributo por direito próprio. Para atributos com valores de formulário, criamos uma tupla para cada item em um conjunto com valores múl�plos. No modelo relacional, formalizamos essa ideia de que os atributos não possuem subestrutura. Um domínio é atômico se os elementos do domínio forem considerados unidades indivisíveis. Dizemos que um esquema de relação R está na primeira forma normal (1NF) se os domínios de todos os atributos de R são atômicos. Um conjunto de nomes é um exemplo de um valor não-atômico. Por exemplo, se o esquema de uma relação empregado incluiu um atributo filhos cujos elementos de domínio são conjuntos de nomes, o esquema não estaria na primeira forma normal. Atributos compostos, como um endereço de atributo com atributos de componente street, city, state e zip também têm domínios nonatomic (SILBERSCHATZ et al., 2019). 103 27/01/2020 Aula 05 https://iesb-banco-de-dados.webflow.io/unidade-3/aula-05 12/30 Inteiros são assumidos como sendo atômicos, então o conjunto de inteiros é um domínio atômico; no entanto, o conjunto de todos os conjuntos de inteiros é um domínio não atômico. A dis�nção é que, normalmente, não consideramos números inteiros como subpartes, mas consideramos conjuntos de inteiros para ter subpartes - ou seja, os inteiros que compõem o conjunto. Mas a questão importante não é o domínio, em si, é, mas sim como usamos o domínio elementos em nosso banco de dados. O domínio de todos os inteiros seria nonatomic se nós considerássemos cada inteiro como uma lista ordenada de dígitos. Como uma ilustração prá�ca do ponto acima, considere uma organização que atribui números de iden�ficação de funcionários da seguinte forma: as duas primeiras letras especificam o departamento e os quatro dígitos restantes são um número único dentro do departamento para o empregado. Exemplos de tais números seriam “CS001” e “EE1127”. Esses números de iden�ficação podem ser divididos em unidades e, portanto, não são atômicas. Se um esquema de relação �vesse um ATENÇÃO Um domínio atômico é um domínio que não pode ser dividido. Por exemplo, o domínio do atributo ID é atômico pois, em nosso cenário, não faz sen�do dividi- lo em outros atributos. Fonte: Hoffer et al. (2019). 104 27/01/2020 Aula 05 https://iesb-banco-de-dados.webflow.io/unidade-3/aula-05 13/30 atributo cujo domínio consis�sse em números de iden�ficação codificados como acima, o esquema não estaria na primeira forma normal. Quando tais números de iden�ficação são usados, o departamento de um empregado pode ser encontrado ao ser escrito um código que quebre a estrutura de uma iden�ficação número. Fazer isso requer programação extra e as informações são codificadas no programa aplica�vo e não no banco de dados. Mais problemas surgem se tais números de iden�ficação forem usados como chaves primárias: quando empregado departamentos de alterações, o número de iden�ficação do funcionário deve ser alterado em todos os lugares em que ocorre, o que pode ser uma tarefa di�cil, ou o código que interpreta o número dará um resultado errado. A par�r da discussão acima, pode parecer que nosso uso de iden�ficadores de curso como “CS-101”, em que “CS” indica o departamento de Ciência da Computação, significa que o domínio dos iden�ficadores do curso não é atômico. No entanto, o SAIBA MAIS As formas normais foram criadas para se evitar problemas de atualização. Dessa forma, podemos elevar nosso banco de dados a úl�mas formas normais. As mais conhecidas são a 1FN, 2FN2, 3FN, 4FN e a forma normal de Boyce-Codd. Fonte: Silberschatz et al. (2019). 105 27/01/2020 Aula 05 https://iesb-banco-de-dados.webflow.io/unidade-3/aula-05 14/30 aplica�vo de banco de dados ainda trata o domínio como atômico, desde que ele não tente dividir o iden�ficador e interpretar partes do iden�ficador como uma abreviação de departamento. O curso do esquema armazena o nome do departamento como um atributo separado e o banco de dados aplica�vo pode usar esse valor de atributo para localizar o departamento de um curso e interpretar caracteres par�culares do iden�ficador do curso. Assim, em nossa universidade, o esquema pode ser considerado na primeira forma normal. O uso de atributos com valores definidos pode levar ao design com armazenamento redundante de dados, que, por sua vez, pode resultar em inconsistências. Por exemplo, em vez de se ter a relação entre professores e seções representada como uma relação separada chamada ENSINA, um designer de banco de dados pode ser tentado a armazenar um conjunto de seção do curso iden�ficadores com cada professor e um conjunto de iden�ficadores de professor com cada seção. (As chaves primárias da seção e do professor são usadas como iden�ficadores.) Sempre que os dados referentes a qual professor orienta são alterados, a atualização foi para ser realizado em dois lugares: no conjunto de professores para a seção, e no conjunto de seções para o professor. Não executar as duas atualizações pode deixar o banco de dados em um estado inconsistente (SILBERSCHATZ et al., 2019). Ao manter apenas um desses conjuntos, ou o conjunto de professores de uma seção ou o conjunto de seções de um professor, evita-se informação repe�da; no entanto, manter apenas um deles complicaria algumas consultas, e não está claro qual dos dois deve-se manter. Alguns �pos de valores não atômicos podem ser úteis, embora devam ser usados com cuidado. Por exemplo, os atributos de valor composto costumam ser úteis, e atributos definidos também são úteis em muitos casos, e é por isso que ambos são suportados no modelo E-R. Em muitos domínios em que as en�dades têm uma estrutura complexa, forçar uma primeira forma de representação normal representa um ônus desnecessário ao programador de aplica�vos, que tem que escrever código para converter dados em formato atômico. Há também a sobrecarga de tempo de execução de conversão de dados de um lado para outra forma atômica. O suporte para valores não atômicos pode, portanto, ser muito ú�l em tais domínios. Na verdade, sistemas de banco de dados modernos suportam muitos �pos de sistemas não-atômicos. 106 27/01/2020 Aula 05 https://iesb-banco-de-dados.webflow.io/unidade-3/aula-05 15/30 Decomposição Usando Dependências Funcionais Na Seção 1, notamos que existe uma metodologia formal para avaliar se um esquema relacional deve ser decomposto. Essa metodologia baseia-se em conceitos de chaves e dependências funcionais. Ao discu�rmos algoritmos para design de banco de dados relacional, precisamos falar sobre relações arbitrárias e seus esquemas, em vez de falarmos apenas sobre exemplos. Lembrando nossa introdução ao modelo relacional, resumimos nossas anotações da seguinte forma: Em geral, usamos letras gregas para conjuntos de atributos (por exemplo). Nós usamos uma letra romana minúscula seguida por uma letra romana maiúscula em parênteses para se referir a um esquema de relação (por exemplo, r (R)). Nós usamos a notação r (R) para mostrar que o esquema é para relação r, com R denotando o conjunto de atributos, mas às vezes simplifica nossa notação usarmos apenas R quando o nome da relação não importarpara nós. Claro, um esquema de relação é um conjunto de atributos, mas nem todos os conjuntos de atributos são esquemas. Quando usamos uma letra grega minúscula, estamos nos referindo a um conjunto de atributos que podem ou não ser um esquema (SILBERSCHATZ et al., 2019). Quando um conjunto de atributos é uma superchave, nós o denotamos por K. Quando uma superchave pertence a um esquema de relação específico, então usamos a terminologia "K é uma superchave de r (R).” Usamos um nome em minúsculas para as relações. Em nossos exemplos, esses nomes são realistas (por exemplo, professor), enquanto em nossas definições e algoritmos, usamos letras únicas, como r. Uma relação, naturalmente, tem um valor par�cular em um dado momento. Referimo-nos a isso como uma instância e usamos o termo “instance of r”. Quando está claro que estamos falando de uma instância, podemos usar simplesmente o nome da relação (por exemplo, r). 107 27/01/2020 Aula 05 https://iesb-banco-de-dados.webflow.io/unidade-3/aula-05 16/30 Chaves e Dependências Funcionais Um banco de dados modela um conjunto de en�dades e relacionamentos no mundo real. Há, geralmente, uma variedade de restrições (regras) sobre os dados no mundo real. Por exemplo, algumas das restrições que devem ser man�das em um banco de dados universitário são: 1. Alunos e professores são iden�ficados exclusivamente por seu ID. 2. Cada aluno e professor tem apenas um nome. 3. Cada professor e aluno é (principalmente) associado a apenas um departamento. ATENÇÃO Uma dependência funcional representa simplesmente qual atributo depende de qual atributo. Por exemplo, podemos dizer que o atributo nome de uma pessoa depende do atributo CPF (único e atômico) da mesma pessoa. Esse conceito é ú�l para entendermos quais são as dependências funcionais que temos em nosso modelo de banco de dados. Fonte: Silberschatz et al. (2019). 108 27/01/2020 Aula 05 https://iesb-banco-de-dados.webflow.io/unidade-3/aula-05 17/30 4. Cada departamento possui apenas um valor para seu orçamento, e apenas um associado construção. Uma instância de uma relação que sa�sfaz todas essas restrições do mundo real é chamada uma instância legal da relação; uma instância legal de um banco de dados é aquela em que as instâncias de relações são instâncias legais. Alguns dos �pos mais usados de restrições do mundo real podem ser representados formalmente como chaves (superkeys, chaves candidatas e chaves primárias) ou como dependências funcionais, que definimos abaixo. Na Seção 2.3, definimos a noção de uma superchave como um conjunto de um ou mais atributos que, tomados cole�vamente, permitem-nos iden�ficar exclusivamente uma tupla. Relatamos essa definição como segue: Seja r (R) um esquema de relação. Um subconjunto K de R é uma superchave de r (R) se, em qualquer instância legal de r (R), para todos os pares t1 e t2 de tuplas no caso de r se t1? = t2, ent˜ao t1 [K]? = t2 [K]. Isso é, não há duas tuplas em qualquer instância legal de relação r (R) pode ter o mesmo valor em conjunto de atributos K. Claramente, se duas tuplas em r não �verem o mesmo valor em K, então O valor K iden�fica exclusivamente uma tupla em r. Considerando que uma superchave é um conjunto de atributos que iden�fica unicamente a tupla, uma dependência funcional nos permite expressar restrições que, unicamente, iden�ficam os valores de certos atributos. Considere um esquema de relação r (R) e deixe ? ⊆ R e? ⊆ R. Dada uma instância de r (R), dizemos que a instância sa�sfaz a dependência funcional? →? se para todos os pares de tuplas t1 e t2 na instância tal que t1 [?] = t2 [?], também acontece que t1 [?] = t2 [?]. Dizemos que a dependência funcional? → mantém no esquema r (R) se cada instância legal de r (R) sa�sfizer a dependência funcional. Usando a notação de dependência funcional, dizemos que K é uma superchave de r (R) se a dependência funcional K → R mantém em r (R). Em outras palavras, K é uma superchave se, para cada instância legal de r (R) e para cada par de tuplas t1 e t2. Dependências funcionais nos permitem expressar restrições que não podemos expressar com superchave. Na Seção 1.2, consideramos o esquema: inst instância 109 27/01/2020 Aula 05 https://iesb-banco-de-dados.webflow.io/unidade-3/aula-05 18/30 (ID, nome, salário, nome do departamento, prédio, orçamento) em que o nome funcional do departamento de dependência → orçamento é válido porque no departamento (iden�ficado pelo nome do departamento) existe um valor de orçamento único. Denotamos o fato de que o par de atributos (ID, nome do departamento) forma uma superchave para o departamento de entrada ao ser escrito: ID, nome do departamento → nome, salário, prédio, orçamento. Vamos usar dependências funcionais de duas maneiras: 1. Testar instâncias de relações para ver se elas sa�sfazem um dado conjunto F de dependências funcionais. 2. Especificar restrições ao conjunto de relações jurídicas. Assim, devemos nos preocupar com apenas as instâncias de relacionamento que sa�sfazem um determinado conjunto de dependências. Se quisermos nos restringir às relações no esquema r (R) que sa�sfazem um conjunto F de dependências funcionais, dizemos que F mantém em r (R). Vamos considerar a instância da relação r da Figura 4, para ver quais dependências funcionais são sa�sfeitas. Observe que A → C está sa�sfeito. Existem duas tuplas Figura 4 - Exemplo de relação Fonte: adaptada de Elmasri e Navathe (2016). 110 27/01/2020 Aula 05 https://iesb-banco-de-dados.webflow.io/unidade-3/aula-05 19/30 que têm um valor A de a1. Essas tuplas têm o mesmo valor C - a saber, c1. Da mesma forma, as duas tuplas com um valor de A2 têm o mesmo valor de C, c2. Lá não existem outros pares de tuplas dis�ntas que tenham o mesmo valor A. A dependência funcional C → A, no entanto, não está sa�sfeita. Para ver que não é, considere o tuplas t1 = (a2, b3, c2, d3) e t2 = (a3, b3, c2, d4). Estas duas tuplas têm o mesmo valor c2, mas eles têm valores A diferentes, a2 e a3, respec�vamente. Assim, nós descobrimos um par de tuplas t1 e t2 de tal forma que t1 [C] = t2 [C], mas t1 [A] t = t2 [A]. Algumas dependências funcionais são consideradas triviais porque estão sa�sfeitas por todas as relações. Por exemplo, A → A é sa�sfeito por todas as relações envolvendo atributo A. Lendo a definição de dependência funcional, literalmente, vemos que, para todas as tuplas t1 e t2 tais que t1 [A] = t2 [A], é o caso que t1 [A] = t2 [A]. Similarmente, AB → A é sa�sfeito por todas as relações envolvendo o atributo A. Em geral, uma dependência funcional da forma? →? é trivial se? ⊆? É importante perceber que uma instância de uma relação pode sa�sfazer algumas dependências que não são necessárias para se manter o esquema da relação. No exemplo da relação de sala de aula da Figura 5, vemos que o número da sala → capacidade é sa�sfeito. No entanto, acreditamos que, no mundo real, duas salas de aula em diferentes prédios podem ter o mesmo número de sala, mas com capacidade de sala diferente. Assim, é possível, em algum momento, ter uma instância da relação de sala de aula em que número da sala → capacidade não seja sa�sfeita (SILBERSCHATZ et al., 2019). Então, não incluiremos quarto número → capacidade no conjunto de dependências funcionais que se mantêm no esquema para a relação de sala de aula. Dado que um conjunto de dependências funcionais F mantém uma relação r (R), é possível inferir que certas outras dependências funcionais também mantenham 111 27/01/2020 Aula 05 https://iesb-banco-de-dados.webflow.io/unidade-3/aula-05 20/30 a relação. Por exemplo, dado um esquema r (A, B, C), se as dependências funcionais A → B e B → C seguram r, podemos inferir que a dependência funcional A → C também deve segurar r. Isso porque, dado qualquer valor de A, pode haver apenas um valor correspondente para B, e para esse valor de B, só pode haver um valor correspondente para C. Estudaremos mais tarde, na Seção 4.1, como fazer tais inferências. Usaremos a notação F + para denotar o fechamento do conjuntoF, ou seja, o conjunto de todas as dependências funcionais que podem ser inferidas dado o conjunto F. Claramente F + contém todas as dependências funcionais em F. Formas Normais A normalização é o processo de minimizar a redundância de uma relação ou conjunto de relações. Redundância em relação pode causar anomalias de inserção, exclusão e atualização. Formulários normais são usados para eliminar ou reduzir a redundância nas tabelas do banco de dados. 1. Primeira Forma Normal - Se uma relação con�ver um atributo composto ou de vários valores, ela violará a primeira forma normal ou uma relação estará na primeira forma normal se ela não con�ver nenhum atributo composto ou de Figura 5 - Dependências funcionais da relação DEPARTAMENTO Fonte: adaptada de Elmasri e Navathe (2016). 112 27/01/2020 Aula 05 https://iesb-banco-de-dados.webflow.io/unidade-3/aula-05 21/30 vários valores. Uma relação está na primeira forma normal se cada atributo nessa relação for um atributo valorizado. 2. Segunda Forma Normal - Para estar na segunda forma normal, uma relação deve estar na primeira forma normal e a relação não deve conter nenhuma dependência parcial. Uma relação está em 2NF se não �ver Dependência Parcial, ou seja, nenhum atributo não primo (atributos que não fazem parte de nenhuma chave candidata) depende de qualquer subconjunto apropriado de qualquer chave candidata da tabela. 3. Terceira Forma Normal - Uma relação está na terceira forma normal se não houver dependência transi�va para atributos não principais, e também se não es�ver na segunda forma normal. Uma relação está em 3NF se pelo menos uma das seguintes condições for válida em toda dependência de função não-trivial X -> Y 113 27/01/2020 Aula 05 https://iesb-banco-de-dados.webflow.io/unidade-3/aula-05 22/30 QUESTÃO OBJETIVA Um banco de dados do mundo real tem muitos esquemas e um número ainda maior de atributos. O número de tuplas pode estar em milhões ou mais. A técnica alterna�va para o projeto de banco de dados indicada neste cenário é chamada de? Esquemas compar�lhados. Esquemas menores. Esquemas maiores. Dependência funcional. Formas Normais. 114 27/01/2020 Aula 05 https://iesb-banco-de-dados.webflow.io/unidade-3/aula-05 23/30 QUESTÃO OBJETIVA O modelo E-R permite que conjuntos de en�dades e conjuntos de relacionamentos tenham atributos com algum grau de subestrutura. Quando criamos tabelas de Projetos E-R que contêm esses �pos de atributos, eliminamos essa subestrutura. Para atributos compostos, deixamos cada componente ser um atributo por direito próprio. Isso é conhecido como? Primeira Forma Normal. Segunda Forma Normal. Terceira Forma Normal. Quarta Forma Normal. Forma Normal de Boyce-Codd. 115 27/01/2020 Aula 05 https://iesb-banco-de-dados.webflow.io/unidade-3/aula-05 24/30 Fechamento O maior bene�cio de u�lizar boas prá�cas de projetos de banco de dados é a maior longevidade do mesmo. Ao criar projetos de bancos de dados devemos nos preocupar não somente com o modelo E-R, mas também com questões relacionadas a esquemas, domínios e formas normais. Isso faz com que a qualidade do banco de dados aumente, deixando-o mais simples para acomodar eventuais mudanças ao longo do ciclo de vida. Nesta aula, você teve a oportunidade de: Aprender a Alterna�va de design: esquemas maiores; Entender os Domínios Atômicos e Primeira Forma Normal; Aprender sobre a Decomposição Usando Dependências Funcionais. 116 27/01/2020 Aula 05 https://iesb-banco-de-dados.webflow.io/unidade-3/aula-05 25/30 ATIVIDADE COMPLEMENTAR O modelo ACID é implementado por vários bancos de dados como o SQL Server, o Oracle, o DB2, o PostgreSQL e o MySQL. Em ciência da computação, ACID (Atomicidade, Consistência, Isolamento, Durabilidade) é um conjunto de propriedades de transações de banco de dados des�nadas a garan�r validade mesmo em caso de erros, falhas de energia, etc. No contexto de banco de dados, uma seqüência de operações de banco de dados que sa�sfaz as propriedades ACID (e estas podem ser percebidas como uma única operação lógica nos dados) é chamada de transação. Por exemplo, uma transferência de fundos de uma conta bancária para outra, mesmo envolvendo várias alterações, como debitar uma conta e creditar outra, é �da como uma única transação. Leia o material abaixo, para entender com mais detalhes como o MySQL realiza essa implementação, principalmente o isolamento de transações representado por I h�p://bit.ly/2Y08AVz 117 http://bit.ly/2Y08AVz 27/01/2020 Aula 05 https://iesb-banco-de-dados.webflow.io/unidade-3/aula-05 26/30 TEORIA E PRÁTICA O backup de um banco de dados é uma parte importante de um projeto. Dessa forma, a escolha correta da estratégia pode ser a diferença entre con�nuar com o negócio em um cenário de desastre ou não. Para isso, vamos descrever uma estratégia de backup diferencial que deve ser feito com um agendamento específico. Portanto, crie uma estratégia baseada nos requisitos: uma cópia completa deve ser feita no domingo às 23:00. Diariamente, de hora em hora, uma cópia diferencial deve ser feita. Ao final do dia, às 23:00, uma cópia incremental deve ser realizada. A estratégia pode ser implementada pela tabela a seguir Dia Hora Tipo Domingo 23:00 Full Segunda 00:00 Diferencial Segunda 01:00 Diferencial Segunda 02:00 Diferencial Segunda 03:00 Diferencial Segunda 04:00 Diferencial Segunda 05:00 Diferencial 118 27/01/2020 Aula 05 https://iesb-banco-de-dados.webflow.io/unidade-3/aula-05 27/30 Segunda 06:00 Diferencial Segunda 07:00 Diferencial Segunda 08:00 Diferencial Segunda 09:00 Diferencial Segunda 10:00 Diferencial Segunda 11:00 Diferencial Segunda 12:00 Diferencial Segunda 13:00 Diferencial Segunda 14:00 Diferencial Segunda 15:00 Diferencial Segunda 16:00 Diferencial Segunda 17:00 Diferencial Segunda 18:00 Diferencial Segunda 19:00 Diferencial Segunda 20:00 Diferencial Segunda 21:00 Diferencial Segunda 22:00 Incremental Repe�r 119 27/01/2020 Aula 05 https://iesb-banco-de-dados.webflow.io/unidade-3/aula-05 28/30 120 27/01/2020 Aula 05 https://iesb-banco-de-dados.webflow.io/unidade-3/aula-05 29/30 ESTUDO DE CASO Imagine a situação de um projeto de banco de dados que deve atender a um cenário de alta concorrência de venda de ingressos. Com isso vamos ter muitos acessos simultâneos e muitas consultas frequentes. Além disso, devemos evitar problemas com redundância de dados e manter a segurança da aplicação. Dessa forma, a u�lização do modelo ACID deve ser considerado em conjunto com algum protocolo de gerenciamento de bloqueios. Além disso, vamos ter que considerar a normalização dos dados e questões de segurança como SQL Injec�on. Descreva esse cenário de projeto de banco de dados. Considere cada uma das propriedades abaixo. Com a propriedade atomicidade as transações são geralmente compostas de várias declarações. Atomicidade garante que cada transação seja tratada como uma única "unidade", tendo pleno sucesso ou falhando completamente: se alguma das instruções que cons�tuem uma transação não for concluída, a transação inteira falhará e o banco de dados permanecerá inalterado. Um sistema atômico deve garan�r a atomicidade em cada situação, incluindo falhas de energia e erros. A consistência garante que uma transação só pode trazer o banco de dados de um estado válido para outro, mantendo invariantes de banco de dados: quaisquer dados gravados no banco de dados devem ser válidos de acordo com todas as regras definidas, incluindo restrições, cascatas, ga�lhos e qualquer combinação dos mesmos. Isso evita corrupção do banco de dados por uma 121 27/01/2020 Aula 05 https://iesb-banco-de-dados.webflow.io/unidade-3/aula-05 30/30 transação ilegal, mas não garante que uma transação esteja correta. A integridade referencial garante o relacionamento da chave primária - chave estrangeira. O Isolamento garante que as transações geralmente sejam executadas simultaneamente (por exemplo, ler e gravar em várias tabelas ao mesmo tempo). O isolamentogarante que a execução simultânea de transações deixe o banco de dados no mesmo estado que teria sido ob�do se as transações fossem executadas sequencialmente. O isolamento é o principal obje�vo do controle de concorrência; dependendo do método usado, os efeitos de uma transação incompleta podem não ser visíveis para outras transações. A durabilidade garante que uma vez que uma transação tenha sido confirmada, ela permanecerá comprome�da mesmo no caso de uma falha no sistema (por exemplo, falta de energia ou erro). Isso geralmente significa que as transações concluídas (ou seus efeitos) são registradas na memória não volá�l. 122 Mapa Conceitual PROJETOS Transações Concorrência Backup ACID Bloqueios Segurança Escalonamento Desempenho lidam utilizam o gerenciam lida com gerenciam 123