Instituto Superior de Engenharia do Porto Engenharia Informática Computadores e Sistemas “Arquitectura de SQL Server 2000” por Pedro Miguel de Almeida Sousa orientador Eng. João Rocha -2001- Instituto Superior de Engenharia do Porto TABELA DE CONTEÚDOS Tabela de Conteúdos _________________________ ii Lista de Figuras _____________________________ iv Prefácio ___________________________________ 1 Agradecimentos _____________________________ 2 Introdução _________________________________ 3 1. Capítulo ________________________________ 4 1.1) Evolução do Microsoft SQL Server: 1989 a 2000 4 1.1.1) O início do SQL Server _____________________ 4 1.1.2) O lançamento do SQL Server ________________ 6 1.1.3) O papel do OS/2 __________________________ 7 1.1.4) SQL Server 4.2 ___________________________ 8 1.1.4.1) Lançamento do OS/2 2.0 adiado____________ 8 1.1.4.2) Lançamento da versão 4.2 ________________ 8 1.1.5) SQL Server para NT _______________________ 9 1.1.6) O final do desenvolvimento conjunto _________ 11 1.1.7) SQL Server 95___________________________ 12 1.1.8) Nome de Código Sphinx ___________________ 12 1.1.9) Finalmente o SQL Server 2000 ______________ 14 2. Capítulo _______________________________ 16 2.1) A Arquitectura do SQL Server 2000 ________ 16 2.1.1) O motor do SQL Server____________________ 16 2.1.2) O Net-Library ___________________________ 17 2.1.3) Open Data Services_______________________ 20 2.1.3.1) Buffers de input e output do ODS __________ 21 2.1.3.2) As Net-Libraries por defeito do ODS ________ 23 2.1.4) O Relational Engine e o Storage Engine _______ 24 2.1.4.1) O Parser de comandos __________________ 25 2.1.4.2) O Optimizer___________________________ 25 2.1.4.3) O SQL Manager ________________________ 26 2.1.4.4) O Expression Manager __________________ 27 2.1.4.5) O Query Executor ______________________ 28 2.1.4.6) Comunicações entre o relational engine e o storage engine ____________________________________ 28 2.1.5) O Access Methods Manager_________________ 30 2.1.6) O Row Operations Manager e o Index Manager _ 30 2.1.6.1) O Row Operation Manager _______________ 31 2.1.6.2) O Index Manager ______________________ 32 2.1.7) O Page Manager e o Text Manager ___________ 35 2.1.8) O Transaction Manager ____________________ 36 Página ii Instituto Superior de Engenharia do Porto 2.1.8.1) Uncommited Read______________________ 37 2.1.8.2) Commited Read _______________________ 38 2.1.8.3) Repeatable Read _______________________ 38 2.1.8.4) Serializable ___________________________ 39 2.1.9) O Lock Manager _________________________ 40 2.1.10) Outros Gestores ________________________ 41 2.2) A Gestão de Memória ___________________ 41 2.2.1) O Buffer Manager e Memory Pools ___________ 42 2.2.2) Acesso a In-Memory Pages _________________ 43 2.2.3) Acesso a Free Pages (Lazywriter) ____________ 43 2.2.3.1) Manter páginas em cache permanentemente _ 45 2.2.4) Checkpoints_____________________________ 45 2.2.5) Acesso a Páginas utilizando o Buffer Manager __ 47 2.2.6) Questões Relacionadas com Grandes Quantidades de Memória 48 2.2.6.1) Read Ahead___________________________ 49 2.2.6.2) Merry-Go-Round Scans __________________ 50 2.2.6.3) O Log Manager ________________________ 51 2.3) Registo de Transacções e Recuperação _____ 52 2.3.1) Locking e Recuperação ____________________ 55 2.3.2) Páginas LSN e Recuperação ________________ 56 2.4) O Kernel do SQL Server e Interacção com o Sistema Operativo ______________________________ 57 2.4.1) Threading e Multiprocessamento Simétrico_____ 58 2.4.2) O Worker Thread Pool _____________________ 60 2.4.3) E/S de Disco no Windows NT/2000 ___________ 62 3. Conclusão ______________________________ 63 Bibliografia________________________________ 64 Página iii Instituto Superior de Engenharia do Porto LISTA DE FIGURAS Figura 1: Esquema Geral da Arquitectura ____________________ 16 Figura 2: Arquitectura Net-Library do SQL Server 2000. ________ 19 Figura 3: Um Nonclustered Index com bookmarks no nível folha. _ 33 Figura 4: Um Clustered Index com os dados no nível folha. ______ 34 Figura 5: O Merry-Go-Round do SQL Server 2000 Enterprise Edition ____________________________________________________ 51 Figura 6: Três fases de recuperação do SQL Server ____________ 55 Figura 7: Comparação do LSN para verificar o processamento da entrada do registo. _____________________________________ 57 Figura 8: Design de múltiplas threads num único processo do SQL Server _______________________________________________ 60 Página iv Instituto Superior de Engenharia do Porto PREFÁCIO Ao longo da minha vida profissional e de estudante, tive contacto com vários sistemas SGBDR. No primeiro curso de informática que fiz, aprendi a trabalhar com dBase e comecei a compreender o modo de criação e estruturação de uma base de dados. O raciocínio e planeamento de uma base de dados é algo que obriga a um estudo profundo de um problema e constitui a base para a implementação de uma boa solução. Posteriormente, com o surgir do sistema operativo Windows, comecei a trabalhar com Microsoft Access, mas, apesar das diferenças para o dBase, ainda faltava algo. A utilização do miniSQL no meu projecto de Bacharelato veio acrescentar o SQL à minha lista de necessidades para um bom SGBDR. Até que, na cadeira de Bases de Dados 2 leccionada pelo Eng. Melo e Castro, conheci o SQL Server na sua versão 7 (beta). Finalmente tinha conhecido uma base de dados que me fornecia ferramentas e funcionalidades à medida do que eu esperava de um bom sistema SGBDR. Fui convidado, nesse mesmo ano, pelo Eng. Melo e Castro, para trabalhar num projecto desenvolvido pelo IDT – Instituto para o Desenvolvimento Tecnológico, tendo como base o SQL Server 6.5. Foi nesse projecto que aprendi o que realmente é o SQL Server e a gostar ainda mais da linguagem SQL. No ano passado obtive uma bolsa de estudos para frequentar os cursos do percurso oficial Microsoft com vista a atingir o grau de Microsoft Certified Systems Engineering, que concluí com sucesso. Actualmente lecciono cursos desse mesmo percurso na área de Sistemas e pretendo obter as certificações em SQL Server 2000. Como gosto de conhecer as tecnologias com que trabalho a fundo, surgiu a ideia deste trabalho em “Arquitectura de SQL Server 2000”. Página 1 Instituto Superior de Engenharia do Porto AGRADECIMENTOS Este projecto só foi possível com a ajuda do meu coordenador, o Eng. João Rocha, que tenho o prazer de ter aceite o meu convite para orientar pela segunda vez um trabalho meu. O facto de já nos conhecermos há alguns anos fez com que o entendimento entre ambos tenha sido mais fácil. Tenho a agradecer a liberdade de escolha e decisão que me deu desde início, quer para a escolha do tema, quer para a abordagem do mesmo. Sem dúvida que o Eng. Melo e Castro teve também um papel importante na escolha deste tema, uma vez que foi ele quem me ensinou as bases para aquilo que sei hoje em dia sobre o SQL Server. Ao Eng. Alexandre Bragança, por me ter esclarecido algumas dúvidas que tive ao longo do projecto. E também à TecniData e ao coordenador de Formação, Nuno Velho, pela ajuda a nível de recolha de informação e esclarecimento de dúvidas e a disponibilidade de máquina para fazer testes e experiências. Página 2 Instituto Superior de Engenharia do Porto INTRODUÇÃO O objectivo deste trabalho é descrever quais os principais componentes do SQL Server 2000, as suas funcionalidades e interligação. Não se pretende uma descrição pormenorizada das suas ferramentas, nem da criação e manutenção de bases de dados, mas sim do que está por trás de tudo isso. Numa primeira fase teremos uma perspectiva histórica da evolução do SQL Server até aos nossos dias. Segue-se uma descrição dos seus componentes base e a sua interligação. Página 3 Instituto Superior de Engenharia do Porto 1. Capítulo 1.1) EVOLUÇÃO DO MICROSOFT SQL SERVER: 1989 A 2000 Em 1985, a Microsoft e a IBM anunciaram um acordo de desenvolvimento conjunto de longo termo de um sistema operativo e outros produtos de software. Este anuncio era o início do OS/2, o sucessor do sistema operativo Microsoft MS-DOS. O OS/2 seria um sistema operativo mais completo e robusto. Iria explorar os novos poderosos computadores pessoais baseados no processador Intel 80286. E iria permitir aplicações multitarefa, cada uma com o seu espaço de endereçamento de memória e cada em execução no safe ring 3 do esquema da Intel four-ring protection scheme do 80286. O OS/2 foi formalmente anunciado em Abril de 1987, com promessas de lançamento para o final desse mesmo ano (O OS/2 versão 1.0 foi lançado a 16 de Dezembro de 1987). Mas logo após a declaração conjunta, a IBM anunciou uma versão especial do OS/2 denominada OS/2 Extended Edition. Esta versão mais poderosa iria incluir de base o sistema operativo OS/2 mais um sistema SQL SGBDR chamado OS/2 Database Manager. O OS/2 Database Manager seria útil para pequenas aplicações e parcialmente compatível com o DB/2 da IBM e com o menos utilizado SQL/DS. 1.1.1) O início do SQL Server Em 1986, a Microsoft era uma empresa “pequena” e os seus produtos eram essencialmente focados em sistema desktop, sendo o MS-DOS o seu principal produto. Aplicações cliente/servidor não faziam parte do desenvolvimento da Microsoft. A gestão de dados estava no seu início e a maioria das pessoas tinha os dados nos seus PCs na folha de cálculo Lotus 1-2-3. O dBase da Ashton-Tate tinha também começado a ser popular. Embora existissem outros produtos, como o Paradox da Ansa Software, o dBase era claramente líder nos produtos de gestão de dados em PCs. Em 1986, a Microsoft não tinha nenhum produto de gestão de dados (Em 1992 atingiu um grande sucesso com o Access e o FoxPro). Página 4 Instituto Superior de Engenharia do Porto A Microsoft virou-se para a Sybase como rampa de lançamento para a entrada no mercado de SGBDs. A primeira versão do DataServer ainda não tinha sido lançada, mas a sua pré-release tinha obtido boa reputação por conter capacidades inovadoras, tais como os stored procedures e triggers, e porque tinha sido desenhada para um novo paradigma da computação: os ambientes cliente/servidor. Uma vez que a capacidade de processamento de transacções do OS/2 não era esperada que fosse alta, a Sybase poderia utilizar o sistema para preparar o mercado para futuras vendas dos sistemas Unix mais poderosos. A Microsoft podia distribuir o produto em volumes mais elevados do que a Sybase; simplesmente não era economicamente possível para o grupo de vendas da Sybase distribuir a primeira versão de uma base de dados aos utilizadores de PCs. Este acordo foi assinado a 27 de Março de 1987 pelo presidente da Microsoft Jon Shirley e pelo co-fundador e presidente da Sybase Mark Hoffman. No mundo das bases de dados em PCs, o dBase da Ashton-Tate ainda tinha a reputação e grande fatia do mercado, apesar do dBase e o DataServer da Sybase oferecerem capacidades extremamente diferentes. Para ganhar aceitação, este novo e altamente capaz SGBD da Microsoft (licenciado pela Sybase) necessitaria de agradar à comunidade dBase. A melhor forma de o fazer era garantir o patrocínio da Ashton-Tate e assim a Microsoft tratou de o conseguir. Em 1988, um novo produto foi anunciado com o complicado nome de Ashton-Tate/Microsoft SQL Server. Apesar de não fazer parte do título do programa, a Sybase tinha um papel importante na informação que acompanhava o produto. Este produto era uma porta de entrada do DataServer no OS/2, comercializado por Ashton-Tate e Microsoft. A Ashton-Tate prometeu que o seu produto dBase IV também iria estar disponível numa edição servidor que iria utilizar as ferramentas de desenvolvimento e linguagem do dBase IV como uma plataforma cliente e que armazenaria os dados no novo SQL Server. Esta nova característica cliente/servidor prometia dar ao dBase novos níveis de poder que permitiriam suportar alguns utilizadores concorrentes que poderiam ser suportados pela sua existente arquitectura de ficheiros-partilhados. A Ashton-Tate, a Microsoft e a Sybase trabalharam em conjunto para lançar o SQL Server no OS/2 (Esta era a primeira vez que o nome SQL Server era utilizado. Posteriormente a Sybase renomearia o seu DataServer para Unix e VMS como Sybase SQL Server. Nos nossos dias o servidor de base de dados da Sybase chama-se Sybase Adaptive Server). A primeira versão do beta do SQL Server da Microsoft e da Ashton-Tate foi lançado no Outono de 1988. Página 5 Instituto Superior de Engenharia do Porto 1.1.2) O lançamento do SQL Server Em 1990, o acordo de marketing e distribuição conjunta com a Ashton-Tate, que pretendia ligar o SQL Server à grande comunidade dBase, simplesmente não estava a funcionar. Até a versão desktop do dBase IV estava bastante atrasada e tinha a reputação de conter vários bugs quando lançada em 1989. A edição servidor, que iria tornar mais simples desenvolver aplicações de alta-performance para SQL Server utilizando dBase, não estava perto de estar pronta. O desenvolvimento de aplicações mono-utilizador, orientadas a registos é muito diferente de desenvolver aplicações para vários utilizadores onde questões de concorrência, consistência e latência de rede tem que ser consideradas. As primeiras tentativas de juntar o SQL Server com as ferramentas do dBase não resultou, pois tratava o SQL Server como se fosse utilizado um método de acesso sequencial indexado (ISAM). Este tipo de acesso era o que os utilizadores do dBase estavam habituados, mas não tirava partido da potencialidades do SQL Server. Para se listar um conjunto de linhas tinham que ser invocados comandos SQL para cada linha. O dBase não tinha ainda a capacidade de saltar de registo para registo, saltar registo para a frente ou para trás, etc. Ainda não existiam os cursores (scrollable cursors). Apenas dois anos antes, a Ashton-Tate era líder de mercado com o seu produto, mas agora atravessava um mau período e tinha que lutar pela sua sobrevivência. A Microsoft lançou o OS/2 LAN Manager com o seu nome, e necessitava do SQL Server para criar uma base de ferramentas de desenvolvimento em arquitecturas cliente/servidor. Assim a Microsoft e a Ashton-Tate terminaram a sua parceria de distribuição e marketing. O SQL Server iria ser reempacotado e relançado como Microsoft SQL Server. A versão 1.1 do Microsoft SQL Server foi lançado no Verão de 1990 como um upgrade da versão 1.0 da Asthon-Tate/Microsoft SQL Server que havia sido lançada em 1989. A versão 1.1 do SQL Server da Microsoft tinha as mesmas características da versão 1.0, tendo no entanto várias correcções de bugs. Mas a versão 1.1 também continha suporte para uma nova plataforma cliente, o Windows 3.0 da Microsoft que havia sido lançado em Maio de 1990. Este suporte para computadores a correr Windows 3.0 foi uma das chaves do sucesso do SQL Server. Página 6 Instituto Superior de Engenharia do Porto 1.1.3) O papel do OS/2 Em 1991, a Microsoft lançou a versão 1.11, uma versão de manutenção. A arquitectura cliente/servidor não estava ainda muito desenvolvida, mas novos convertidos apareciam todos os dias. A nível de vendas não era um grande sucesso, em parte devido ao desapontamento com o OS/2. No entanto, o Windows 3.0 tinha sido um grande sucesso e os utilizadores estavam a migrar de MS-DOS para Windows 3.0, e não para OS/2. Simultaneamente, a Microsoft estava a desenvolver uma versão do SQL Server que servia para sincronizar com o novo produto da Sybase para Unix, versão 4.2. Quando a versão 1.0 da Microsoft foi lançada, o produto da Sybase era designado versão 3.0. Eles acrescentaram algumas características necessárias para o mercado de PCs, tais como tipos de dados de texto e imagem e modos de visualização. A Sybase subsequentemente lançou a versão 4.0 para várias plataformas, seguida da versão 4.2 num lançamento mais limitado. Entretanto, em Maio de 1991, a Microsoft e a IBM anunciaram o fim da sua parceria de desenvolvimento do OS/2. A Microsoft decidiu apostar e concentrar esforços nas novas versões do Windows e aplicações para Windows. A Microsoft estava bem lançada no desenvolvimento de um novo sistema operativo baseado num microkernel denominado internamente como NT (“New Technology”). Este novo sistema era para ser uma futura versão de OS/2 e foi várias vezes denominado OS/2 versão 3.0. Depois da ruptura com a IBM, o projecto NT foi alterado para integrar o interface do sistema Windows e as APIs de programação Win32, e ficou conhecido como Microsoft Windows NT. A primeira versão do Windows NT só era esperada daí a dois anos. O SQL Server seria eventualmente migrado para Windows NT. No entanto, a Microsoft tinha que continuar o desenvolvimento do SQL Server em OS/2, apesar de este agora ser um programa que competia com a Microsoft. Página 7 Instituto Superior de Engenharia do Porto 1.1.4) SQL Server 4.2 A Microsoft estava a desenvolver o SQL Server 4.2 para o futuro OS/2 2.0, a primeira versão de 32-bits do OS/2. Como o SQL Server 4.2 também estava desenhado para ser uma versão de 32-bits, migrar o produto da versão de Unix seria mais fácil uma vez que a segmentação de memória não seria um problema. Na teoria, o SQL Server a 32-bits também seria mais rápido. O principal ganho de performance esperado devia-se ao endereçamento de memória. Uma vez que o endereçamento de memória é tão comum, alguns cálculos rápidos mostravam que as versões de 32-bits poderiam ter um aumento de performance de até 20% ou mais, mesmo que todas as outras operações se mantivessem. 1.1.4.1) Lançamento do OS/2 2.0 adiado A versão do OS/2 2.0 foi subitamente adiada no fim de 1991. De facto, não havia a certeza se a IBM seria capaz de lançar o produto. Assim, a Microsoft teve que migrar novamente o SQL Server para 16-bits e lançá-lo para OS/2 1.3. Esta alteração custou à equipa de desenvolvimento da Microsoft 3 meses. No entanto, outro problema surgiu com o lançamento do OS/2 1.3, uma vez que este só funcionava com máquinas IBM. Na teoria, os fabricantes podiam licenciar uma versão do OS/2 OEM da Microsoft e inclui-lo nos seus produtos, mas tal não aconteceu e os pedidos de OS/2 desceram. Pela primeira vez, a Microsoft lançou um produto denominado OS/2 versão 1.3, com o nome de código Tiger. O Tiger incluía o SQL Server e o LAN Manager, minimizando o problema do produto estar a ser lançado para um sistema operativo morto. 1.1.4.2) Lançamento da versão 4.2 O SQL Server versão 4.2 entrou em fase beta no Outono de 1991, e em Janeiro de 1992, o CEO da Microsoft, Bill Gates, anunciou formalmente o produto numa conferência para programadores de SQL Server em San Francisco. A versão 4.2 tinha sido na realidade um esforço de desenvolvimento conjunto entre a Microsoft e a Sybase. O motor da base de dados tinha sido migrado de Unix da Página 8 Instituto Superior de Engenharia do Porto versão 4.2, com os engenheiros da Microsoft e da Sybase a trabalhar em conjunto na migração e correcção de erros. Adicionalmente, a Microsoft ainda produziu bibliotecas para interface cliente de MSDOS, Windows e OS/2, e pela primeira vez incluiu uma ferramenta de administração com um GUI Windows. O código fonte do motor da base de dados foi adicionado nas instalações da Sybase, com ficheiros a serem transferidos via modem e fitas magnéticas. O SQL Server 4.2 foi lançado em Março de 1992. As críticas eram boas e o feedback dos clientes era positivo. Faltava o lançamento de uma versão de 32-bits do SQL Server. 1.1.5) SQL Server para NT O desenvolvimento de uma versão completa de 32-bits nunca foi abandonado pela Microsoft. Nos inícios de 1992, a equipa de desenvolvimento da Microsoft tinha alguns problemas a resolver. Por um lado, tinha os seus clientes baseados em OS/2, mas esses mesmos clientes tinham deixado clara a necessidade de uma versão de 32-bits. A ideia era claramente lançar uma versão para Windows NT, pois esse sistema operativo representava o futuro. Seria a solução de sistema operativo de grande porte da Microsoft, e de um ponto de vista de desenvolvimento, apresentava uma série de vantagens sobre o OS/2, incluindo I/O assíncrono, multiprocessamento simétrico e portabilidade para arquitecturas RISC. Embora a Microsoft tenha decidido em 1991 retornar a versões de 16-bits do SQL Server, o desenvolvimento de uma versão de 32-bits não parou. Aquando do lançamento do OS/2 2.0, os testes das versões de 16-bits e 32-bits do SQL Server não tinham a performance esperada. Aliás a versão de 16-bits era mais rápida no Tiger (OS/2 1.3) Chegou-se a uma etapa em que o desenvolvimento de duas versões, uma para OS/2 e outra para NT, complicava o desenvolvimento. Em primeiro lugar, aumentar o número de pessoas da equipa de desenvolvimento era uma má solução (normalmente representava o problema e não a solução no desenvolvimento de software). O desenvolvimento para os dois sistemas iria necessitar da construção de um nível (camada) de abstracção, o que levaria muito tempo de reengenharia do produto, além de que não se iria tirar partido das características e potencialidades dos dois sistemas. Assim foi decidido parar o desenvolvimento da versão para OS/2 e concentrar os esforços de desenvolvimento para fazer evoluir a versão para Windows NT. Página 9 Instituto Superior de Engenharia do Porto Por esta altura a Sybase estava a trabalhar numa nova versão do seu produto, que iria receber o nome de System 10. Existia assim uma agenda de prioridades diferentes entre a Microsoft e a Sybase. Por um lado a Sybase necessitava do sucesso do seu novo System 10, a Microsoft apostava na migração do seu produto para NT o mais rápido possível. Assim a Microsoft migrava o SQL Server de OS/2 para NT, ficando a Sybase com os clientes que pretendiam continuar em OS/2 e a Sybase teria no NT um sistema operativo que seria dos primeiros a suportar o System 10. A equipa de desenvolvimento concentrou-se apenas na migração para NT, tendo como um dos principais objectivos o seu lançamento logo 90 dias após o lançamento de Windows NT. Não houve qualquer preocupação em criar uma layer de abstracção, uma vez que só desenvolviam para uma plataforma, o NT. O próprio sistema operativo estava desenhado para ser portável, suportando diferentes tipos de arquitecturas; ou seja, a layer de abstracção do SQL Server seria o próprio NT. O SQL Server estaria intimamente ligado ao NT a nível de gestão, tal como o lançamento de eventos, a instalação baseada num serviço e a exportação de estatísticas para o Performance Monitor do Windows NT. A utilização de DLLs pelo NT, permitiu a criação de um suporte que permitisse aos programadores a criação de aplicações que estendessem as capacidades do SQL Server. No final, esta nova versão do SQL Server acabou por ser mais do que uma simples migração, uma vez que todo o kernel foi rescrito para a API Win32. Um outro objectivo era a capacidade de migração das versões de OS/2 para esta nova versão e sistema operativo. Era necessário que existisse uma forma de migração das aplicações SQL Server versão 4.2 para OS/2 sem alteração para a nova versão a correr em NT. Uma das características do NT era a capacidade de dual-boot com OS/2 ou MS-DOS. A nova versão do SQL Server tinha que permitir a leitura e escrita de bases de dados directamente da versão OS/2. As alterações foram efectuadas apenas no núcleo interno do SQL Server, acrescentando novas características a nível de gestão, suporte de rede e extensões, sem alterar o núcleo externo do motor da base de dados o que iria comprometer a compatibilidade. Em Julho de 1992, a Microsoft distribuiu numa conferência para programadores sobre Windows NT uma versão pré-beta do Windows NT e, apesar do SQL Server ainda não se encontrar em fase beta, disponibilizou bibliotecas que permitissem ao programadores iniciar a migração de OS/2 ou Windows 16-bits para NT. Para dar ênfase à compatibilidade entre esta versão e a versão 4.2 baseada em OS/2, a Microsoft designou esta nova versão como SQL Server 4.2. Página 10 Instituto Superior de Engenharia do Porto Em Outubro de 1992, a Microsoft lançou a primeira versão beta do SQL Server para Windows NT. Esta versão beta apresentava quase todas as características de um produto final e fornecia versões Win32 completas de todos os componentes. Foi lançada em 100 sites beta, o que era algo sem precedentes para uma base de dados: normalmente seriam aproximadamente 10. Em Dezembro de 1993, quase todos os clientes baseados em OS/2 tinham já migrado para esta nova versão e para o Windows NT. Isto deveu-se não só ao facto da migração ser feita quase sem problemas e sem alterações, mas principalmente porque apresentavam um ganho de performance. 1.1.6) O final do desenvolvimento conjunto O sucesso da Microsoft levou a que as relações com a Sybase de deteriorassem, uma vez que desde 1987 até 1993 muito havia mudado a nível competitivo e de mercado. Ambas as empresas haviam crescido imenso no mercado e as razões para o seu acordo inicial tinham deixado de existir. Também a equipa de desenvolvimento do SQL Server tinha crescido ao longo dos anos, de um grupo de algumas pessoas para mais de 50. Esta equipa tinha os conhecimentos e experiência de desenvolvimento para Windows NT que era necessária para desenvolver ainda mais o SQL Server, mas as condições do acordo com a Sybase impediam que a Microsoft implementasse novas características ou alterações sem o acordo da Sybase. A Sybase tinha necessidades e prioridades diferentes das da Microsoft, nomeadamente algumas novas características que se poderiam implementar, tais como integração de messaging utilizando MAPI e que não eram possíveis pois eram específicas dos sistemas operativos da Microsoft. As duas versões do SQL Server, para Windows NT da Microsoft e para Unix/NetWare/VMS da Sybase estavam a competir no mesmo mercado, levando a perda de clientes e vendas por parte da Sybase. Como seria de esperar, a 12 de Abril de 1994 a Sybase e a Microsoft anunciaram o fim do seu acordo. Cada empresa iria desenvolver separadamente a sua versão do SQL Server. Estava aberto o caminho para acrescentar novas características ao produto e mudar o rumo do desenvolvimento. Ambas as versões teriam compatibilidade com as versões anteriores, mas a partir deste ponto o seu desenvolvimento divergiu e as novas versões apresentaram características diferentes. Começavam assim a competir directamente uma com a outra. Página 11 Instituto Superior de Engenharia do Porto 1.1.7) SQL Server 95 No início de 1995, estava planeado que a nova versão do SQL Server acrescentasse novas características do System 10, mas o fim do acordo de desenvolvimento veio alterar este cenário. O lançamento do System 10 no final desse ano fez com que a Microsoft perdesse clientes. Iniciava-se uma corrida para o lançamento de uma nova versão com muitas características novas e melhorias a nível de performance. Foi denominada SQL95 adoptando a designação da nova versão do Windows a ser lançada por essa altura. Nesta altura o problema de replicação estava na moda, tornando-se uma característica chave desta versão. Os scrollable cursors, que se achava necessário incluir, eram outra característica importante. Uma outra característica a ser incluída passava por um novo sistema de gestão com o nome de código StarFighter (conhecido hoje como SQL Server Enterprise Manager) que também estava em desenvolvimento. A primeira versão beta foi lançada nos finais de Outubro de 1994, ainda com o StarFighter incompleto, mas com o motor da base de dados final. A 14 de Junho de 1995, o produto final era lançado com o nome de SQL Server 6.0. Logo após o lançamento desta versão, começou o trabalho numa nova versão que iria ser conhecida com SQL Server 6.5. Devido ao lançamento de uma versão como a 6.0, cheia de novas características, algumas funcionalidades foram adiadas e novas necessidades surgiram. Por exemplo, a explosão da Internet e do Data Warehousing. Estas características seriam incluídas no SQL Server 6.5. A primeira versão beta foi lançada a 15 de Dezembro de 1995 e a versão final em Abril de 1996. 1.1.8) Nome de Código Sphinx Ainda antes do lançamento do SQL Server 6.5 uma equipa de desenvolvimento já preparava separadamente o futuro. Em 1993, a Microsoft havia decidido que as bases de dados eram uma área chave e, em finais de 1994, começou a contratar profissionais da DEC e de outras grandes companhias para trabalhar com as equipas de desenvolvimento do Microsoft JET e do SQL Server numa nova geração de tecnologias de bases de dados. Durante 1995, o período de lançamento do SQL Server 6.0 e 6.5, esta equipa construiu um novo motor de consultas (query processor) que daria origem ao Microsoft Data Engine (MSDE). Página 12 Instituto Superior de Engenharia do Porto O desenvolvimento do MSDE foi complementado com o desenvolvimento simultâneo do OLE BD, que permitiu que elementos base do SQL Server fossem desenvolvidos como componentes independentes. Estes componentes podiam assim comunicar utilizando a layer de OLE BD. Nos finais de 1995, o novo componente de processamento de consultas foi integrado no código base do SQL Server e o desenvolvimento do novo SQL Server, denominado Sphinx, começou. O desenvolvimento desta nova versão tinha um objectivo primordial: rescrever o motor da base de dados de forma a que o SQL Server pudesse ser escalável até às necessidades dos utilizadores. Isto significava capacidade para tirar partido de maior quantidade e velocidade dos processadores e da memória que o sistema operativo conseguisse suportar. Este crescimento implicava a capacidade de suportar alterações aos seus componentes de uma forma modular. Também seria alterado de forma a correr em plataformas mais leves como desktops e portáteis. Existiam dois objectivos principais: • Full row-level locking1 com um novo gestor de smart lock; • Um novo motor de processamento de queries que permitisse tecnologias como processamento de queries heterogéneas distribuídas e processamento eficiente de ad hoc queries (necessário para a Internet e Data Warehousing). A versão beta 1 do SQL Server 7.0 foi lançada numa edição limitada nos finais de 1997, sendo lançado em Dezembro de 1997 a versão beta 2. Devido à nova arquitectura, todas as bases de dados e estruturas de dados contidas tiveram que ser completamente reconstruídas no processo de upgrade. Havia um compromisso com os clientes de que as suas bases de dados seriam completamente actualizáveis na migração da versão 6.5 para a versão 7.0. Foi instituído um programa designado 1K Challenge, em que 1000 clientes foram convidados a enviar cópias das suas bases de dados para a equipa de desenvolvimento para serem migradas para a versão 7.0. Foi instalado um laboratório para efectuar estas migrações e onde equipas de desenvolvimento convidadas efectuaram testes de compatibilidade das suas aplicações com a nova versão. Estes testes permitiram que a detecção e correcção de problemas com a nova versão ainda antes dela ser lançada como 1 Mecanismo de bloqueio. 2 Comandos de interrogação à base de dados. Página 13 Instituto Superior de Engenharia do Porto produto final e a discussão de estratégias para tirar partido das novas funcionalidades do produto. Em Junho de 1998, foi lançada a versão beta 3 a partir do site SQL Server Web, conjuntamente com exercícios que demonstravam as novas características e capacidades do produto. A 16 de Novembro de 1998, na COMDEX em Las Vegas foi publicamente apresentado o novo produto, que seria lançado no mercado em Janeiro de 1999. 1.1.9) Finalmente o SQL Server 2000 Como seria de esperar, o desenvolvimento do SQL Server não parou por aqui. Muitas características que não tinham sido incluídas na versão 7.0 passariam a fazer parte da nova versão em desenvolvimento. Nesta altura estavam planeado duas novas versões, o Shiloh que seria uma actualização da versão 7.0 para 7.5 e o Yukon que seria a próxima grande versão a ser lançada. As expectativas em relação ao Shiloh não eram muitas, uma vez que era esperado que a maior parte dos clientes não instalassem esta versão por a considerarem uma versão que necessitaria de alguns service packs até atingir estabilidade. No entanto, isto não se verificou. Na realidade o SQL Server 7.0 recebeu uma boa aceitação e a maior parte dos problemas pode ser resolvido através de alguns Service Packs simples, não existindo necessidade para uma versão .5. Inclusive os clientes pediam novas características há muito prometidas e sempre adiadas, como suporte para cascade deletes e updates, melhorias a nível de partitioned views. Existia também um desafio lançado pela Oracle Corporation que evidenciava características que estavam incluídas no Oracle e não no SQL Server. Assim foi decidido que a versão 7.5 seria não apenas uma actualização da versão 7.0, mas uma nova versão completa, acrescentando novas características. Com um período de desenvolvimento de 18 meses, a objectivo inicial passava por melhorias a nível de performance (o objectivo era um aumento de pelo menos 20%). Uma vez que era um objectivo pouco concreto, a equipa de desenvolvimento decidiu concretizar essa melhoria para o processamento de queries do SAP R3, o que implicaria melhorias também para muitas outras aplicações. Na apresentação do Windows 2000 em Fevereiro de 2000, San Francisco, foram anunciados os resultados do teste efectuado com 6700 utilizadores no Sales and Distribution benchmark do SAP R3 em comparação com o SQL Server 7.0 que apenas atingiu os 4500 utilizadores (testes realizado com o Página 14 Instituto Superior de Engenharia do Porto mesmo hardware, uma máquina com 8 processadores Pentium-III 550 MHz). Isto representava uma melhoria de 48%, superando os objectivos iniciais. Secretamente uma nova característica estava a ser acrescentada ao SQL Server que não foi anunciada, nem incluída nas primeiras versões beta. Só aquando do lançamento do Windows 2000 é que foi revelado a inclusão de partitioned views no SQL Server e que tinham permitido atingir as melhorias da performance anunciadas. Esta característica foi denominada internamente por Coyote. A versão Beta 1 do SQL Server foi lançada em Setembro de 1999 apenas para um grupo restrito de clientes e beta testers. Pouco depois a Microsoft anunciava que o nome definitivo do produto seria SQL Server 2000. Existiam duas razões para esta alteração de nome. Em primeiro lugar, as características deste produto faziam com que não fosse apenas uma versão intermédia, mas um produto completamente novo. Em segundo lugar, se o produto adoptasse o nome de versão 8.0, seria o único produto do BackOffice que não utilizava o nome 2000. Para se enquadrar com os restantes produtos da mesma linha foi decidido que adoptaria as mesmas linhas guia. No entanto, internamente esta versão ainda utiliza o número 8.00.194 visível através da função @@VERSION. Do ponto de vista do utilizador esta versão introduziu uma série de novas funcionalidade, ainda mais do que a sua antecessora. A versão 7.0 teve várias alterações, a rescrita do motor da base de dados e outras alterações internas, mas a nível externo as alterações ou novidades foram poucas. O SQL Server 2000 acrescentou novas funcionalidades a nível de suporte multilíngue e alterações a objectos tais como constraints de tabelas, vistas, triggers. Devido às poucas alterações a nível do motor interno, foram apenas previstas duas versões beta, sendo a Beta 2 lançada em Abril de 2000. A 6 de Agosto de 2000, a equipa de desenvolvimento deu o código por terminado e compilou a versão final, que entraria em produção três dias mais tarde. Se analisarmos a história deste produto vemos que ela passa por uma série de alterações e acrescentar de características que os utilizadores necessitam, sendo previsível que no futuro sejam lançadas novas versões que devem estar hoje em desenvolvimento. Página 15 Instituto Superior de Engenharia do Porto 2. Capítulo 2.1) A ARQUITECTURA DO SQL SERVER 2000 Este capítulo pretende descrever quais os componentes da arquitectura do motor do SQL Server 2000. 2.1.1) O motor do SQL Server A Figura 1 mostra um esquema geral da arquitectura. A partir deste esquema serão descritos os vários componentes estudados para este trabalho. Figura 1: Esquema Geral da Arquitectura Página 16 Instituto Superior de Engenharia do Porto 2.1.2) O Net-Library O Net-Library (frequentemente denominado Net-Lib) constitui um nível (camada) de abstracção do SQL Server que lhe permite o suporte de vários protocolos de comunicações de rede. Assim, a forma de escrita e leitura de dados do SQL Server é feita através desta camada que comunica com os protocolo utilizados através dos drivers que os suportam. Esta implementação permite que os SQL Server possa comunicar com vários tipos de protocolos, além de possibilitar a alteração de suporte para novos protocolos ou alterações aos já suportados. A Net-Library é basicamente um driver para um mecanismo de comunicação entre processos (interprocess communication – IPC). Todo o código do SQL Server, inclusive o Net-Library, utiliza chamadas ao subsistema Win32 da Microsoft. O SQL Server utiliza um interface interno comum entre os Open Data Services (ODS) – que fazem a gestão do utilização de rede – e cada driver da NetLibrary. Se existir necessidade de utilizar um protocolo de comunicações completamente novo, o seu suporte em SQL Server 2000 passa pela criação de um simples driver Net-Library que o suporte. Adicionalmente, podem ser chamados vários drivers NetLibrary simultaneamente, um para cada mecanismo IPC em uso. O SQL Server constitui a camada de abstracção Net-Library em ambas as máquinas (cliente e servidor), tornando possível o suporte a vários clientes simultaneamente em redes diferentes. Os sistemas operativos Windows, desde as versões NT/2000 ou 9x, suportam a utilização de várias pilhas de protocolos simultaneamente; o NetLibrary baseia-se nos mesmos princípios. Existem dois aplicativos: o Client Network Utility e o Server Network Utility que permitem escolher e configurar o SQL Server. O SQL Server 2000 tem duas bibliotecas principais de NetLibrary: Super Socket e Shared Memory. Além destas duas, existem ainda bibliotecas consideradas secundárias que permitem o suporte a TCP/IP, Named Pipes, IPX/SPX, etc. O OLE BD Provider para SQL Server, o driver de ODBC do SQL Server, o DB-Library e o motor da base de dados comunicam directamente com estas duas bibliotecas principais. Comunicações entre dois computadores são efectuadas pelo Super Socket, enquanto que comunicações locais, como por exemplo entre uma aplicação e uma instância do SQL Server no mesmo computador utilizam memória partilhada (Shared Memory suportado em todas as plataformas Windows). Página 17 Instituto Superior de Engenharia do Porto O Super Socket Net-Library é constituído por dois componentes: • Communication path Æ Se o cliente está configurado para comunicar por TCP/IP Sockets ou NWLink IPX/SPX, o Super Socket Net-Library chama directamente a API Windows Socket 2 para o processo de comunicações entre a aplicação e a instância do SQL Server. Se o cliente estiver configurado para comunicar sobre Named Pipes, Multiprotocol, AppleTalk ou conexão Banyan Vines, um sub-componente do Super Socket Net-Library chamado Net-Library router invoca a biblioteca secundária necessária e reencaminha todos os pedidos para esta. • Encryption layer Æ A encriptação é implementada através da API Secure Sockets Layer (SSL). O nível de encriptação, de 40 bits ou 128 bits, depende da versão do Windows nos computadores com a aplicação e o servidor de SQL. A utilização de encriptação pode afectar a performance de rede não só porque é necessário processamento adicional para encriptar e desencriptar as comunicações mas também devido ao tempo de retorno extra necessário entre o cliente e o servidor sempre que uma conexão é efectuada. As comunicações Shared Memory Net-Library são inerentemente seguras sem a necessidade de encriptação. A Shared Memory Net-Library nunca participa em comunicações entre computadores. A área de memória partilhada entre processos de aplicações e o processo do motor da base de dados não pode ser acedida por nenhum outro processo do Windows. Por questões de compatibilidade com versões anteriores do SQL Server, a Multiprotocol Net-Library continua a suportar a sua própria encriptação. Esta encriptação é especificada independentemente da encriptação SSL e é implementada por chamadas à API de encriptação Windows RPC. A Figura 2 mostra a arquitectura do Net-Library do SQL Server 2000. A distinção entre os mecanismos de IPC e os subsequentes protocolos de rede é importante. Os mecanismos de IPC utilizados pelo SQL Server incluem Named Pipes, RPC, SPX e Windows Sockets. Os protocolos de rede utilizados incluem TCP/IP, NetBEUI, Shared Memory, NWLink IPX/SPX, Banyan Vines SPP e AppletTalk ADSP. Duas bibliotecas Net-Library, Multiprotocol e Named Pipes, podem ser utilizadas simultaneamente sobre vários protocolos de rede (NetBEUI, TCP/IP, NWLink IPX/SPX). Página 18 Instituto Superior de Engenharia do Porto Figura 2: Arquitectura Net-Library do SQL Server 2000. O SQL Server 2000 sobre Windows NT/2000 suporta a personificação de contextos de segurança para permitir autenticação de acesso integrada chamada Windows Authentication operando sobre os protocolos de rede que suportam autenticação entre cliente e servidor. Este tipo de conexões são denominadas trusted connections e são suportadas pelo SQL Server 2000 utilizando qualquer Net-Library disponível. Em vez de necessitar de um utilizador/password a cada ligação ao servidor, o SQL Server pode personificar o contexto de segurança do utilizador a executar a aplicação que efectua o pedido de conexão. Se esse utilizador tiver privilégios suficientes (ou fizer parte de um grupo de utilizadores de Página 19 Instituto Superior de Engenharia do Porto Windows NT/2000 que tenha), a conexão é estabelecida. Esta tecnologia não está disponível se o SQL Server estiver a ser utilizado em Windows 98. Nesta situação é necessário especificar um utilizador e uma password no próprio SQL Server. 2.1.3) Open Data Services Os Open Data Services (ODS) funcionam como o gestor de clientes do SQL Server, constituindo basicamente um interface entre as Net-Libraries do servidor e aplicações server-based, incluindo o SQL Server. O ODS faz a gestão da rede: escuta pedidos de novas conexões, termina conexões falhadas, confirma pedidos, coordena serviços de threading do SQL Server e retorna resultados de pedidos, mensagens, e valores de estado aos clientes. Os clientes e servidores de SQL Server comunicam utilizando um protocolo privado denominado Tabular Data Stream (TDS). O TDS contém tokens que descrevem nomes de colunas, tipos de dados, eventos e valores de estado na “conversa” entre cliente e servidor. O servidor notifica o cliente que está a enviar um conjunto de resultados (result set), indica o número de colunas e tipos de dados dos resultados, etc. – tudo codificado em TDS. Nem cliente nem servidor escrevem directamente para TDS. Em vez disso, os interfaces OLE-DB, ODBC e DB-Library no cliente emitem em TDS utilizando uma implementação cliente de Net-Library. O ODS aceita novas conexões e se o cliente inesperadamente desligar (por exemplo, se um utilizador fizer um reboot ao computador em vez de terminar pacificamente a aplicação), o ODS automaticamente liberta recursos como por exemplo os locks (bloqueios) desse cliente. O ODS pode ser utilizado para estender as funcionalidades do SQL Server através de extended stored procedures. O código da API do ODS estava anteriormente guardado externamente numa DLL (opends60.dll). No SQL Server 2000, para melhorar o desempenho dos mecanismos internos do SQL Server que necessitavam de extended procedures pré-carregados, o código que constitui o ODS está internamente no motor do SQL Server. DLLs com extended stored procedures tem que incluir o opends60.dll, que contém stubs para aceder às rotinas reais do ODS internamente no SQL Server. 3 Arquitectura baseada em duas camadas: servidor e cliente. 4 Programa baseado numa rotina pequena que substitui um programa mais longo, possivelmente para ser carregado mais rápidamente ou remotamente. Por exemplo, um programa que utilize RPC é compilado com stubs que substituem o (continua) Página 20 Instituto Superior de Engenharia do Porto 2.1.3.1) Buffers de input e output do ODS Após o SQL Server colocar o conjunto de resultados num buffer de output de rede (write buffer) que tem tamanho igual ao tamanho do pacote do protocolo configurado, o Net-Library, é enviado para o buffer do cliente. O primeiro pacote é enviado logo que o buffer esteja cheio ou se um conjunto de resultados completo couber num único pacote quando o batch tiver finalizado. Um batch é considerado um conjunto de um ou mais comandos enviados ao SQL Server para serem processados (parsed) e executados em conjunto. Por exemplo, se estivermos a utilizar o OSLQ.EXE, um batch é a colecção de todos os comandos que estão antes de uma instrução GO. Em algumas operações excepcionais (como a que fornece informação de progresso de um dump da base de dados ou mensagens DBCC), o output buffer é enviado antes de estar completamente cheio ou a operação de batch completa. O SQL Server tem dois buffers de input (read buffers) e um buffer de output por cliente. O double-buffering é necessário para as leituras porque o SQL Server lê sequências (streams) de dados da conexão do cliente e também tem que escutar por possíveis mensagens (attention) do cliente. Mensagens deste tipo podem ser interpretadas como dados “out-of-band”5, embora possam ser enviados através de protocolos de rede que não tem explicitamente um canal “out-of-band”. Foram efectuadas experiências, pela equipa de desenvolvimento, de double-buffering e técnicas assíncronas para os buffer de output mas não houve uma melhoria de performance substancial. Apesar das escritas não serem assíncronas, o SQL Server não necessita ultrapassar a cache do sistema operativo para isso, tal como faz para escritas em disco. Uma vez que o sistema operativo fornece cache para escritas na rede, as acções de escrita parecem ser imediatas sem uma latência significativa. Se, no entanto, são emitidas várias acções de escrita para o mesmo cliente e o cliente não está a ler dados da rede, a cache de rede ficará eventualmente cheia e as escritas bloqueiam. Desde que a aplicação cliente esteja a processar resultados, o SQL Server contém algumas filas de cache prontas para o processamento programa que requer um procedimento remoto. O stub aceita o pedido e depois reenvia-o (através de outto programa) para o procedimento remoto. Quando esse procedimento acabar o seu serviço, retorna o resultado ou outro estado ao stub que o passa ao programa que fez o pedido. 5 Canal lógico de transmissão independente associado a cada par de sockets conectados. Utilizado para transmissão de dados de controlo. Página 21 Instituto Superior de Engenharia do Porto da conexão do cliente. Mas se a fila do cliente está cheia com resultados e o cliente não os processa, o SQL Server deixa de os enviar e as escritas de rede para esse cliente tem que esperar. Uma vez que o SQL Server tem apenas um buffer de output por cliente, os dados não podem ser enviados para a conexão desse cliente enquanto ele não ler a informação da rede de forma a libertar espaço para que a operação de escrita possa finalizar (as acções de escrita para os restantes clientes não são afectadas por este bloqueio). Escritas para a rede bloqueadas podem também afectar os locks. Por exemplo, se READ COMMITTED está a ser utilizado (opção por defeito), um lock partilhado pode normalmente ser libertado depois do SQL Server ter completado o page scan6. (Locks exclusivos utilizados para modificar dados tem que ser sempre mantidos até ao fim da transacção para garantir a possibilidade de rollback da transacção). No entanto, se a busca encontrar mais dados relativos e o output buffer não estiver livre, o scan vai bloquear. Quando a escrita para a rede anterior acabar, o output buffer fica livre e o scan pode continuar. Se uma conexão de um cliente demorar o processamento de resultados que lhe são destinados, podem existir problemas de concorrência porque os locks são mantidos mais tempo do que contrariamente seriam. Ocorre uma espécie de acção em cadeia - se o cliente não leu uma série de pacotes de rede, posteriores escritas do output buffer do lado do servidor de SQL têm que esperar porque a fila está cheia. Uma vez que o output buffer não está disponível, o scan por dados pode também ser suspenso por que não existe espaço para adicionar os resultados. Uma vez que o scan foi suspenso, qualquer lock nos dados não pode ser libertado. Em resumo, se uma aplicação cliente não processar convenientemente e atempadamente os resultados, a concorrência na base de dados pode ser afectada. O tamanho do output buffer também pode afectar a velocidade a que os clientes recebem o primeiro conjunto de resultados. Como foi mencionado anteriormente, o output buffer é enviado quando o batch ( e não simplesmente o comando) acabar, ainda que o buffer não esteja cheio. Se existem duas consultas no mesmo batch e a primeira apenas tem um conjunto de dados pequeno, os seus resultados não são enviados para o cliente até que a segunda consulta acabe ou forneça dados suficientes para encher o buffer. Se ambas as consultas se processarem rapidamente, esperar pelos resultados não é problemático. Mas suponhamos que a primeira consulta é rápida e a segunda não. Adicionalmente suponhamos que 6 Consulta de dados, sem utilização de índices, numa página que implica uma passagem completa por toda a página. Página 22 Instituto Superior de Engenharia do Porto a primeira consulta retorna 1000 bytes de dados. Se o tamanho do pacote de rede for 4096 bytes, os resultados da primeira consulta tem que aguardar que os resultados da segunda consulta o encham. A solução óbvia aqui seria colocar o primeiro comando no seu próprio batch ou diminuir o tamanho do pacote de rede. A primeira solução parece o ideal, uma vez que é difícil afinar uma aplicação para determinar qual o tamanho ideal de pacote para cada comando. Claro que isto não significa que cada comando deva correr no seu próprio batch, muito pelo contrário. Em circunstâncias normais, o agrupamento de múltiplos comandos num único batch é mais eficiente e recomendável porque reduz o número de handshakes entre cliente e servidor. 2.1.3.2) As Net-Libraries por defeito do ODS No lado do servidor, e ODS espelha as funções do ODBC, OLE DB ou DB-Library no cliente. As chamadas a uma aplicação servidor ODS permitem descrever e enviar conjuntos de resultados, converter valores entre tipos de dados, controlar o contexto de segurança associado com uma conexão específica a ser gerida e lançar eventos de erro e mensagens às aplicações cliente. O ODS utiliza um modelo de programação orientada a eventos. Pedidos de servidores e dos clientes disparam eventos a que o servidor deve responder. Utilizando a API do ODS, podem ser criadas rotinas personalizadas, chamadas event handler, para cada tipo possível de evento. Essencialmente, o ODS conduz a aplicação servidora invocando os seus event handlers personalizados como resposta aos pedidos dos clientes. As aplicações do servidor ODS respondem aos seguintes eventos: • Eventos de conexão Æ Quando uma conexão ocorre, o SQL Server inicializa uma verificação de segurança para determinar se a conexão é permitida. Outras aplicações ODS, tais como o gateway do DB/2, têm os seus próprios handlers de validação (logon) que determinam se as conexões são permitidas. • Eventos de linguagem Æ Quando um cliente envia um comando, tal como uma instrução SQL, o SQL Server passa este comando para o parser. Uma aplicação ODS diferente, 7 Estabelecimento de um acordo entre as partes envolvidas numa comunicação ou transacção de dados. Neste acordo, são estabelecidos parâmetros de comunicação, tais como: velocidade de transmissão, tamanho do pacote (trama), etc. Página 23 Instituto Superior de Engenharia do Porto tal como um gateway, iria instalar o seu próprio handler que aceitaria e executaria o comando. • Eventos de RPC (Remote Procedure Call) Æ Estes eventos ocorrem de cada vez que um cliente ou servidor SQL Server dirige um pedido de processamento remoto ao ODS. O ODS também gera eventos relacionados com certas actividades dos clientes e das aplicações. Estes eventos permitem a uma aplicação servidor de ODS responder a alterações ao estado da conexão do cliente ou do servidor ODS. Adicionalmente ao controlo de conexões, o ODS faz a gestão de processos (threads) e fibers para o SQL Server (o SQL Server deixa o sistema operativo fazer a gestão das threads no sistema. No entanto, em situações extremas de sobrecarga do processador, o SQL Server pode assumir esse papel baixando o nível de processamento para um nível mais próximo do micro-kernel e utilizando processos mais pequenos denominados fibers). Toma conta da criação e terminação de processos e disponibiliza o processo para o User Mode Scheduler (UMS). Uma vez que o ODS é um interface aberto com uma API de programação completa e um conjunto de ferramentas, a escrita de aplicações servidor com ODS tem os mesmo benefícios que o SQL Server deste componente, incluindo gestão e pooling de processos com SMP, assim como gestão de rede para múltiplas redes simultâneas. Esta operação multithread8 permite à aplicação servidor de ODS manter um nível alto de performance e disponibilidade e utilizar múltiplos processadores de uma forma transparente sobre Windows NT/2000 uma vez que o sistema operativo consegue escalonar qualquer processo em qualquer processador disponível. 2.1.4) O Relational Engine e o Storage Engine O motor da base de dados do SQL Server é composto por dois componentes, o relational engine e o storage engine. Estes dois componentes estão claramente separados e o seu método primário de comunicações é através do OLE BD. O relational engine contém todos os componentes necessários para parsing e optimização de queries. Também é responsável por gerir a execução de queries enquanto estas solicitam os dados do storage engine em termos de conjuntos de registos (row set) OLE BD e posterior processamento de resultados. O storage engine compreende os componentes necessários ao acesso e modificação de dados em disco. 8 Operação executada em múltiplos processos. Página 24 Instituto Superior de Engenharia do Porto 2.1.4.1) O Parser de comandos O parser de comandos controla eventos de linguagem do ODS. Verifica a sintaxe correcta e traduz os comandos Transact-SQL num formato interno que pode ser executado. Este formato interno é conhecido como uma árvore de pesquisa (query tree). Se o parser não reconhecer a sintaxe, um erro de sintaxe é lançado e identifica onde o erro ocorreu. No entanto, mensagens de erro sem ser de sintaxe não podem explícitas sobre o local exacto no código fonte da linha que causou erro. Uma vez que apenas o parser pode aceder ao código fonte de um comando, o comando não está disponível em formato fonte quando é executado. 2.1.4.2) O Optimizer O optimizer retira a árvore de execução do parser e prepara-a para execução. Este módulo compila um batch inteiro, optimiza as queries e verifica a segurança. A optimização e compilação resultam num plano de execução. O primeiro passo na criação de um plano deste tipo é a normalização de cada query o que normalmente resulta na divisão de uma query em várias mais pequenas. Após o optimizer normalizar a query, optimiza-a, o que significa que o optimizer determina um plano de execução para essa query. A optimização de queries é baseada em custos; o optimizer escolhe o plano com menor custo baseado em métricas internas que incluem requisitos de memória, utilização estimada da CPU e número de pedidos de I/O previstos. O optimizer considera o tipo de pedido, verifica o tamanho dos dados nas várias tabelas afectadas, verifica os índices para cada uma das tabelas e depois efectua uma amostragem de dados mantida para cada índice ou coluna referenciada pela query. A amostragem de dados é designada por distribution statistics. Baseado na informação disponível, o optimizer considera os vários métodos de acesso e estratégias de join que pode utilizar para executar a query e escolhe o de menor custo. O optimizer também decide quais os índices, se algum, a serem utilizados para cada tabela afectada e, no caso de uma multitable query, a ordem em que devem ser acedidas e qual a estratégia de join. O optimizer utiliza heurísticas de “corte” (pruning) para garantir que não é despendido mais tempo a optimizar uma query do que simplesmente escolhendo um plano e executá-la. O optimizer não faz necessariamente uma optimização exaustiva. Página 25 Instituto Superior de Engenharia do Porto Após a finalização da normalização e optimização, a árvore normalizada produzida é compilada num plano de execução que constitui, na realidade, uma estrutura de dados. Cada comando incluído especifica exactamente qual a tabela afectada, que índices vão ser utilizados (se algum), que verificações de segurança tem que ser feitas e quais os critérios (condições de pesquisa) que devem ser classificados como TRUE. Este plano de execução pode ser consideravelmente mais complexo do que é aparente. Adicionalmente aos comandos, o plano de execução inclui todos os passos necessários para garantir que as restrições (constraints) são verificadas. Os passos para chamar um trigger são um pouco diferentes dos necessários para verificar uma restrição. Se um trigger é incluído nas acções a serem efectuadas, a chamada ao procedimento que inclui o trigger é adicionado. Se o trigger é do tipo instead-of trigger, a chamada ao trigger pode substituir o próprio comando de modificação de dados. Para after triggers10, o plano do trigger é ramificado após o plano de execução do comando de modificação que disparou o trigger, antes que essa modificação faça COMMIT. Os passos específicos do trigger não são compilados no plano de execução, ao contrário dos de verificação de uma restrição (constraint). O simples pedido de inserção de uma linha numa tabela com várias restrições pode resultar num plano de execução que necessite que várias outras tabelas também sejam acedidas ou que expressões sejam avaliadas. A existência de um trigger também pode provocar que muitos outros passos sejam executados. O passo que executa realmente o comando de inserção pode ser uma pequena parte do plano de execução total necessário para garantir que todas as acções e verificações de restrições associadas à inserção de uma linha sejam cumpridas. 2.1.4.3) O SQL Manager O SQL Manager é responsável por todas as acções que se relacionam com a gestão de stored procedures e com os seus planos de execução. Determina quando um stored procedure necessita de 9 Este tipo de trigger constitui uma das novidades do SQL Server 2000. Um trigger é constituído por comandos SQL que executados mediante disparos de eventos sobre tabelas. Este novo tipo, acrescenta a característica de substituir as acções que dispararam o trigger. 10 Triggers executados após a execução dos comandos que dispararam o trigger. Página 26 Instituto Superior de Engenharia do Porto ser recompilado baseado em mudanças no schema11 de objectos e gere a cache dos planos de execução de forma a que outros processos os possam utilizar. O SQL Manager também controla a autoparametrização de queries. No SQL Server 2000, certo tipo de ad hoc queries12 são tratadas como se fossem stored procedures parametrizados e os planos de execução são criados e guardados para tal. Isto pode acontecer se uma query utiliza uma simples comparação de igualdade de uma constante, como o exemplo seguinte: SELECT * FROM pubs.dbo.titles WHERE type = ‘business’ Esta query pode ser parametrizada como se fosse um stored procedure com um parâmetro para o valor de type: SELECT * FROM pubs.dbo.titles WHERE type = @param Uma outra query pode, diferindo apenas no valor de type, utilizar o plano de execução que foi gerado para a query original. 2.1.4.4) O Expression Manager O Expression Manager controla a computação13, comparação e movimentação de dados. Suponhamos que uma query contém algo do género: SELECT @myqty = qty * 10 FROM mytable 11 Numa comparação com a normal SQL92, o schema é o equivalente á informação sobre base de dados. 12 Uma ad hoc querie é considerada como uma consulta de dados sobre múltiplas fontes de dados com uma periodicidade muito baixa. 13 Dados obtidos através de cálculos. Por exemplo, uma coluna de uma tabela obtida em função de uma operação aritmética sobre outras colunas. Página 27 Instituto Superior de Engenharia do Porto O Expression Manager copia o valor de qty do row set14 retornado pelo storage engine, multiplica-o por 10 e guarda o resultado em @myqty. 2.1.4.5) O Query Executor O Query Executor executa o plano de execução que o Optimizer criou, funcionando como um intermediário para todos os comandos na execução do plano. Este módulo passa por cada passo de cada comando do plano de execução até o batch ter terminado. A maioria dos comandos necessita de interacção com o storage engine para modificar ou obter dados e para gerir transacções e locking. 2.1.4.6) Comunicações entre o relational engine e o storage engine O motor relacional utiliza OLE DB para a maior parte das comunicações com o motor de armazenamento. A descrição seguinte é uma adaptação da secção intitulada “Database Engine Concepts” do SQL Server Books Online. Descreve como uma instrução SELECT que processa dados apenas de tabela locais é processada: 1. O motor relacional compila a instrução SELECT num plano de execução optimizado. O plano de execução define um conjunto de operações sobre conjuntos simples de row sets OLE BD de tabelas individuais ou índices referenciados na instrução SELECT. O row set requisitado pelo motor relacional retorna o conjunto de dados necessário da tabela ou índice para executar uma das operações utilizadas para construir o conjunto de resultados da instrução. Por exemplo, esta instrução SELECT necessita de um table scan se referencia uma tabela sem índices. SELECT * FROM Northwind.dbo.ScanTable 14 Um row set corresponde a um conjunto de registo obtidos através de uma consulta à base de dados. Este termo, normalmente, é utilizado para designar o conjunto de dados retornado ao cliente que efectuou a pesquisa. Página 28 Instituto Superior de Engenharia do Porto O motor relacional implementa o index scan através de um pedido de um row set contendo todos os registos de ScanTable. Esta próxima instrução SELECT necessita apenas informação contida num índice: SELECT DISTINCT LastName FROM Northwind.dbo.Employees O motor relacional implementa o index scan pedindo um row sets que contém as folhas (leaf level rows) do índice que foi construído sobre a coluna LastName. A próxima instrução necessita de informação a partir de dois índices: SELECT CompanyName, OrderID, ShippedDate FROM Northwind.dbo.Customers As Cst JOIN Northwind.dbo.Orders As Ord ON ( Cst.CustomerID = Ord.CustomerID ) O motor relacional pede dois row sets: um para o índice nonclustered em Customers e o outro para um índice clustered de Orders. 2. O motor relacional utiliza a API OLE DB para pedir ao motor de armazenamento acesso aos row sets. 3. Enquanto o motor relacional processa os vários passos do plano de execução e necessita de dados, utiliza OLE DB para ler os registos do row set que pediu ao motor de armazenamento para abrir. O motor de armazenamento transfere os dados dos buffers de dados para o motor relacional. 4. O motor relacional combina os dados dos rows sets recebidos do motor de armazenamento com o result set final transmitido para o utilizador. Nem todas as comunicações entre o motor relacional e o de armazenamento utilizam OLE DB. Alguns comandos não podem ser explicitados em termos de row sets de OLE DB. O melhor e mais explícito exemplo é quando o motor relacional processa comandos de data definition language (DDL) para criar uma tabela ou outro objecto do SQL Server. Página 29 Instituto Superior de Engenharia do Porto 2.1.5) O Access Methods Manager Quando o SQL Server necessita de localizar dados, invoca o gestor de métodos de acesso (Access Methods Manager). Este gestor prepara e executa scans em data pages e index pages e prepara os row sets de OLE DB para retornarem dados ao motor relacional. Contém serviços para aceder à tabela, buscar os dados qualificados15 e actualizar dados. Este gestor não lê na realidade as páginas; faz apenas o pedido ao gestor de buffer, que em última instância serve a página da sua cache ou a lê do disco para cache. Quando é iniciado o scan, um mecanismo de look-ahead qualifica os registos ou índices na página. A leitura dos registos que se enquadram no critério especificado é designada como qualified retrieval. O gestor de métodos de acesso é utilizado não só nas consultas (queries) mas também em updates ou deletes qualificados (por exemplo, uma instrução UPDATE com uma clausula WHERE). Uma sessão abre uma tabela, requisita e avalia um conjunto de registos contra as condições na clausula WHERE e, depois, fecha a tabela. Um session descriptor data structure (SDES) mantém um registo da linha corrente e das condições de pesquisa para o objecto a ser operado (que é identificado por um object descriptor data structure ou DES). 2.1.6) O Row Operations Manager e o Index Manager Podemos considerar este dois gestores como parte integrante do gestor de métodos de acesso (access methods manager) uma vez que eles implementam, na realidade, o método de acesso. Cada um é responsável por manipular e gerir as suas estruturas de dados em disco, nomeadamente registos de dados e índices B-Tree (o SQL Server utiliza uma implementação de B-Tree denominada B-Tree*). Eles compreendem e manipulam a informação nas páginas. 15 Dados que estão dentro dos critérios de selecção da instrução SQL. Por exemplo, numa instrução SELECT com uma cláusula WHERE, os dados qualificados seriam aqueles que estivessem dentro do critério definido na cláusula WHERE. Página 30 Instituto Superior de Engenharia do Porto 2.1.6.1) O Row Operation Manager O row operation manager lê, modifica e executa acções em registos individuais. Ele executa uma operação dentro de um registo, tal como “ler o campo 2” ou “escrever este valor no campo 3”. Como resultado do trabalho executado pelo gestor de métodos de acesso, pelo gestor de locks e pelo gestor de transacções, o registo será encontrado e será devidamente bloqueado e considerado parte da transacção. Após formatar ou modificar o registo em memória, esta acção insere ou apaga o registo. Este gestor também controla as alterações. O SQL Server 2000 fornece três métodos para alteração de dados. Todos são directos, o que significa que não há necessidade de duas passagens pelo registo de transacções (transaction log), como acontecia com os deferred updates16 nas versões anteriores ao SQL Server 7. O SQL Server 2000 desconhece o conceito de uma operação de deferred update. O SQL Server 2000 tem três métodos de alteração: • In-place mode Æ Este método é utilizado para actualizar uma heap ou clustered index quando nenhuma chave de clustering é modificada. A actualização pode ser executada localmente, e os novos dados são escritos no slot na página de dados. • Split mode Æ Este método é utilizado para actualizar nonunique indexes quando as chaves do índice são alteradas. A alteração é separada em duas operações – uma eliminação seguida de uma inserção – e estas operações são executadas independentemente uma da outra. • Split with collapse mode Æ Este método é utilizado para alterar um unique index quando as chaves do índice são alteradas. Após a alteração ser re-escrita como operações de eliminação e inserção, se a mesma chave é eliminada e posteriormente inserida com um novo valor, a eliminação e inserção é “condensada” numa só operação. 16 Actualizações de dados adiadas. Página 31 Instituto Superior de Engenharia do Porto 2.1.6.2) O Index Manager O index manager mantém e dá suporte a pesquisas em B-Trees, que são utilizadas para os índices do SQL Server. Um índice é uma estrutura em árvore, com uma página raiz, páginas de níveis intermédios e folha. Uma B-Tree agrupa registos com um índice semelhante, permitindo assim um acesso aos dados mais rápido através de pesquisa sobre um valor chave. O princípio de uma BTree é o balanceamento da árvore (o B significa Balanced). Os ramos da árvore de índices são juntos ou separados quando necessário de forma a que a pesquisa por um registo atravesse sempre o mesmo número de níveis e assim necessite do mesmo número acessos a páginas. A travessia é iniciada na raiz, progredindo para níveis intermédios e, finalmente, para páginas de níveis inferiores denominadas páginas folha. Numa pesquisa qualificada ou numa eliminação, a folha correcta é a página mais baixa da árvore onde um ou mais registos com a chave ou chaves especificadas reside. O SQL Server suporta tanto clustered como nonclustered indexes. Num nonclustered index (Figura 3), o nível folha da árvore contém todos os valores chave do índice em conjunto com um bookmark para cada valor da chave. O bookmark indica onde se encontram os dados referenciados e pode assumir de duas formas, dependendo se as tabelas base tem um clustered index. Se a tabela base não contém um clustered index, a tabela é referenciada como sendo uma heap. O bookmark em páginas folha de um nonclustered index para um heap são ponteiros (apontadores) para registos onde podem ser encontrados os dados. Estes ponteiros consistem num ID de linha (RID), que é um número de ficheiro, num número de página e num número de linha nessa página. Se a tabela base tem um clustered index, o bookmark em páginas folha de um nonclustered index contém os valores da chave do clustered index para o registo. Após atingir o nível folha num nonclustered index, podemos encontrar a localização exacta dos dados, apesar de ainda termos que obter separadamente a página onde os dados se encontram. Uma vez que se pode aceder directamente aos dados, não é necessário percorrer todas as páginas de dados para encontrar um registo qualificado. Num clustered index (Figura 4), o nível folha contém na realidade todos os dados, não simplesmente valores chave. Um clustered index mantém os dados numa tabela ordenada logicamente pela chave do clustered index e as páginas folha são de facto as páginas de dados da tabela. Todas as páginas de dados com um clustered index estão ligadas por listas duplamente ligadas. Página 32 Instituto Superior de Engenharia do Porto Seguindo as páginas, e as linhas dessas páginas, desde a primeira página até à última obtém-se a ordem lógica dos dados. Um vez que os dados apenas podem ser ordenados uma vez, só um clustered index pode existir por tabela. Isto faz com que a escolha da chave do índice seja um aspecto importante nas considerações de desempenho. Também se podem utilizar índices para garantir a unicidade do valor de uma chave específica. De facto, as cláusulas PRIMARY KEY e UNIQUE de uma coluna, funcionam pela criação de um índice único sobre os valores dessa coluna. O optimizer pode utilizar o conhecimento sobre a unicidade de índice para a formulação de um plano de execução efectivo. Internamente, o SQL Server garante sempre que os cluster indexes são únicos pela adição de um uniqueifier de 4 bytes aos valores da chave do clustered index que ocorrem mais do que uma vez. Este valor torna-se parte da chave e é utilizado em todos os níveis do clustered index e referencia a chave do clustered index em todos os nonclustered indexes. Figura 3: Um Nonclustered Index com bookmarks no nível folha. Página 33 Instituto Superior de Engenharia do Porto Um vez que o SQL Server mantém uma ordenação em índices no nível folha, não é necessário descarregar e recarregar os dados para manter as propriedades de clustering quando dados são acrescentados ou movidos. O SQL Server adiciona sempre linhas nas páginas correctas numa sequência de cluster. Para um clustered index, a página folha correcta é a página de dados onde uma linha de dados é inserida. Para um nonclustered index, a página folha correcta é aquela onde o SQL Server insere a linha contendo o valor chave (e bookmark) para a nova linha inserida. Se os dados são alterados e os valores chave de um índice são alterados ou se a linha é movida para uma página diferente, o controlo de transações do SQL Server garante que todos os índices afectados são modificados para reflectir essas alterações. Com o controlo de transações, as operações em índices são executadas como sendo operações atómicas. As acções são registadas e completamente recuperadas na eventualidade de uma falha de sistema. Figura 4: Um Clustered Index com os dados no nível folha. Página 34 Instituto Superior de Engenharia do Porto 2.1.7) O Page Manager e o Text Manager O page manager e o text manager colaboram para gerir a colecção de páginas como bases de dados identificadas (named databases). Cada base de dados é constituída por um conjunto de páginas em disco com 8 Kb, que estão espalhadas por um ou mais ficheiros físicos. O SQL Server utiliza oito tipos de páginas em disco: data pages, text/image pages, index pages, Page Free Space (PFS) pages, Global Allocation Map (GAM e SGAM) pages, Index Allocation Map (IAM) pages, Bulk Changed Map pages e Differential Changed Map pages. Todos os dados, excepto os tipos de dados text, ntext e image, são armazenados em data pages. Estes três tipos de dados, que são utilizados para armazenar grandes quantidades de informação (até 2 Gb cada de texto ou dados binários), podem utilizar o seu próprio conjunto separado de páginas. Assim os dados não são tipicamente armazenados em páginas de dados normais com o resto dos registos. Em vez disso, um apontador na página de dados identifica a página de início e o offset dos dados text/image. No entanto, no SQL Server 2000, grandes objectos de dados que contenham apenas alguns bytes podem opcionalmente ser armazenados na própria linha de dados. As index pages armazenam as B-Trees que permitem o acesso rápido aos dados. Páginas PFS mantém um controlo sobre quais as páginas de uma base de dados que podem conter novos dados. As allocation pages (GAM, SGAM e IAM) mantém controlo sobre as outras páginas. Elas não contém qualquer registo da base de dados e são utilizadas apenas internamente. As páginas Bulk Changed Map e Differential Changed Map são utilizadas para backup e recuperação de uma forma mais eficiente. O page manager aloca e desaloca todos os tipos de páginas em disco, organizando extents de oito páginas cada. Um extent pode ser uniforme, onde todas as oito páginas alocadas são do mesmo objecto (tabela ou índice), ou misto, que pode conter páginas de múltiplos objectos. Se um objecto utiliza menos de oito páginas, o page manager aloca novas páginas para esse objecto a partir de extents mistos. Quando o tamanho de um objecto excede oito páginas, o page manager aloca novo espaço para esse objecto em unidades de extents uniformes inteiros. Esta optimização evita o overhead da alocação de acontecer sempre que uma nova página é necessária para grandes tabelas; este overhead apenas acontece a cada oito vezes. Talvez mais importante, esta optimização força os dados da mesma tabela a serem contínuos, na sua maioria. Ao mesmo tempo, a capacidade para utilizar extents mistos impede o SQL Server de Página 35 Instituto Superior de Engenharia do Porto desperdiçar espaço se uma base de dados contiver várias tabelas pequenas. Para determinar a continuidade dos dados de uma tabela, podemos utilizar o comando DBCC SHOWCONTIG. Uma tabela com muita alocação e desalocação pode ficar muito fragmentada. A reconstrução do clustered index (o que também reconstrói a tabela) ou executar DBCC INDEXDEFRAG podem melhorar o desempenho, especialmente se a tabela for acedida com frequência utilizando index s Programa baseado numa rotina pequena que substitui um programa mais longo, possivelmente para ser carregado mais rápidamente ou remotamente. Por exemplo, um programa que utilize RPC é compilado com stubs que substituem o programa que requer um procedimento remoto. O stub aceita o pedido e depois reenvia-o (através de outto programa) para o procedimento remoto. Quando esse procedimento acabar o seu serviço, retorna o resultado ou outro estado ao stub que o passa ao programa que fez o pedido.cans ordenados. 2.1.8) O Transaction Manager Uma característica base do SQL Server é a sua capacidade para garantir que as transacções seguem as ACID properties. As ACID properties significam: atomicidade (atomicity), consistência (consistency), isolamento (isolation) e durabilidade (durability). As transacções devem ser atómicas, ou seja, tudo ou nada. Se uma transacção fez COMMIT17, deve ser recuperável pelo SQL Server independentemente da situação - mesmo se ocorrer uma falha total do sistema um milisegundo após a confirmação do COMMIT. No SQL Server se um trabalho estava a ser executado e houve uma falha de sistema antes de a transacção ter feito COMMIT, todo o trabalho sofre um ROLL BACK18 para o estado em que se encontrava antes de o trabalho ter sido iniciado. O write-ahead logging torna sempre possível efectuar um ROLL BACK de trabalho em progresso ou um ROLL FOWARD de trabalho que já fez COMMIT mas que ainda não foi aplicado às páginas de dados. O write-ahead logging garante que as 17 Acção que confirma a execução completa e com sucesso de uma transacção. Quando uma transação efectua COMMIT, significa que todas as escritas/leituras físicas ocorreram com sucesso e foram devidamente registadas no registo de transacções 18 Ao contrário do COMMIT, um ROLL BACK identifica uma situação em que uma ou todas as acções de uma transação falharam e tem que ser desfeitas. A anulação dessas acções é feita mediante informação do registo de transacções e garante a integridade dos dados. Página 36 Instituto Superior de Engenharia do Porto alterações de uma transacção – as before e after images – são armazenadas em disco no registo de transacções antes de uma transacção fazer COMMIT. As escritas para o registo de transacções são sempre síncronas – isto é, o SQL Server tem que aguardar que elas terminem. Escritas para páginas de dados podem ser assíncronas porque todos os efeitos podem ser reconstruídos a partir do registo se tal for necessário. O transaction manager coordena a escrita no registo de transacções, recuperação e gestão do buffer. O transaction manager define os limites das instruções que devem ser agrupadas para formar uma operação. Controla transacções que atravessam bases de dados no mesmo servidor SQL Server e permite sequências de transacções encadeadas. Para uma transacção distribuída para outro SQL Server (ou outro gestor de recursos), o transaction manager coordena-se com o serviço Microsoft Distributed Transaction Coordinator (MS DTC) utilizando remote procedure calls (RPC). O transaction manager marca ponto de salvaguarda, que permite designar locais dentro de uma transacção onde um trabalho pode ser parcialmente desfeito ou ROLLED BACK. O transaction manager também se coordena com o lock manager no que se relaciona com libertação de bloqueios, baseado no nível de isolamento. O nível de isolamento em que uma transacção é executada determina qual a sensibilidade da aplicação a alterações efectuadas por outras e consequentemente o tempo que essa aplicação deve manter bloqueios para se proteger contra essas alterações. Existem quatro níveis de isolamento disponíveis no SQL Server 2000: Uncommited Read (também designado dirty read), Commited Read, Repeatable Read e Serializable. O comportamento de uma transacção depende do nível de isolamento. Vamos analisar esses níveis, embora uma completa compreensão dos níveis de isolamento implique uma compreensão do bloqueio (locking) uma vez que estão intimamente ligados. 2.1.8.1) Uncommited Read Uncommited Read, ou dirty read, permite que uma transacção leia qualquer conjunto de dados contido numa página de dados, tenham ou não esses dados efectuado COMMIT. Por exemplo, outro utilizador pode estar a executar uma transacção que actualize dados e, apesar de ter exclusive locks sobre os dados, outra transação poderia lê-los na mesma. O outro utilizador poderia posteriormente decidir efectuar um ROLL BACK da sua transacção, o que, para todos os efeitos, seria como se essa transacção nunca tivesse ocorrido. Se fosse um sistema mono-utilizador e todos os pedidos permanecessem numa fila de espera para aceder aos dados, as alterações não seriam Página 37 Instituto Superior de Engenharia do Porto visíveis. Mas num sistema multi-utilizador, os dados seriam lidos e seriam efectuadas acções sobre eles. Embora este cenário não seja desejável, com uncommited read não ficaríamos à espera que um lock fosse libertado, nem as nossas leituras emitiriam shared locks que afectassem outros. Quando se utiliza uncommited reads perde-se a garantia de dados altamente consistentes em favor de alta concorrência no sistema sem que os utilizadores se bloqueiem uns aos outros. Afinal quando se deve utilizar uncommited reads? Claramente que não devem ser utilizados em aplicações financeiras onde cada valor deve ser coerente e correcto. No entanto, seria possível para certas aplicações de suporte à decisão – por exemplo, análise de tendências de vendas – onde precisão não é necessária e a troca por alto nível de concorrência justifica a sua utilização. 2.1.8.2) Commited Read Commited Read é o nível de isolamento por defeito do SQL Server. Garante que uma operação nunca lê dados que outra alterou e ainda não efectuou COMMIT. (Ou seja, nunca lê dados que logicamente nunca existiram). Com commited read, se uma transacção está a alterar dados e consequentemente detêm um exclusive lock em linhas de dados, outras transações devem, aguardar que esses locks sejam libertados antes de utilizarem os dados (sejam leituras ou alterações). Também, uma transacção deve colocar share locks (no mínimo) sobre os dados que vão ser visitados, o que significa que os dados podem estar indisponíveis para que outros os utilizem. Um share lock não impede que outros leiam os dados, mas faz com que aguardem para efectuar alterações. Os shared locks podem ser libertados após os dados terem sido enviados para o cliente que efectuou o pedido – não têm que ser mantidos durante toda a duração da transacção. 2.1.8.3) Repeatable Read O nível de isolamento repeatable read adiciona às propriedades do committed read a garantia que se uma transacção torna a visitar dados ou se uma query é reemitida, os dados não sofreram alterações. Por outras palavras, executando a mesma pesquisa duas vezes dentro de uma transacção não vai receber alterações aos valores dos dados efectuados por uma transacção de outro utilizador. No entanto, o nível de isolamento repeatable read não permite que registos “fantasma” apareçam. Página 38 Instituto Superior de Engenharia do Porto Prevenir que apareçam nonrepeatable reads é uma garantia desejável. O custo de esta garantia extra é de que todos os shared locks numa transacção têm que ser mantidos até ao fim (COMMIT ou ROLLBACK) de uma transacção. Nenhum outro utilizador pode modificar dados visitados por esta transacção enquanto esta transacção estiver em processamento. Obviamente, isto pode reduzir imenso a concorrência e degradar o desempenho. Se as transacção não forem pequenas ou se as aplicações não forem escritas para ter em conta potenciais questões de contenção destes locks, o SQL Server vai aparentar uma “paragem” enquanto aguarda simplesmente pela libertação dos bloqueios. 2.1.8.4) Serializable O nível de isolamento serializable adiciona ao repeatable read a garantia de que se uma query é relançada, não vão ser adicionados registos. Por outras palavras, não vão aparecer “fantasmas” se a mesma consulta é feita duas vezes no interior de uma transacção. Mais precisamente, os níveis serializable e repeatable read afectam a sensibilidade às alterações efectuadas por outras conexões, sendo ou não o ID do utilizador o mesmo. Cada transação em SQL Server tem o seu próprio espaço de transacção e bloqueio. Prevenir o aparecimento de “fantasmas” é outra garantia desejável. Mas, mais uma vez, enfrentamos problemas de custos adicionais. Os custos adicionais deste nível são semelhantes aos do repeatable read – todos os shared locks numa transacção devem ser mantidos até ao final da transacção. Adicionalmente, implementar o nível de isolamento serializable requer que não só os dados que são lidos mantenham o bloqueio, mas também que existam lock nos dados que “não existem”! Por exemplo, suponhamos que no interior de uma transacção é executada uma instrução SELECT para ler os dados de todos os clientes que têm um código postal entre 1000 e 4000, e na primeira execução nenhum registo verifica esta condição. Para implementar o nível de isolamento serializable, deve-se bloquear o conjunto de potenciais registos com o código postal entre 1000 e 4000 de forma a que se a mesma consulta é executada, não existam linhas que verifiquem a condição. O SQL Server garante isto através da utilização de um tipo de bloqueio especial denominado key-range lock. O nome serializable advém do facto que executar várias transacções em simultâneo é igual a executá-las em sequência, ou seja, em série. Por exemplo, suponhamos as transacções A, B e C a ser executadas simultaneamente e cada uma a tentar actualizar os mesmos dados. Se a sequência em que as transacções conseguem locks do conjunto de dados é B, C e A, os resultados obtidos por executar todas simultaneamente é o mesmo Página 39 Instituto Superior de Engenharia do Porto do que executar as transacções na sequência B, C e A. O nível serializable não implica que se conheça previamente a ordem. A ordem é considerada um evento aleatório. Mesmo num sistema mono-utilizador, a ordem das transacções a chegarem è fila de espera seria essencialmente aleatória. Se a ordem do batch for importante numa aplicação, deve ser implementado um sistema puro de batch. A parte complicada da gestão de transacções, operações de rollback/rollforward e recuperação. 2.1.9) é garantir O Lock Manager O bloqueio é uma função crucial de um sistema de gestão de bases de dados multi-utilizador tal como o SQL Server. O SQL Server permite a gestão de múltiplos utilizadores simultaneamente e garante que as transacções observam as propriedades do nível de isolamento escolhido. No nível superior, serializable, o SQL Server deve levar o sistema multi-utilizador a actuar como um sistema mono-utilizador – apesar de cada utilizador estar em fila de espera para utilizar o sistema sem actividade de outros. O lock guarda os dados e os recursos internos que tornam possível a vários utilizadores em simultâneo utilizar a base de dados e não afectar seriamente a utilização de outro utilizador. O lock manager adquire e liberta vários tipos de locks, tais como shared locks para leitura, exclusive locks para alocação de espaço, etc. Gere a compatibilidade entre tipos de locks, resolve deadlocks, escala locks se necessário. O lock manager controla locks de tabelas, páginas e linhas além de locks de dados de sistema. (Os dados de sistema, tais como cabeçalhos e índices de páginas, são privados do sistema de base de dados). O lock manager fornece dois tipos de sistemas de lock. O primeiro permite row locks, page locks e table locks para todos as data tables, data pages e rows, text pages e leaf-level index pages e index rows. O segundo sistema de locking é utilizado internamente apenas para dados restritos de sistema; protege a raiz e páginas intermédias dos índices enquanto estes estão a ser atravessados. Este mecanismo interno utiliza latches, uma variação mais leve e de curta duração de locks de dados que não necessita de bloqueio até ao fim da transacção. Se fossem utilizados locks completos isso atrasaria o sistema. Adicionalmente à protecção dos níveis superiores dos índices, os latches protegem as linhas enquanto elas estão a ser transferidas do motor de armazenamento para o motor relacional. Se se examinar os locks através do stored procedure sp_lock ou de um mecanismo semelhante que receba a sua informação da tabela de Página 40 Instituto Superior de Engenharia do Porto sistema syslocksinfo, não se vem os latches; apenas se visualizam os locks de dados. No entanto, estão disponíveis contadores no System Monitor para monitorizar pedidos de latches, aquisições e libertações. 2.1.10) Outros Gestores Também incluído no motor de armazenamento existem gestores para controlar utilitários tais como bulk loads, comandos DBCC, operações de backup e restore e o Virtual Device Interface (VDI). O VDI permite que programadores construam os seus próprios utilitários de backup e restore e acedem directamente às estruturas de dados do SQL Server, sem necessitar de aceder através do motor relacional. Existe um gestor para controlar operações de ordenação e outro para manter fisicamente os ficheiros e dispositivos de backup em disco. 2.2) A GESTÃO DE MEMÓRIA Um dos principais objectivos do SQL Server 2000 é a facilidade de escalar o sistema onde é instalado. Desde um computador portátil com Windows 98 até a um servidor poderoso a correr Windows 2000 DataCenter Server. Para que esta política funcione é necessário que a gestão de memória seja implementada de uma forma robusta. Por defeito, o SQL Server 2000 ajusta a sua utilização da memória do sistema de forma a balancear as necessidades das outras aplicações a correrem na mesma máquina e as necessidades dos seus componentes internos. Quando se determina a quantidade óptima de memória para ser atribuída dinamicamente ao SQL Server, o memory manager tenta deixar pelo menos 4 Mb livres para o sistema operativo. O tamanho reservado para o sistema é parcialmente determinado pelo tempo estimado de vida de uma página de cache em memória. O memory manager determina um valor para Life Expectancy que indica quantos segundos, em média, uma página fica em cache se não for utilizada. O Performance Monitor tem um contador que permite visualizar o valor corrente de Life Expectancy. Este valor é apenas uma estimativa e é baseado na velocidade a que o Lazywriter verifica referências a páginas e o valor total de memória disponível. Se o valor de Life Expectancy de uma página é pequeno, o memory manager tenta manter a memória reservada a cerca de 4 Mb para aumentar a memória disponível para o SQL Server. Se o valor de Life Expectancy aumenta, o tamanho de memória reservada para o sistema operativo aumenta para cerca de 20 Mb e a memória total Página 41 Instituto Superior de Engenharia do Porto para o SQL Server diminui. Todas as instância do SQL Server na mesma máquina trabalham para o mesmo valor reservado e Life Expectancy. Como uma alternativa à computação dinâmica de memória, o SQL Server pode ser configurado para um valor fixo de memória. Quer a atribuição de memória seja dinâmica ou um valor fixo, o espaço de memória total para cada instância é considerado como uma cache unificada e é gerida como uma colecção de pools com as suas próprias políticas e finalidades. A memória pode ser requisitada e atribuída a qualquer um dos vários componentes internos. 2.2.1) O Buffer Manager e Memory Pools O principal componente de memória no SQL Server é o buffer pool. Toda a memória não utilizada por outro componente de memória fica em buffer pool. O buffer manager faz a gestão de funções de I/O de disco para leitura de dados e páginas de índices para o buffer pool de forma a que os dados possam ser partilhados pelos utilizadores. Quando outros componentes requisitam memória, podem requisitar um buffer do buffer pool. Um buffer é uma página em memória que tem o mesmo tamanho que uma página de dados ou página de índice. Outro pool de memória é o próprio sistema operativo. Ocasionalmente, o SQL Server tem que requisitar blocos contínuos de memória maiores que os 8 Kb de página que o buffer pool pode fornecer. Tipicamente, a utilização de grandes blocos de memória está limitada ao mínimo, de forma a que a utilização de memória do SQL Server faça poucas chamadas directas ao sistema operativo. Podemos associar a procedure cache como outro memory pool, onde as árvores de pesquisa e os planos de execução de stored procedures, triggers, funções de utilizador e ad hoc queries são armazenados. Outras pools são utilizadas por queries com alta utilização de memória que utilizam hashing (a definição de hashing no SQL Server irá ser descrita posteriormente) ou ordenação e por objectos especiais de memória que necessitam de menos de 8 Kb de página. Página 42 Instituto Superior de Engenharia do Porto 2.2.2) Acesso a In-Memory Pages O acesso a páginas no buffer pool deve ser rápido. Mesmo com memória real, seria ineficiente termos que percorrer toda a cache por uma página quando temos centenas de Mb de dados. Para evitar esta ineficiência, as páginas em buffer pool passam por funções de hash para serem de acesso rápido. O Hashing é uma técnica que mapeia uniformemente uma chave através de uma função de hash a um conjunto de hash buckets. Um hash bucket é uma estrutura em memória que contém um vector de ponteiros (implementado como uma lista ligada) para as páginas do buffer. Se todos os ponteiros para páginas do buffer não cabem numa página de hash, uma lista ligada liga a páginas de hash adicionais. Através de um identificador dbid-fileno-pageno (o primeiro valor identifica a base de dados, o segundo o ficheiro físico e o último a página de dados), a função de hash converte a chave para o hash bucket que deve ser verificado; essencialmente, o hash bucket funciona como um índice para a página especifica necessária. Através da utilização de hashing, mesmo quando grandes conjuntos de memória são utilizados, o SQL Server pode encontrar uma página de dados específica em cache com apenas algumas leituras de memória. De forma semelhante, são necessárias apenas algumas leituras de memória para determinar que a página necessária não está em cache e é necessário lê-la do disco. 2.2.3) Acesso a Free Pages (Lazywriter) Uma página de dados ou de índice só pode ser utilizada se estiver em memória. Assim, um buffer no buffer pool deve estar disponível para que a página possa ser lida para ele. Manter um conjunto de buffers disponíveis para uso imediato é uma optimização de desempenho importante. Se um buffer não está rapidamente disponível, muitas páginas de memória podem ter que ser pesquisadas para localizar um buffer que possa ser libertado. O buffer pool é gerido por um processo chamado lazywriter que utiliza um algoritmo cíclico para atravessar o buffer pool. Basicamente, o lazywriter visita cada buffer e determina se esse buffer foi referenciado desde a última passagem através de um contador no cabeçalho do buffer. Se o valor de referência não é 0, o buffer continua em pool e o seu valor de referência é decrementado em preparação para a próxima passagem; caso contrário, o buffer é disponibilizado para ser reutilizado. Página 43 Instituto Superior de Engenharia do Porto O valor de referência dum buffer é incrementado de cada vez que o seu conteúdo é acedido por um processo. Para páginas de dados ou índices, este valor é incrementado em uma unidade. Mas objectos com custos maiores de criação, tais como planos de execução de stored procedures, têm um valor de referência mais elevado que reflecte o seu “valor de substituição”. Quando o lazywriter passa e verifica as páginas que foram referenciadas, não utiliza simplesmente uma decrementação. Divide o valor de referência por 4. Isto significa que páginas referenciadas com frequência e as valor de substituição elevado são favorecidas, pelo que o seu contador não chegará a 0 tão rapidamente, mantendo-as em pool. O lazywriter passa através do buffer pool quando o número de páginas disponíveis na lista de disponibilidades cai abaixo do seu valor mínimo. O valor mínimo é calculado como sendo uma percentagem do tamanho total do buffer pool que está sempre entre 128 Kb e 4 Mb. O SQL Server calcula as necessidades de páginas livres baseado na carga do sistema e no número de paragens ocorridas. Uma paragem ocorre quando um processo necessita de uma página livre e nenhuma está disponível; o processo “adormece” e aguarda que o lazywriter liberte algumas páginas. Se ocorrem muitas paragens o SQL Server aumenta o tamanho mínimo de disponibilidades. Se a carga sobre o sistema é leve e poucos stalls ocorrem, esse valor é reduzido e as páginas em excesso podem ser utilizadas para hash de páginas de dados e de índices ou planos de execução adicionais. Estes valores podem ser verificados através de contadores no Performance Monitor. Threads do utilizador também executam a mesma função de pesquisa de páginas que podem ser libertadas. Isto acontece quando um processo do utilizador necessita de ler uma página do disco para um buffer. Quando uma leitura é inicializada, a thread do utilizador verifica se as disponibilidades são reduzidas. Em caso afirmativo, a thread do utilizador age como o lazywriter e verifica se existem buffers que possam ser libertados. A razão para ter threads de utilizador a partilhar o trabalho do lazywriter é para distribuir os custos por todos os processadores num ambiente SMP. De facto, o SQL Server 2000 tem uma lista de disponibilidades separada para cada processador para ajudar ainda mais à distribuição de custos e para melhorar a escalabilidade. Uma thread do utilizador que necessite de uma página livre verifica primeiro a lista de disponibilidades para o processador onde é executada, verificando as listas do outros processadores apenas se não existir nenhuma página livre. Página 44 Instituto Superior de Engenharia do Porto 2.2.3.1) Manter páginas em cache permanentemente Podemos marcar tabela de forma a que as suas páginas nunca sejam libertadas e desta forma mantidas em memória indefinidamente. Este processo é designado por pinning de uma tabela. Qualquer página (dados, índices ou text19) pertencentes a uma tabela marcada nunca é marcada como disponível e nunca é reutilizada a não ser que seja desmarcada. O Pinning ou unpinnig é efectuado utilizando a opção pinnable do stored procedure sp_tableoption. Atribuir o valor TRUE a esta opção para uma tabela não faz com que a tabela seja lida para cache, nem marca as páginas desta como favorecidas de alguma forma; em vez disso, é evitado o overhead desnecessário e simplesmente não se permite que as páginas pertencentes a essa tabela possam ser colocadas na lista de disponibilidades para possível substituição. Uma vez que mecanismos como o write-ahead logging e o checkpointing não são afectados, tal operação não implica de forma alguma recuperação. No entanto, o pinning de muitas tabelas pode resultar em poucas ou nenhuma páginas disponíveis em memória quando um novo buffer é necessário. Páginas que são acedidas com frequência nunca são colocadas na lista de disponibilidades. Uma página que tem um valor do contador diferente de 0, tal como uma página lida ou criada recentemente, não é adicionada à lista de disponíveis até que o seu contador caia a 0. Antes deste ponto, é claramente acedida com frequência e não é uma boa candidata a ser reutilizada. Páginas com acesso extremamente frequente podem nunca ser libertadas, mesmos que os seus objectos não tenham sido marcados (pinned). 2.2.4) Checkpoints As operações de checkpoint minimizam o trabalho que o SQL Server deve executar quando as bases de dados são recuperadas no arranque do sistema. Os checkpoints são executados base de dados a base de dados. Eles descarregam dirty pages para disco de forma a que essas alterações não tenham que ser refeitas durante a recuperação da base de dados. Uma dirty page é uma página que foi modificada desde que foi carregada de disco para o buffer pool. 19 Os tipo de dados text, ntext e image são armazenados em páginas separadas devido à sua dimensão (tamanho máximo de 2 Gb de dados). Página 45 Instituto Superior de Engenharia do Porto Quando ocorre um checkpoint, o SQL Server escreve um registo de checkpoint no registo de transacções, que lista todas as transacções que estão activas. Isto permite que o processo de recuperação construa uma tabela contendo uma lista de todas as potenciais dirty pages. Os checkpoints são activados quando: • Um dono de uma base de dados emite um comando checkpoint para efectuar um checkpoint sobre essa base de dados. • O log está a ficar cheio (mais de 70% da sua capacidade) e a base de dados está em modo de recuperação SIMPLE ou a opção trunc log on chkpt está activa. Um checkpoint é disparado para truncar o transaction log e libertar espaço. No entanto, se nenhum espaço pode ser liberto, talvez devido a uma longa transacção, não ocorre um checkpoint. • É estimado um tempo de recuperação longo. Quando o tempo de recuperação é previsto como sendo superior ao valor da opção de configuração recovery interval, um checkpoint é disparado. O SQL Server 2000 utiliza uma métrica simples para prever o tempo de recuperação porque pode recuperar, ou refazer, em menos tempo do que foi necessário na operação original. Assim, se os checkpoint são disparados pelos menos com a frequência do recovery interval, a recuperação é completada dentro do intervalo. Um intervalo de recuperação com o valor 1 significa que os checkpoints ocorrem a cada minuto durante a execução de uma transacção na base de dados. Uma quantidade mínima de trabalho deve ser efectuada para que o disparo automático do checkpoint seja atingido; cerca de 10 Mb de log por minuto. Desta forma o SQL Server não desperdiça tempo com bases de dados sem transacções. Um valor de 0 significa que o SQL Server escolhe o valor apropriado automaticamente; na versão corrente, é de 1 minuto. Num sistema com uma grande quantidade de memória, os checkpoints podem gerar potencialmente muitas operações de escrita para forçar todas as dirty pages para disco. Para limitar a quantidade de recursos que os checkpoints consomem, o SQL Server limita o número de checkpoints de uma transacção a um máximo de 100 operações de escrita concorrentes. Pode parecer um valor grande, mas num sistema de grande dimensão, mesmo 100 operações concorrentes podem demorar muito tempo a escrever todas as dirty pages. Para optimizar os checkpoints e para garantir que estes não necessitam de efectuar mais trabalho do que o necessário, o algoritmo de checkpoint controla um valor gerado para Página 46 Instituto Superior de Engenharia do Porto cada buffer na cache. Sem este valor de controlo, os checkpoints poderiam escrever as mesmas páginas para disco várias vezes. O processo de checkpoint atravessa o buffer pool, avaliando as páginas por ordem de número de buffer e, quando encontra uma dirty page, pesquisa por páginas físicas contíguas (em disco) que também estão “dirty” para poder efectuar uma escrita de um grande bloco. Isto significa que poderia, por exemplo, escrever as páginas 14, 200, 260 e 1000 quando descobre que a página 14 está “dirty” (estas páginas podem ter localizações físicas contíguas mesmo que estejam separadas no buffer pool). Quando o processo continua a verificar o buffer pool, chega à página 1000. Potencialmente, esta página pode estar outra vez “dirty”, e pode ser escrita uma segunda vez. Quanto maior o buffer pool, maiores as hipóteses de um buffer que já foi escrito se tornar “dirty” antes do checkpoint finalizar. Para evitar esta situação, cada buffer tem um bit associado designado generation number. No início do checkpoint, todos os bits são modificados para o mesmo valor, ou todos a 0 ou todos a 1. Quando um checkpoint verifica uma página, modifica o valor para o oposto. Quando o checkpoint encontra uma página onde o valor já foi alterado, não escreve essa página. Também, todas as novas páginas carregadas para o buffer durante o checkpoint, recebem o novo valor de generation number; assim não vão ser escritas durante este ciclo de checkpoint. Qualquer página já escrita por se encontrar na vizinhança de outra não vai ser escrita. 2.2.5) Acesso Manager a Páginas utilizando o Buffer O Buffer Manager gere a versão em memória de cada página física de disco e fornece a todos os outros módulos acesso a estas (com as medidas de segurança apropriadas). A imagem da memória no buffer pool, se existir, tem precedência sobre a imagem do disco. Se a página está “dirty”, a cópia em memória da página de dados inclui actualizações que não foram ainda escritas em disco. Quando uma página é necessária para um processo, tem que existir em memória no buffer pool. Se a página não existe, um I/O físico é executado para a obter. Obviamente, devido aos custo de um I/O físico, quanto menos I/O físicos forem executados melhor. Quanto mais memória existir (maior o buffer pool), mais páginas podem existir em memória e maior as probabilidades de ela poder ser encontrada lá. Uma base de dados é vista como uma sequência de páginas numeradas. O identificador dbid-fileno-pageno especifica unicamente uma página para o ambiente do SQL Server. Quando outro módulo (tais como o access method manager, row manager, index manager Página 47 Instituto Superior de Engenharia do Porto ou text manager) necessita acesso a uma página, requer o acesso através do buffer manager através do identificador dbid-filenopageno. O buffer manager responde à chamada do módulo com um ponteiro para o buffer de memória que contém essa página. A resposta pode ser imediata se a página já se encontra em cache ou pode demorar um instante para um I/O de disco completar e carregar a página em memória. Tipicamente, o módulo que efectua a chamada também requisita que o lock manager efectue o lock apropriado para essa página. O módulo informa o buffer manager se e quando acabar de alterar a página. O buffer manager é responsável por escrever essas alterações para disco de forma coordenada com a gestão de logging e transacção. 2.2.6) Questões Relacionadas Quantidades de Memória com Grandes Sistemas com várias centenas de Mb de RAM não são incomuns. De facto, para questões de benchmarking a Microsoft utiliza sistemas com até 2 Gb de memória RAM física. A versão Enterprise Edition do SQL Server permite a utilização de ainda maiores quantidades de memória. A razão para termos uma máquina com grande quantidade de memória é para minimizar os I/O físicos de disco aumentado o cache-hit ratio. A Enterprise Edition do SQL Server 2000 num sistema com Windows 2000 permite a quantidade de memória que o Windows 2000 Advanced Server ou Windows 2000 DataCenter Server aceitam utilizando a API Address Windowing Extensions (AWE) para suportar grandes quantidades de memória. Deve-se especificar na configuração de uma instância do SQL Server a utilização das extensões AWE; a instância pode então suportar até 8 Gb de memória física num Windows 2000 Advanced Server e 64 Gb de memória física num Windows 2000 DataCenter Server. Apesar do endereçamento de 32-bits standard só suportar 4 Gb de memória física, as extensões permitem que a memória adicional seja utilizada como memória não paginada. O memory manager podem então mapear dinamicamente vistas da memória não paginada para o espaço de endereçamento de 32-bits. Página 48 Instituto Superior de Engenharia do Porto 2.2.6.1) Read Ahead O SQL Server suporta um mecanismo denominado read ahead, onde a necessidade de dados e índices pode ser antecipada e as páginas carregadas no buffer pool antes de serem efectivamente lidas. Esta optimização de desempenho permite que grandes quantidades de dados sejam processados. Este mecanismo é gerido internamente e não são necessários ajustes de configuração. Adicionalmente, o read ahead não utiliza threads de sistema separados. Isto garante que o read ahead está em avanço, mas não demais, sobre a leitura efectiva dos dados. Existem dois tipos de read ahead: um para table scans em heaps e outro para index ranges. Para table scans, a estrutura de alocação da tabela é consultada para ler a tabela em ordem de armazenamento em disco. Até 32 extents (32 * 8 paginas/extent * 8192 bytes/página = 2 Mb) de read ahead estão a aguardar de cada vez. Quatro extents (32 páginas) de cada vez são lidas com uma simples scatter read de 256 Kb. Se a tabela estiver dispersa por múltiplos ficheiro num grupo de ficheiro (file group), o SQL Server tem uma read ahead thread por ficheiro. Na versão Standard Edition do SQL Server 2000, cada thread pode ler até 4 extents de cada vez para um ficheiro e até 32 ficheiros podem ser processados concorrentemente. Isto significa que as threads de read ahead podem processar até 128 páginas de dados. No SQL Server Enterprise Edition, podem ser lidos mais extents de cada ficheiro e mais ficheiros podem ser processados concorrentemente. Aliás, não existe definido um limite e extents ou ficheiros para esta versão, podendo ler em avanço até 1% do buffer pool. Para index ranges, é utilizado o primeiro nível da estrutura do índice (nível anterior ao nível folha) para determinar as páginas a ler em avanço. Quando é iniciada a consulta ao índice, o read ahead é invocado na descida inicial do índice para minimizar o número de leituras efectuadas. Por exemplo, para uma consulta de WHERE state=’WA’, o read ahead pesquisa o índice pela chave=’WA’ e pode dizer pelos nós de primeiro nível quantas páginas tem que ser examinadas para satisfazer a consulta. Se o número de páginas antecipadas é pequeno, todas as páginas são requisitadas pelo read ahead inicial; se as páginas são contíguas, são lidas em scatter reads. Se contém um grande número de páginas, o read ahead inicial é executado e a partir daí a cada 16 páginas utilizadas pela consulta, o índice é consultado para serem lidas mais 16 páginas. Isto tem vários efeitos interessantes: Página 49 Instituto Superior de Engenharia do Porto • Gamas pequenas podem ser processadas numa simples leitura no nível das páginas de dados sempre que o índice é contíguo. • O scan range (por exemplo, state=’WA’) pode ser utilizado para prevenir leituras em avanço de páginas que não vão ser utilizadas uma vez que esta informação está disponível no índice. • O read ahead não é atrasado por ter que seguir ligações de páginas ao nível das páginas de dados. (O read ahead pode ser efectuado quer em clustered indexes quer em nonclustered indexes). 2.2.6.2) Merry-Go-Round Scans A Enterprise Edition do SQL Server 2000 incluí outra optimização para melhorar a performance de nonordered scans (uma consulta que não é pedida numa ordem específica), particularmente em múltiplas consultas desordenadas da mesma tabela requisitadas simultaneamente por vários processos. Sem esta optimização, um processo podia iniciar uma consulta e chegar a 20% do caminho através da tabela antes de outro processo requisitar os mesmos dados. Se a cache é pequena ou está a ser utilizada por outros processos para dados completamente não relacionados, as páginas consultadas pelo processo original podem ter sido trocadas, o que significa que o buffer manager tem que retornar ao disco para ler as primeiras páginas outra vez. Quando a consulta original recomeçar, qualquer página lida em avanço pode ter desaparecido e mais leituras de disco são necessárias. Isto pode provocar desfragmentação de disco. Uma nova optimização denominada Merry-Go-Round Scans permite ao SQL Server 2000 Enterprise Edition evitar esta situação por permitir que o segundo processo se inicie no mesmo ponto que o processo original chegou. Ambos os processos podem assim ler os mesmos dados, e cada página pode ser lida de disco apenas uma vez e ser utilizada por ambas as consultas. Quando o primeiro processo terminar, o segundo pode ler os 20% iniciais da tabela. A Figura 5 ilustra um Merry-Go-Round Scan. Página 50 Instituto Superior de Engenharia do Porto Figura 5: O Merry-Go-Round do SQL Server 2000 Enterprise Edition 2.2.6.3) O Log Manager Todas as alterações são escritas em avanço pelo buffer manager no transaction log. Isto significa que o log regista uma transacção em disco antes das páginas de dados modificadas serem escritas. A escrita em avanço do log garante que todas as bases de dados podem ser recuperadas a um estado consistente, mesmo em caso de uma falha completa de sistema, desde que o disco sobreviva. Um processo nunca recebe confirmação que uma transacção efectuou COMMIT a menos que esteja em disco no transaction log. Por esta razão, todas as escritas no transaction log são síncronas - o SQL Server deve esperar por uma confirmação de conclusão. As escritas em páginas de dados podem ser assíncronas, sem terem que esperar por confirmação, uma vez que se uma falha ocorrer a transação pode ser desfeita ou refeita através da informação do transaction log. O log manager formata os registos do transaction log em memória antes de os escrever em disco. Para formatar estes registo de log, o log manager mantém regiões contíguas de memória denominadas Página 51 Instituto Superior de Engenharia do Porto log caches. No SQL Server 2000, o registo de log não partilham o buffer pool com as páginas de dados e índices. Os registos de log são mantidos apenas nos log caches. Para atingir maior capacidade, o log manager tem duas ou mais log caches. Uma é a log cache corrente, onde os novos registos vão ser adicionados. Adicionalmente, existem uma ou mais log caches disponíveis para serem utilizadas quando o log cache corrente estiver cheio. O log manager também mantém duas filas de espera de log caches: uma flushQueue, que contém log caches cheias à espera de serem descarregadas, e uma freeQueue, que contém log caches sem dados (que foram descarregadas) e que podem ser reutilizadas. Quando um processo de utilizador requisita o descarregar de uma log cache específica (por exemplo, quando uma transacção efectua COMMIT), a log cache é colocada em flushQueue. De seguida, a thread (ou fiber) é colocada na lista de conexões e espera que a log cache seja descarregada. A conexão não faz mais nada enquanto os seus registos em log não forem descarregados. O Log Writer é um processo dedicado que verifica a flushQueue por ordem e descarrega as log caches para disco. As log caches são escritas uma de cada vez. O log writer primeiro verifica se a log cache é a log cache corrente. Se for, o log writer utiliza padding20 sobre a log cache e modifica alguma informação de cabeçalho. Depois emite um evento I/O para esta log cache. Quando o descarregar de uma log cache específica está terminada, qualquer processo que aguarda por esta log cache é acordado e pode continuar o trabalho. 2.3) REGISTO DE TRANSACÇÕES E RECUPERAÇÃO O registo de transacções regista todas as alterações efectuadas sobre a base de dados e armazena informação suficiente para permitir que qualquer alteração seja desfeita (rolled back) ou refeita (rolled foward) na eventualidade de uma falha de sistema ou se for ordenado para o fazer pela aplicação (no caso de uma instrução de rollback). Fisicamente, o registo de transacções é um conjunto de ficheiros associados a uma base de dados na altura de criação ou alteração da base de dados. Módulos que efectuem alterações à base de dados escrevem entradas no registo que descrevem exactamente as alterações efectuadas. Cada entrada do registo é marcada com um número de sequência de registo (log sequence number - LSN) 20 Informação adicional escrita sobre o log cache. Página 52 Instituto Superior de Engenharia do Porto que é garantidamente único. Todas as entradas do registo que fazem parte da mesma transacção estão ligadas em conjunto de forma a que todas as partes de uma transacção possam ser facilmente encontradas para acções de anular ou refazer. O buffer manager garante que o registo de transacção é escrito antes das mudanças à base de dados serem escritas (write-ahead logging). Isto é possível porque o SQL Server verifica a sua posição actual no registo através do LSN. Cada vez que uma página é mudada, o LSN correspondente a essa alteração é escrito no cabeçalho da página de dados. As dirty pages podem ser escritas para disco apenas quando o LSN da página é inferior ao LSN da última página escrita no registo. O buffer manager também garante que as páginas do registo são escritas numa ordem específica, tornando claro quais as páginas a serem processadas na eventualidade de uma falha de sistema, independentemente de quando ocorreu a falha. As entradas do registo de uma transacção são escritas para disco antes da confirmação de COMMIT ser enviada ao processo do cliente, mas os dados alterados podem ainda não ter sido fisicamente escritos nas páginas de dados. Assim sendo, apesar das escritas no registo serem síncronas (o SQL Server tem que aguardar que estas completem para ter a certeza que ficaram guardadas em disco), as escritas em páginas de dados podem ser assíncronas. Isto é, escritas em páginas de dados têm apenas que ser anunciadas ao sistema operativo e o SQL Server pode verificar depois se elas foram completadas. Não tem necessidade de acabar logo uma vez que o SQL Server tem o registo que contém toda a informação para refazer todo o trabalho, mesmo na eventualidade de uma falha de corrente ou falha de sistema antes das escritas completarem. O sistema seria muito mais lento se tivesse que aguardar que cada acção de I/O acabasse antes de poder continuar. Registar implica demarcar o início e fim de cada transacção (e savepoints, se forem utilizados). Entre o início e fim, existe informação sobre alterações efectuadas sobre os dados. Esta informação pode tomar a forma de valores “antes e depois” ou pode referenciar as operações que foram efectuadas de forma a que esses valores possam ser derivados. O fim de uma transacção típica é marcado com um registo COMMIT, que indica que uma transacção tem que estar reflectida na base de dados ou refeita se necessário. Uma transacção abortada durante execução normal devido a um rollback explícito ou algo como uma falha de um recurso (não existir memória disponível) na realidade desfaz a operação aplicando modificações sobre os dados que tinham sido alterados pela transacção abortada. As entradas destas alterações são escritas no registo e marcadas como “compensation log records”. Se o sistema falhar após uma transacção fazer COMMIT mas antes dos dados serem escritos nas páginas de dados, a transacção tem que ser Página 53 Instituto Superior de Engenharia do Porto recuperada. O processo de recuperação automaticamente no arranque do sistema. é executado A recuperação executa tanto a operação de refazer (rollfoward) ou desfazer (rollback). Numa operação de refazer, o registo é examinado e cada modificação é verificada como sendo já reflectida na base de dados (após esta acção, cada modificação efectuada pela transacção está garantidamente aplicada). Se a modificação não aparece na base de dados, é de novo executada a partir da informação do registo. Desfazer implica a remoção de parte das alterações efectuadas por uma transacção que não completou inteiramente. Durante a recuperação, apenas modificações que ocorreram ou estão em aberto (em progresso) desde o último checkpoint são refeitas ou desfeitas. Existem três fases que estão ilustradas na Figura 6. A descrição refere-se a uma falha do SQL Server, mas estes mesmo planos de recuperação ocorrem se o SQL Server é parado intencionalmente. • Fase 1: Análise Æ A primeira fase é um passagem para a frente a partir do último checkpoint registado no registo de transacções. Esta passagem determina e constrói uma tabela de dirty pages (DPT) constituída por páginas que poderiam estar “dirty” na altura da falha (ou quando o SQL Server foi parado). É construída um tabela de transacções activas que consiste nas transacção que não tinham feito COMMIT na altura da falha. • Fase 2: Refazer Æ Esta fase repete os eventos de forma a colocar a base de dados no mesmo estado em que estava na altura da falha. O ponto de início desta fase é o menor LSN no DPT. O DPT é utilizado para evitar ler páginas que não necessitam recuperação e evitar escrever alteração não registadas. • Fase 3: Desfazer Æ Esta fase volta para trás do fim do registo, seguindo as ligações entre entradas no registo para cada transacção. Qualquer transacção que não tenha feito COMMIT na altura da falha de sistema é desfeita de forma a que nenhuma das suas alterações esteja reflectida na base de dados. Página 54 Instituto Superior de Engenharia do Porto Figura 6: Três fases de recuperação do SQL Server 2.3.1) Locking e Recuperação O locking, gestão de transacções (rollback ou rollfoward) e recuperação do sistema estão intimamente ligadas. Uma transacção pode ser desfeita apenas se todos os dados afectados estavam bloqueados exclusivamente de forma a que nenhum outro processo pudesse ver as modificações em progresso (que ainda poderiam ser desfeitas) ou pudesse ter feito modificações a recursos utilizados pela transacção que impedissem que fosse desfeita. Apenas uma transacção activa pode modificar uma linha de cada vez. Isto é a razão porque os bloqueios exclusivos tem que ser mantidos até que uma transacção efectue COMMIT ou seja abortada. Até ao momento em que faz COMMIT, a transacção logicamente não existe. Uma transacção com nível de isolamento Read Uncommited pode por vezes ler dados que logicamente nunca existiram uma vez que não liga à existência de bloqueios exclusivos. Mas quaisquer outras transacções com um nível de isolamento superior (o que se verifica por defeito) nunca permitiriam esta situação. Página 55 Instituto Superior de Engenharia do Porto 2.3.2) Páginas LSN e Recuperação Cada página de uma base de dados tem um LSN no cabeçalho da página que identifica unicamente, por versão, como as linhas de uma página são modificadas ao longo do tempo. Este LSN de página reflecte a localização no registo de transacções da última entrada no registo que modificou dados nesta página. Durante uma operação de refazer uma transacção, o LSN de cada registo é comparado com o LSN da página que o registo de transacções modificou; se o LSN é menor que o LSN do registo, a operação indicada no registo é refeita, como se vê na Figura 7. Uma vez que a recuperação encontra o registo do último checkpoint no registo de transacções (além das transacções que estavam activas no altura do checkpoint) e processa a partir daí, o tempo de recuperação é curto e todas as modificações com COMMIT anteriores ao checkpoint podem ser eliminadas do registo ou arquivadas. De outra forma, a recuperação demorava muito tempo e os registos de transacções tornavam-se muito grandes. O registo de transacções não pode ser limpo para além da primeira transacção que ainda está em aberto, independentemente de quantos checkpoints ocorreram subsequentemente. Se uma transacção permanece em aberto, o registo tem que ser mantido uma vez que ainda não está claro se completou ou irá alguma vez completar. A transacção pode necessitar de ser desfeita ou refeita. Foi notado que alguns registos de transacções não podem ser limpos para libertar espaço, mesmo após terem sido arquivados. Este problema resulta com frequência de algum processo ter aberto uma transacção que depois esqueceu. Por esta razão, do ponto de vista de desenvolvimento de aplicações, devemos garantir que as transacções são curtas. Outra razão possível para este problema relaciona-se com uma tabela ser replicada utilizando replicação transaccional quando o leitor do registo de replicação não foi processado ainda. Esta situação é menos comum, uma vez que uma latência de alguns segundos ocorre enquanto este leitor processa. Podemos utilizar o DBCC OPENTRAN para localizar a primeira transacção aberta, ou a última transacção de replicação ainda não processada e tomar as medida correctivas necessárias (tal como matar o processo ou executar o stored procedure sp_repldone para permitir que sejam limpas as transacções de replicação). Página 56 Instituto Superior de Engenharia do Porto Figura 7: Comparação do LSN para verificar o processamento da entrada do registo. 2.4) O KERNEL DO SQL SERVER E INTERACÇÃO COM O SISTEMA OPERATIVO O kernel do SQL Server é responsável pela interacção com o sistema operativo. É uma simplificação sugerir que o SQL Server tem um módulo para todas as chamadas ao sistema operativo, mas para simplificar podemos pensar assim. Todas as chamadas ao sistema operativo são efectuadas pela API Win32 e pelas bibliotecas run-time em C. Quando o SQL Server corre sobre uma plataforma Windows NT/2000, está inteiramente no subsistema Win32 protected. Não são efectuadas absolutamente nenhumas chamadas em Modo Privilegiado do Windows NT/2000 (Kernel Mode); as chamadas são feitas em Modo de Utilizador (User Mode). Isto significa que o SQL Server não pode bloquear todo o sistema, bloquear outros processos em Modo de Utilizador ou ser bloqueado por estes. Não pode efectuar chamadas não documentadas ao sistema operativo ou aceder directamente aos dispositivos (chamadas em driver-level). Teoricamente se um servidor bloquear com um “écran azul”, supostamente a culpa seria de um processo em Modo Privilegiado, por exemplo drivers defeituosos, ou do próprio sistema operativo. Um dos pontos chave deste produto é a sua capacidade de escalabilidade, o mesmo se passando com o Windows NT/2000. por Página 57 Instituto Superior de Engenharia do Porto este facto, os mesmo ficheiros binários executáveis que são utilizados num sistema portátil, executam num sistema com servidores de grande porte e com multiprocessamento simétrico (SMP). O Windows NT/2000 é a plataforma ideal para o SQL Server devido ao seu ambiente de 32 bits, seguro e protegido. Características como escalonamento preemptivo, gestão de memória virtual paginada, multiprocessamento simétrico e E/S assíncrona são necessárias para uma boa plataforma de um servidor de bases de dados. Estas características estão presentes no Windows NT/2000 e o SQL Server tira partido delas. O SQL Server corre como um único processo dentro do Windows NT/2000, contendo várias threads de execução. O sistema operativo encarrega-se de escalonar cada thread no(s) processador(es) disponível(eis). 2.4.1) Threading e Multiprocessamento Simétrico O SQL Server tem uma abordagem diferente para a escalabilidade com múltiplos processadores do que outros sistemas de bases de dados com capacidade de multiprocessamento simétrico. Nomeadamente em duas características: • Arquitectura com um único processo Æ O SQL Server tem apenas um processo, com uma arquitectura multithreaded que reduz a carga (overhead) do sistema e da memória utilizada. Isto é designado por Symmetric Server Architecture. • Multiprocessamento Nativo em Thread-level Æ O SQL Server suporta multiprocessamento ao nível da thread em vez de ao nível de processo, o que permite operações preemptivas e balanceamento dinâmico de carga sobre múltiplos processadores. A utilização de múltiplas threads é mais eficiente do que a utilização de múltiplos processos. Para se compreender melhor esta estratégia podemos compará-la com as estratégias utilizadas por outros sistemas. Num sistema sem threads como algumas variantes do UNIX, um servidor de bases de dados SMP típico tem vários processos de SGBD, cada um “ligado” a um processador. Alguns utilizam inclusive um processo por cada utilizador, o que eleva os custos de memória. Estes processos utilizam Memória Partilhada para comunicarem, o que mantém a cache, bloqueios, filas de tarefas, informação de contexto do utilizador. Os SGBD tem que incluir lógicas complexas que substituem as funções do sistema operativo: escalonamento de tarefas do utilizador, simulação de threads, coordenação entre múltiplos processos, etc. Uma vez que os processos estão ligados a um processador específico, não existe ou é difícil implementar Página 58 Instituto Superior de Engenharia do Porto balanceamento de carga dinâmico. Por questões de portabilidade, estes sistemas mantém esta abordagem mesmo que corram sobre um sistema que suporte serviços de threading nativos. O SQL Server, por outro lado, tem um design com um único processo e múltiplas threads. As threads são escalonadas nos processadores por um escalonador em Modo de Utilizador. A Figura 8 mostra as diferenças entre a arquitectura de threading do SQL Server e outros SGBD típicos. O SQL Server utiliza sempre várias threads, mesmo num sistema com um único processador. As threads são criadas e destruídas dependendo da actividade do sistema, daí que o número de threads não seja constante. Tipicamente, o número de threads do SQL Server varia entre 16 e 100, dependendo da actividade e configuração do sistema. Uma pool de threads controla cada uma das Net-Libraries que o SQL Server suporta simultaneamente, outra thread controla os checkpoints da base de dados, outra controla o processo lazywriter e outra o log writer. Outra thread separada controla actividades de limpeza de tarefas, como o encolher periódico da base de dados se no modo de autoshrink. Finalmente, uma pool de threads controla todos os comandos do utilizador. Página 59 Instituto Superior de Engenharia do Porto Figura 8: Design de múltiplas threads num único processo do SQL Server 2.4.2) O Worker Thread Pool Embora pareça que o SQL Server ofereça uma thread separada a cada utilizador, o sistema é na realidade um pouco mais complexo. Uma vez que é muito ineficiente manter centenas de threads de sistema para suportar centenas de utilizadores, o SQL Server mantém uma pool de worker threads. Quando um cliente executa um comando, o handler de rede do SQL Server coloca o comando numa “fila de conclusão” e a próxima thread livre encarrega-se do comando. Tecnicamente, esta fila é uma característica do sistema operativo denominada IOCompletion port. A worker thread aguarda na fila por pedido de rede na IOCompletion port. Se não existir nenhuma worker thread há espera, o SQL Server cria uma nova dinamicamente até atingir o valor máximo da Página 60 Instituto Superior de Engenharia do Porto configuração de worker threads. O comando do cliente tem que aguardar por uma worker thread livre. Mesmo num sistema sobrecarregado com centenas de utilizadores ligados, a maior parte das threads estão paradas num dado momento. Quando a carga diminuí o SQL Server encarrega-se de as eliminar para melhorar o desempenho e libertar memória. O design do worker thread pool é eficiente para gerir milhares de utilizadores conectados sem a necessidade de um monitor de transacções. No entanto, estes componentes são utilizados em grandes sistemas para atingir níveis de utilizadores activos que o SQL Server não suporta sem esses componentes extra (por exemplo, o Microsoft Distributed Transaction Coordinator, Transaction Processing (TP) Monitor). Uma thread do serviço worker thread pool serve cada comando para permitir a utilização completa de múltiplos processadores enquanto vários comandos de utilizadores estiverem pendentes. Adicionalmente, um único comando do utilizador sem outras actividades no servidor pode beneficiar dos múltiplos processadores se a query for complexa. O SQL Server pode dividir uma query complexa em várias partes simples e executá-las em paralelo nos vários processadores. Deve-se notar que este paralelismo só é possível se existirem processadores livres – ou seja, se o número de processadores é superior ao número de conexões. Adicionalmente, este paralelismo não é considerado se o comando não tiver custo de execução elevado. Sob o esquema normal de pooling, uma worker thread executa um pedido do cliente até ao fim. Se uma determinada thread causar uma falha de paginação, só aquela thread, e por sua vez só aquele cliente, é bloqueado (Uma falha de paginação ocorre se uma thread requisita uma página de memória que ainda não foi carregada em RAM, tendo o gestor de memória virtual do sistema operativo de a carregar de disco. Este pedido de memória deve esperar um tempo superior ao tempo normal de acesso a memória uma vez que um I/O físico é mais custoso do que uma leitura de memória). Suponhamos algo mais sério do que uma falha de memória. Suponhamos que durante a execução de um pedido do utilizador, uma falha do SQL Server é exposta e resulta numa operação ilegal que provoca uma violação de acesso. O sistema operativo termina imediatamente a thread causadora. Uma vez que o SQL Server utiliza a gestão de excepções estruturada do Windows NT/2000, apenas o utilizador específico do SQL Server que fez o pedido é afectado. Todos os outros utilizadores ou outras aplicações no sistema não são afectadas e o sistema operativo não deve bloquear. Claro que na teoria este sistema é óptimo e não se espera que ocorram estes Página 61 Instituto Superior de Engenharia do Porto problemas, mas se ocorrerem é bom que este sistema exista e que se comporte como é esperado. 2.4.3) E/S de Disco no Windows NT/2000 O SQL Server 2000 utiliza duas características do Windows NT/2000 para melhorar a performance de E/S de disco: scattergather I/O e asynchronous I/O. • Scatter-gather I/O Æ Este sistema foi introduzido com o NT 4.0, Service Pack 2. Anteriormente, todos os dados para uma escrita ou leitura de disco no Windows NT tinham que estar numa área contígua de memória. Se uma leitura transferia 64 Kb de dados, o pedido de leitura tinha que especificar o endereço de uma área de 64 Kb de memória contínua. O Scatter-gather I/O permite uma escrita ou leitura de e para áreas descontínuas de memória. Se o SQL Server ler um extent com 64 Kb, não tem que alocar uma área única de 64 Kb e depois copiar as páginas individuais para páginas do buffer cache. Podem alocar oito páginas de buffer e depois fazer um único scatter-gather I/O que especifica o endereçamento das oito páginas. O Windows NT/2000 coloca as oito páginas directamente em páginas de buffer, eliminando a necessidade do SQL Server fazer uma cópia de memória separada. • Asynchronous I/O Æ Num Asynchronous I/O, após uma aplicação requisitar uma operação de leitura ou escrita, o Windows NT/2000 imediatamente devolve o controlo à aplicação. A aplicação pode então efectuar trabalho adicional e posteriormente verificar se a escrita ou leitura foi completada. Por contraste, num Synchronous I/O, o sistema operativo não devolve o controlo à aplicação até que a escrita ou leitura acabe. O SQL Server suporta múltiplas operação concorrentes de Asynchronous I/O sobre cada ficheiro da base de dados. O número máximo de operação de I/O para cada ficheiro são determinadas pelos recursos do sistema, e o SQL Server emite quantas operações forem possíveis. Página 62 Instituto Superior de Engenharia do Porto 3. Conclusão Neste relatório, pretendi estudar e compreender o modo de funcionamento interno do SQL Server 2000. A abordagem inicial, pretendeu mostrar que a evolução deste produto está intimamente ligada aos sistemas operativos da Microsoft e à sua evolução, bem como às necessidades dos utilizadores de ambos e que foi ainda influenciada pelas características necessárias em novas áreas de mercado. A ideia fundamental foi dar-me e a quem ler este relatório uma perspectiva histórica que situe o produto e que explique os motivos das suas evoluções/inovações, bem como os momentos em que ocorreram. Na segunda, e mais importante, parte deste relatório, descrevemse os principais componentes do SQL Server. Neste momento, posso dizer que este estudo terá que continuar. A descrição de alguns componentes pode, e deve, ser mais aprofundada para uma total compreensão de um sistema tão complexo. Nem eu próprio tinha uma ideia do que este estudo implicava, quando me decidi abordar este tema. O conteúdo do relatório foi ainda influenciado pelas limitações temporais próprias deste tipo de trabalhos e pela necessidade de simplificação de alguns assuntos, principalmente quando não focavam directamente os objectivos deste relatório. Mas o mais importante é que me fez compreender melhor o modo de funcionamento deste produto e, principalmente, fez-me querer saber mais. Não podemos separar o funcionamento interno do SQL Server de todo um conjunto de factores e funcionalidades que normalmente são abordados do ponto de vista do programador ou do administrador. E este funcionamento depende do nível de conhecimentos nessas áreas para a sua total compreensão. Espero que quem leia este relatório queira saber mais sobre o assunto, tal como eu. Considero, se for o caso, que um dos objectivos deste trabalho foi plenamente atingido. Página 63 Instituto Superior de Engenharia do Porto BIBLIOGRAFIA Livros “Microsoft SQL Server 2000 - Administrator’s Companion” Garcia, Reding, Whalen e DeLuca Microsoft Press “Inside Microsoft SQL Server 2000” Kalen Delaney Microsoft Press “Microsoft SQL Server 2000 Books Online” Manuais “Microsoft Official Curriculum” Curso 2071A “Querying Microsoft SQL Server 2000 with Transact-SQL” Curso 2072A “Administering a Microsoft SQL Server 2000 Database” Curso 2073A “Programming a Microsoft SQL Server 2000 Database” Sites na Internet SQL Server Magazine – www.sqlmag.com SQL Server Resources - www.labmice.net/Sql.htm SQL Zone – www.sql-zone.com Dblinks.net - www.dblinks.net/Microsoft_Sql_Server/ Microsoft – www.microsoft.com/sql Definições de Termos Técnicos – www.whatis.com Página 64