Sistemas de Base de Dados 2011-2012 Análise de Sistemas de Base de Dados Armazenamento e estruturas de indexação Grupo 06: Alexandre Pinote no 36917 Carlos Loureiro no 37770 Pedro Tiple no 37902 3 de Dezembro de 2011 Resumo Este documento foi desenvolvido no contexto da cadeira Sistemas de Bases de Dados, nele são descritos detalhes de funcionamento de 3 sistemas de bases de dados. As funcionalidades descritas incidem sobre o tema Armazenamento e estruturas de indexação. É feita uma comparação de como os vários sistemas funcionam em vários aspectos, no caso de existirem, são explicitados quais os comandos ou parâmetros que permitem alterar o funcionamento do sistema. Conteúdo 1 Introdução 3 2 Armazenamento 2.1 Controlo de Buffer Management 2.2 File System . . . . . . . . . . . . 2.3 Mecanismos de partições . . . . . 2.4 Organização dos tuplos . . . . . . 2.5 Registos de tamanho variável . . 2.6 Multitable Clustering . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3 Estruturas de indexação 3.1 Estruturas de indexação . . . . . . . . . . . . . . . . 3.1.1 PostgreSQL . . . . . . . . . . . . . . . . . . . 3.1.2 DB2 . . . . . . . . . . . . . . . . . . . . . . . 3.1.3 Oracle . . . . . . . . . . . . . . . . . . . . . . 3.2 Estruturas dos ı́ndices para organização de ficheiros . 3.3 Indexação com mais de um ficheiro para conjuntos de 3.4 Hashing . . . . . . . . . . . . . . . . . . . . . . . . . 3.5 Estruturas temporariamente inconsistentes . . . . . . 4 Conclusão . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . atributos . . . . . . . . . . 4 4 5 8 11 13 14 16 16 16 17 17 18 19 20 21 23 1 Lista de Figuras 2.1 2.2 2.3 2.4 Hierarquia de armazenamento do DB2. . . . . . . Hierarquia de armazenamento do Oracle. . . . . . Ilustração de particionamento de tabelas no DB2. Estrutura de uma página em DB2. . . . . . . . . . . . . 7 8 10 12 3.1 3.2 3.3 3.4 Organização de ficheiros no DB2. . . . . . . . . . . . . . . . . Indexações particionadas no DB2. . . . . . . . . . . . . . . . Ilustração da função de hash. . . . . . . . . . . . . . . . . . . Ilustração do comando SET CONSTRAINTS onde é possı́vel aplicar a clausula DEFERRABLE. . . . . . . . . . . . . . . . 18 19 21 2 . . . . . . . . . . . . . . . . . . . . . . . . 22 Capı́tulo 1 Introdução Sistemas de bases de dados são sistemas complexos que ainda nos dias de hoje estão a ser melhoradas. Devido a diferentes requisitos e ideais, há um número largo de sistemas de bases de dados actualmente em utilização. Nesta realidade estudar sistemas de bases de dados implica o conhecimento de mais do que um sistema, no entanto, é difı́cil ter um conhecimento aprofundado de todos eles devido às suas complexas diferenças e número elevado. Actualmente o sistema de bases de dados de referência é o Oracle Database que é um sistema proprietário da Oracle, de modo a ter uma visão de mais opções existentes no mercado faz sentido compará-lo com outro sistema, que neste caso vai ser o DB2 da IBM. Sistemas proprietários não é tudo o que está disponı́vel, existem vários sistemas open source que exibem capacidades equivalentes ao dos grandes sistemas, um exemplo é o PostgresSQL, este sistema é desenvolvido em comunidade aberta e está disponı́vel sem custos. 3 Capı́tulo 2 Armazenamento 2.1 Controlo de Buffer Management De modo a que se reduza o número de leituras ao disco, os sistemas de bases de dados usam buffers próprios para manter em memória informação que possa vir a ser lida mais que uma vez. Estes buffers diferem das caches do SO porque os buffers mantêm páginas da base de dados enquanto as caches guardam blocos do disco. PostgreSQL Neste sistema o buffer é um vector simples em que cada entrada é um buffer. Fazer uma procura no buffer é feito usando um processo chamado clock-sweep que consiste em percorrer por ordem crescente as entradas do vector. Cada buffer pode estar no estado pinned ou unpinned e limpo ou sujo. Está no estado pinned quando está a ser referenciado por um ou mais clientes, neste estado o buffer não pode ser reciclado no caso de ser preciso um buffer novo. Sempre que novos dados são escritos para um buffer, este passa a sujo que indica que deve ser escrito para o disco. Inicialmente existem já buffers alocados e o valor por defeito são 32 megabytes alocados para o total dos buffers, o tamanho destes pode ser alterado com o parâmetro shared buffers(). A alocação de novos buffers consiste em verificar a lista de buffers vazios que o sistema mantém e usar o primeiro livre, ou se estiverem todos ocupados, escolhe um para libertar e coloca lá o novo. O processo de escolha consiste em efectuar o clock-sweep previamente descrito à procura do primeiro buffer com um estado diferente de pinned. DB2 No sistema DB2 existem buffer pools que inicialmente têm espaço suficiente para 16 páginas, cada pool guarda páginas de tamanho 4 KB, 8 KB, 16 KB e 32 KB. A memória necessária para manter as buffer pools é alocada quando a base de dados é activada usando os parâmetros definidos e sempre 4 que a base de dados é desactivada o espaço dos buffer pools é libertado. As primeiras quatro pools são automaticamente criadas de modo a que haja sempre uma buffer pool em qualquer circunstância e estas são apenas usadas pelo sistema e não podem ser removidas. A gestão das pools é feita pelo database manager, é este que tem a responsabilidade de verificar se já existe uma certa página no buffer e no caso de não existir, ir buscá-la ao disco. O número de páginas de uma dada pool cresce automaticamente no caso de serem precisas mais páginas, no entanto é possı́vel aumentar o tamanho de uma buffer pool usando o comando ALTER BUFFERPOOL. Novas buffer pools podem ser criadas com CREATE BUFFERPOOL. O sistema disponibiliza o comando db2mtrk que mostra a quantidade de memória da base de dados que está alocada para buffer pools. As páginas dos buffer pools podem estar em vários estados, a ser usada ou não e suja ou limpa. Páginas em uso são páginas que estão a ser lida ou actualizadas, se a página está a ser actualizada só pode ser acedida por quem a está a actualizar, no entanto se estiver a ser lida, pode ser por mais que um utilizador. No caso de ser necessário remover uma página do buffer, a escolha da página para remoção é feita segundo os critérios: quando foi a ultima vez que a página foi referênciada, qual a probabilidade de a página voltar a ser refênciada, o tipo de dados que a página contem e se a página foi alterada sem ser escrita para o disco. Oracle O Oracle usa buffers que estão organizados usando tabelas de endereçamento e listas ligadas. Operações de pesquisa sobre todos os buffers fazem uso da buffer address table que indexa os buffers por número do buffer. Operações de pesquisa sobre buffers com um identificador de página especifico usam a buffer hash table que está organizada em buckets de buffers, em que cada buffer bucket contem uma lista ligada de todos os buffers que o hash do seu id seja o mesmo que o id do bucket. Para libertar buffers, é usado o algoritmo LRU(Least Recently Used ) que como o nome indica, liberta o buffer que não é usado à mais tempo. A entidade que gere os buffers chamase Database Writer (DBWR), este processo tem três estruturas interna: • cadeias de buffers; • uma lista LRUW(a lista com os buffers ”sujos”); • a lista LRU. 2.2 File System Uma vez que os sistemas de bases de dados normalmente estão a funcionar por cima de um sistema operativo, faz sentido usar o sistema de ficheiros 5 do mesmo, no entanto, por questões de segurança e optimização, pode ser melhor implementar um sistema de ficheiros proprietário que está especificamente desenhado para atender às necessidades do sistema de bases de dados. Usar o sistema de ficheiros do sistema operativo implica a necessidade de ter compatibilidade com os vários SOs mais comuns mas simplifica o desenvolvimento da base de dados. Usando um sistema de ficheiros próprio garante que a base de dados funciona com qualquer sistema operativo, no entanto adiciona complexidade ao sistema da base de dados. PostgreSQL O PostgreSQL faz uso do sistema de ficheiros do sistema operativo para manter as directorias e os ficheiros, dos quais existem vários. Cada tabela e ı́ndice é mantido num ficheiro individual e sempre que um destes ficheiros excede o tamanho de 1GB o mesmo é separado em segmentos de até 1GB cada, deste modo garante-se compatibilidade com plataformas que tenham limitações no tamanho máximo de ficheiros, o valor de 1GB é definido pelo valor por defeito de um segmento e pode ser alterado com a opção –with-segsize no momento de construção da base de dados. De maneira a manter eficientemente espaços livres, cada tabela ou ı́ndice tem associado um freespace map que representa os espaços livres de cada tabela ou ı́ndice. Tabelas com colunas que tenham entradas potencialmente muito grandes têm uma tabela TOAST(The Oversized-Attribute Storage Technique) associada, no PostgreSQL são usadas páginas de tamanho fixo normalmente com 8kb e não é permitido que um tuplo ocupe mais que uma página, dai usar-se o TOAST, este vai comprimir ou partir campos grandes de mais em mais que uma row. DB2 O DB2 guarda a informação em áreas chamadas tablespaces que podem ser System Managed Space ou Database Managed Space. No caso de um System Managed Space o sistema de ficheiros do sistema operativo é usado e as tabelas e as suas entradas são guardadas em directorias organizadas hierarquicamente. Em Database Managed Space o sistema aloca inicialmente espaço para guardar informação, este bloco que deve ocupar um espaço razoavelmente grande é considerado um só ficheiro para o sistema operativo e a estrutura do ficheiro é própria do DB2. A criação de um novo tablespace é feito com o comando CREATE TABLESPACE e os seus parâmetros podem ser alterados com o comando ALTER TABLESPACE. Ter mais que um tablespace pode ser útil porque no DB2, a informação é guardada como páginas. Dependendo do tamanho das página de um tablespace e o tamanho de linhas nas suas tabelas, uma linha pode ocupar muitas 6 páginas, ou uma página pode conter muitas linhas. Armazenar uma linha, ou muitas linhas, em uma única página, permite que toda a linha ou linhas ao sejam lidas como uma única página de disco. Tamanhos de página grandes são bons para armazenar tabelas com linhas muito longas ou tabelas usadas regularmente para acesso de dados sequenciais. Por outro lado, armazenar linhas pequenas acedidas aleatoriamente em páginas grandes é uma utilização pouco eficiente das buffer pools. Para permitir que diferentes tabelas sejam armazenadas com tamanhos de página e tamanhos diferentes e para permitir que o buffer seja separado, é melhor usar vários tablespaces com tamanhos diferentes. Figura 2.1: Hierarquia de armazenamento do DB2. Oracle Na base de dados Oracle a informação é mantida de uma maneira muita semelhante ao DB2, como se pode ver pela figura 2.2 a estrutura é igual e a única coisa que se altera é o nome atribuido aos vários objectos. O equivalente às páginas do DB2 são os blocos, os blocos mantêm informação de linhas, dentro do bloco novas linhas crescem ”para cima”a partir do fim do bloco. Quando uma nova entrada é introduzida e esta não cabe no bloco, um novo bloco é criado e a informação é partida entre os dois blocos. 7 Figura 2.2: Hierarquia de armazenamento do Oracle. 2.3 Mecanismos de partições Particionar uma base de dados, que consiste em dispersar os elementos que constituem a base de dados ou as tabelas em partes independentes, pode trazer vantagens em termos de performance, manutenção e disponibilidade. Uma capacidade útil deste mecanismo é permitir distribuir a carga da base de dados por vários nós, o que cria uma base de dados distribuı́da que introduz possivelmente redundância, evite um ponto central de falha e permite uma maior escalabilidade do sistema. PostgreSQL Ainda que de um modo descrito pelo próprio PostgreSQL como simples, este sistema suporta particionamento de tabelas. O benefı́cio de usar particionamento só se nota para tabelas bastante grandes, com um tamanho maior que a quantidade de memória fı́sica disponı́vel. O particionamento é feito através de herança de tabelas, cada partição tem de ser criada como filha de uma única tabela pai, estando esta vazia e apenas serve para representar o data set inteiro. São suportadas as seguintes formas de particionamento: • Particionamento por intervalo: a tabela é particionada em intervalos definidos por uma coluna chave ou grupo de colunas, sem sobreposição entre intervalos. • Particionamento de listas: a tabela é particionada por definição explicita de quais valores chave aparecem em quais partições. 8 O particionamento é definido da seguinte forma: • Cria-se a tabela mestre que vai ser herdade por todas as partições, esta tabela não deve ter informação e não deve ter check constraints a não se que se deseje que todas as partições as tenham; • Cria-se várias tabelas filhas da tabela mestre, estas tabelas são as partições; • Adiciona-se restrições às partições que definem os valores chaves permitidos em cada tabela. Exemplo: CHECK ( x = 1 ) CHECK ( county IN ( ’Oxfordshire’, ’Buckinghamshire’, ’Warwickshire’ )) CHECK ( outletID >= 100 AND outletID < 200 ) • Para cada partição, cria-se um ı́ndice nas colunas chaves; • Opcionalmente define-se triggers ou regras para redireccionar informação inserida na tabela mestre para a partição correcta; • Verificar que o parâmetro de configuração contraint exclusion não está desactivado no ficheiro postgresql.conf porque se estiver, as procuras não vão ser optimizadas. DB2 O gestor da base de dados do DB2 permite particionar a base de dados com bastante flexibilidade, permite escolher a maneira que a informação é distribuı́da usando chaves de distribuição e em quantas partições as tabelas são distribuı́das por meio de escolha de grupos de partições e tablespaces sobre os quais se deve fazer a distribuição. O sistema mantém um mapa de distribuição actualizável que especifica a atribuição de chaves às várias partições, isto permite uma maior flexibilidade de paralelização para tabelas grandes enquanto ao mesmo tempo permite guardar tabelas pequenas em poucas partições. As partições podem ser definidas no ficheiro db2nodes.cfg e o seu conteúdo pode ser acedido fazendo um select da tabela DB PARTITIONS(). A chave de distribuição de cada tabela pode ser definida no momento de criação ou com ALTER TABLE, se a chave de distribuição não for definida o seu valor por defeito é a primeira coluna da chave primária. Uma tabela particionada tem de ter pelo menos um campo que não seja do tipo long ou LOB. As suas entradas são distribuı́das pelas partições do seguinte modo: um algoritmo de hashing é aplicado a todas as colunas da chave de distribuição e o resultado é o valor de ı́ndice do mapa de distribuição, com o valor que se encontra no ı́ndice gerado atribui-se a partição a que a entrada faz parte. 9 Figura 2.3: Ilustração de particionamento de tabelas no DB2. Oracle No Oracle, partições não são uma funcionalidade base, é necessária uma licença à parte que só está disponı́vel para a versão Enterprise Edition. Os mecanismos de particionamento permitem particionar uma tabela em 1 milhão de partições. São disponibilizados os seguintes tipos de particionamento: • Range partitioning – diferentes ranges são atribuı́dos às várias partições. Exemplo: PARTITION BY RANGE(empno) ( partition e1 values less than (1000) tablespace ts1, partition e2 values less than (2000) tablespace ts2, partition e3 values less than (MAXVALUE) tablespace ts3 ); • Hash partitioning – uma chave hash é usada para atribuir entradas pelas partições. Exemplo: PARTITION BY HASH(empno) 10 PARTITIONS 3 STORE IN (empts1, empts2, empts3); • Composite partitioning – particiona usando dois métodos de particionamento, faz uma partição inicial com o primeiro método e depois cada partição nova é sub-particionada com o segundo método. PARTITION BY RANGE(orderdate) SUBPARTITION BY HASH(prod#) SUBPARTITIONS 4 ( PARTITION q1 VALUES LESS THAN (TO_DATE(’01-APR-2009’, ’DD-MON-YYYY’)), PARTITION q2 VALUES LESS THAN (TO_DATE(’01-JUL-2009’, ’DD-MON-YYYY’)), PARTITION q3 VALUES LESS THAN (TO_DATE(’01-OCT-2009’, ’DD-MON-YYYY’)), PARTITION q4 VALUES LESS THAN (MAXVALUE) ); • List partitioning – atribui listas de chaves de particionamento a cada partição individualmente. PARTITION BY LIST (deptno) ( PARTITION p10 VALUES (10), PARTITION p20 VALUES (20), PARTITION p30 VALUES (30,40) ); • Interval partitioning – evolução do range partitioning em que se uma nova entrada não corresponde a nenhum range, é criado uma nova partição para guardar estas entradas. • System partitioning – permite a uma aplicação controlar o particionamento da tabela. • Reference partitioning – o método de particionamento é herdado da tabela pai. 2.4 Organização dos tuplos A maneira como os tuplos das tabelas são mantidos vai afectar directamente e eficiência da base de dados, devido a isso é necessário escolher a melhor organização possı́vel para os requisitos do sistema. Como os diferentes sistemas de bases de dados funcionam de maneiras diferentes, uma organização pode ser vantajosa para um sistema e para outro não. 11 PostgreSQL Como vimos na secção ”File System”o PostgreSQL mantém um freespace map que sugere que a organização dos tuplos é em Heap, ou seja, os tuplos são introduzidos no primeiro espaço livre no ficheiro da tabela. Esta organização elimina a necessidade de efectuar cálculos para descobrir onde deve ser colocado o tuplo, mas no momento de leitura, toda a página tem de ser percorrida para descobrir o tuplo desejado. DB2 O DB2 organiza os tuplos dentro do ficheiro num heap, de cada vez que um tuplo é adicionado, é procurado um espaço livre suficientemente grande dentro da página, no caso de não haver espaço, uma nova página é criada. A gestão dos espaços livres é feito da seguinte maneira, no cabeçalho da página existe um apontador para o primeiro espaço livre contı́guo, um apontador para o começo da ”cadeia de buracos”e o espaço total livre no bloco. Figura 2.4: Estrutura de uma página em DB2. Oracle De modo igual às duas bases de dados vistas anteriormente, o Oracle organiza os tuplos em heap, dentro de um bloco os tuplos são introduzidos ”de baixo para cima”e no caso de se introduzir um tuplo que não caiba no bloco, um novo é criado para o acomodar. 12 2.5 Registos de tamanho variável Os sistemas de bases de dados usam um leque variado de tipos de atributos. Para isso os registos no sistema de base de dados têm de ter uma certa implementação para permitir tamanhos fixos desses registos ou para disponibilizar registos de tamanho variáveis. PostgreSQL O PostgreSQL permite registos de tamanho variável usando o TOAST (The Overside-Attribute Storage Technique). Por defeito a estrutura do sistema é implementada em slotted pages e um registo não pode passar o tamanho da slotted page mas foi criado o TOAST para contornar isso. O TOAST para contornar esta limitação vai comprimir os registos ou decompôlos em várias linhas sendo que existe uma tabela TOAST com apontadores para linhas que não a original. Este processo é transparente para o utilizador e existem várias técnicas que o TOAST usa para as diferentes colunas: • PLAIN – neste tipo de técnica não é utilizada qualquer compressão nem decomposição em mais linhas, é o tipo de estratégia usado para colunas em que o TOAST não actua; • EXTENDED – usa compressão e decomposição em várias linhas • EXTERNAL – usa decomposição em várias linhas mas não compressão • MAIN – usa compressão e não decomposição em outras linhas DB2 Em DB2 são usadas páginas com tamanhos fixos sendo que têm 4 tamanhos: 4, 8, 16 e 32 Kb. Numa tabela podemos ter até 1012 colunas com páginas de 32Kb. Quando aparecem registos de tamanho variável em DB2 a forma de os tratar pode ser diferente. No caso de ser LOB (Large object) é usada uma técnica de criar uma nova página a cada 4, 8, 16 ou 32Mb dependendo do tamanho de página. Estas páginas estão num local diferente dos dados actuais. No caso de ser LF (Long Field ) os dados são guardados em pequenos segmentos numa área de 32Kb. Dados como Long Varchar ou Long VarGraphic, tal como LOB, usam alocação de novas páginas com tamanho 4Kb. Oracle O Oracle tal como no DB2 implementa LOB ou Large Object. Em Oracle este tipo de dados também é guardado no table space da tabela ou fora da linha da tabela. São guardados fora da linha da tabela quando o utilizador especifica que quer que assim seja recorrendo ao comando DISABLE STORAGE IN ROW quando se cria uma tabela, quando o tamanho do LOB 13 ultrapassa os 4000 bytes ou quando o tamanho já esteve acima dos 4000 bytes. Para o caso de nunca ter ultrapassado os 4000 bytes é armazenado na própria linha da tabela. Os segmentos onde são armazenados os conteúdos podem ser personalizáveis pelo comando STORE AS na criação da tabela. Exemplo de sintaxe de um objecto LOB: CREATE TABLE ContainsLOB_tab (n NUMBER, c CLOB) lob (c) STORE AS BASICFILE segname ( TABLESPACE lobtbs1 CHUNK 4096 PCTVERSION 5 NOCACHE LOGGING STORAGE (MAXEXTENTS 5) ); 2.6 Multitable Clustering Os Multitable clusters são usados quando duas ou mais tabelas compartilham a chave do mesmo cluster e as tabelas são frequentemente juntas na chave de cluster. PostgreSQL Em PostGreSQL é possı́vel criar um cluster de acordo com uma indexação. Para se criar um cluster usa-se a seguinte sintaxe: CLUSTER [VERBOSE] table_name [ USING index_name ] O parâmetro VERBOSE serve para mostrar um debug enquanto é feito o clustering. Não é possı́vel criar multitable clustering como em Oracle, mas é possı́vel para uma uma única tabela. DB2 Não foi encontrado na documentação do DB2 se é possı́vel ou não criar multitable clustering. Ainda assim contém um método para criar clustering multidimensional (MDC). Oracle No Oracle é possı́vel fazer multitable clustering por hash ou por index. Para criar um multitable clustering deve-se começar por criar um cluster por hash: CREATE CLUSTER cluster_attr_part (atributo_partilhado NUMBER(10)); E no final da declaração de cada uma das tabelas que partilham o mesmo atributo: 14 CLUSTER cluster_attr_part (atributo_partilhado); Assim o Oracle pode aumentar a sua performance recorrendo a estes clusters que guardam dados das suas tabelas. 15 Capı́tulo 3 Estruturas de indexação 3.1 Estruturas de indexação 3.1.1 PostgreSQL Em PostgreSQL são suportadas várias estruturas de indexação tais como B + -tree, Hash, GiST e GIN mas a que o PostgreSQL usa por defeito são as B + -tree. B + -tree Tendo um certo atributo indexável, as B + -tree no PostGreSQL são capazes de lidar com as seguintes comparações para esse atributo: < ; <= ; => ; = ; > Também podem ser usadas B + -tree em comparações usando LIKE ou m̃as tem de se usar strings em que o seu inı́cio seja constante e não % por exemplo. As B + -tree podem também ser utilizadas para ordenar. Hash No PostgreSQL o hash é só automaticamente usado para comparações de igualdade “=”. Para se criar uma indexação em hash corre-se o comando: CREATE INDEX name ON table USING hash (column); GiST A indexação GiST ou Generalized Search Tree é essencialmente usada para comparações de dados bidimensionais das quais: << ; & < ; & > ; >> ; << | ; & < | ; |& > ; | >> ; @ > ; < @ ; = ; && 16 Uma das capacidades que o GiST tem é encontrar vizinhos próximos de um ponto onde, por exemplo nesta query, ele vai encontrar os 5 pontos mais próximos do ponto (10,10): SELECT * FROM places ORDER BY location <-> point ’(10,10)’ LIMIT 5; GIN A indexação GIN ou Generalized Inverted Index é usada onde os valores têm mais de uma chave, ou seja, por exemplo array’s. Para isso o GIN consegue tratar as seguintes comparações: < @ ; @ > ; = ; && 3.1.2 DB2 Em DB2 são suportadas as B + -tree para estrutura de indexação na maior parte dos casos. Para criar uma indexação devemos seguir a seguinte sintaxe: CREATE UNIQUE INDEX UNIQUE_NAME ON PROJECT(PROJNAME) Em casos especı́ficos como geo-localização são utilizados também Spatial grid indexes e Geodetic Voronoi indexes. 3.1.3 Oracle É possı́vel usar no Oracle dois tipos de indexação: B + -tree e bitmaps. Para criar indexações do tipo B + -tree usa-se a seguinte sintaxe: CREATE [UNIQUE] INDEX nome_indexaçao ON nome_tabela (coluna1, coluna2, ... ,coluna_n) [ COMPUTE STATISTICS ]; UNIQUE indica que a combinação de valores da indexação têm de ser únicos. COMPUTE STATISTICS é uma opção do comando bastante aconselhada porque permite aos optimizadores do Oracle reunirem estatı́sticas enquanto criam a indexação. Estas estatı́sticas vão permitir aos optimizadores escolher a melhor execução de queries do SQL. Para criar indexações do tipo bitmap usa-se a seguinte sintaxe: CREATE BITMAP INDEX nome_bitmap ON nome_tabela (coluna); Este comando vai permitir criar bitmaps. Os bitmaps vão criar arrays bidimensionais com os valores de uma coluna para cada linha da tabela. Assim, quando o Oracle precisar de retornar uma linha numa query, o Oracle vai descomprimir o bitmap para a RAM e poderá ser rapidamente encontrar a linha que deseja. 17 3.2 Estruturas dos ı́ndices para organização de ficheiros PostgreSQL Não foi encontrado na documentação do PostgreSQL se este utiliza as estruturas dos ı́ndices para organização de ficheiros. DB2 Usa também as B + -tree para organização de ficheiros de ı́ndice para a localização de records das tabelas. Em DB2 existe um ı́ndice organizado numa B + -tree sendo que nesse ı́ndice estão os RID (record ID). Os RID são responsáveis por guardar a localização real dos dados, informação essa que se expressa numa pagina e no slot. Figura 3.1: Organização de ficheiros no DB2. Na figura acima pode-se perceber facilmente como DB2 gere e usa organização de ficheiros. Existe uma B + -tree que tem o ı́ndice para as páginas reais implementado que depois em cada pagina de ı́ndice contem o RID. Oracle Em Oracle, para a organização dos ficheiros, são usados Heaps e Hashing, ao que as estruturas de indexação não são usadas para este fim. 18 3.3 Indexação com mais de um ficheiro para conjuntos de atributos PostgreSQL O PostgreSQL só suporta um ficheiro ı́ndex por atributos, não permite que haja vários como em DB2. DB2 O DB2 suporta indexações particionadas para conjuntos de atributos. Quando criamos uma indexação temos uma opção disponı́vel PARTITIONED que serve para alocar a indexação na “table spaces” onde estão os respectivos atributos. Para clarificar melhor a ideia o DB2 tem “table spaces”, que é onde as tabelas estão alocadas, sendo que essas tabelas podem estar particionadas por vários table spaces ou não. No caso de estarem particionadas é possı́vel que o ı́ndice seja também particionado e cada parte esteja no mesmo “table space” dos valores que ele indexa. Para se criar uma indexação particionada utiliza-se a seguinte sintaxe: CREATE INDEX StoreNum ON sales(store_num) PARTITIONED Figura 3.2: Indexações particionadas no DB2. 19 Oracle Tal como em DB2, as indexações podem ser particionadas. Em Oracle são permitidas vários tipos de partições como locais e globais. As partições de indexações locais referem-se a que uma dessas partições indexáveis vêm de uma certa partição de uma tabela. As partições de indexações globais podem referir-se a que uma dessas partições indexáveis vêm de várias partições da tabela. Para criar indexações destes tipos seguimos a seguinte sintaxe: CREATE INDEX invoices_idx ON invoices (invoice_date) LOCAL; Ou CREATE INDEX invoices_idx ON invoices (invoice_date); Que correspondem a criar uma indexação particionada local e a uma indexação particionada global respectivamente. 3.4 Hashing Existe duas técnicas de hashing, o hashing estático e dinâmico. O hashing estático tem o número de páginas primárias no directório fixo. Assim, quando um bucket 1 está cheio, é necessário um overflow bucket para armazenar qualquer registro adicional que seja para ser inserido no bucket cheio. Este problema pode ser resolvido com um link para uma página de overflow, ou com uma lista ligada de páginas de overflow. A lista ligada pode ser separada para cada bucket, ou é possı́vel usar a mesma lista para todos os bucket em overflow. Ao procurar por um registo, o bucket original é acedido primeiro, depois os overflow buckets. Desde que haja muitas chaves com um hash para o mesmo bucket, encontrar um registro pode exigir o acesso a várias páginas em disco, o que muito prejudica o desempenho. O problema da procura longa de overflow bucket é resolvido por Hashing Dinâmico. Em Hashing Dinâmico o tamanho do directório cresce com o número de colisões para acomodar novos registros e evitar longas páginas de overflow. Hashing Extensı́vel e lineares são duas técnicas de hashing dinâmico. PostgreSQL O algoritmo de hashing usado pelo PostgreSQL foi desenvolvido por W. Litwin [1]. Este hashing é dinâmico, não possuindo qualquer rehashing que permita a eliminação dos buckets de overflow. É de salientar que este tipo de indexação é relativamente pior que a indexação por B + -tree. Para além de um maior uso de recursos, este indexação por hash não suporta ı́ndices de múltiplas colunas. Por tudo isto, o uso deste tipo de indexação é bastante desencorajado, até mesmo pelos responsáveis pelo PostgreSQL. 1 O termo bucket refere-se a uma unidade de armazenamento que pode armazenar um ou mais registos. Tipicamente um bucket é um bloco do disco. 20 DB2 O DB2 não suporta indexação por hash. Apesar disso o DB2 tem uma forma de computar o id da linha da tabela através da chave primária em tabelas apropriadas para o efeito (range clustered table). Oracle O Oracle não permite ı́ndices hash, permite apenas organização estática hash. Figura 3.3: Ilustração da função de hash. 3.5 Estruturas temporariamente inconsistentes Existem Sistemas de Base de Dados que permitem que as suas estruturas de dados estejam temporariamente inconsistentes. O estado inconsistente das estruturas acontece principalmente quando há necessidade de adiar a verificação de restrições de integridade, por exemplo, em transacções. Para além de alguns sistemas permitirem desactivar as restrições no inicio das transacções e activá-las automaticamente a quando o termino da transacção ainda é possı́vel definir o relaxamento das restrições durante a criação de uma tabela. PostgreSQL Este Sistema de Base de Dados permite o adiamento da verificação de certas restrições de integridade usando a clausula DEFERRABLE. Quando usada, a verificação da restrição é realizada no final da transacção (usando o comando SET CONSTRAINTS ). Actualmente apenas as restrições UNIQUE, PRIMARY KEY, EXCLUDE e REFERENCES permitem o uso desta clausula. Por defeito todas as restrições são verificadas em cada operação (NOT DEFERRABLE ). 21 DB2 Este Sistema de Base de Dados permite o adiamento da verificação de restrições de chaves estrangeiras mas é necessário o uso do utilitário LOAD. Existe, no entanto, alguns produtos que disponibilizam a clausula DEFERRABLE para atrasar a verificação de restrições. Oracle No Oracle a funcionalidade de adiamento da verificação de restrições de integridade é idêntico ao do PostgresSQL(Ver acima). Figura 3.4: Ilustração do comando SET CONSTRAINTS onde é possı́vel aplicar a clausula DEFERRABLE. 22 Capı́tulo 4 Conclusão No âmbito de estudar um tema entre vários sistemas de bases de dados, foi possı́vel compreender que existem diferentes implementações para as mesmas funcionalidades nos sistemas. No nosso tema notou-se uma variação maior porque comparámos dois sistemas bastantes diferentes, principalmente por um ser open-source e o outro não. Também por este motivo verificámos que a documentação encontrada é completamente diferente sendo que a documentação open-source está mais simples também devido ao seu sistema de base de dados ser mais simples. De uma forma geral conseguimos perceber as ideias base da matéria dada nas aulas com diferentes implementações não só direccionadas para o Oracle. 23 Bibliografia [1] Witold Litwin, Linear Hashing: A new Algorithm for Files and Tables Addressing. ICOD, 1980 [2] http://publib.boulder.ibm.com/infocenter/db2luw/v8/index. jsp?topic=/com.ibm.db2.udb.doc/core/r0008305.html [3] http://www.postgresql.org/docs/9.1/static/indexes-types. html [4] http://publib.boulder.ibm.com/infocenter/db2luw/v9r8/ index.jsp?topic=%2Fcom.ibm.db2.luw.admin.perf.doc%2Fdoc% 2Fc0005393.html [5] http://publib.boulder.ibm.com/infocenter/db2luw/v9r8/ index.jsp?topic=%2Fcom.ibm.db2.luw.admin.perf.doc%2Fdoc% 2Fc0005391.html [6] http://www.postgresql.org/docs/manuals/ [7] http://www.westnet.com/~gsmith/gregsmith/content/ postgresql/PostgreSQLBufferManagement.htm [8] http://publib.boulder.ibm.com/infocenter/db2luw/v9r8/ index.jsp?topic=%2Fcom.ibm.db2.luw.admin.perf.doc%2Fdoc% 2Fc0005393.html [9] http://www.devx.com/getHelpOn/10MinuteSolution/16575/1954 [10] http://www.postgresql.org/docs/9.1/interactive/storage. html [11] http://www.postgresql.org/docs/9.1/interactive/ storage-file-layout.html [12] http://en.wikibooks.org/wiki/Oracle_and_DB2,_Comparison_ and_Compatibility/Storage_Model/Physical_Storage/Oracle [13] http://en.wikipedia.org/wiki/Partition_%28database%29 24 [14] http://publib.boulder.ibm.com/infocenter/db2luw/v9r5/ topic/com.ibm.db2.luw.admin.partition.doc/doc/c0004126. html?resultof=%22partition%22%20%22partit%22 [15] http://www.postgresql.org/docs/current/static/ ddl-partitioning.html [16] http://en.wikibooks.org/wiki/Oracle_and_DB2,_Comparison_ and_Compatibility/Storage_Model/Physical_Storage/DB2#Page [17] http://www.postgresql.org/docs/9.1/static/storage-fsm.html [18] http://en.wikibooks.org/wiki/Oracle_and_DB2,_Comparison_ and_Compatibility/Storage_Model/Physical_Storage/Oracle# Block [19] https://forums.oracle.com/forums/thread.jspa?threadID= 487488 [20] http://docs.oracle.com/cd/E11882_01/server.112/e17118/ statements_10003.htm [21] http://www.orafaq.com/forum/t/66928/2/ [22] http://docs.oracle.com/cd/B19306_01/server.102/b14200/ clauses002.htm [23] http://euler.vcsu.edu:7000/11719/ [24] http://www.orafaq.com/tuningguide/advanced%20objects.html [25] http://www.orafaq.com/tuningguide/advanced%20objects.html [26] http://publib.boulder.ibm.com/infocenter/db2luw/v8/index. jsp?topic=/com.ibm.db2.udb.doc/admin/c0007201.htm [27] http://en.wikibooks.org/wiki/Category:Oracle_and_DB2, _Comparison_and_Compatibility [28] http://en.wikipedia.org/wiki/Linear_hashing [29] http://www.cs.sfu.ca/CourseCentral/354/zaiane/material/ notes/Chapter11/node1.html [30] http://publib.boulder.ibm.com/infocenter/db2luw/v8/index. jsp?topic=/com.ibm.db2.udb.doc/core/r0008305.htm [31] http://ssdi.di.fct.unl.pt/sbd/func/teoricas 25