otimização de consultas paralelas usando o - FACOM

Transcrição

otimização de consultas paralelas usando o - FACOM
OTIMIZAÇÃO DE CONSULTAS PARALELAS
USANDO O AGRUPAMENTO PRÉVIO
E UM FILTRO SELETIVO
Nilton Cézar de Paula
Dissertação de Mestrado
Orientador: Prof. Dr. José Craveiro da Costa Neto
Área de Concentração: Ciência da Computação
Dissertação apresentada ao Departamento de Computação e Estatística
(DCT) da Universidade Federal de Mato Grosso do Sul (UFMS) como
parte dos requisitos para a obtenção do título de Mestre em Ciência da
Computação.
Departamento de Computação e Estatística
Centro de Ciências Exatas e Tecnologia
Universidade Federal de Mato Grosso do Sul
Novembro de 2003
"...As invenções são sobretudo o resultado
de um trabalho teimoso..."
Alberto Santos Dumont
i
Dedicatória
Aos meus pais, José Ramos (in memorian)
e Maria Veloso, por todos os esforços e
sacrifícios
realizados
para
me
proporcionar o término do curso de
graduação.
A Elisângela, pela sua presença constante
e efetiva, que com seu estímulo e sua
ajuda me faz enfrentar e ultrapassar
desafios.
ii
Agradecimentos
"Não mostre para Deus o tamanho do seu problema, mostre para o problema o tamanho
do seu Deus" (autor desconhecido). Deus, obrigado pelo dom da vida e pela paciência.
Ao Prof. Dr. José Craveiro da Costa Neto, pela orientação, acompanhamento e
paciência que dedicou a este trabalho e a mim. Pelas sugestões valiosas, conduzindo de forma
coerente a construção deste trabalho. Por orientar um aluno que não é da mesma cidade e que
não podia dedicar tempo integral para os estudos.
À Profª. Liria Matsumoto Sato, ao Prof. Marcelo Augusto Santos Turine e ao Prof.
Hélio Crestana Guardia, pelas sugestões e contribuições feitas na qualificação. Aos membros
da banca examinadora, pela boa vontade em aceitar o convite para participar da minha defesa.
Aos professores do DCT/UFMS, que lutaram para tornar realidade o curso de Mestrado
em Ciência da Computação. Muito obrigado. Em especial ao Prof. Marcelo Henriques de
Carvalho e ao Prof. Nalvo Franco de Almeida Júnior, pelos conselhos, mas com destaque
daquele da primeira semana de aula do mestrado, ao Prof. Edson Norberto Cáceres pela
amizade desde a sua passagem na Pró-Reitoria de Graduação-UFMS, ao Prof. Henrique
Mongelli, Coordenador do Mestrado, pela dedicação que vem demonstrando na direção do
curso e por nos manter sempre informado dos acontecimentos.
Aos professores das disciplinas do mestrado, que além de ensinarem conteúdos também
demonstraram exemplos de vida e amor. Aos funcionários do DCT/UFMS, pela atenção
dispensada em todos os momentos que lá estive.
Aos colegas da turma de mestrado, pelo apoio e amizade, com destaque para o
Alexandre, Christian, Daniel, Erik, Érika, Graziela, Humberto, Luciana, Luciano, Marta,
Sibelis, Rodrigo e Welton. Se esqueci de mencionar alguém me perdoe.
A todos os meus parentes e familiares, pelo apoio, incentivo e soberam compreender a
minha ausência em muitos momentos de confraternização. À minha irmã Adriana Betânia,
iii
Mário Marcos, Flávia Aline e Larissa Beatriz pelo carinho e palavras de força e estímulo. Ao
meu irmão Fabrício que não mediu esforços para conseguir inúmeros artigos e que também
teve paciência e disposição de fazer a correção deste texto. À Danieli, Oséias, Maria Hilda,
Joaquim Arcanjo, Eliane, Franklin, Franklin Júnior, Willian, Aparecida e Milton Molgora que
torceram pela finalização deste texto.
Ao meu filho Juninho, por estar conosco e, assim, com seu sorriso nos faz reviver a
criança que existe dentro de nós.
Aos meus alunos da UEMS e da UNIGRAN, que souberam compreender a minha
ausência às aulas quando estive em muitos momentos em Campo Grande-Ms.
Aos colegas professores da UEMS e da UNIGRAN, pelo apoio nos momentos em que
sempre precisei.
Aos técnicos do laboratório de computação da UEMS que organizaram as máquinas
para os testes.
Ao Adriano Câmara, Diretor de Informática da UNIGRAN, pela amizade e apoio ao
acesso ao provedor de internet através do dourados.br.
À Universidade Estadual de Mato Grosso do Sul, pela concessão de afastamento total
no último ano do mestrado.
À UNIGRAN, pelo apoio às viagens para Campo Grande-Ms.
À demais pessoas que contribuiram para o desenvolvimento deste trabalho, direta ou
indiretamente.
iv
Sumário
LISTA DE FIGURAS............................................................................................................viii
LISTA DE TABELAS..............................................................................................................x
RESUMO..................................................................................................................................xi
ABSTRACT..............................................................................................................................xii
1. INTRODUÇÃO ..........................................................................................................1
1.1. Definição do Problema ...................................................................................................... 1
1.2. Motivação ........................................................................................................................... 2
1.3. Objetivos do Trabalho ...................................................................................................... 3
1.4. Organização do Texto ....................................................................................................... 3
2. BANCO DE DADOS E PROCESSAMENTO DE CONSULTAS .............................5
2.1. Introdução .......................................................................................................................... 5
2.2. Bancos de Dados Relacionais............................................................................................ 5
2.2.1. Data Warehouses.......................................................................................................... 6
2.2.2. Bancos de Dados Distribuídos e Paralelos ................................................................... 7
2.2.3. CDBS............................................................................................................................ 9
2.3. Processamento de Consultas........................................................................................... 11
2.3.1. Processador de Consultas ........................................................................................... 13
2.4. Técnicas de Otimização de Consultas............................................................................ 14
2.4.1. Da Álgebra Relacional para um Plano Lógico Otimizado ......................................... 15
2.4.2. Do Plano Lógico Otimizado para Planos de Execução ..............................................17
2.4.3. Ordem para Junções ................................................................................................... 17
2.4.4. Abordagens para Enumerar Planos de Execução ....................................................... 18
2.4.5. Otimização de Consultas Paralelas.............................................................................19
2.5. Considerações Finais ....................................................................................................... 23
3. PARADIGMA DE TROCA DE MENSAGENS........................................................24
3.1. Introdução ........................................................................................................................ 24
3.2. Criação de Processos ....................................................................................................... 24
3.3. Envio e Recebimento de Mensagens ..............................................................................25
v
3.4. Ambientes de Troca de Mensagens................................................................................25
3.5. MPI-2.0 ............................................................................................................................. 26
3.6. Métricas para Avaliar Programas Paralelos................................................................. 31
3.7. Considerações Finais ....................................................................................................... 31
4. AGRUPAMENTO PRÉVIO E FILTRO SELETIVO ................................................33
4.1. Introdução ........................................................................................................................ 33
4.2. Aplicando o Agrupamento Prévio..................................................................................33
4.2.1. Tipos de transformação .............................................................................................. 36
4.2.2. Conjuntos necessários para a transformação .............................................................. 37
4.2.3. Identificando o nó de transformação .......................................................................... 37
4.3. Estratégias para o Agrupamento Prévio ....................................................................... 39
4.3.1. Processamento Seqüencial de Agregados................................................................... 39
4.3.2. Processamento Paralelo de Agregados ....................................................................... 41
4.3.3. Usando um Filtro Seletivo.......................................................................................... 43
4.4. Considerações Finais ....................................................................................................... 46
5. FAP: UM AMBIENTE PARA A EXECUÇÃO DE CONSULTAS PARALELAS
COM AGREGADOS ...................................................................................................48
5.1. Introdução ........................................................................................................................ 48
5.2. Execução de Consultas com Agregados......................................................................... 49
5.2.1. Estratégias para a Junção e Agregação....................................................................... 49
5.2.2. Aplicando o Agrupamento Prévio em Paralelo .......................................................... 53
5.2.3. Aplicando o Filtro Seletivo......................................................................................... 54
5.3. Arquitetura do FAP ........................................................................................................ 55
5.4. O Módulo Cliente ............................................................................................................ 57
5.4.1. Catálogo...................................................................................................................... 57
5.4.2. Gerador de Catálogo................................................................................................... 58
5.4.3. Replicador de Catálogo .............................................................................................. 58
5.4.4. Atualizador de Instância ............................................................................................. 59
5.4.5. Gerador Estatístico .....................................................................................................59
5.4.6. Analisador de Sintaxe................................................................................................. 60
5.4.7. Gerador de Plano Inicial ............................................................................................. 61
5.4.8. Otimizador Heurístico ................................................................................................ 61
5.4.9. Otimizador de Agregação........................................................................................... 62
5.4.10. Gerador de Plano de Execução.................................................................................62
5.4.11. Coordenador de Execução ........................................................................................ 62
5.5. O Módulo Servidor de Arquivos Paralelos ................................................................... 63
vi
5.6. Aspectos de Implementação do FAP..............................................................................64
5.7. Considerações Finais ....................................................................................................... 68
6. MEDIDAS, DESEMPENHO E COMPARAÇÕES ..................................................70
6.1. Introdução ........................................................................................................................ 70
6.2. Um Estudo de Caso com o FAP...................................................................................... 71
6.3. Comparativo entre Consultas com/sem o Agrupamento Prévio ................................. 72
6.4. Comparativo entre Consultas com/sem o Filtro Seletivo.............................................78
6.5. Comparativo entre Consultas com/sem um Data Warehouse...................................... 82
6.6. Comparativo entre Consultas Variando a Carga de Trabalho................................... 86
6.7. Considerações Finais ....................................................................................................... 88
7. CONCLUSÕES, CONTRIBUIÇÕES E TRABALHOS FUTUROS.........................89
7.1. Conclusões ........................................................................................................................ 89
7.2. Contribuições ...................................................................................................................90
7.3. Trabalhos Futuros ........................................................................................................... 91
REFERÊNCIAS BIBLIOGRÁFICAS ..........................................................................93
APÊNDICES................................................................................................................97
Apêndice A. Um Exemplo de uma Aplicação de Banco de Dados ..................................... 97
Apêndice B. Principais Classes do FAP................................................................................99
Apêndice C. Estrutura de Diretórios do FAP .................................................................... 105
Apêndice D. Catálogo do Banco de Dados para o Estudo de Caso .................................. 106
Apêndice E. Código Fonte utilizado no Estudo de Caso ................................................... 108
vii
Lista de Figuras
Figura 2-1: Arquiteturas de Bancos de Dados Paralelos.................................................................... 9
Figura 2-2: Arquitetura do Sistema CDBS [Cos01, p. 64]................................................................. 10
Figura 2-3: Componentes do Processador de Consultas. ................................................................ 13
Figura 2-4: Árvore de Consulta Inicial. ........................................................................................... 16
Figura 2-5: Árvore de Consulta Otimizada...................................................................................... 16
Figura 2-6: Representações de Junções numa Árvore de Consulta..................................................18
Figura 2-7: Mecanismos de Paralelismo. ....................................................................................... 20
Figura 2-8: Distribuição de dados – (a) circular, (b) por faixa de valores e (c) hash............................ 21
Figura 3-1: Componentes para um Esquema de um Arquivo no MPI-IO. .......................................... 29
Figura 3-2: Exemplo de um Particionamento de um Arquivo entre 2 Processos................................. 29
Figura 4-1: Árvore de Consulta Otimizada...................................................................................... 34
Figura 4-2: Árvore de Consulta Otimizada com Agrupamento Prévio................................................35
Figura 4-3: Plano de Consulta Otimizado para Q2 com Agrupamento Prévio. ................................... 44
Figura 4-4: Exemplo de Construção de Vetores de Bits para a Consulta Q2. .................................... 46
Figura 4-5: Fase de Filtragem para a Consulta Q2.......................................................................... 46
Figura 5-1: Junção de uma única Passagem..................................................................................50
Figura 5-2: Esquema das Estratégias de Agregação....................................................................... 51
Figura 5-3: Esquema de um Algoritmo de duas Passagens. ............................................................ 52
Figura 5-4: Um Esquema para a fase de Mesclagem no Agrupamento Prévio................................... 52
Figura 5-5: Diagrama da Estratégia para o Agrupamento Prévio em Paralelo.................................... 53
Figura 5-6: Arquitetura do FAP...................................................................................................... 56
Figura 5-7: Estrutura t_left_deep_tree Existente no FAP. ................................................................ 67
Figura 5-8: Estrutura t_input_aggregate Existente no FAP............................................................... 68
Figura 6-1: Tempo de Execução da Consulta Q3............................................................................ 73
Figura 6-2: Tempo de Execução da Consulta Q4............................................................................ 73
Figura 6-3: Desempenho para a Consulta Q3.................................................................................74
Figura 6-4: Desempenho para a Consulta Q4.................................................................................75
Figura 6-5: Eficiência para a Consulta Q3. ..................................................................................... 75
Figura 6-6: Eficiência para a Consulta Q4. ..................................................................................... 76
Figura 6-7: Espaço em Disco para os Arquivos Temporários nas Consultas Q3 e Q4. ....................... 77
viii
Figura 6-8: Tempos de Execução da Junção e Agregação nas Consultas Q3 e Q4. .......................... 77
Figura 6-9: Aplicação do Filtro Seletivo na Consulta Q5. ................................................................. 79
Figura 6-10: Aplicação do Filtro Seletivo na Consulta Q6. ............................................................... 79
Figura 6-11: A Ocorrência de Falsos Positivos na Consulta Q5........................................................ 80
Figura 6-12: A Ocorrência de Falsos Positivos na Consulta Q6........................................................ 80
Figura 6-13: Nº de Grupos para a Consulta Q5 Com/Sem Falsos Positivos. ..................................... 81
Figura 6-14: Nº de Grupos para a Consulta Q6 Com/Sem Falsos Positivos. ..................................... 81
Figura 6-15: Tempos de Execução das Consultas Q3 e Q7 sem Agrupamento Prévio. ...................... 83
Figura 6-16: Tempos de Execução das Consultas Q3 e Q7 com Agrupamento Prévio. ...................... 83
Figura 6-17: Speedup das Consultas Q3 e Q7 sem Agrupamento Prévio.......................................... 84
Figura 6-18: Eficiência das Consultas Q3 e Q7 sem Agrupamento Prévio......................................... 85
Figura 6-19: Speedup das Consultas Q3 e Q7 com Agrupamento Prévio.......................................... 85
Figura 6-20: Eficiência das Consultas Q3 e Q7 com Agrupamento Prévio......................................... 86
Figura 6-21: Tempo de Execução de Consultas Variando a Carga de Trabalho ................................ 87
ix
Lista de Tabelas
Tabela 2-1: Operadores da Álgebra Relacional. .............................................................................12
Tabela 5-1: Principais Classes Implementadas do FAP................................................................... 65
Tabela 6-1:Consultas Executadas no Estudo de Caso. ................................................................... 72
x
Resumo
Processamento paralelo e distribuído é uma alternativa para melhorar o desempenho de
consultas sobre data warehouses. A técnica de agrupamento prévio tem sido enfatizada
recentemente em sistemas centralizados para melhorar as consultas com agregação. Esta
técnica permite a execução da operação de agregação antes da junção. Como resultado, a
eficiência da consulta é aumentada. Este trabalho propõe e implementa um ambiente de
software, denominado FAP, para a execução de consultas com agregados. FAP faz uso do
paralelismo, agrupamento prévio e um filtro seletivo. FAP também adiciona novas
características ao CDBS (Concurrent Database System), tornando possível analisar a
execução de consultas com agregados. Finalmente, a implementação modular do FAP provê
uma maneira fácil de incluir novas funcionalidades e modificar as existentes. Os resultados
obtidos com o estudo de caso no uso do FAP mostram que a aplicação do agrupamento prévio
em um ambiente paralelo reduz o tempo de execução da consulta e os acessos a disco. Além
disso, o desempenho das consultas com agregados fica mais interessante se o agrupamento
prévio é combinado com o filtro seletivo, que também é estudado neste trabalho.
xi
Abstract
Parallel and distributed processing is an alternative to improve the performance of
queries on data warehouses. The early grouping technique has been recently emphasized
in centralized systems to improve queries with aggregation. This technique allows the
execution of aggregates before the join operation. As a result, query efficiency is
increased. This work proposes and implements a software environment, called FAP, for
the execution of queries with aggregates. FAP makes use of parallelism, previous
grouping and a selective filter. FAP also adds new features to CDBS (Concurrent
Database System), which make it possible to analyze the execution of queries with
aggregates. Finally, the modular implementation of FAP provides an easier way of
including new functionalities and modifying existent ones. The results obtained by a
case study in the use of FAP show that the application of the early grouping in a parallel
environment reduces both query execution time and disk access. Furthermnore, the
performance of queries with aggregates becomes even more attractive if early grouping
is combined with a selective filter, which is also studied in this work.
xii
1
1. Introdução
1.1. Definição do Problema
Os sistemas de gerenciamento de bancos de dados (SGBDs) têm se tornado ferramentas
indispensáveis para usuários de computadores. Eles são projetados para gerenciar grandes
quantidades de dados de forma eficiente e permitir que esses dados estejam disponíveis ao
longo de anos e com segurança. O acesso aos dados em um banco de dados pode ser realizado
através do processador de consultas, um componente do SGBD, que recebe uma consulta do
usuário em linguagem declarativa, analisa-a, transforma-a e executa-a [Jar84]. Para garantir o
processamento eficiente de uma consulta são utilizadas técnicas de otimização de consultas.
As técnicas de otimização de consultas mais utilizadas são as baseadas em heurísticas e
as baseadas em estimativas de custos [Elm00]. A primeira, utiliza regras de transformações da
álgebra relacional para gerar uma consulta equivalente mais eficiente. A segunda, estima e
compara os custos de alguns planos de consulta e escolhe, para execução, o de menor custo.
Em ambientes especializados como os data warehouses [Kim98], responder uma
consulta de maneira eficiente é uma tarefa bastante complexa para o processador de consultas,
mesmo usando as técnicas de otimização existentes. Esses ambientes, geralmente, armazenam
muitos dados, que podem chegar a algumas centenas de gigabytes e, até mesmo, terabytes.
Além disso, as consultas submetidas, em geral, são complexas e ad-hoc e requerem, com
freqüência, operações que consomem bastante tempo de processamento como a junção e o
agrupamento [Cha97].
Como as consultas nos data warehouses são importantes para ajudar na tomada de
decisões nas empresas e possuem características que diferem esses ambientes dos ambientes
tradicionais [Gar99], novas propostas têm surgido para melhorar o tempo de resposta dessas
consultas e resolver o problema do armazenamento de grandes volumes de dados. Uma
proposta indica a aplicação do processamento paralelo e distribuído [Cha97, Gar99, Cos01].
2
As pesquisas para o processamento de consultas têm sido direcionadas, em sua maioria,
para a construção de algoritmos paralelos e distribuídos visando o processamento eficiente da
operação de junção [Yan97]. Tal fato justifica-se porque a ordem de execução dessa operação
pode levar o processamento de uma consulta a diferentes tempos de execução. Existem
trabalhos, porém, que exploram outras operações, como o agrupamento. Um estudo
interessante feito em [Yan94a] e [Cha94] apresenta a idéia de executar a operação de
agrupamento antes da operação de junção, de maneira a reduzir o tamanho de uma tabela
antes de aplicar operações de junções, denominada neste trabalho de agrupamento prévio.
Embora seja uma idéia interessante, poucos trabalhos têm explorado este assunto.
Surge, assim, uma oportunidade para unir os conceitos do processamento paralelo de
consultas e as idéias do agrupamento prévio para explorar novas técnicas em ambientes de
data warehousing paralelos e distribuídos.
1.2. Motivação
As consultas em SQL com agregados têm sido comuns em bancos de dados para suporte à
decisão, como os data warehouses, que particionam os dados em grupos e aplicam funções de
agregação (por exemplo, COUNT, SUM, AVG, MAX e MIN) sobre cada grupo. Devido ao
grande volume de informações existentes nos data warehouses, é indispensável a aplicação de
técnicas para processar as consultas de maneira eficiente.
O processamento paralelo tem sido uma opção interessante para melhorar o
desempenho na execução de consultas com agregados, pois os dados distribuídos podem ser
processados por diversos processadores simultaneamente. No entanto, as plataformas atuais
para o processamento paralelo ainda são pouco difundidas e, em geral, possuem custo
elevado. Neste contexto, são necessários mecanismos que auxiliem na compreensão da
aplicação do paralelismo e do agrupamento prévio.
Assim, a motivação inicial deste trabalho foi contribuir para a otimização de consultas
através de um ambiente de software para a execução de consultas com agregados usando o
processamento paralelo e a técnica do agrupamento prévio.
3
1.3. Objetivos do Trabalho
Este trabalho apresenta o FAP, um ambiente de software que visa apoiar o processamento
paralelo e distribuído de consultas. O FAP propõe a inclusão de uma nova facilidade no
sistema CDBS (Concurrent Database System), que foi proposto em [Cos01]. A arquitetura do
FAP define as unidades de software, as interfaces, o catálogo do banco de dados e as
principais estratégias para a execução de uma consulta em paralelo.
O FAP tem como objetivo principal fornecer um ambiente para melhor compreensão do
comportamento da execução de uma consulta com a aplicação do paralelismo, do
agrupamento prévio e de um filtro seletivo. Desta forma, a partir do entendimento de certos
comportamentos, podem-se gerar contribuições teóricas no sentido de melhorar a eficiência
na execução de consultas para data warehouses paralelos e distribuídos.
Para alcançar o objetivo do ambiente proposto, seus módulos básicos (Cliente e
Servidor de Arquivos Paralelos) foram implementados usando as especificações do CDBS
que descrevem as primitivas para a criação e manutenção de um banco de dados paralelo e um
data warehouse. A linguagem de programação utilizada no desenvolvimento é C++ com a
distribuição LAM/MPI-2 (Local Area Multicomputer/Message Passing Interface) para a troca
de mensagens.
Por fim, para que se possa ilustrar a arquitetura proposta, apresenta-se um estudo de
caso e, através do mesmo, resultados experimentais são obtidos durante a execução de vários
tipos de consultas. O estudo de caso escolhido relaciona-se ao sistema de uma rede de
locadoras, onde são apresentadas situações que exigem a utilização do paralelismo [Cos01].
Para tanto, foram avaliados aspectos tais como: (i) a aplicação do agrupamento prévio; (ii) o
custo da execução de uma consulta com ou sem um data warehouse; (iii) o custo de uma
consulta em ambiente centralizado ou paralelo e (iv) o uso do filtro seletivo, que é uma
proposta deste trabalho.
1.4. Organização do Texto
Este texto está organizado em sete capítulos e cinco apêndices. O primeiro capítulo
apresentou o problema, a motivação e os objetivos pretendidos no presente trabalho.
4
O segundo capítulo apresentará uma revisão de conceitos de banco de dados e
processamento e otimização de consultas em ambientes monoprocessados e multiprocessados.
O terceiro capítulo descreverá o paradigma e um ambiente de troca de mensagens e
métricas para avaliar programas paralelos.
O quarto capítulo apresentará o conceito de agrupamento prévio e fará uma revisão das
principais estratégias utilizadas para o processamento de consultas com agregados.
O quinto capítulo apresentará o FAP, descrevendo seus objetivos e detalhes de sua
especificação, projeto e implementação.
O sexto capítulo apresentará um estudo de caso para ilustrar a aplicação das idéias
desenvolvidas nesta dissertação e os resultados obtidos durante sua execução no FAP são
comentados.
O sétimo capítulo apresentará as conclusões e contribuições conquistadas com este
trabalho e uma relação de trabalhos futuros que deverão ser conduzidos no sentido de
evidenciar novas contribuições nesta área.
Os apêndices apresentarão um exemplo de uma aplicação de banco de dados que será
utilizada no decorrer deste trabalho, as principais classes implementadas no FAP, a estrutura
de diretórios usada pelo ambiente, o catálogo do banco de dados e o código fonte das
principais rotinas usadas durante a execução do estudo de caso.
5
2. Banco de Dados e Processamento de Consultas
2.1. Introdução
A grande maioria das interações do usuário com um SGBD ocorre através de uma consulta.
Por isto, um SGBD deve oferecer mecanismos eficientes para obter dados de um banco de
dados através de seu processador. Neste capítulo serão apresentados os conceitos básicos
necessários para a compreensão de um processador de consultas.
2.2. Bancos de Dados Relacionais
Os bancos de dados têm se tornado essenciais, ajudando a organizar as diversas atividades das
pessoas e empresas, tais como data warehouses, bancos de dados distribuídos e bancos de
dados paralelos.
Um banco de dados é uma coleção de dados relacionados que representam qualquer
aspecto do mundo real para a solução de problemas [Elm00]. Esses dados podem ser gerados,
mantidos e guardados em meios físicos para o acesso ao longo dos anos usando mecanismos
manuais ou informatizados. Um banco de dados informatizado pode ser criado e mantido por
um grupo de programas escritos especificamente para aquela tarefa ou por um SGBD.
Um SGBD facilita o gerenciamento de um banco de dados usando um conjunto de
programas de finalidade genérica [Ull97]. Estes programas automatizam os processos de
definição e manipulação de um banco de dados. A definição de dados consiste em criar,
alterar e excluir as estruturas de dados necessárias para o acesso aos dados em um banco de
dados. Na manipulação de dados, os dados do banco de dados são consultados ou
modificados.
Uma tecnologia de banco de dados bastante consolidada no mercado é a de banco de
dados relacional, que está baseada no modelo relacional [Cod70]. Esse modelo representa o
banco de dados como um conjunto de tabelas (relações) que são compostas por tuplas (linhas)
e atributos (colunas). Cada tupla representa uma entidade do mundo real ou um
relacionamento entre entidades. Cada atributo é associado a um domínio indicando o conjunto
6
de valores que pode assumir. Uma tabela é descrita por um esquema que consiste no nome da
tabela e seus atributos. Para qualquer tupla e qualquer atributo de uma tabela, é requerido que
o valor do atributo seja atômico, isto é, não pode ser um atributo composto ou multivalorado.
Para cada tabela, existe um atributo ou combinação de atributos que apresentam valor único
ou combinação única de valores, chamados de superchave da tabela. Toda tabela possui pelo
menos uma superchave; um número mínimo de atributos que garantem a combinação única de
valores é chamado de superchave minimal ou, apenas, chave. Dentre todas as chaves de uma
tabela, escolhe-se uma, que será denominada de chave primária.
Em bancos de dados relacionais, existem tabelas de base e visões [Ull97]. Uma tabela
de base armazena os dados em um meio físico, de tal forma que eles persistem por tempo
indeterminado e podem ser consultados e modificados. Uma visão é construída a partir de
uma ou mais tabelas através de uma consulta e não precisa ser necessariamente armazenada;
porém, se o for, é chamada de visão materializada.
Um aspecto importante que favorece o desempenho dos bancos de dados relacionais é a
utilização de um catálogo para o acesso aos dados pelo SGBD. O catálogo oferece
informações sobre as estruturas de dados, os tipos e formatos de armazenamento e as
restrições sobre os dados. Estas informações são armazenadas na forma de tabelas e são
requisitadas várias vezes; logo, uma implementação não planejada do catálogo poderá
ocasionar um baixo desempenho no acesso aos dados. Por isto, recomenda-se utilizar uma
estrutura de dados que consiga oferecer um bom desempenho.
2.2.1. Data Warehouses
Um banco de dados usado extensivamente no dia-a-dia é também chamado de banco de dados
de produção, pois registra os dados gerados pela execução das rotinas da organização. A partir
de um banco de dados de produção, podem ser gerados novos conjuntos de dados que
auxiliam na tomada de decisões nas empresas e são armazenados em um banco de dados
específico, que será chamado banco de dados para análise ou data warehouse.
Um data warehouse é constituído por dados derivados de fontes de dados e é
consultado através de um tipo especial de processamento conhecido como processamento
analítico [Gar99]. Em geral, as aplicações de data warehousing diferem das aplicações
7
tradicionais de bancos de dados, pois: (i) suas consultas são de longa duração devido ao
grande volume de dados armazenados; (ii) são mantidos os estados anteriores do banco de
dados, acrescentando informações temporais; (iii) processam sumários pré-computados e (iv)
são estruturados para execução de consultas analíticas e construção de relatórios [Kim98].
A implementação de um data warehouse é feita, geralmente, usando-se um esquema em
estrela que é composto por uma tabela de fatos e duas ou mais tabelas de dimensão. A tabela
de fatos é representada no centro da estrela e contém dados numéricos e chaves estrangeiras
que apontam para as tabelas de dimensão [Wei02].
2.2.2. Bancos de Dados Distribuídos e Paralelos
As tecnologias em bancos de dados centralizados e as redes de computadores tornaram viável
a utilização de bancos de dados distribuídos e bancos de dados paralelos. Os primeiros bancos
de dados eram gerenciados e armazenados usando um único computador, o que, com seu
crescimento, tornou-se um problema devido às limitações de armazenamento e processamento
de grandes volumes de dados. Uma solução para ajudar a diminuir estes problemas foram a
descentralização do armazenamento e a autonomia de processamento, possível com a
disseminação das redes de computadores.
Um sistema de banco de dados distribuído consiste em uma coleção de vários bancos de
dados logicamente inter-relacionados e distribuídos em diversos nós de uma rede de
computadores, de maneira tal que cada nó possui capacidade de processamento autônomo e
pode cooperar com os outros na execução de tarefas que requerem o acesso a dados
distribuídos [Kim95].
Sistemas de bancos de dados distribuídos podem ser executados em diferentes tipos de
arquiteturas. Para isto, possuem um conjunto de facilidades para a troca de dados e serviços,
provêem diferentes níveis de transparência de distribuição de dados de forma que os dados
podem ser representados em uma variedade de modelos [Kim95].
A distribuição de dados oferece oportunidades para aplicar técnicas de paralelismo. Para
tanto, formas de distribuição estão disponíveis como a fragmentação e a replicação [Yu98]. A
fragmentação consiste em particionar horizontalmente (tuplas) ou verticalmente (atributos) os
8
dados de uma tabela. A replicação consiste no armazenamento de cópias de tabelas completas
ou fragmentadas nos diferentes nós da rede.
Um sistema de banco de dados paralelo consiste na distribuição dos dados do banco de
dados pelos vários nós do sistema de uma maneira que permita transparência plena. A
distribuição dos dados em vários discos também oferece a oportunidade de redução do custo
de acesso aos dados em disco, pois a divisão do banco de dados em muitos discos aumenta a
largura de banda de E/S (entrada e saída) que, assim, permite o acesso simultâneo aos dados
[DeW90].
Arquiteturas de bancos de dados paralelos têm sido propostas envolvendo a combinação
de três recursos: processadores (P), memórias (M) e discos (D). Segundo [Waq96], as
arquiteturas são: memória compartilhada, discos compartilhados e memória distribuída,
conforme ilustra a Figura 2-1.
Na arquitetura de memória compartilhada, todos os processadores têm acesso a
qualquer módulo de memória ou disco através de uma rede de interconexão. Esta arquitetura
permite um balanceamento de carga adequado com o uso da memória compartilhada, mas
possui custo elevado porque os componentes (processador, memória e disco) devem ser
ligados entre si. Um outro problema é o acesso conflitante aos recursos compartilhados,
reduzindo, assim, a escabilidade [Tha90]. Bancos de dados paralelos com esta arquitetura
incluem os protótipos XPRS [Hon92], o DBS3 [Ber91] e o Volcano [Gra90].
Na arquitetura de discos compartilhados, cada processador possui uma memória
exclusiva e tem acesso a qualquer unidade de disco através de uma rede de interconexão. O
custo desta rede é bem menor que no caso da arquitetura de memória compartilhada, porque o
barramento padrão de interconexão pode ser utilizado. O balanceamento de carga pode ser tão
bom quanto na memória compartilhada e falhas na memória podem ser isoladas dos outros
nós, possibilitando, assim, uma maior disponibilidade. O acesso a discos compartilhados
representa um gargalo desta arquitetura e é mais indicada para aplicações de bancos de dados
somente de leituras ou para as aplicações sem compartilhamentos [DeW92]. Bancos de dados
paralelos com esta arquitetura são IMS/VS Data Sharing(IBM) e VAX DBMS(DEC),
conforme [DeW92].
9
M
P
P
M
P
D
...
P
...
D
D
...
D
...
D
...
M
P
M
P
M
P
P
M
D
Memória
Compartilhada
Discos
Compartilhados
Memória
Distribuída
Figura 2-1: Arquiteturas de Bancos de Dados Paralelos.
Na arquitetura de memória distribuída, cada processador tem acesso exclusivo à sua
memória e às suas unidades de discos. Cada nó (processador + memória + discos) comunicase para trocar informações através da rede que liga os demais nós. O custo para acrescentar
novos nós é relativamente baixo em comparação com a arquitetura de memória compartilhada
e favorece uma escalabilidade bem maior, pois o crescimento suave pela adição de novos nós
pode chegar na ordem de milhares (o DBC da Teradata pode acomodar até 1024 nós). Um dos
maiores problemas desta arquitetura é garantir um balanceamento de carga adequado entre os
vários nós, principalmente quando os dados apresentam uma distribuição não uniforme.
Exemplos de bancos de dados paralelos que utilizam esta arquitetura incluem os produtos
comerciais DBC(Teradata), NonStop SQL/MP(Tandem) [Eng95, Tan95] e DB2-PE(IBM)
[Bar95], além de protótipos como o BUBBA [Bor90] e o GAMMA [DeW90].
Segundo [DeW92], vários trabalhos têm explorado a arquitetura de memória distribuída
em bancos de dados paralelos, porque esta arquitetura alcança speedups (ganhos de
velocidade) próximos do linear no processamento de consultas complexas.
2.2.3. CDBS
O CDBS (Concurrent Database System) é a especificação e o projeto de um sistema que
integra um banco de dados de produção e um data warehouse paralelos, que foi proposto em
[Cos01] para oferecer um maior desempenho nas atividades de data warehousing. Os dados
10
são integrados em um único sistema, denominado ambiente de dados paralelo, favorecendo a
consistência entre as tabelas e visões materializadas. A Figura 2-2 ilustra a integração no
CDBS.
Processamento
de Transações
Banco de
Dados
de Produção
Processamento
Analítico
Integração dos Dados
Data
Warehouse
Ambiente de Dados Paralelo
Sistema de Arquivos Paralelos
Figura 2-2: Arquitetura do Sistema CDBS [Cos01, p. 64].
No ambiente de dados paralelo, o banco de dados é formado por um conjunto de tabelas
que visam apoiar tanto o processamento de transações como também o processamento
analítico. Para permitir o processamento analítico, visões materializadas são criadas a partir
das tabelas do banco de dados de produção (tabelas fontes), de maneira que o custo de
execução de uma consulta submetida ao data warehouse seja reduzido e a interferência no
banco de dados de produção seja pequena. Essas visões materializadas são atualizadas
automaticamente através de um conjunto de primitivas usando os critérios de atualização
completo ou incremental. O critério de atualização completo recria uma visão materializada a
partir da leitura completa das tabelas fontes que lhe dão origem; já no incremental, apenas os
registros das tabelas fontes que sofreram modificações desde a última atualização serão
usados para a atualização da visão materializada.
Para oferecer um alto desempenho no ambiente de dados paralelo foi adotado o sistema
de arquivos NPFS (Network Parallel File System) [Gua99]. O NPFS é um sistema de
arquivos paralelos destinado a um ambiente computacional distribuído, onde diferentes tipos
de estações de trabalho podem manipular os arquivos paralelos de maneira cooperativa em
uma rede. A estratégia adotada pelo NPFS consiste em utilizar o modelo cliente/servidor para
11
possibilitar o acesso paralelo aos arquivos distribuídos entre os discos das estações de trabalho
da rede. A técnica de distribuição de dados é baseada na ordem de definição dos servidores.
Além das primitivas já existentes no NPFS, outras foram adicionadas para atender
especificações do CDBS, tratando problemas de replicação e distribuição de dados por faixa
de valores e por função de hashing.
2.3. Processamento de Consultas
Uma consulta expressa em uma linguagem de consulta é uma especificação do usuário para
obter os dados de um banco de dados. No contexto de bancos de dados relacionais, dois tipos
de linguagens descrevem uma consulta: a formal e a comercial. A linguagem formal define a
base matemática para a construção de linguagens comerciais. A linguagem comercial é uma
interface mais amigável para obter os dados de um banco de dados.
Uma linguagem formal utilizada nos bancos de dados relacionais é a álgebra relacional
[Ull97] que é representada por operações da teoria dos conjuntos (produto cartesiano, união,
intersecção e diferença) e operações específicas para bancos de dados relacionais (seleção,
projeção, junção e agregação). O resultado de uma operação é dado em forma de tabela. A
Tabela 2-1 ilustra as características e notações dos operadores que representam as operações
da álgebra relacional que serão utilizadas neste trabalho, conforme notação apresentada em
[Gar00].
Uma linguagem comercial para representar as operações de um banco de dados
relacional é a SQL (Structured Query Language), que se tornou um padrão universal na
construção e na manipulação de bancos de dados relacionais [Ull97]. SQL apresenta vários
componentes para o gerenciamento dos dados em um banco de dados, tais como definição e
manipulação de dados, interface com linguagens de programação hospedeiras, definição de
restrições e suporte para transações.
Uma consulta escrita em SQL especifica o que o usuário quer do banco de dados, mas
não como serão produzidos os resultados, ficando a cargo do SGBD o processamento e
otimização necessária para conseguir esses resultados. Devido a esta facilidade, a linguagem
SQL tem se tornado bastante popular e amplamente utilizada como uma ferramenta de apoio
nas aplicações comerciais. SQL apresenta uma série de operações que podem ser executadas
12
sobre um banco de dados, tais como seleção, projeção, junção, agregação e ordenação.
Operador
Seleção
Projeção
Junção
Agrupamento
Álgebra
Relacional
Significado
σC(R)
πL(R)
R
Seleciona as tuplas da relação R que satisfazem a condição de seleção C.
Seleciona os atributos da relação R que satisfazem a lista de atributos L.
Cada tupla da relação R é combinada com cada tupla da relação S que
satisfazem a condição de junção C.
As tuplas com valores idênticos nos atributos L da relação R são
agrupadas em grupos. Cada grupo é convertido, através da aplicação de
uma ou mais funções F, em uma única tupla. F representa as funções de
agregação COUNT, SUM, AVG, MAX e MIN. O resultado de cada F será
armazenado em um novo atributo A. Se A não for especificado, então será
utilizado o mesmo nome do atributo de R que está sendo aplicado a F.
cS
γL, FÆA (R)
ou
γL, F (R)
Tabela 2-1: Operadores da Álgebra Relacional.
Uma consulta SQL pode consistir de até seis cláusulas, mas somente as duas primeiras,
SELECT e FROM, são obrigatórias. As cláusulas são especificadas na seguinte ordem, com as
cláusulas entre colchetes [...] sendo opcionais:
SELECT
<lista de atributos e ou funções de agregação>
FROM
<lista de tabelas>
[WHERE <condição>]
[GROUP BY <lista de atributos de agrupamento>
[HAVING <condição de agrupamento>]]
[ORDER BY <listas de atributos >];
As três primeiras cláusulas definem a forma básica em SQL: a cláusula SELECT
relaciona os atributos que representam os dados desejados da consulta; a cláusula FROM
relaciona as tabelas envolvidas na consulta; e a cláusula WHERE especifica as condições de
escolha das tuplas das tabelas.
A cláusula GROUP BY agrupa tuplas que possuem o mesmo valor para a lista de
atributos de agrupamento em grupos e, sobre estes, são aplicadas funções de agregação. Os
atributos de agrupamento podem aparecer na lista de atributos da cláusula SELECT juntamente
com os resultados das funções de agregação.
13
A cláusula HAVING especifica as condições de escolha dos grupos de tuplas produzidos
pela cláusula GROUP BY. Por último, a cláusula ORDER BY especifica a ordem da saída dos
resultados.
Uma consulta escrita em uma linguagem de alto nível, como a SQL, é submetida ao
processador de consultas, um componente do SGBD, para ser transformada em uma
seqüência de operações que serão executadas sobre o banco de dados. Determinadas
seqüências de operações podem levar a execução da consulta a demorar mais tempo do que
outras.
2.3.1. Processador de Consultas
O processador de consultas, ilustrado na Figura 2-3, pode ser dividido em duas etapas: a
compilação e a execução [Gar00].
consulta
Compilação
metadados
plano de execução
Execução
dados
Banco de
Dados
Figura 2-3: Componentes do Processador de Consultas.
Na compilação de uma consulta são definidas três tarefas principais: a análise, a geração
do plano lógico e a geração do plano de execução. A análise consiste em construir uma árvore
de análise para representar a consulta e sua estrutura. Na geração do plano lógico, a árvore de
análise é convertida em um plano de consulta inicial, uma representação algébrica da
consulta, e, posteriormente, este plano é transformado em um plano equivalente que deverá
exigir menor tempo para ser executado. Na geração do plano de execução, o plano lógico é
transformado utilizando os algoritmos de implementação de cada operador lógico e a seleção
14
de uma ordem de execução para esses operadores.
Na execução, as operações do plano de execução são processadas e o resultado da
consulta é entregue ao usuário.
Em geral, o número de possíveis planos de execução gerados para uma consulta é
grande e dois fatores influenciam nessa geração: o número de operações na consulta e o
número de métodos que podem ser usados para avaliar cada operação. Esses métodos podem
ser encontrados em [Gra93]. A quantidade de planos de execução pode aumentar ainda mais
caso a consulta seja executada em um ambiente distribuído porque o fator de localização dos
dados deve ser considerado. Encontrar o melhor plano de execução não é uma tarefa trivial e,
por isso, técnicas de otimização de consultas têm sido estudadas [Cha98].
2.4. Técnicas de Otimização de Consultas
A execução eficiente de uma consulta depende de como as técnicas de otimização de
consultas são aplicadas pelo otimizador de consultas, um outro componente do SGBD. Como
foi visto na seção anterior, uma consulta pode levar a muitos planos (tanto lógicos como de
execução) e escolher um desses planos que seja adequado para processar a consulta é um
processo conhecido como otimização de consultas.
O termo otimização talvez não seja apropriado porque, em alguns casos, o plano de
execução escolhido não é a melhor estratégia, mas apenas uma estratégia razoavelmente
eficiente para executar a consulta. Encontrar a melhor estratégia geralmente consome muito
tempo, exceto para consultas muito simples, pois pode requerer informações sobre a maneira
como as tabelas estão implementadas e, até mesmo, sobre o conteúdo das tabelas, que
geralmente podem não estar plenamente disponíveis no catálogo do banco de dados. Assim, o
planejamento de uma estratégia de execução pode ser o termo mais apropriado do que
otimização de consultas.
Em seguida serão detalhados os passos para a aplicação da otimização de consultas e
serão apresentadas as técnicas de otimização baseadas em heurísticas e em estimativas de
custos.
15
2.4.1. Da Álgebra Relacional para um Plano Lógico Otimizado
Uma consulta SQL é inicialmente transformada em uma expressão equivalente da álgebra
relacional e representada por uma estrutura de dados conhecida como árvore de consulta. A
vantagem da estrutura em árvore em relação a outras formas de representações é que esta
mostra a ordem de execução de cada operação de uma consulta, onde os nós folhas
representam as relações de entrada e os nós internos, as operações da álgebra relacional. Uma
execução da árvore de consulta consiste na execução de uma operação do nó interno sempre
que seus operandos estejam disponíveis e, em seguida, na substituição desse nó interno pela
relação resultante da execução da operação. A execução termina quando o nó raiz da árvore é
executado e produz os resultados de uma consulta.
Com a aplicação de transformações algébricas [Elm00, Gar00] espera-se obter um plano
lógico otimizado a partir da árvore de consulta inicial que reduza o tempo de execução da
consulta. No entanto, várias expressões algébricas serão construídas até chegar a esse plano
otimizado através da utilização de algumas estratégias resultando em uma otimização baseada
em heurísticas. Nesse tipo de otimização são aplicadas estratégias como:
1ª.
Uma seleção pode ser movida para baixo no plano, atuando sobre uma tabela ou
produto cartesiano. Se uma condição de seleção é o AND de várias seleções, então
divide-se a condição e cada fragmento será movido separadamente. Essa estratégia
deve ser a técnica de otimização mais efetiva, pois uma operação de seleção tende
a reduzir bastante o tamanho de uma relação;
2ª.
Novas projeções podem ser adicionadas na árvore para reduzir o comprimento das
tuplas;
3ª.
Há seleções que podem ser combinadas com o produto cartesiano sobre o qual
estão operando, convertendo-se numa junção, cuja avaliação, em geral, é muito
mais eficiente que a avaliação das duas operações separadamente.
As Figuras 2-4 e 2-5 representam respectivamente as árvores de consulta inicial e
otimizada para a consulta Q1 que: define a quantidade de fitas locadas e o valor faturado com
locações, por bairro, anualmente, para filmes do gênero 'drama' e locações efetuadas a partir
de 1993.
16
Q1: SELECT
FROM
WHERE
GROUP BY
bairro, anoloc, COUNT(*), SUM(valorlocfita)
Loja, Locacao, Filme
idloja=idlojaloc AND idfilme=idfilmeloc AND anoloc≥1993 AND genero='drama'
bairro, anoloc
Para a construção da árvore de consulta otimizada foram aplicadas as três heurísticas
apresentadas: a 1ª (por exemplo, σanoloc≥1993 na relação LOCACAO); a 2ª (por exemplo, πidloja,
bairro na
relação LOJA) e a 3ª (por exemplo, a troca de duas operações por uma).
γbairro, anoloc, COUNT(*)Ænloc, SUM(valorlocfita)Ævfat
π bairro, anoloc, valorlocfita
σ idloja= idlojaloc AND idfilme= idfilmeloc AND anoloc≥1993 AND genero='drama'
X
X
Loja
Filme
Locacao
Figura 2-4: Árvore de Consulta Inicial.
γbairro, anoloc, COUNT(*)Ænloc, SUM(valorlocfita)Ævfat
π bairro, anoloc, valorlocfita
idfilmeloc=idfilme
π idfilme
idloja=idlojaloc
π idloja, bairro
Loja
π idlojaloc, idfilmeloc, anoloc, valorlocfita
σ genero='drama'
σ anoloc≥1993
Filme
Locacao
Figura 2-5: Árvore de Consulta Otimizada.
Essas heurísticas permitem melhorar o desempenho de uma consulta, pois reduzem o
tamanho de uma relação beneficiando operações como a junção, reduzem o comprimento das
17
tuplas permitindo um melhor aproveitamento dos buffers de memória e aumentam as opções
de escolha de algoritmos para a implementação de operações.
2.4.2. Do Plano Lógico Otimizado para Planos de Execução
O plano de execução de uma consulta inclui informações sobre os métodos de acesso
disponíveis para cada relação, bem como os algoritmos a serem utilizados na execução dos
operadores do plano. Freqüentemente, cada operação do plano lógico será representada por
um operador do plano de execução, mas existem operadores que precisam ser acrescentados
ao plano e estes não têm representação na álgebra relacional, por exemplo, o operador de
ordenação. Os principais métodos de acesso e algoritmos podem ser encontrados em [Elm00]
e [Gar00].
Para executar uma consulta, muitos planos de execução poderão ser obtidos devido à
grande quantidade de métodos de acesso e algoritmos disponíveis. Para escolher o plano mais
adequado é preciso saber seu custo. Assim sendo, o otimizador de consultas deve calcular e
comparar o custo de execução de cada plano e escolher o de custo menor. Essa abordagem é a
otimização baseada em custos que, geralmente, é calculado o custo do componente que tem
maior importância, pois desta maneira chega-se a fórmulas menos complicadas. Entre os
componentes existentes têm-se: o acesso a disco, o armazenamento dos dados, a computação,
o uso de memória e a comunicação.
2.4.3. Ordem para Junções
As leis algébricas para transformar uma árvore de consulta incluem uma regra comutativa e
uma regra associativa para a operação de junção que aumentam o número de árvores
equivalentes e, por conseguinte, o número de planos de execução será muito maior. Portanto,
para minimizar esse problema foram definidas formas para representar uma árvore de
consulta como a árvore de profundidade à esquerda e a árvore balanceada [Gar00], conforme
ilustra a Figura 2-6.
A árvore de profundidade à esquerda é a representação natural de um plano de execução
porque favorece a execução dos algoritmos de junção (ordem linear), mas não favorece o
paralelismo. O melhor paralelismo é verificado com a utilização de uma árvore balanceada
18
quando mais de uma junção pode ser executada ao mesmo tempo.
U
T
R
S
Árvore de profundidade
à esquerda
R
S
T
U
Árvore balanceada
Figura 2-6: Representações de Junções numa Árvore de Consulta.
Para encontrar uma ordem de execução das operações de junção usando uma árvore de
profundidade à esquerda pode ser utilizada a programação dinâmica. Essa abordagem
proposta em [Sel79] tem como idéia central manter a cada passo da solução a junção de
menor custo.
2.4.4. Abordagens para Enumerar Planos de Execução
Para enumerar os planos de execução de um determinado plano lógico, as seguintes tarefas
ajudam nesse processo: (i) definir a ordem das operações de junção; (ii) escolher um método
de acesso, se existir, para cada relação; (iii) escolher um algoritmo para cada operação; (iv)
inserir operações adicionais, por exemplo, a ordenação e (v) definir a forma como os
resultados intermediários serão repassados de uma operação para a seguinte.
As estratégias mais comuns para enumerar planos de execução são baseadas no estilo
bottom-up que computam os custos de todos os modos possíveis de cada sub-expressão da
árvore do plano lógico [Gar00]. Essas estratégias ou utilizam a programação dinâmica ou a
enumeração no estilo Selinger [Sel79].
A programação dinâmica mantém para cada sub-expressão do plano lógico apenas o
plano de menor custo. No estilo Selinger, mantém-se para cada sub-expressão não apenas o
plano de menor custo, mas também outros planos que têm custo mais alto. Esses planos com
custo elevado podem favorecer um resultado ordenado em uma ordem que poderá ser útil
mais acima na árvore, chamada de ordem de interesse. Essas ordens ocorrem quando o
19
resultado da sub-expressão é ordenado pelos atributos de operações como a ordenação, a
junção e o agrupamento.
2.4.5. Otimização de Consultas Paralelas
O paralelismo para aplicações de bancos de dados paralelos pode ser alcançado em três
níveis: paralelismo entre consultas (o nível de consulta), entre operações (o nível de operação)
e dentro da operação (o nível de instrução) [DeW92, Yu98]. No paralelismo entre consultas,
múltiplas consultas podem ser executadas em paralelo por diferentes processadores. No
paralelismo entre operações, diferentes operações de uma consulta podem ser processadas em
paralelo por diferentes processadores e, assim, o resultado de uma operação é enviado para
outra operação. No paralelismo dentro da operação, uma operação pode ser processada por
diferentes processadores em paralelo. Os dois últimos tipos de paralelismo são mais
interessantes, por oferecerem maior desempenho; por outro lado, requerem maiores cuidados
por parte do processamento.
O trabalho de computação de uma consulta pode ser dividido usando três formas de
paralelismo: independente, pipelined e particionado [Waq96], conforme ilustra a Figura 2-7.
Com o paralelismo independente, algumas operações de uma consulta são processadas
independentemente, de tal forma que não usam os dados produzidos entre elas. Por exemplo,
em uma consulta com quatro junções, pode-se tomar duas a duas e executá-las de maneira
independente e depois uma nova junção definirá o resultado final. Com o paralelismo
pipelined, duas operações de uma consulta produzem e consomem dados entre elas, assim
sendo é uma outra forma para conseguir o paralelismo entre operações. Com o paralelismo
particionado divide-se a entrada em subconjuntos menores, utilizam-se diferentes
processadores para processar cada subconjunto simultaneamente e, no final, combinam-se os
resultados parciais produzidos compondo o resultado final. Este tipo de paralelismo também é
uma outra forma para conseguir o paralelismo dentro da operação.
Os três mecanismos de paralelismo apresentados podem ser utilizados juntos, buscando
oferecer uma boa estratégia de processamento paralelo para consultas complexas [Yu98].
20
Entrada de dados
Operação 1
Processador b
Entrada de dados
...
Entrada de dados
Operação n
Processador k
Operações
adicionais
Resultado
Paralelismo Independente
Entrada de dados
Operação 1
Processador b
...
Operação n
Processador k
Resultado
Paralelismo Pipelined
Operação 1
Processador b
Entrada de dados
Particionar
.
.
.
Combinar
Resultado
Operação 1
Processador k
Paralelismo Particionado
Figura 2-7: Mecanismos de Paralelismo.
Segundo [Waq96], os benefícios da aplicação do paralelismo estão limitados a
restrições existentes nos elementos utilizados durante o processamento paralelo. Por exemplo,
uma tabela hash impõe restrições de tempo para uma operação de junção porque somente
poderá ser utilizada quando estiver completamente construída.
O tempo de execução de uma consulta ou operação pode ser reduzido com o uso de
processadores e discos simultaneamente; porém, para um melhor aproveitamento desses
recursos, as tabelas que fazem parte da operação são particionadas em vários fragmentos, que
são distribuídos por diferentes processadores [DeW92]. Estes fragmentos permitem que os
bancos de dados paralelos explorem a largura de banda de E/S de múltiplos discos para a
leitura e escrita dos dados em paralelo sem a necessidade de técnicas especiais, tais como a
RAID (Redundant Array of Independent Disks) [Pat88].
O processo de distribuição associa os fragmentos aos diversos processadores
disponíveis e pode ser realizado com ou sem replicação de fragmentos. Assim, a base de
dados pode apresentar-se totalmente replicada, parcialmente replicada ou sem replicação. As
21
técnicas de distribuição são: (a) circular, (b) por faixa de valores e (c) hash, ilustradas na
Figura 2-8, conforme [Yu98].
P1
P2
D
D
...
o o ... o o o
Pn
P1
P2
D
D
D
A .. G
H .. N
...
…
Pn
P1
P2
D
D
D
T .. Z
Pn
...
D
o o ... o o o
(a)
(b)
(c)
Figura 2-8: Distribuição de dados – (a) circular, (b) por faixa de valores e (c) hash
A distribuição circular consiste da associação seqüencial de cada fragmento de uma
relação sem levar em consideração o valor de qualquer atributo. Sua principal vantagem é o
balanceamento de carga, mas não há garantias de que os processadores terão a mesma
quantidade de trabalho porque porções de uma tabela podem ser utilizadas mais do que outras
e os tamanhos dos resultados intermediários podem ser diferentes. Por outro lado, para
acessos sofisticados, como operações de junção, haverá muito tráfego de comunicação entre
os processadores para que os fragmentos sejam juntados corretamente.
A distribuição por faixa de valores é o esquema de distribuição baseado em um atributo
escolhido da relação, chamado de atributo de distribuição. O método consiste de dois passos.
No primeiro passo, o domínio do atributo de distribuição é dividido em um número de
intervalos e cada um desses intervalos é associado a um processador. No segundo passo, as
tuplas da relação são distribuídas aos diferentes processadores. Este tipo de distribuição
favorece consultas com condição de seleção sobre atributos de distribuição, pois apenas os
processadores que contém os fragmentos que envolvem a condição serão necessários para a
execução dessa seleção. O grande problema da distribuição por faixa de valores é que na
definição dos intervalos não há garantia de um balanceamento de carga adequado, a não ser
que seja feita uma análise da distribuição dos valores da relação.
A distribuição por hash é o esquema de distribuição baseado na técnica de hashing, que
consiste em aplicar uma função hash aos valores do atributo de distribuição. Embora possa
ocorrer a distribuição de todas tuplas para um único ou poucos fragmentos, será muito menor
essa ocorrência em relação à distribuição por faixa de valores, pois uma função hash
22
adequada tende a distribuir as tuplas de maneira balanceada e facilita sua localização. Este
tipo de distribuição é bastante eficaz para o processamento paralelo da operação de junção
[Yu98].
Outras questões sobre a distribuição de dados são o número de fragmentos e o
balanceamento de carga de execução. Uma estratégia interessante é aumentar o número de
fragmentos e, assim, pode-se ter um processamento mais rápido, uma vez que o tamanho de
cada fragmento tende a ser menor. No entanto, esse aumento também aumenta o esforço para
juntar os fragmentos e, se o tamanho do fragmento for muito pequeno, então o custo para
iniciar os processos deverá ser significativo em comparação com o custo do processamento
em um ambiente monoprocessado. Para tanto, muitas estratégias têm sido propostas para
resolver o problema da execução balanceada, por exemplo, a estratégia conhecida como
execução balanceada centralizada [Wil99].
A distribuição dos dados é a base para explorar o paralelismo nas consultas em bancos
de dados paralelos. Em arquiteturas de memória distribuída, por exemplo, o princípio básico é
o de execução onde estiver localizado o dado, de tal modo que a comunicação entre os
processadores seja a mínima possível [DeW92].
A otimização de uma consulta paralela trata de técnicas de otimização apresentadas com
maior nível de complexidade. Além de determinar a ordem das junções, os métodos de acesso
apropriados e os algoritmos de cada operação, deve-se, também, considerar os níveis e
mecanismos de paralelismo, a forma de distribuição dos dados e a escala e a alocação dos
recursos.
Uma escala determina a ordem de utilização dos recursos alocados, tais como memória
e processadores, necessários para o processamento paralelo de uma consulta. Por exemplo,
uma forma de alocação de processadores para executar as operações de junção seria processar
cada junção separadamente usando todos os processadores e, assim, explorar o paralelismo
dentro da operação. Uma outra forma de alocação poderia ser a execução em paralelo das
junções, uma para cada conjunto de processadores, de tal forma que possa explorar o
paralelismo pipelined e também os paralelismos entre operações e dentro da operação [Yu98].
23
Na otimização de uma consulta paralela o problema de construir o melhor plano de
execução pode ser resolvido usando uma das duas estratégias seguintes. Na primeira
estratégia, um plano de execução é construído sem considerar a escala e a alocação de
recursos, tal como é feito em um ambiente monoprocessado. Depois, produz-se a escala e a
alocação para as operações descritas no plano de execução. Na segunda estratégia, tenta-se
gerar os planos de execução e alocação ao mesmo tempo [Has96].
Os principais algoritmos paralelos que são utilizados no processamento de consultas
podem ser encontrados em [Yu98].
2.5. Considerações Finais
O processamento de consultas é uma tarefa importante de um sistema de banco de dados e a
maioria das pesquisas tem sido desenvolvida com o objetivo de melhorar cada vez mais o
desempenho de execução das consultas.
Os principais tópicos envolvidos com o processamento de consultas foram apresentados
neste capítulo; a otimização de consultas mostra-se como o requisito mais importante e o mais
discutido na literatura.
Com o avanço tecnológico dos processadores e das redes de comunicação os sistemas
bancos de dados começaram a ser utilizados em ambientes paralelos e distribuídos,
oferecendo assim mais uma opção para melhorar a execução das consultas. Para tanto,
surgiram os ambientes de troca de mensagens para a construção de aplicações paralelas.
24
3. Paradigma de Troca de Mensagens
3.1. Introdução
A programação paralela teve início com os sistemas multiprocessados com memória
compartilhada. Um dos problemas nesses ambientes é a dificuldade em implementar uma
máquina em que todos os processadores acessem rapidamente qualquer parte da memória.
Uma forma alternativa para esses sistemas é a construção de uma rede de computadores que
se comunicam através de troca de mensagens.
Em um ambiente com troca de mensagens, uma forma de programação é levada adiante
usando uma linguagem de programação seqüencial de alto nível e uma biblioteca com rotinas
para a troca de mensagens [Wil99]. Neste trabalho será utilizada esta opção que possui os
seguintes mecanismos para a troca de mensagens: (i) criação de processos e (ii) envio e
recebimento de mensagens.
3.2. Criação de Processos
A criação de um processo pode ocorrer de modo estático ou dinâmico. No modo estático, o
sistema executará um número fixo de processos que foram especificados antes de sua
execução. No modo dinâmico, um processo pode ser criado, destruído e executado durante a
execução do sistema. A última técnica é muito poderosa porque permite um melhor
gerenciamento dos processos; porém, exige-se maior esforço computacional durante a criação
de um processo.
Na maioria das aplicações existe um processo (mestre) que controla os demais
processos (escravos). O código executável de cada processo pode ser escrito usando o modelo
SPMD (Single Program Multiple Data) ou o modelo MPMD (Multiple Program Multiple
Data). A diferença básica entre os dois modelos é que no SPMD são utilizados processos
estáticos que selecionam suas tarefas de um único programa executável e no MPMD, cada
processo dinâmico executa suas tarefas localizadas em programas separados.
25
3.3. Envio e Recebimento de Mensagens
O envio e recebimento de uma mensagem ocorrem através de rotinas de troca de mensagens.
Em cada rotina devem ser fornecidas a identificação do processo e a localização dos dados a
serem enviados. Estas rotinas podem ser implementadas através de técnicas com bloqueio ou
sem bloqueio. Uma rotina com bloqueio espera até que a mensagem seja enviada ou recebida
e a rotina sem bloqueio não aguarda o recebimento da mensagem. Uma rotina sem bloqueio
melhora o desempenho das aplicações paralelas porque a computação pode continuar
enquanto as operações de comunicação estão em andamento.
3.4. Ambientes de Troca de Mensagens
Existem dois ambientes principais que usam o paradigma de troca de mensagens: o PVM
(Parallel Virtual Maquine) e o MPI (Message Passing Interface) [Wil99]. Esses ambientes
foram concebidos para serem portáveis para sistemas heterogêneos.
O PVM é um conjunto integrado de bibliotecas e de ferramentas de software com o
objetivo de permitir que dois ou mais computadores conectados, apresentando, possivelmente,
diferentes arquiteturas, possam trabalhar cooperativamente formando uma máquina paralela
virtual. Seu projeto teve início em 1989 no Oak Ridge National Laboratory (ORNL). A partir
da versão 2.0, liberada em 1991, outras instituições começaram a utilizar esse ambiente em
aplicações científicas [Gei94].
Várias mudanças foram introduzidas no PVM para retirar erros de implementação e
permitir o seu uso em novas plataformas. Atualmente, em sua versão mais recente, a 3.4.4, as
aplicações podem ser desenvolvidas usando as linguagens Fortan, C e C++, oferecendo,
também, suporte para as plataformas Unix e Windows. A escolha desse conjunto de
linguagens deve-se ao fato de que as maiorias das aplicações sujeitas a paralelização estão
escritas
nessas
linguagens.
Este
ambiente
pode
ser
obtido
no
endereço
http://www.csm.ornl.gov/pvm/.
O MPI resultou de um esforço de padronização para tentar resolver os problemas de
portabilidade que ainda persistiam nos ambientes de troca de mensagens existentes, como o
PVM [Wil99], pois a maioria possui apenas um subconjunto das características necessárias
para os diversos equipamentos fabricados, dificultando a tarefa de implementação em
26
diferentes máquinas. Assim, em 1992, o Comitê MPI definiu um padrão para esses ambientes
com os seguintes objetivos principais: (i) melhorar a comunicação entre os processos evitando
a cópia de dados e permitir sobreposição de computação e comunicação, quando possível; (ii)
permitir que a aplicação possa ser executada em um ambiente heterogêneo sem a necessidade
de mudança no código; (iii) utilizar as linguagens Fortran e C para a construção das
aplicações paralelas; (iv) garantir a execução da aplicação sobre uma interface de
comunicação confiável, sem a necessidade da interferência do usuário nas falhas de
comunicação e (v) definir uma interface semelhante à do padrão PVM, Express, P4 ou Linda,
provendo extensões para maior flexibilidade [Mpi95].
No MPI existem quatro versões, neste trabalho será descrita brevemente sua última
versão, a MPI-2.0 [Mpi97] que dá suporte a E/S paralela através do padrão MPI-IO que é um
recurso útil para a criação e manipulação de arquivos paralelos.
3.5. MPI-2.0
Um programa MPI é executado por processos autônomos (estáticos ou dinâmicos) que
utilizam seu próprio espaço de endereçamento, embora implementações de memória
compartilhada sejam possíveis. O código de cada processo pode ser diferente e a comunicação
entre os processos ocorre através das rotinas de envio e recebimento de mensagens. Um
processo é identificado pelo seu rank que corresponde a um número inteiro que varia entre
zero e N - 1 (onde N representa a quantidade de processos ativos).
A comunicação no MPI é realizada de modo seguro, de maneira que uma mensagem
enviada por um processo não seja recebida por um outro indevidamente. Para tanto, utiliza-se
um identificador de mensagem chamado de tag. Mas, seu uso incorreto pode ocasionar um
problema de deadlock1. Um outro mecanismo para evitar o recebimento indevido de uma
mensagem é a delimitação do domínio de comunicação entre os processos através da criação
de grupos de processos, revelando-se como uma característica importante para a construção
de aplicações complexas.
1
Deadlock ou impasse é um erro que ocorre quando dois processos ou mais ficam aguardando um pelo outro para que
possam dar continuidade ao processamento.
27
O envio e o recebimento de mensagens no MPI é realizado através de rotinas de troca
de mensagens. Entre as principais características dessas rotinas pode-se citar: com e sem
bloqueio e com comunicação nos dois ou único sentido.
A ocorrência de deadlocks em uma aplicação paralela é muito comum com rotinas de
comunicação com um único sentido. O deadlock pode ser evitado quando se utiliza rotinas de
comunicação em dois sentidos, que são formadas pela aglutinação de operações de envio e
recebimento de mensagens consecutivas em uma única rotina. Desta maneira, as rotinas são
ativadas ao mesmo tempo e executam concorrentemente, permitindo ganho de desempenho
em determinadas situações. As rotinas de comunicação em dois sentidos são implementadas
com a técnica de bloqueio e combinam-se com quaisquer outras rotinas de envio ou
recebimento.
Uma novidade no MPI-2.0 é a proposta de uma interface padrão para E/S paralela.
MPI-IO, como é conhecido, suporta uma interface de alto nível para descrever o
particionamento dos dados de um arquivo entre processos, fornece uma interface para
transferência coletiva de dados entre arquivos e memória, suporta operações de E/S
assíncronas, permite a sobreposição de computação com E/S e, resumindo, sua interface visa
o estabelecimento de um padrão flexível, portável e eficiente para descrever as operações E/S
independentes e coletivas realizadas pelos processos de uma aplicação paralela.
Os sistemas de arquivos paralelos existentes suportam interfaces similares ao do MPIIO, mas as aplicações paralelas sobre esses arquivos não são portáveis [Tha99]. É difícil
desenvolver aplicações científicas complexas, por exemplo, para cada geração de máquinas
paralelas, devido às diferenças de desempenho.
No padrão de E/S de arquivos do Unix, o acesso simultâneo a um arquivo por vários
processos não é possível, a menos que seja realizado por pipes (um processo passa os dados a
outro processo) e, ainda, de modo muito restrito. Este ambiente também não provê operações
para o acesso a arquivos como é feito em memória, de forma não contígua. Estas restrições
reduzem o desempenho de aplicações paralelas que exigem muito acesso a disco. Assim, o
MPI-IO surge como uma tentativa de minimizar os problemas nessas aplicações.
28
MPI-IO é baseado na idéia que E/S em arquivo pode ser tratada como uma troca de
mensagens. Desta maneira, escrever em um arquivo é como se estivesse enviando uma
mensagem e ler em um arquivo é como se estivesse recebendo uma mensagem. A interface do
MPI-IO foi desenvolvida com os seguintes objetivos: (i) primeiramente, atender às aplicações
científicas, embora atenda a outros tipos de aplicações; (ii) permitir o uso de padrões sobre
diferentes unidades de acesso; (iii) oferecer características aplicáveis ao mundo real, por
exemplo, estruturas de acesso à memória e aos discos; (iv) permitir ao programador
especificar informações de alto nível sobre E/S e (v) oferecer desempenho.
Quando um arquivo é aberto com o MPI-IO, um comunicador2 é especificado para
determinar que grupo de processos poderá acessar o arquivo. O acesso poderá ser
independente, quando não existe um coordenador entre os processos, ou coletivo, quando
todos os processos participam da mesma operação de E/S. Para tanto, define-se um esquema
de particionamento usando tipos derivados dos tipos básicos do MPI. Desta forma, permite-se
ampliar um padrão de acesso existente garantindo maior flexibilidade para as aplicações
paralelas.
Assim, um arquivo no MPI-IO pode ser definido como sendo uma coleção ordenada de
itens de tipos de dados que são acessíveis seqüencialmente ou randomicamente. A seguir,
serão apresentados os conceitos que determinam o esquema de particionamento de um
arquivo paralelo, conforme ilustrados nas Figuras 3-1 e 3-2:
• Deslocamento (displacement): É um valor que define a localização inicial dos dados
para um processo. Esse valor também pode ser utilizado para determinar uma área
para o cabeçalho de um arquivo;
• Tipo elementar (etype): Uma unidade de acesso ou de posicionamento é
representada por um dos tipos básico (por exemplo, numérico) do MPI, ou um tipo
derivado de um básico, ou ainda um tipo estendido daquele;
• Tipo de arquivo (filetype): Um tipo de arquivo é a base para o particionamento de
um arquivo entre os processos e define um esquema de acesso ao arquivo. Este
esquema é composto por uma quantidade de tipos elementares e buracos (os quais
são de tamanhos múltiplos de um tipo elementar). Um tipo de arquivo básico repete2
Um comunicador é um domínio de comunicação que define um conjunto de processos que podem comunicar-se. Um
comunicador global para todos processos no MPI é o MPI_COMM_WORLD.
29
se várias vezes, criando regiões de acesso permitidas (onde são definidos os tipos
elementares) e regiões de acesso negado (onde são definidos os buracos) para os
processos;
• Visão (view): Define quais regiões de um arquivo que um processo terá acesso. Uma
visão é descrita pelo deslocamento, tipo elementar e tipo de arquivo;
• Posição relativa (offset): Determina o posicionamento dentro de um arquivo para
uma visão corrente, expressa em quantidades de um tipo elementar;
• Tamanho do arquivo (filesize): O tamanho de um arquivo no MPI é medido em bytes
a partir do seu início.
Tipo de arquivo
Deslocamento
E
B
E
B
Tipo elementar
B
B
B
E
E
B
B
B
...
Buracos
Figura 3-1: Componentes para um Esquema de um Arquivo no MPI-IO.
Para melhorar o desempenho em uma aplicação paralela, o MPI-IO suporta
sobreposição de computação com E/S em disco através das rotinas sem bloqueio para o
acesso a dados. Essas rotinas mantêm a mesma idéia de funcionamento das rotinas com e sem
bloqueios. Uma outra maneira de melhorar desempenho das aplicações é o acesso coletivo
dos dados pelos processos, cada um obtendo seus próprios. Para tanto, deve-se definir,
durante a abertura do arquivo, qual grupo de processos realizará esse tipo de acesso.
Tipo elementar
Tipo de arquivo – Processo 0
Tipo de arquivo – Processo 1
...
Deslocamento
Figura 3-2: Exemplo de um Particionamento de um Arquivo entre 2 Processos.
30
Hoje em dia, são oferecidas várias implementações do padrão MPI entre as quais
destacam-se HP-MPI, IBM-MPI, SGI-MPT e SUN-MPI. Contudo, parte de seu sucesso é
creditado às duas primeiras implementações livres que foram oferecidas, que são a LAM e a
MPICH.
A LAM (Local Área Multicomputer) foi desenvolvida inicialmente pela Universidade
de Ohio (Ohio Supercomputing Center), mas a partir da versão 6.2b, a Universidade de Notre
Dame vem dando continuidade no projeto.
A última versão disponibilizada recentemente é a 7.0 que provê alto desempenho para
uma variedade de plataformas, que vão desde pequenos clusters com máquinas com um único
processador até máquinas mutiprocessadas. Essa versão inclui a implementação completa do
padrão MPI-1.2 e grande parte do MPI-2.0, como por exemplo, a criação de processos, MPIIO usando o ROMIO3, suporte a threads, compatível com C++, entre outras. No entanto, a
LAM ainda não dispõe uma implementação para o ambiente windows e pode ser obtida nos
endereços http://www.mpi.nd.edu/lam/download/ ou http://www.lam-mpi.org/.
A MPICH surgiu durante o processo de padronização do MPI com o intuito de prover
um feedback ao fórum de implementação. Suas primeiras versões desenvolvidas no Argonne
National Laboratory e na Universidade do Estado do Mississippi atendem completamente o
padrão inicialmente proposto.
A versão recente da MPICH 1.2.5 tem evoluído para o ambiente windows
(NT4/2000/XP Professional) com a implementação completa do padrão MPI-1.2 e partes do
MPI-2.0. Entre os recursos existentes pode-se citar a implementação do padrão MPI/IO
suportado através do ROMIO, o suporte para construção de programas no modelo MPMD, o
uso de threads, a compatibilidade com C++, entre outras. O MPICH pode ser obtido no
endereço http://www-unix.mcs.anl.gov/mpi/mpich/.
3
ROMIO é uma implementação portável do padrão MPI-IO para alto desempenho com suporte a diversos tipos de
máquinas e sistemas de arquivos tais como IBM PIOFS, Intel PFS, HP HFS, SGI XFS, NEC SFS, NFS, NTFS, entre outros.
31
3.6. Métricas para Avaliar Programas Paralelos
Na computação paralela, o aumento de velocidade de processamento obtida com o
paralelismo é um dos fatores mais importantes. Para se calcular esse aumento, dois
parâmetros são abordados na literatura: o speedup e a eficiência [Wil99].
O speedup (Sp) é utilizado para determinar o aumento de velocidade obtido durante a
execução de um programa paralelo em relação ao seqüencial.
Sp = Ts / Tp, onde:
Ts = tempo para executar o melhor programa seqüencial;
Tp = tempo para executar o programa paralelo utilizando p processadores.
O caso ótimo é obtido quando Sp = p, ou seja, na medida em que aumenta o número de
processadores, aumenta-se diretamente a velocidade de processamento. Fatores que
influenciam a obtenção do caso ótimo estão relacionados principalmente com a comunicação
entre os processadores e a parte seqüencial (aquela que não pode ser paralelizada) do
algoritmo.
A eficiência (Ep) determina o quanto que está sendo utilizado dos processadores, ou
seja, quando Sp não é diretamente proporcional a p, há uma perda de desempenho.
Ep = Sp / p, onde:
p = é o número de processadores.
A variação de Ep é entre zero e um, sendo que o valor um indica uma eficiência de
100%.
3.7. Considerações Finais
Nos últimos anos, os ambientes de troca de mensagens tornaram-se bastante populares e
muitos ambientes têm sido propostos e desenvolvidos com o objetivo de melhorar cada vez
mais o uso dos recursos computacionais. As principais características de ambientes de troca
32
de mensagens foram apresentadas neste capítulo; a padronização mostra-se como um requisito
importante e o mais discutido nesses tipos de ambientes.
Escolher um ambiente de troca de mensagens para o desenvolvimento de aplicações
paralelas não é uma tarefa simples e deve ser feita analisando a real necessidade da aplicação.
Levando em consideração apenas a necessidade de acesso paralelo aos arquivos, o MPI-IO
possui as especificações e implementações para atender essa necessidade. No caso do PVM,
mesmo existindo alguns projetos nesta área, ainda não houve resultados.
Com o crescimento dos bancos de dados, muitas maneiras têm surgido para melhorar o
desempenho da execução de consultas; o uso do paralelismo através de ambientes de troca de
mensagens é um exemplo. A aplicação do agrupamento prévio também é uma outra forma
que surgiu como mais uma alternativa para reduzir o tempo de execução das consultas sobre
grandes volumes de dados.
33
4. Agrupamento Prévio e Filtro Seletivo
4.1. Introdução
A agregação é uma operação importante em uma consulta para construir dados précomputados. Esses dados construídos podem ser utilizados pelo usuário ou armazenados em
data warehouses, que posteriormente poderão ser consultados.
Uma agregação pode ser dividida em dois passos. O primeiro passo é o agrupamento
que consiste em localizar os registros do banco de dados que compartilham os mesmos
valores sobre o atributo de agrupamento. O segundo, é avaliar a agregação, aplicando-se as
funções para os grupos encontrados.
No restante do capítulo será apresentada uma técnica para otimizar consultas
envolvendo a operação de agregação. Além disso, serão detalhadas as principais estratégias
estudadas para o processamento seqüencial e paralelo de consultas com agregados.
4.2. Aplicando o Agrupamento Prévio
As consultas formuladas em SQL para data warehouses, em geral, utilizam a cláusula GROUP
BY e funções de agregação. Como exemplo, a consulta Q1, já apresentada anteriormente, tem
esta característica.
Q1: SELECT
FROM
WHERE
GROUP BY
bairro, anoloc, COUNT(*), SUM(valorlocfita)
Loja , Locacao, Filme
idloja= idlojaloc AND idfilme= idfilmeloc AND anoloc≥1993 AND genero='drama'
bairro, anoloc
Os dados são particionados em grupos (locações anuais por bairro) e agregados sobre
atributos (quantidade de locações e valor faturado). A eficiência de tais consultas deve ser
tratada com muita atenção, embora muito pouco tenha sido feito para melhorar seu
desempenho.
34
Os processadores de consultas em bancos de dados relacionais ainda exploram o modelo
tradicional para o processamento de consultas, isto é, a execução do operador de junção antes
do operador de agrupamento, conforme ilustra a Figura 4-1.
γbairro, anoloc, COUNT(*)Ænloc, SUM(valorlocfita)Ævfat
π bairro, anoloc, valorlocfita
idfilmeloc=idfilme
π idfilme
idloja=idlojaloc
π idloja, bairro
Loja
π idlojaloc, idfilmeloc, anoloc, valorlocfita
σ genero='drama'
σ anoloc≥1993
Filme
Locacao
Figura 4-1: Árvore de Consulta Otimizada.
Em dois importantes trabalhos, Yan e Larson [Yan94a] e Chaudhuri e Shim [Cha94],
mostram como o operador de agrupamento pode ser executado antes do operador de junção. A
aplicação desta estratégia visa reduzir o número de tuplas antes da execução do operador de
junção; desta forma, o desempenho da consulta pode ser melhorado. A diferença entre os dois
estudos é a maneira como é realizada a otimização.
No trabalho de Yan e Larson [Yan94a], utiliza-se à transformação de uma consulta em
SQL em outras duas: uma com o operador de agrupamento e a outra sem este operador. O
resultado da consulta é determinado pela junção dos resultados obtidos com a execução das
duas consultas. Devido ao fato de se estar tratando duas consultas separadamente, a ordem das
junções fica restrita, reduzindo o espaço de busca pelo otimizador.
No estudo apresentado por Chaudhuri e Shim [Cha94], generaliza-se a transformação
apresentada por [Yan94a]. Busca-se transformar um plano de consulta otimizado em outro
equivalente. Na construção do plano equivalente, a ordem das junções e dos agrupamentos é
considerada, diminuindo, desta forma, o problema do espaço de busca pelo otimizador. Para
35
tanto, utiliza-se uma heurística que ajuda encontrar um plano de execução eficiente a partir de
sub-planos, ótimos ou não, e, no final, é escolhido um plano considerado o melhor.
Um exemplo da aplicação do agrupamento prévio está ilustrado na Figura 4-2. Neste
novo plano, um agrupamento é executado antes da junção, causando diminuição no custo da
junção.
γbairro, anoloc, SUM(nloc), SUM(vfat)
idfilmeloc=idfilme
γidfilmeloc, bairro, anoloc, SUM(nloc), SUM(vfat)
π idfilme
idloja=idlojaloc
π idloja, bairro
σ genero='drama'
γidlojaloc, idfilmeloc, anoloc, COUNT(*)Ænloc, SUM(valorlocfita)Ævfat
Filme
Loja
σ anoloc≥1993
Locacao
Figura 4-2: Árvore de Consulta Otimizada com Agrupamento Prévio.
Levando em consideração a massa de dados de exemplos do Apêndice A, pode-se
chegar a alguns resultados interessantes neste novo plano. Por exemplo, se a quantidade de
registros que satisfazem as condições de seleção das tabelas LOCACAO e FILME são
respectivamente 900.000 e 1.000 registros, conclui-se que no plano tradicional não haverá
nenhuma redução do número de tuplas para as operações de junção. A primeira junção
utilizará 16 e 900.000 registros. Mas, optando-se pelo plano com agrupamento prévio, então,
na mesma junção, serão usados 16 e 160.000 registros. A redução do número de registros de
900.000 para 160.000 é possível porque o primeiro operador de agrupamento agrupa os
registros sobre os atributos idlojaloc, idfilmeloc e anoloc. Além disso, a segunda junção será
beneficiada por uma nova redução, pois um outro operador de agrupamento será executado
antes da junção.
36
A seguir, apresentam-se os tipos de transformação, as definições e as condições
necessárias para aplicação do agrupamento prévio segundo os estudos em [Cha94].
4.2.1. Tipos de transformação
Existem três tipos de transformação para o agrupamento prévio: o invariante, o de união
simples e o de união generalizada.
No agrupamento invariante o operador de agrupamento é movimentado da raiz para
algum nó interno da árvore de consulta.
No agrupamento de união simples, novos operadores de agrupamento são adicionados
à árvore de consulta, correspondendo a uma generalização do agrupamento invariante. Os
operadores de agrupamento adicionais são necessários tendo em vista que as operações
subseqüentes poderão gerar mais de uma tupla por grupo. Por esta razão, estas tuplas
precisam ser juntadas ao mesmo grupo. A união é possível porque as funções de agregação
podem ser calculadas sobre partições.
O agrupamento de união generalizada é um tipo de agrupamento de união simples; a
diferença é que para cada operador de agrupamento adicionado no plano, também é
adicionado um contador de tuplas por grupo. Para aplicar esta transformação, as funções de
agregação devem ser calculadas conforme as seguintes derivações: MIN(N,s)=s, MAX(N,s)=s,
AVG(N,s)=s, SUM(N,s)=N*s, e COUNT (N,s)=N, onde N é o número de tuplas s em um grupo.
Cada transformação apresentada está em uma ordem de generalidade e complexidade
crescentes. As transformações adicionam complexidade para a construção do plano de
execução da consulta em relação aos planos tradicionais, pois o espaço de busca por uma
solução é muito maior. Com isto, alguns problemas surgem: (i) a quantidade de planos de
execução equivalentes cresce rapidamente quando se considera às ordens de interesse das
junções e dos agrupamentos; (ii) é difícil construir um plano que satisfaça, a um mesmo
tempo, as orderns de interesse das junções e dos agrupamentos e (iii) se os operadores de
agrupamento são implementados usando uma estratégia de ordenação, o número de ordens de
interesse cresce.
37
As transformações apresentadas devem ser aplicadas levando em consideração um
modelo de estimativa de custos, sem esquecer, no entanto, os problemas apresentados; senão,
o custo da enumeração de planos pode ser proibitivo.
4.2.2. Conjuntos necessários para a transformação
Para aplicar uma das transformações descritas anteriormente é necessária a apresentação de
algumas definições. Por exemplo, em uma consulta SQL com agregados, analisam-se seus
componentes (atributos de agrupamento e de agregação) e anotam-se informações na árvore
de consulta. Essas anotações são úteis para determinar o tipo de agrupamento prévio a
empregar.
Em cada nó da árvore de consulta, são definidos três conjuntos: colunas de junção,
colunas requeridas e colunas candidatas à agregação. As colunas de junção são as
colunas de um nó do plano que participam em predicados de junção que são avaliados por nós
ancestrais. As colunas requeridas compreendem as colunas de junção de um nó do plano
mais as colunas de agrupamento da consulta. As colunas candidatas à agregação são as
colunas de um nó do plano que também são colunas de agregação da consulta, mas não estão
entre as colunas requeridas. Esta definição exclui as colunas de agregação que participarão de
predicados futuros, embora sejam colunas requeridas, devendo ser preservadas no plano por
um nó até que os predicados sejam avaliados. As colunas que serão utilizadas em um
processamento subseqüente estarão entre as colunas requeridas e as colunas candidatas à
agregação.
4.2.3. Identificando o nó de transformação
O nó da árvore de consulta que será escolhido para a aplicação do agrupamento prévio deverá
satisfazer uma ou mais condições dentre as apresentadas a seguir: (i) cada coluna de
agregação de uma consulta está no conjunto de colunas candidatas à agregação de um nó
candidato da árvore de consulta; (ii) cada coluna de junção do nó candidato da árvore de
consulta pertence ao conjunto de colunas de agrupamento de um consulta e (iii) os nós
ancestrais ao nó candidato avaliam cada predicado de junção sobre uma chave estrangeira.
38
A primeira condição não permite que o nó candidato realize a agregação sobre colunas
que pertencem a outras tabelas; pois, se assim fosse, tuplas poderiam ser perdidas na
agregação. Neste caso, esta condição será satisfeita quando uma operação de junção
determina a união das colunas de agregação da consulta avaliada. As outras condições
determinam o nó apropriado de tal forma que as junções subseqüentes não resultem em mais
que uma tupla para um mesmo grupo, pelo fato das junções subseqüentes serem feitas sobre
chaves estrangeiras.
Um nó apresenta a propriedade de agrupamento invariante quando satisfaz as três
condições. Seus nós ancestrais também terão esta propriedade; desta forma, qualquer um
poderá ser escolhido para a movimentação do operador GROUP-BY, constituindo, assim, uma
importante informação sob o ponto de vista do espaço de execução pelo otimizador.
No agrupamento de união simples, não há obrigação que as colunas de junção sejam
iguais às colunas de agrupamento da consulta correspondentes, dispensando a segunda
condição. Desta forma, o nó escolhido só precisa satisfazer as condições 1 e 3.
Um nó será identificado com a propriedade de agrupamento de união generalizada
quando algumas colunas de agregação da consulta estão presentes neste nó, satisfazendo de
forma parcial a condição 1.
Com o resultado desta discussão fica fácil deduzir que a aplicação da estratégia de
agrupamento prévio deve reduzir significativamente o tempo de execução de uma operação de
junção e, conseqüentemente, melhorar o desempenho de execução da consulta.
A árvore de consulta com agrupamento prévio é construída a partir da identificação dos
três conjuntos, conforme apresentados anteriormente. Por exemplo, na árvore de consulta
representada na Figura 4-1, esses conjuntos são os seguintes para o nó LOCACAO:
•
Colunas de junção: idlojaloc, idfilmeloc;
•
Colunas requeridas: idlojaloc, idfilmeloc, anoloc e
•
Colunas candidatas à agregação: *,valorlocfita.
39
Assim, configuração do operador de agrupamento para o nó LOCACAO será definida
usando as seguintes regras: (i) as colunas requeridas são transformadas em colunas de
agrupamento e (ii) as colunas candidatas à agregação são transformadas em colunas de
agregação. Esta configuração está representada na Figura 4-2.
Considerando uma variação da consulta Q1, onde a condição de seleção
(valorlocfita*numfitasloja>200) é adicionada, então o conjunto de colunas candidatas à agregação
será vazio para os nós de LOCACAO e junções; portanto, não haverá o agrupamento prévio,
enquanto não for avaliada esta condição.
4.3. Estratégias para o Agrupamento Prévio
Nesta seção serão apresentados os principais trabalhos estudados sobre o processamento
seqüencial e paralelo de agregados. Além disso, será apresentada uma nova estratégia para ser
utilizada junto com o agrupamento prévio, denominada de filtro seletivo.
4.3.1. Processamento Seqüencial de Agregados
Em [Gra93] é relatada uma estratégia baseada em ordenação para execução da agregação.
Nessa estratégia, os resultados, enviados a um arquivo temporário, somente serão utilizados
quando todas as entradas forem processadas. Graefe apresenta três algoritmos para o
processamento do agrupamento baseados em: (i) loop aninhado, (ii) ordenação e (iii) hashing,
respectivamente. Os mais utilizados em bancos de dados relacionais são os dois últimos, por
apresentarem melhor desempenho para grandes volumes de dados.
Em [Yan94b] é apresentada uma estratégia para o agrupamento usando o método
ordenação-mesclagem (sort-merge), chamada de agregação ansiosa. A idéia consiste em
aplicar a agregação na fase de ordenação, usando uma tabela heap, com o objetivo de reduzir
o número de tuplas durante a fase de mesclagem e, conseqüentemente, o acesso a disco.
Outras vantagens são a possibilidade de descartar a fase de mesclagem caso o número de
grupos produzidos seja pequeno e reduzir a quantidade de níveis de processamento durante a
mesclagem. No entanto, pode ocorrer de não haver agrupamentos durante a ordenação devido
aos seguintes fatores: tamanho de memória menor que o número de grupos ou à distância
40
entre duas tuplas pertencentes ao mesmo grupo é sempre maior que o número de grupos que
cabem na memória.
Em [Lar97] são apresentados algoritmos que usam a idéia da agregação ansiosa
baseados em: varredura repetida, ordenação e particionamento.
Na agregação por varredura repetida, uma varredura completa da tabela de entrada
define o primeiro conjunto de grupos em memória e também uma tabela temporária com as
tuplas que não coincidem com esses grupos. Os demais grupos são formados usando a tabela
temporária e termina quando todas tuplas são consumidas pelos grupos. O número de passos
desta estratégia é definido em função do tamanho da memória e do número de grupos, que
determina o custo de acesso a disco.
Na agregação por ordenação, a ordenação somente ocorre quando os grupos forem
gravados em disco, desta maneira deve-se utilizar pesquisa seqüencial para encontrar um
grupo de uma determinada tupla.
A agregação usando particionamento consiste em particionar a entrada em pequenos
arquivos temporários através de uma função hashing sobre os atributos de agrupamento e,
então, aplicar uma outra função hashing sobre cada partição. O objetivo dessa estratégia é
criar partições contendo poucos grupos de maneira que o agrupamento final possa ser feito em
memória. A agregação ansiosa é aplicada antes de gravar as partições em disco. Um problema
desta estratégia é determinar o tamanho das partições de maneira que não desperdice memória
sem aumentar o custo do acesso a disco.
A estratégia que usa varredura repetida possui baixo desempenho quando menos de
45% dos grupos cabem dentro da memória. Para valores acima de 45%, o desempenho fica
muito próximo da estratégia por particionamento. Dentre as três estratégias a que apresenta
pior desempenho é a baseada em ordenação para todas configurações de memória e a melhor
de todas é usando particionamento [Lar97].
41
4.3.2. Processamento Paralelo de Agregados
Em [Bit83] é apresentada uma estratégia para o processamento paralelo de agregados a qual
foi implementada no projeto Gamma [DeW90], sendo baseada em um único coordenador
central. O resultado do processamento em cada nó é enviado para o coordenador central que
compõe o resultado final. Esta abordagem é indicada para consultas em que o número de
grupos gerados é pequeno, pois, caso contrário, o coordenador central ficará sobrecarregado.
É apresentada, também, a estratégia baseada no método de broadcast que evita o
problema da sobrecarga de trabalho do coordenador central, pois ao invés de apenas um nó
fazer a composição do resultado final, composições parciais intermediárias são realizadas
através de um esquema de merge binário, em pipeline; mas, no final, um nó fará a composição
do resultado final. Este esquema é realizado em log2N - 1 passos de distribuição, onde N é o
número de processadores, sendo ideal para agrupamentos que não produzem muitos grupos,
pois caso contrário, a fase merge será o gargalo.
Em [Sha94] são apresentadas duas estratégias para o processamento de agregados:
agregação de duas fases e agregação por redistribuição. Na agregação de duas fases, primeiro,
realiza-se a agregação local em cada processador e, depois, os grupos produzidos são
distribuídos entre os processadores usando uma função hashing. Nesta fase, cada processador,
em paralelo, produzirá o resultado final das tuplas pertencentes a um mesmo grupo. Na
agregação por redistribuição, o agrupamento é feito em uma única fase. Esta estratégia deve
ser utilizada em redes de alta velocidade e seus problemas são relacionados à ociosidade em
alguns processadores devido a dois fatores: o número de grupos formados é menor que o
número de processadores ou os grupos são distribuídos a alguns processadores.
Com relação às estratégias apresentadas têm-se as seguintes conclusões: (i) para muitos
grupos formados, a estratégia de duas fases é um pouco inferior em relação à redistribuição,
mas, se pouca memória estiver disponível, o desempenho da estratégia de redistribuição é
superior; (ii) para poucos grupos produzidos, a estratégia de duas fases é a melhor alternativa,
mesmo existindo pouca memória e (iii) aumentando-se a quantidade de nós, a estratégia de
duas fases tem desempenho muito próximo ao da estratégia de redistribuição. A escolha de
uma das estratégias deve ser feita baseada na estimativa do número de grupos, que nem
sempre está disponível, mas, se estiver, pode ser imprecisa.
42
Para evitar uma escolha errada de uma das estratégias apresentadas em [Sha94], foram
apresentados os algoritmos adaptativos em [Sha95]. A idéia consiste em trocar o algoritmo
por outro durante o processamento do agrupamento conforme varia a carga de trabalho. Esta
estratégia deve ser evitada em redes de banda limitada.
Em [Tan00a] são apresentados três algoritmos para o processamento de agregados
usando uma única tabela. Estes algoritmos seguem as estratégias apresentadas em [Sha94],
sendo que os dois primeiros são propostos para arquiteturas de memória distribuída e o último
é especializado para uma arquitetura em cluster (cada nó com memória compartilhada). Além
disso, outro ponto é aplicação ou não da agregação local antes da distribuição.
No algoritmo de duas fases, o número de grupos produzidos reduz a comunicação entre
os nós, mas, se a redução do número de tuplas for mínima, então, a agregação local não
oferecer benefícios.
O algoritmo para a arquitetura em cluster divide o processamento em duas etapas: na
primeira, o processamento local de cada nó é feito usando a estratégia de redistribuição e, na
segunda, a comunicação entre os nós é realizada através da estratégia de duas fases. O
algoritmo teve melhor desempenho nesta arquitetura devido a dois fatores: (i) a redistribuição,
na fase inicial, ocorre dentro do nó usando memória compartilhada e (ii) a comunicação entre
os nós é feita após o agrupamento local.
Em [Tan00b] são apresentados três algoritmos para o processamento de agregados
usando mais de uma tabela que exploram a questão da escolha do atributo de distribuição
(junção/agrupamento). Para tanto, duas estratégias foram apresentadas: distribuição por
junção e distribuição por agregação.
Na distribuição por junção, usa-se o atributo de junção das duas tabelas para a distribuir
os dados entre os processadores e após esse processo são realizadas a junção local e a
agregação local. No final, os resultados parciais são redistribuídos usando o atributo de
agrupamento para a composição do resultado final. Na distribuição por agregação, a tabela
com o atributo de agrupamento é distribuída e a outra tabela é replicada.
43
Essas estratégias foram implementadas em uma arquitetura de memória distribuída e
também em uma arquitetura em cluster (cada nó com memória compartilhada), onde cada nó
usa a estratégia de distribuição por agregação para seu processamento local e a comunicação
entre os nós é feita utilizando a distribuição por junção. Na arquitetura em cluster, a
replicação de uma tabela é feita usando a memória compartilhada, favorecendo esta tarefa.
Em [Tan01] são apresentadas duas estratégias para o processamento de consultas na
qual os atributos de junção e agrupamento são iguais. Estas estratégias, implementadas sobre
uma arquitetura de memória distribuída, assemelham-se com as estratégias apresentadas em
[Sha94] com relação à aplicação ou não da agregação local antes da distribuição. As
estratégias serão apresentadas usando a seguinte notação para as tabelas envolvidas: R é
tabela que contém pelo menos um atributo de agregação e S não contém esse atributo.
A primeira estratégia, chamada de distribuição preguiçosa, é dividida em três fases:
agregação local, distribuição e agregação/junção final. A agregação local consiste em realizar
a operação de agregação sobre R em cada processador; depois, os resultados parciais são
distribuídos juntamente com S baseado no atributo de junção/agregação. Finalmente, é
realizada a agregação de R e a junção com S. O custo da comunicação existente na fase de
distribuição depende do número de grupos produzidos de R e se esse número for inferior ao
número de processadores, o desempenho durante a etapa paralela é reduzido.
A distribuição ansiosa é ideal para redes de alta velocidade e divide-se em duas fases:
distribuição e agregação/junção. Na distribuição particiona-se R e S com base no atributo de
agrupamento/junção para cada processador. Na segunda fase, uma operação de agregação
sobre R define o resultado que deverá ser juntado com a tabela S. Depois da junção, cada nó
terá o resultado da consulta local. O resultado final da consulta é a união dos resultados
produzidos em cada nó.
4.3.3. Usando um Filtro Seletivo
O agrupamento prévio é uma técnica que pode reduzir o custo de uma consulta, sendo
importante a sua aplicação em bancos de dados com muitas informações. Geralmente, essas
consultas realizam algum tipo de seleção sobre os dados que devem ser executadas o quanto
antes pelo processador de consultas. Esta seção apresenta um filtro seletivo para ser usado
44
durante a aplicação do agrupamento prévio. Esse filtro está baseado nas idéias apresentadas
em [Wei02] para o processamento de consultas envolvendo junções.
Costa Neto apresenta em [Cos01] idéias para reduzir o tempo de execução de uma
consulta e evitar a sua interferência no banco de dados de produção. Estas idéias estão
baseadas na criação e manipulação de visões materializadas sobre uma tabela de fatos. O filtro
seletivo poderá também ser aplicado durante a criação de visões materializadas.
A consulta Q2 será usada para exemplificar o filtro seletivo que determina mensalmente
a quantidade de locações de filmes do gênero 'faroeste'. Seu plano de consulta está ilustrado
na Figura 4-3 e será executado usando a massa de dados de exemplos do Apêndice A.
Q2: SELECT
FROM
WHERE
GROUP BY
nomefilme, anoloc, mesloc, COUNT(*)
Filme, Locacao
idfilme=idfilmeloc AND genero='faroeste'
nomefilme, anoloc, mesloc
Se 200 filmes são do gênero 'faroeste', então o plano da consulta Q2 produzirá 26.400
registros. O custo dominante do plano deverá ser sobre a tabela LOCACAO (tabela de fatos), na
qual serão produzidos 264.000 registros pelo operador de agrupamento. Essa consulta possui
duas características essenciais para o uso do filtro seletivo: (i) envolve uma tabela de fatos e
(ii) pelo menos uma de suas tabelas de dimensão possui ao menos uma condição de seleção.
π nomefilme, anoloc, mesloc, nloc
idfilme =idfilmeloc
π idfilme
γidfilmeloc, anoloc, mesloc, COUNT(*)Ænloc
σ genero='faroeste'
Locacao
Filme
Figura 4-3: Plano de Consulta Otimizado para Q2 com Agrupamento Prévio.
Um filtro seletivo tem por objetivo reduzir o número de grupos durante a execução do
primeiro agrupamento prévio. Os grupos possivelmente descartados, da tabela de fatos, não
45
serão necessários para as operações subseqüentes do plano de uma consulta, por exemplo, na
junção da consulta Q2; assim sendo, reduz-se o custo da consulta. Portanto, os 264.000
grupos produzidos pela agregação deverão ser reduzidos em 90%, ficando apenas 26.400
grupos para serem processados pela operação de junção. Esta quantidade de grupos,
provavelmente, poderá ser processada por uma estrutura que caiba na memória principal.
Para utilizar o filtro seletivo são consideradas duas fases: (i) fase de construção e (ii)
fase de filtragem.
Na fase de construção, constrói-se um vetor de bits para cada tabela de dimensão com
condições seletivas. Cada posição do vetor de bits é, inicialmente, preenchida com 0 (zeros).
Durante a varredura da tabela de dimensão preenche-se com 1 as posições que satisfazem a
condição de seleção. Por exemplo, para a consulta Q2 existirão 200 posições no vetor
marcadas com 1. Estas marcas são determinadas através de uma função de hashing que
mapeia o atributo chave para um valor v dentro da faixa {0, . . ., n – 1}, onde n representa a
quantidade de posições do vetor de bits. O tamanho do vetor de bits deverá ser, de
preferência, do mesmo tamanho da tabela de dimensão, mas se essa tabela for relativamente
grande pode-se determinar um tamanho menor. Neste caso, uma mesma posição será mapeada
por diferentes valores e, assim, os chamados falsos positivos poderão existir. Se uma tabela de
dimensão apresentar mais de uma condição de seleção, mesmo assim, apenas um vetor de bits
precisa ser construído. Para tanto, os operadores conjuntivos (OR) e disjuntivos (AND),
existentes em uma consulta, deverão ser aplicados durante a construção do vetor de bits. A
Figura 4-4 ilustra dois vetores de bits para a consulta Q2 que se diferenciam nos tamanhos.
A fase de filtragem corresponde à utilização do filtro seletivo e deve ser realizada
conforme a seguir. À medida que os registros da tabela de fatos são percorridos para a
execução do agrupamento, deve-se aplicar à mesma função de hashing utilizada pela fase de
construção nos valores dos atributos de ligação e os resultados são comparados com os bits do
vetor de bits. Se a posição de comparação tiver marcada com um zero, então o registro
correspondente da tabela de fatos será descartado, caso contrário, o registro é enviado para o
operador de agregação. A Figura 4-5 ilustra a fase de filtragem usando a consulta Q2.
46
idfilme mod 2000
Falsos positivos
Filme
Idfilme
1
2
3
4
5
6
7
8
9
...
... Genero
...
'drama'
... 'faroeste'
... 'bíblico'
... 'policial'
... 'faroeste'
... 'faroeste'
... 'guerra'
... 'policial'
... 'bíblico'
...
...
Censura
16
12
0
16
12
15
16
16
0
...
0 0 1 0 0 1 1 0 0 0 ... 0
0 1 2 3 4 5 6 7 8 9 ... 1999
Vetor de bits sem falsos positivos
σ genero='faroeste'
1 1 1 0 0
0 1 2 3 4
Vetor de bits com falsos positivos
σ genero='faroeste'
idfilme mod 5
Figura 4-4: Exemplo de Construção de Vetores de Bits para a Consulta Q2.
Assim, o filtro seletivo é um mecanismo para melhorar o desempenho durante a
aplicação do agrupamento prévio.
π nomefilme, anoloc, mesloc, nloc
0 0 1 0 0 1 1 0 0 0 ... 0
0 1 2 3 4 5 6 7 8 9 ... 1999
Vetor de bits sem falsos positivos
idfilme =idfilmeloc
π idfilme
Filtragem (idfilmeloc mod 2000)
γidfilmeloc, anoloc, mesloc, COUNT(*)Ænloc
σ genero='faroeste'
Locacao
Filme
Figura 4-5: Fase de Filtragem para a Consulta Q2.
4.4. Considerações Finais
Com o crescimento do número de aplicações que tratam dados para o gerenciamento nas
empresas, cada vez mais se faz necessária a adoção de estratégias para minimizar os
problemas do processamento e armazenamento de grandes volumes de dados. Entre estas
estratégias, tem-se a aplicação do paralelismo e, mais recentemente, a utilização do
agrupamento prévio como mais uma alternativa para a otimização de consultas com
agregados. Um filtro seletivo também é apresentado como sendo uma nova opção para
melhorar o agrupamento prévio e conseqüentemente o desempenho das consultas.
47
A construção de um ambiente de software para executar consultas constitui um desafio.
Assim, o próximo capítulo apresentará a especificação e o projeto de um ambiente para a
execução de consultas paralelas com a aplicação do agrupamento prévio e do filtro seletivo.
48
5. FAP: Um Ambiente para a Execução de Consultas Paralelas com
Agregados
5.1. Introdução
Para analisar o desempenho de uma consulta com agregados faz-se necessária a
disponibilidade de um ambiente que proporcione a sua execução.
Para tanto, apresenta-se o FAP, que é um ambiente de software responsável pela
execução de consultas com a aplicação do paralelismo, do agrupamento prévio e de um filtro
seletivo. Sua arquitetura alvo consiste de um conjunto de estações de trabalho com memória
distribuída que se comunicam através de troca de mensagens.
Uma implementação portável do FAP possibilita a escolha de um ambiente de troca de
mensagens para o gerenciamento da comunicação entre as estações de trabalho e para a
manipulação de arquivos paralelos. Isso é possível graças a duas características presentes no
projeto do FAP: a modularidade existente na estrutura do ambiente e a flexibilidade nas
classes de software.
Considerando o grande número de estratégias existentes para a implementação das
operações de junção e agregação, outra característica desse ambiente é a possibilidade do
acréscimo de novas estratégias para as operações de uma consulta. Assim, permite-se que um
usuário escolha as estratégias que sejam de seu interesse para serem analisadas.
Na concepção e no desenvolvimento do FAP, foram desenvolvidas ações que se
preocuparam com a resolução dos três problemas seguintes: (i) determinar estratégias para a
execução eficiente de consultas com agregados envolvendo muitos dados; (ii) criar um
ambiente de dados paralelos, composto de arquivos paralelos para a execução das consultas e
(iii) oferecer mecanismos para a construção, otimização e execução de consultas.
Com a resolução destes três problemas tem-se favorecida a execução de consultas,
dando oportunidades para a análise de desempenho dessas consultas.
49
5.2. Execução de Consultas com Agregados
A execução eficiente de uma consulta envolvendo o operador de agrupamento sobre grandes
quantidades de dados requer a aplicação de estratégias para esse operador. Neste contexto, o
FAP oferece mecanismos para a otimização de consultas usando estratégias para as operações
de junção e agregação. Além disso, o processamento paralelo é uma outra forma de melhorar
o desempenho das consultas.
No restante do capítulo são discutidas as idéias do ambiente proposto, para a resolução
dos três problemas anteriormente apresentados.
5.2.1. Estratégias para a Junção e Agregação
As estratégias para a execução das operações de junção e agregação utilizadas no FAP são
discutidas nesta seção. Estas estratégias são versões seqüenciais, tendo em vista que o
ambiente explora a localidade dos dados para o processamento de uma consulta.
Para a operação de junção estão disponíveis três estratégias: junção de laço aninhado
usando blocos, junção baseada em fusão e junção baseada em função hash.
A junção de laço aninhado usando blocos é a estratégia mais simples e o mais
genérica, pois pode ser empregada com qualquer condição de junção e com tabelas de
qualquer tamanho. Seu desempenho depende da quantidade de memória para a tabela do laço
externo. Para isto, utilizou-se a seguinte fórmula: buffersexterno=buffersmáximo – 2, sendo reservado
um buffer para o laço interno, um para os resultados e os demais para o laço externo.
Na junção baseada em fusão considera-se que as tabelas estão ordenadas sobre o
atributo de junção e a condição de junção ocorra na igualdade. Desta forma, os registros das
tabelas podem ser percorridos ao mesmo tempo, compondo um resultado também ordenado.
Como essa estratégia exige menos memória que a anterior, optou-se por reservar três buffers,
um para cada tabela e um para os resultados.
A junção baseada em função hash é, geralmente, a estratégia mais eficiente, sendo
utilizada quando não existem índices para os atributos de junção. Para melhorar seu
desempenho, optou-se por construir a tabela hash na memória principal usando a menor
50
tabela. Desta maneira apenas três buffers são necessários. As colisões são tratadas usando uma
lista encadeada. A quantidade de entradas da tabela hash é determinada pelo usuário da
aplicação e, assim, pode-se, por exemplo, analisar diferentes desempenhos para a execução de
uma consulta.
Essas estratégias usam algoritmos de uma única passagem. Sendo assim, exige-se
apenas leituras dos dados em disco para completar a operação, conforme ilustra a Figura 5-1.
R
T
R.a=S.a
S
buffer de
entrada
buffer de
saída
Figura 5-1: Junção de uma única Passagem.
Os buffers de entrada, um para cada tabela, são preenchidos com os registros das tabelas
R e S, quantas vezes for necessário, de acordo com o tipo de junção utilizada. A junção é
aplicada nos buffers de entrada e seus resultados são enviados para o buffer de saída.
Para a operação de agregação, escolheu-se algumas estratégias baseadas em:
ordenação, varredura repetida, função hashing e árvore binária de busca. Todas se
beneficiam, de algum modo, da agregação ansiosa. Assim, o objetivo é tentar reduzir a
quantidade de dados intermediários transferidos entre memória principal e disco durante o
processamento. As duas primeiras estratégias foram discutidas neste trabalho e as demais são
exploradas a seguir.
A agregação baseada em função hashing é uma estratégia bastante eficiente e, no
melhor caso (sem colisões), o acesso é direto. Para cada entrada da tabela hash definiu-se uma
árvore binária de busca para o tratamento de colisões, de forma que possa oferecer bom
desempenho durante a busca dos grupos e, que, no pior caso, seja necessário percorrer todos
os grupos da entrada. Além disso, o usuário da aplicação pode escolher a quantidade de
entradas e, assim, realizar os testes com diferentes valores.
51
A agregação baseada em árvore binária de busca compreende em usar uma árvore
binária de busca para o armazenamento dos grupos, assim a quantidade de nós determinará o
número de grupos existentes na estrutura. Além disso, a ordem dos grupos na árvore poderá
ser útil para uma outra operação, por exemplo, a junção baseada em fusão. Para que o
desempenho da busca não seja ruim, esta estrutura é evitada se os atributos de agrupamento já
estão ordenados. Isto pode ser testado através do n primeiros, médios e últimos registros da
tabela de entrada. Outra forma é detectar o desbalanceamento da árvore durante a execução do
agrupamento e trocá-la por outra estrutura. Novos estudos poderão apontar mecanismos para a
decisão da aplicação deste tipo de agregação.
A Figura 5-2 apresenta um resumo das estratégias de agregação apresentadas
anteriormente.
Estratégia
Mesclagem
Agrupamento
Resultado dos
Grupos
Ordenados
Partições de
Grupos
Ordenados
Registros na
Tabela R
1ª fase
2ª fase
Figura 5-2: Esquema das Estratégias de Agregação.
As estratégias de agregação podem utilizar algoritmos de uma única passagem. Mas,
adotou-se um algoritmo de duas passagens, tendo em vista que as consultas deverão ser
submetidas a grandes quantidades de dados. Um algoritmo de duas passagens carrega os
dados do disco uma primeira vez, processa-os, grava todos ou parte deles no disco e, depois,
faz uma segunda leitura para o processamento adicional durante a segunda passagem [Gar00].
Uma idéia geral para esse tipo de algoritmo é apresentada na Figura 5-3.
O algoritmo de duas passagens possui duas fases: a partição e a mesclagem. Na fase de
partição, os dados são lidos da tabela R (origem) até o tamanho máximo do buffer e depois
são organizados de alguma forma e gravados em um arquivo temporário. Esse processo se
52
repete até serem processados todos os registros da tabela de origem, formando várias
partições (arquivos temporários). O número de partições depende do tamanho do buffer e da
tabela de origem. A fase de mesclagem compreende em obter repetidamente o menor valor
do atributo de agrupamento presente entre os primeiros registros disponíveis nos buffers,
aplicar a agregação e gravar o resultado final na tabela de destino.
R
R1
buffer
S
...
...
Rn
buffers
fase de
partição
fase de
mesclagem
Figura 5-3: Esquema de um Algoritmo de duas Passagens.
Na estratégia baseada em ordenação utilizou-se o esquema da Figura 5-3, mas, para as
estratégias baseadas em função hashing e árvore binária de busca, esse esquema foi
modificado de forma que apenas três buffers são necessários para a fase de mesclagem,
conforme ilustra a Figura 5-4.
buffers
...
...
S
fase de mesclagem
Figura 5-4: Um Esquema para a fase de Mesclagem no Agrupamento Prévio.
Esta modificação constitui uma característica importante para ambientes com pouca
memória disponível. A idéia consiste em processar um par de partições por vez ao invés de
envolver todas as partições ao mesmo tempo. O processo termina quando não existem mais
pares de partições a serem processados. Os grupos de cada partição são ordenados para
53
facilitar o processo de mesclagem. Espera-se, também, que o tamanho de cada partição
resultante seja menor que a soma dos tamanhos das partições envolvidas, pois, desta maneira,
alguns grupos serão unidos.
5.2.2. Aplicando o Agrupamento Prévio em Paralelo
Para o processamento do agrupamento prévio em paralelo, pode-se adotar uma das estratégias
apresentadas na seção 4.3. No entanto, para explorar a localidade dos dados em uma
arquitetura de memória distribuída será utilizado um único coordenador central, conforme os
estudos apresentados em [Bit83]. Desta forma, o objetivo principal da estratégia será o de
minimizar a comunicação entre os nós durante o processamento da consulta. Ocorrerá
comunicação entre os nós somente durante a distribuição do plano de execução e o
recebimento dos resultados parciais entregues ao nó coordenador. A seguir serão apresentados
os passos desta estratégia conforme o diagrama de execução que está ilustrado na Figura 5-5,
onde Pn representa um nó.
Composição do
Resultado Final
P1
Resultados
Parciais
Distribuição de um Plano de
Execução de uma Consulta
P2
P3
...
Pn
Figura 5-5: Diagrama da Estratégia para o Agrupamento Prévio em Paralelo.
1º.
O plano lógico de uma consulta é construído em um nó (nó emissor), otimizado
aplicando-se heurísticas e a estratégia de agrupamento prévio e transformado no
plano de execução;
2º.
O plano de execução é distribuído entre os nós para ser executado, inclusive o nó
emissor pode executá-lo;
54
3º.
Cada nó processa todas as operações correspondentes ao plano de execução e
envia os resultados parciais obtidos ao nó emissor e
4º.
O nó emissor realizará a composição do resultado final da consulta.
A escolha dos nós para a distribuição do plano de execução de uma consulta é feita de
acordo com a consulta e informações existentes no catálogo do banco de dados. Além disso, o
plano de execução deverá ser codificado antes de sua distribuição e decodificado após o seu
recebimento. Assim, os nós precisarão conhecer o padrão de mapeamento existente entre a
codificação e decodificação do plano. Esse padrão descreve as tabelas e operações do plano
de tal modo que a sua decodificação seja realizada de maneira correta.
5.2.3. Aplicando o Filtro Seletivo
A idéia de usar o filtro seletivo consiste em selecionar as tuplas que são de interesse para o
agrupamento prévio. Desta forma, o custo de execução dessa operação é reduzido e
conseqüentemente a consulta será executada em menos tempo. Para a aplicação do filtro
seletivo são consideradas três fases, conforme descritas a seguir.
A primeira fase consiste em determinar se a consulta tem as características necessárias
para a aplicação do filtro. Para isto, deve-se determinar se na consulta existe uma operação de
junção entre tabelas de dimensão e fatos e a tabela de dimensão possui pelo menos uma
condição de seleção. Caso essas condições sejam satisfeitas então o vetor de bits é construído
e suas posições são preenchidas com 0 (zeros). O tamanho do vetor de bits é definido como
sendo o mesmo tamanho da tabela de dimensão ou um valor determinado pelo usuário.
A segunda fase corresponde em marcar as posições do vetor de bits com 1. Essas
posições são calculadas usando os valores do atributo chave das tuplas da tabela de dimensão
que satisfazem a condição de seleção. Para o cálculo utiliza-se uma função de hashing. Essa
fase é realizada antes da execução do primeiro agrupamento prévio.
A terceira fase ocorre durante a execução do primeiro agrupamento prévio. Essa fase
corresponde em selecionar as tuplas da tabela de fatos que possuem correspondência com o
vetor de bits. Para isto, os valores do atributo chave de cada tupla são utilizados para o cálculo
das posições do vetor de bits usando a mesma função de hashing da fase anterior. Caso a
55
posição calculada esteja marcada com 1 então a tupla é enviada para o operador de
agrupamento.
Com a aplicação do filtro seletivo espera-se que o agrupamento prévio possa ser
executado usando-se uma estrutura que caiba na memória principal e, assim, minimizam-se os
acessos a disco.
Uma vez escolhidas as estratégias que serão utilizadas para a execução das consultas,
deve-se oferecer mecanismos para a construção de um ambiente de dados para a execução
dessas consultas. Além disso, esses mecanismos também devem favorecer a execução das
consultas. Neste contexto, a seguir será apresentada a arquitetura do FAP que tem objetivo
resolver essas questões.
5.3. Arquitetura do FAP
A arquitetura do FAP, apresentada na Figura 5-6, é composta por dois módulos principais: o
Cliente e o Servidor de Arquivos Paralelos [Pau03]. O módulo Cliente é responsável por
receber as solicitações dos usuários de aplicação e prepará-las para serem executadas pelo
módulo Servidor de Arquivos Paralelos. Além disso, o módulo Cliente também poderá
realizar um pré-processamento, como em uma consulta.
A divisão modular do FAP permite uma melhor distribuição do processamento de uma
consulta, pois cada módulo estará envolvido em uma parte da solução. Por exemplo, as tarefas
para criar um plano de consulta e otimizá-lo são realizadas pelo módulo Cliente e a execução
do plano é feita pelo módulo Servidor de Arquivos Paralelos. Essa divisão permite uma
maior modularidade ao ambiente e facilita a portabilidade para outras plataformas.
O módulo Cliente é pouco dependente da plataforma que está sendo utilizada, podendo
ser executado facilmente em outras plataformas que não a usada inicialmente. Já o módulo
Servidor de Arquivos Paralelos é mais dependente, pois utiliza primitivas para E/S paralela.
No módulo Cliente encontra-se uma interface pela qual o usuário da aplicação tem
acesso às várias opções do ambiente. Através dessa interface pode-se definir as especificações
do banco de dados, criar o catálogo, gerar as estatísticas dos dados, inserir e modificar dados,
56
definir e executar uma consulta, determinar se uma consulta será materializada, escolher as
estratégias para execução das operações de uma consulta e determinar se o ambiente aplicará
o agrupamento prévio e o filtro seletivo. Além disso, nesse módulo encontram-se os
algoritmos disponíveis para a aplicação das otimizações no plano de uma consulta.
Módulo Cliente
Consulta em SQL
Analisador de Sintaxe
Especificação
do banco de dados
Gerador de Catálogo
Gerador de Plano Inicial
Otimizador Heurístico
Replicador de Catálogo
Otimizador de Agregação
Catálogo
resultado
Atualizações
Atualizador de
Instância
Gerador de Plano
de Execução
Coordenador
de Execução
Atualizar
estatística
Gerador Estatístico
Barramento Comunicação
Servidor de
Arquivos
Servidor de
Arquivos
Servidor de
Arquivos
...
Catálogo
Instância
de Dados
Catálogo
Instância
de Dados
Catálogo
Instância
de Dados
Módulo Servidor de Arquivos Paralelos
Figura 5-6: Arquitetura do FAP.
No módulo Servidor de Arquivos Paralelos encontram-se as estruturas e os algoritmos
necessários para a execução de um plano de consulta, assim como a interface necessária para
o acesso aos arquivos paralelos. Essas interfaces serão discutidas durante apresentação das
características de implementação do ambiente.
57
Nas duas próximas seções, é feita uma apresentação detalhada dos módulos do sistema
FAP.
5.4. O Módulo Cliente
O módulo Cliente é a interface entre os usuários de aplicação e o FAP. Através dele as
solicitações emitidas pelos usuários são enviadas para o módulo Servidor de Arquivos
Paralelos para serem executadas. Os resultados dessas solicitações são enviados ao usuário.
Esse módulo será um processo que deverá ser ativado em uma das estações de trabalho
utilizada pelo usuário da aplicação. Durante sua inicialização, algumas tarefas básicas serão
realizadas antes de executar qualquer consulta, como: (i) criar o catálogo com as
especificações do banco de dados; (ii) determinar os servidores de arquivos paralelos de
acordo com informações do catálogo; (iii) enviar aos servidores o catálogo e (iv) criar o banco
de dados.
O módulo Cliente interage com o restante do ambiente através de chamadas a métodos
do sistema de maneira transparente para a aplicação, usando serviços encapsulados nas
classes. Para cada serviço, pode ser necessária a comunicação com os servidores de arquivos
paralelos.
Os seguintes componentes4 são utilizados para o processamento de uma solicitação no
módulo Cliente: catálogo; gerador e replicador de catálogo; atualizador de instância; gerador
estatístico; analisador de sintaxe; gerador de plano inicial; otimizador heurístico; otimizador
de agregação; gerador de plano de execução e coordenador de execução, como já se ilustrou
na Figura 5-6.
5.4.1. Catálogo
O catálogo armazena as informações que serão utilizadas pelos componentes do FAP durante
o processamento das solicitações. Essas informações são guardadas em um arquivo e
detalham as características das tabelas do ambiente, como seus atributos e restrições de sua
utilização. Outra informação do catálogo é a especificação dos servidores de arquivos
4
O termo componente utilizado neste capítulo descreve elementos que compõe a arquitetura do FAP.
58
paralelos que acessam o banco de dados. No Apêndice B são apresentados maiores detalhes
sobre as informações que são armazenadas no catálogo e no Apêndice D um exemplo de um
arquivo de catálogo, adaptado do trabalho de [Cos01].
O acesso aos dados do catálogo é feito com a ajuda de uma tabela hash; desta forma, o
ambiente oferece um meio para obter estes dados de maneira eficiente. Em um sistema
paralelo e distribuído, deve-se adotar outras estratégias para o acesso eficiente ao catálogo;
assim, optou-se por manter o catálogo replicado nos módulos. Essa decisão permite uma
independência de processamento entre os módulos e é possível porque o tamanho do arquivo
de catálogo é pequeno, quando comparado com o volume de dados armazenados pelo
ambiente.
5.4.2. Gerador de Catálogo
O gerador de catálogo é responsável por armazenar as especificações do banco de dados no
arquivo de catálogo. Inicialmente, essas especificações são criadas na estação de trabalho
onde o processo cliente está em execução e, depois, são replicadas usando o componente
replicador de catálogo. Para que as informações do catálogo sejam obtidas de maneira correta,
elas devem estar organizadas dentro do arquivo. Assim, para cada conjunto de informações é
armazenado também um cabeçalho que indica o tipo de informação de cada coluna do
arquivo, conforme ilustra o catálogo para o estudo de caso apresentado no Apêndice D.
5.4.3. Replicador de Catálogo
O replicador de catálogo é um componente que é ativado de maneira automática cada vez que
o arquivo de catálogo é criado pelo componente gerador de catálogo. Durante a replicação, o
processo cliente determina quais servidores de arquivos paralelos deverão armazenar o
catálogo, lê os dados do arquivo de catálogo e transfere-os para os servidores. Cada servidor é
responsável por armazenar os dados recebidos em seu próprio arquivo de catálogo.
Desta maneira, elimina-se uma comunicação entre os módulos para obter as
informações do catálogo quando a aplicação é inicializada. Outra vantagem é o baixo custo
para aplicar replicação, pois a comunicação durante essa tarefa pode ser desprezível devido a
dois fatores: o tamanho do catálogo é pequeno e a sua manutenção é pouco freqüente.
59
5.4.4. Atualizador de Instância
O atualizador de instância é responsável apenas por obter do usuário da aplicação as
atualizações (inserções, alterações ou remoções) e repassá-las aos servidores de arquivos
paralelos que atuam sobre o banco de dados a ser modificado. Para isto, o atualizador deverá
utilizar informações do catálogo.
Dentre as atualizações existentes, a alteração é a que deve ser tratada com mais cautela,
pois quando ela envolve um campo de segmentação, o registro deverá ser transferido para o
segmento apropriado e o registro antigo deverá ser removido. Na remoção, por questões de
desempenho, será colocada uma marca de remoção no registro. As alterações em uma visão
materializada serão realizadas através de consultas ao banco de dados.
5.4.5. Gerador Estatístico
O gerador estatístico realiza uma estatística sobre a base dados para obter uma contagem dos
valores distintos dos atributos das tabelas que estão pré-definidos no catálogo para participar
desta estatística. Essas informações são armazenadas no catálogo e serão úteis para orientar
cada servidor de arquivos paralelos na decisão quanto à aplicação da otimização baseada no
agrupamento prévio.
O processo de obter as informações estatísticas ocorre em cada servidor de arquivos
paralelos que armazena no seu catálogo apenas as estatísticas coletadas de seu próprio banco
de dados. As informações coletadas em todos servidores são enviadas para o módulo Cliente
e serão úteis para gerar planos individuais para cada servidor. Essa funcionalidade deverá ser
implementada em trabalhos futuros.
Quanto ao período de atualização das informações estatísticas, não há necessidade de
uma atualização constante. Mas, sua atualização reflete diretamente no desempenho da
execução das consultas submetidas ao FAP. No ambiente proposto, essa atualização fica sob
responsabilidade do usuário da aplicação que realiza essa tarefa usando uma interface
oferecida por este componente.
60
5.4.6. Analisador de Sintaxe
O analisador de sintaxe recebe uma consulta escrita em SQL e faz uma série de análises, para
garantir sua execução corretamente. Para tanto, extrai seus elementos léxicos tais como as
palavras reservadas (por exemplo, GROUP BY), os nomes das tabelas e atributos e analisa a
semântica da consulta verificando a existência das tabelas e atributos no catálogo do banco de
dados e uso dos tipos dos atributos. Por fim, se existem condições de seleção analisa seus
operandos e operadores.
Esse componente é o mais simples entre todos os componentes do FAP. No entanto,
exerce um papel fundamental durante o processamento de uma consulta porque essa somente
será executada se sua escrita for reconhecida pelo padrão do analisador. Esse padrão é
representado pelas cláusulas do SQL conforme a seguir.
SELECT
<lista de atributos e ou funções de agregação>
FROM
<lista de tabelas>
[WHERE <condição>]
[GROUP BY <lista de atributos de agrupamento>
[HAVING <condição de agrupamento>]]
[ORDER BY <listas de atributos >];
As regras utilizadas pelo analisador de sintaxe para reconhecimento do padrão de escrita
de uma consulta são: (i) as cláusulas, as funções de agregação e os conectores (AND e OR) são
reconhecidos com letras maiúsculas, já os nomes de tabelas e atributos devem coincidir com a
forma que foram informados pelo usuário da aplicação; (ii) apenas as cláusulas SELECT e
FROM são obrigatórias; (iii) o nome de cada tabela na cláusula FROM deve possuir um apelido
seguido pela palavra reservada AS, por exemplo, locacao AS loc; (iv) o nome de cada atributo
deve ser referenciado através do apelido de uma tabela separado por um ponto, por exemplo,
loc.idfilmeloc; (v) a função de agregação COUNT aceita como argumento o sinal asterisco (*) e
as demais funções o nome do atributo; (vi) um operador pode ser um dos seguintes sinais >, <,
>=, <=, =, <> e (vi) um operando pode ser um número ou uma palavra, sendo esta entre aspas
simples (' '). Exemplos de consultas usando estas regras podem visualizadas no Apêndice E.
O analisador de sintaxe também reconhece uma visão que será materializada pela
aplicação e segue as mesmas regras apresentadas. Se uma consulta não está escrita conforme
61
as regras apresentadas, então uma mensagem apropriada é mostrada ao usuário da aplicação,
caso contrário, a consulta é repassada para o gerador de plano inicial.
5.4.7. Gerador de Plano Inicial
O gerador de plano inicial transforma uma consulta em uma representação não otimizada
usando a álgebra relacional e uma árvore de profundidade à esquerda. Este tipo de árvore
define a ordem de execução das operações de uma consulta e limita o número de planos
equivalentes que serão gerados durante a aplicação das otimizações e da geração do plano de
execução.
Quando um plano inicial é construído uma operação de projeção que é aplicada antes da
agregação, próxima à raiz da árvore, será retirada do plano. Assim, o desempenho da consulta
poderá ser melhorado, tendo em vista que a projeção será resolvida quando for executada a
agregação. Mas, isto só é possível quando existir igualdade nos atributos das cláusulas
SELECT e GROUP BY. Esta estratégia será utilizada também durante a aplicação do
agrupamento prévio.
5.4.8. Otimizador Heurístico
O otimizador heurístico transforma o plano inicial, usando heurísticas para obter um plano
equivalente que se espera ser mais eficiente. Uma característica importante desse componente
é que as novas projeções não são adicionadas antes da operação de agregação por questões de
desempenho.
O otimizador heurístico também determina a ordem de execução para as operações de
junção. Inicialmente, segue a ordem das tabelas definida na cláusula FROM, mas caso esta
ordem não possibilite a aplicação das junções o otimizador utilizará a ordem das condições de
junção existentes na cláusula WHERE. Desta forma, este componente apenas determina uma
ordem possível para a aplicação da junção sem, no entanto, garantir que a ordem encontrada é
a melhor estratégia para a execução da consulta.
A solução aplicada pelo otimizador heurístico para resolver a questão da ordem de
execução das junções permite que o usuário da aplicação possa determinar sua própria
62
configuração. Desta forma, pode-se obter diferentes medidas de desempenho para realizar os
estudos dos comparativos entre diferentes configurações.
5.4.9. Otimizador de Agregação
O otimizador de agregação aplica o agrupamento prévio no plano de consulta otimizado. Para
tanto, são construídos três conjuntos de atributos para cada nó da árvore a partir da análise dos
atributos das cláusulas SELECT e GROUP BY da consulta e dos atributos do plano de consulta.
Depois, anota-se em cada nó da árvore o tipo de agrupamento testando as informações dos
conjuntos e, finalmente, uma varredura completa na árvore determinará os nós nos quais será
aplicado o agrupamento prévio e realizará as transformações necessárias na árvore. Além
disso, anota também no plano se aplicará o filtro seletivo.
O agrupamento prévio não melhora o desempenho para todas as consultas, assim esse
componente deverá decidir quando aplicá-lo. No ambiente proposto essa questão é resolvida
no módulo Servidor de Arquivos Paralelos através de um modelo de custo básico aplicado
no operador de agrupamento que está próximo a uma das tabelas no plano de consulta. Para
isto, estima-se seu número de grupos usando a quantidade de valores distintos dos atributos de
agrupamento e calcula-se a taxa de redução da tabela envolvida na agregação.
A determinação de uma taxa de redução para qualquer consulta submetida ao ambiente
proposto está fora do escopo do trabalho. Essa questão poderá ser melhor resolvida, por
exemplo, usando um modelo de estimativa de custo envolvendo as outras operações do plano.
5.4.10. Gerador de Plano de Execução
O gerador de plano de execução é responsável por transformar o plano otimizado de uma
consulta no plano de execução. Assim, deve-se escolher uma estratégia para cada operação do
plano otimizado. Essa escolha é realizada pelo usuário da aplicação dando a ele a liberdade
para que possa executar as estratégias para os comparativos de desempenho.
5.4.11. Coordenador de Execução
A última tarefa do módulo Cliente para execução de uma consulta é realizada pelo
coordenador de execução. Neste componente, o plano de execução é distribuído aos
63
servidores de arquivos paralelos que cooperarão em sua execução. A decisão de escolher um
servidor é tomada levando em consideração a disponibilidade do servidor, a técnica de
fragmentação por faixa de valores dos dados e a existência ou não de tabelas replicadas. As
informações necessárias para essa decisão estão armazenadas no catálogo do banco de dados.
Quando o plano de consulta possui tabelas que estão fragmentadas por seus atributos de
ligação e não envolve uma condição de seleção sobre esses atributos, então todos os
servidores especificados na criação do banco de dados deverão executar a consulta. Caso esse
mesmo plano tenha tabelas replicadas e pelo menos uma condição de seleção baseada no
atributo de fragmentação, então apenas os servidores envolvidos na faixa da distribuição serão
escolhidos. Uma outra configuração ocorre quando o plano de consulta tem apenas tabelas
replicadas, assim sendo direciona-se a consulta para um dos servidores.
Finalmente, o coordenador de execução deverá repassar para o módulo Servidor de
Arquivos Paralelos o plano de execução da consulta e aguardar o recebimento dos
resultados. Esses resultados poderão representar o resultado final, quando o plano é executado
por um único servidor, ou um resultado parcial, se mais de um servidor é utilizado. Quando se
tratar de um resultado parcial, então o coordenador de execução deverá compor o resultado
final. Esse resultado é gravado em arquivo para que o usuário possa visualizá-lo.
5.5. O Módulo Servidor de Arquivos Paralelos
O módulo Servidor de Arquivos Paralelos é responsável por armazenar e obter os dados dos
arquivos paralelos em disco. Para tanto, um processo será executado nas estações de trabalho
escolhidas para compartilhar seu disco local. O padrão de armazenamento e acesso é feito
usando as informações sobre as tabelas detalhadas no catálogo. Deste modo, suas operações
resumem-se ao recebimento das requisições através da rede e à leitura ou escrita dos dados
solicitados. Além disso, cada servidor possui uma estatística sobre seus dados para decidir o
uso da estratégia de agrupamento prévio.
O processo de ativação e término de cada processo servidor é feito pela aplicação
paralela através de chamadas a métodos no módulo Cliente. Toda interação entre os módulos
Cliente e Servidor de Arquivos Paralelos ocorre de maneira transparente para o usuário da
aplicação e através dos serviços encapsulados nas chamadas.
64
O número de servidores de arquivos paralelos será determinado pelo usuário da
aplicação de acordo com suas necessidades e qualquer alteração desse valor implicará em uma
redistribuição dos dados do banco de dados. Isto poderá também ocorrer se a política de
fragmentação ou replicação dos dados for alterada.
Na ativação do processo servidor deve ser especificado o nome do banco de dados que
será utilizado. Esse nome determina o local de armazenamento na estrutura de diretórios para
conter os arquivos paralelos do banco de dados. Se os dados forem armazenados em um
diretório remoto utilizando, por exemplo, o NFS (Network File System), então a aplicação
paralela deverá informar aos servidores a existência desse tipo de diretório. No Apêndice C é
mostrada a estrutura de diretórios do FAP.
Durante a execução de uma consulta, cada servidor cumpre apenas as tarefas definidas
no seu plano de execução. No entanto, um determinado servidor pode alterar seu plano sem a
necessidade de informar os demais, o que ocorre quando ele decide em não aplicar o
agrupamento prévio existente no plano de execução.
5.6. Aspectos de Implementação do FAP
A implementação do ambiente proposto tem por objetivo abranger aplicações paralelas sobre
o sistema operacional Linux. A escolha dessa plataforma deve-se à sua grande utilização e à
facilidade de se encontrar os recursos de software que viabilizam a construção do ambiente
proposto.
Esses recursos de software normalmente são encontrados em ferramentas de
programação, aplicações diversas e no próprio sistema operacional. Para a comunicação entre
as estações de trabalho está sendo considerada a distribuição LAM com recursos de E/S
paralela.
As funcionalidades do FAP foram implementadas usando o paradigma orientado a
objetos através da linguagem de programação C++ e a biblioteca de comunicação e
tratamento de arquivos paralelos LAM/MPI-2. No Apêndice B, encontra-se parte da interface
das principais classes implementadas. Nesta seção são apresentadas as principais classes e a
descrição de seu funcionamento, conforme a Tabela 5-1.
65
Classe
BitVector
Buffer_Data
Catalog
Client, Server
DbFap
Field
File_MPI
File_Text
Sql
Table
Objetivo
Interface para gerenciar o filtro seletivo.
Interface para gerenciar área de buffers para o armazenamento temporário de registros.
Interface para gerenciar o catálogo.
Interface para gerenciar uma estação de trabalho cliente ou servidor.
Interface para gerenciar todos os eventos do sistema FAP.
Interface para um campo de uma tabela.
Interface para gerenciar o armazenamento e acesso dos dados no disco usando arquivo
do padrão MPI. Classe derivada da classe File.
Interface para gerenciar o armazenamento e acesso dos dados no disco usando arquivo
do padrão texto. Classe derivada da classe File.
Interface para gerenciar a execução das consultas.
Interface para uma tabela do banco de dados.
Tabela 5-1: Principais Classes Implementadas do FAP.
Antes que possa manipular os arquivos paralelos, cada estação de trabalho precisa ser
identificada através de uma relação hierárquica do tipo cliente (mestre) e servidor (escravo).
Isto é feito de acordo com a especificação do usuário da aplicação usando o modelo SPMD. A
idéia central dessa atribuição é determinar uma estação como cliente e as demais como
servidores. Desta forma, o módulo Cliente é implementado como um processo cliente e o
módulo Servidor de Arquivos Paralelos como um processo servidor. O gerenciamento do
cliente e do servidor é feito respectivamente pelas classes Client e Server.
O usuário da aplicação interage com o processo cliente através da criação e instanciação
de um único objeto da classe DbFap, que oferece uma interface transparente para a aplicação.
O argumento deste objeto determinará o banco de dados que será utilizado e o local de
armazenamento dos dados e do catálogo na estrutura de diretório, conforme descrito no
Apêndice C.
O catálogo é criado, inicialmente, na estação cliente usando os seguintes métodos: o
AddServer() que adiciona os nomes dos servidores de arquivos paralelos em que os dados serão
armazenados; o AddTable() e o AddFieldTable() que adiciona a tabela e seus campos para o
armazenamento dos dados; e o AddMatView() e o AddFieldMatView(), que adiciona
respectivamente uma visão materializada e seus campos.
66
A execução do método CreateCatalog() determina quais servidores serão utilizados para
o gerenciamento dos arquivos paralelos e replica o catálogo. Desta maneira, o ambiente está
preparado para que as estruturas das tabelas e visões materializadas possam ser criadas. Isso é
feito executando o método Create() que busca no catálogo as características das tabelas e das
visões materializadas. Além disso, são construídas em memória estruturas para armazenar as
informações do catálogo que permitam agilizar as pesquisas.
As alterações e consultas aos dados no ambiente podem ser realizadas quando as tabelas
e visões materializadas estiverem disponíveis. Para tanto, o método Open() faz a abertura de
todos os arquivos do ambiente usando as informações do catálogo. Enquanto o ambiente
estiver sendo usado, esses arquivos permanecerão abertos, o que melhora seu o desempenho.
Ao encerrar o processamento sobre o ambiente, são fechados todos os arquivos do banco de
dados que estão abertos, com a execução do método Close().
Uma consulta é executada através do método Query(). As estratégias que serão usadas
durante o processamento da consulta são aquelas pré-definidas pelo ambiente. Contudo, o
usuário da aplicação tem a liberdade de alterá-las para obter diferentes desempenhos, por
exemplo, o método ApplyGroupByBeforeJoin_Yes() e o método SetTechnical_GroupBy_Hash()
determinam que no processamento de uma consulta deverá ser aplicado o agrupamento prévio
e a estratégia hash para a agregação, respectivamente. Para construção de uma visão
materializada é utilizado o método MatView() que difere do método Query() porque seus
resultados deverão ser gravados no próprio ambiente, em arquivos paralelos ou não, para
servir como base para outras consultas.
O suporte à execução de consultas foi definido através da estrutura t_left_deep_tree que é
utilizada durante a construção do plano de consulta, conforme ilustra a Figura 5-7. Essa
estrutura armazena a característica de uma tabela ou operação do plano. Assim, o conjunto de
estruturas t_left_deep_tree determina uma árvore de profundidade à esquerda que será
posteriormente otimizada e executada. As informações do agrupamento prévio serão anotadas
na área estendida da estrutura, permitindo flexibilidade para a determinação do tipo de
agrupamento prévio em cada nó.
67
typedef struct t_left_deep_tree {
char *tablename;
// nome da tabela
int operation;
// nome da operação (seleção, projeção, produto, agregação, junção, nenhuma)
struct t_condition *condition;
//condição de junção ou seleção
int *n_condition;
//quantidade de condições de junção ou seleção
char *fields[20];
//campos de projeção ou agregação
int *n_fields;
//quantidade de campos de projeção ou agregação
struct t_left_deep_tree *left;
//próxima operação ou tabela à esquerda
struct t_left_deep_tree *right;
//próxima operação ou tabela à direita
struct t_left_deep_tree *father;
//nó pai
// para uso pela arvore estendida
ListString *list_table;
// as tabelas de um NÓ que estão abaixo de uma determinada operação/tabela
ListString *cj;
//colunas de junção
ListString *cr;
//colunas requeridas
ListString *cac;
//colunas de agregação candidatas
int *type_transformation;
//tipo de agrupamento prévio
int *is_filter_selective;
//aplicar ou não o filtro seletivo
int ordem_node;
//ordem para auxiliar na decodificação do plano
int execute;
//flag para executar ou não o NÓ
} LEFT_DEEP_TREE;
Figura 5-7: Estrutura t_left_deep_tree Existente no FAP.
Um plano de consulta é codificado pelo cliente e enviado aos servidores para ser
executado. O trabalho do servidor consiste em decodificar o plano de consulta de tal forma
que a árvore que representa esse plano tenha a mesma estrutura da árvore existente no cliente.
Essas funções de codificação e decodificação são realizadas pelos métodos QueryPlanCod() e
QueryPlanDecodif(). O paralelismo é aplicado aproveitando-se da localidade dos dados e, desta
forma são determinados os servidores que executarão a consulta de acordo com a técnica de
distribuição existente no catálogo.
Ao executar o operador de agrupamento, cada servidor mantém uma cópia da estrutura
t_input_aggregate para armazenar o cálculo das funções de agregação para cada grupo,
conforme Figura 5-8, que representa uma entrada para cada grupo. Se um campo de uma
tabela está relacionado a mais de uma função de agregação, então apenas uma entrada é
suficiente para registrar os valores destas funções. Outra vantagem desta estrutura é realizar o
cálculo da média (val_avg) a partir dos campos val_count e val_sum.
68
typedef struct t_input_aggregate {
char fieldname[MAX_FIELDNAME];
long val_count;
//cálculo count
long val_sum;
//calculo sum
long val_avg;
//calculo avg
long val_max;
//calculo max
long val_min;
//calculo min
//campo que será aplicado a função de agregação
} INPUT_AGGREGATE;
Figura 5-8: Estrutura t_input_aggregate Existente no FAP.
Para utilizar o FAP, deve-se considerar o perfil do usuário que irá utilizá-lo. São
considerados dois tipos de usuários: o da aplicação e o da implementação.
Um usuário da aplicação obterá os resultados de desempenho para análise quando uma
consulta for submetida à execução. Para analisar os resultados, esse usuário deverá ter
conhecimento do funcionamento das estratégias de execução disponíveis no ambiente,
podendo tirar suas conclusões de maneira mais clara. Além disso, deverá decidir quais
estratégias serão utilizadas para o processamento de cada operação da consulta e se o
agrupamento prévio e o filtro seletivo serão aplicados. Outras tarefas, como a definição das
informações do catálogo e a inserção dos dados no banco de dados, também serão realizadas
por esse tipo de usuário.
Um usuário de implementação deverá ser responsável por acrescentar novas estratégias
de execução no FAP ou adotar um novo ambiente de troca de mensagens. Assim, esse usuário
deverá ter um conhecimento maior sobre os recursos utilizados no desenvolvimento do FAP.
5.7. Considerações Finais
Neste capítulo foi descrito o FAP, um ambiente de execução de consultas paralelas que
oferece mecanismos para a análise de desempenho de consultas usando estratégias como o
agrupamento prévio e o filtro seletivo. Sua arquitetura em módulos é uma de suas principais
características, permitindo adicionar gradativamente novas funcionalidades não previstas no
projeto inicial, como o filtro seletivo.
69
Outra característica do ambiente é a transparência. O usuário da aplicação pode interagir
com o ambiente sem dominar profundamente as funcionalidades de um processador de
consultas, oferecendo assim um ambiente para um maior número de usuários.
O uso de uma linguagem de programação orientada a objetos ajudou na implementação
das especificações dos componentes dos módulos, permitindo um maior gerenciamento do
código durante o desenvolvimento e o acréscimo de estratégias para a junção e a agregação.
A interação entre o usuário e o FAP é relativamente simples. Para auxiliar nessa
interação foram descritas as principais classes e métodos implementados.
No próximo capítulo ilustram-se as idéias desenvolvidas neste capítulo com a execução
de consultas no ambiente proposto e são discutidos os resultados obtidos com essas
execuções.
70
6. Medidas, Desempenho e Comparações
6.1. Introdução
Neste capítulo, mostram-se os resultados obtidos na execução de um estudo de caso de um
sistema de uma rede de locadoras [Cos01]. Serão apresentadas as situações em que é
interessante aplicar o agrupamento prévio e o filtro seletivo. Várias comparações
possibilitarão confrontar o custo de execução de consultas submetidas a ambientes
centralizados e paralelos e avaliar o desempenho de consultas submetidas diretamente ao
banco de dados e a um data warehouse. O Apêndice E apresenta as principais rotinas
implementadas no estudo de caso.
Para analisar as situações propostas, os resultados foram avaliados segundo o tempo de
relógio de parede [Cro94], que reflete o intervalo de tempo entre a submissão da consulta ao
sistema e a obtenção da resposta final. Neste tipo de medição são considerados tanto os custos
computacionais como a espera por bloqueios, paginação e E/S em disco. A aferição do tempo
foi feita no processo cliente para obtenção do tempo total da execução da consulta e nos
processos servidores de arquivos paralelos para obter os tempos de execução de cada
operação de uma consulta. Uma outra medida foi obter o espaço em disco utilizado pela
consulta para que o comportamento do armazenamento temporário fosse avaliado.
Os experimentos foram realizados no LABCOMP/UEMS (Laboratório do Curso de
Computação da UEMS) com 1, 2, 4, 8 e 16 servidores de arquivos paralelos conectados a uma
rede Ethernet de 10Mbps. Cada servidor possui um único processador Pentium III 1.3GHz,
128 MB de memória e 2GB de disco com o sistema Linux e o ambiente LAM-MPI. A rede de
estações de trabalho não foi isolada para a realização dos experimentos; apesar disso, pode-se
garantir que, durante os testes, as estações estavam dedicadas à execução das consultas.
Tendo em vista a capacidade das máquinas e da rede de interconexão existente no laboratório
são apresentadas projeções sobre uma amostra reduzida do volume dos dados.
Analisar os resultados em aplicações paralelas de bancos de dados não é uma tarefa
trivial, pois um grande número de variáveis pode influenciar esses resultados. Como não se
71
dispõe de um modelo que avalie as variáveis de forma adequada, então os resultados são
apresentados mostrando-se os tempos de execução das consultas e seus ganhos obtidos com o
aumento do número de nós na execução paralela.
A seguir são apresentados mais detalhes sobre o estudo de caso, as medidas, os
desempenhos e os comparativos para as situações propostas.
6.2. Um Estudo de Caso com o FAP
Devido às limitações já mencionadas, referentes ao ambiente de testes, será utilizada a massa
de dados de testes do Apêndice A.
Para garantir um bom desempenho nas consultas através da maximização do
paralelismo, explorou-se a localidade dos dados através de políticas de replicação e
fragmentação. Assim, os dados utilizados nos experimentos foram armazenados nos
servidores de arquivos paralelos através dos passos do algoritmo a seguir executado no
cliente.
1º. Obter as informações do catálogo, determinar a quantidade de servidores de
arquivos paralelos, inicializar, em cada um, o processo servidor e replicar o
catálogo;
2º. Replicar os dados gerados das tabelas LOJA e FILME nos servidores;
3º. Determinar a política de fragmentação para as tabelas CLIENTE e LOCACAO a partir
do número de lojas, determinando a faixa de valores correspondente a cada
servidor;
4º. Distribuir os dados gerados das tabelas CLIENTE através do atributo idlojacli e
LOCACAO usando o atributo idlojaloc, de acordo com a política definida no passo
anterior.
Para a execução do estudo de caso e avaliação do ambiente proposto foram definidas
dez consultas e uma visão materializada, mostradas na Tabela 6-1. Todas as consultas foram
executadas tanto no ambiente centralizado como no paralelo.
Nas próximas seções são mostrados os resultados dos testes e desempenhos para o
processamento destas consultas, executadas no FAP, segundo o número de nós já definidos, e
72
será feita a análise comparativa dos resultados. Nas figuras, as siglas SAP, CAP, SFS e CFS
representam, respectivamente, sem agrupamento prévio, com agrupamento prévio, sem filtro
seletivo e com filtro seletivo.
Consulta
Q3
Descrição
Define a quantidade de fitas locadas e o valor
faturado com locações, por bairro, anualmente,
para filmes do gênero 'drama'.
Q4
Define a quantidade de fitas locadas diariamente,
para filmes do gênero 'faroeste'.
Q5
Define a quantidade de fitas locadas anualmente,
para filmes do gênero 'faroeste'.
Q6
V1
Q7
Q8, Q9,
Q10, Q11,
Q12
Define a quantidade de fitas locadas diariamente,
para filmes do gênero 'faroeste'.
Principais
Características
Qual Situação a
Avaliar?
Agrupamento de união
simples (produz 90
grupos)
Aplicação do
agrupamento prévio
Agrupamento de união
simples (produz 10.781
grupos)
Agrupamento de união
simples (produz 30
grupos).
Agrupamento de união
simples (produz 10.781
grupos)
Aplicação do
agrupamento prévio
Aplicação do filtro
seletivo com e sem
falsos positivos
Aplicação do filtro
seletivo com e sem
falsos positivos
Define a quantidade de locações e o valor faturado
com locações, diariamente, filme por filme, para
cada loja.
Cria uma Visão
Materializada
-
A mesma descrição da consulta Q3, mas utilizando
a visão materializada V1 no lugar da tabela
LOCACAO.
Agrupamento de união
simples (produz 90
grupos)
Uso ou não da visão
materializada e
aplicação do
agrupamento prévio
Define o valor faturado com locações por gênero
cuja loja tenha idlojaloc=16 (Q8) ou idlojaloc>=15
(Q9) ou idlojaloc>=13 (Q10) ou idlojaloc>=9
(Q11) ou idlojaloc>=1 (Q12).
Agrupamento de união
simples (produz 16
grupos)
Variação da carga de
trabalho para os
servidores
Tabela 6-1:Consultas Executadas no Estudo de Caso.
6.3. Comparativo entre Consultas com/sem o Agrupamento Prévio
As consultas Q3 e Q4 foram definidas com o intuito de verificar em que circunstâncias a
aplicação do agrupamento prévio é viável e estão representadas em SQL a seguir.
Q3: SELECT
FROM
WHERE
GROUP BY
bairro, anoloc, COUNT(*), SUM(valorlocfita)
Loja , Locacao, Filme
idloja=idlojaloc AND idfilmeloc=idfilme AND genero='drama'
bairro, anoloc
Q4: SELECT
FROM
WHERE
GROUP BY
nomefilme, anoloc, mesloc, dialoc, COUNT(*)
Filme, Locacao
idfilme =idfilmeloc AND genero='faroeste'
nomefilme, anoloc, mesloc, dialoc
73
As Figuras 6-1 e 6-2 apresentam os tempos de execução das consultas Q3 e Q4 levando
em consideração a aplicação ou não do agrupamento prévio (SAP e CAP) e o número de
grupos produzidos durante o primeiro agrupamento. Na consulta Q3 são produzidos 10.240
grupos durante o primeiro agrupamento, o que é uma quantidade muito inferior aos 229.245
grupos produzidos pela consulta Q4. Outra diferença entre essas consultas é que a Q3 realiza
três agrupamentos, enquanto na consulta Q4 faz dois agrupamentos.
Tempo de execução da consulta Q3
1.600
Tempos em segundos
SAP
1.483,49
1.400
CAP
1.200
1.000
800
748,38
600
354,88
315,82
400
218,28
200
97,72
35,71
74,07
17,88
0
1
2
4
8
16
9,60
Nº de servidores de arquivos paralelos
Figura 6-1: Tempo de Execução da Consulta Q3.
Tempo de execução da Consulta Q4
1.000
976,62
Tempos em segudos
SAP
804,31
800
659,29
600
CAP
582,54
494,37
400
200
172,94
141,96
119,56
140,00
129,80
0
1
2
4
8
16
Nº de servidores de arquivos paralelos
Figura 6-2: Tempo de Execução da Consulta Q4.
Na execução da consulta Q3, observa-se que o tempo de execução diminui à medida
que se aumenta o número de servidores, isto porque os dados distribuídos permitem a
74
aplicação do paralelismo. Cada servidor contribui para a execução da consulta levando em
consideração a localidade dos dados.
A aplicação da técnica CAP revelou-se interessante quando a consulta produz poucos
grupos durante o primeiro agrupamento, conforme apresenta o gráfico da Figura 6-1. Esta
característica permite que os grupos sejam construídos diretamente na memória principal
utilizando um algoritmo de agregação de uma única passagem. Assim, os agrupamentos
intermediários não influenciam de maneira negativa quando aplicado o agrupamento prévio.
Em todas as configurações de servidores obteve-se os melhores desempenhos com a técnica
CAP.
O desempenho da consulta Q4 mostra que o agrupamento prévio deve ser evitado nesse
tipo de consulta, que produz muitos grupos durante o primeiro agrupamento, pois na
construção dos grupos exige-se a utilização de arquivos temporários. Assim, será necessária a
aplicação de um algoritmo de duas passagens para a execução dos agrupamentos da consulta.
Outro aspecto importante que pode ser observado nas Figuras 6-3 e 6-4 diz respeito ao
speedup para a execução das consultas Q3 e Q4, ou seja, o aumento de desempenho em
função do aumento do número de servidores.
Speedup da consulta Q3
SAP
CAP
36
32,911
32
28
24
20,029
20
17,659
16
12
8
4
8,844
3,232
6,796
4,180
1,982
0
2
4
8
16
Nº servidores de arquivos paralelos
Figura 6-3: Desempenho para a Consulta Q3.
Observa-se que o aumento de desempenho proporcionado pelo acréscimo de novos
servidores para a consulta Q3 ocorre tanto no SAP como no CAP, mas com a aplicação do
75
agrupamento prévio esse desempenho é quase o dobro em todas as configurações de
servidores. Isto porque a redução do número de grupos no primeiro agrupamento contribui
para a diminuição do custo de execução das operações de junção. No entanto, para consultas
com muitos agrupamentos, como a Q4, o desempenho fica prejudicado devido aos acessos a
disco para compor os grupos. Apesar disso, a aplicação do agrupamento prévio tende a
reduzir o custo de acesso aos arquivos temporários.
Speedup da consulta Q4
SAP
2,0
CAP
1,976
1,8
1,676
1,6
1,481
1,4
1,446
1,214
1,332
1,2
1,218
1,235
1,0
2
4
8
16
Nº servidores de arquivos paralelos
Figura 6-4: Desempenho para a Consulta Q4.
A eficiência das consultas também muda em relação ao número de grupos criados
durante o primeiro agrupamento, conforme apresenta as Figuras 6-5 e 6-6.
Eficiência da consulta Q3
SAP
CAP
2,6
2,211
2,207
2,2
2,057
1,8
1,616
1,4
1,252
1,0
0,991
1,045
0,850
0,6
2
4
8
16
Nº servidores de arquivos paralelos
Figura 6-5: Eficiência para a Consulta Q3.
Como se pode observar, a eficiência da consulta Q3 é melhor com aplicação do
agrupamento prévio para até 8 servidores de arquivos e diminui quando são utilizados 16
76
servidores, mesmo apresentado um bom speedup nesta configuração. Essa diminuição reflete
a sobreposição das cargas de comunicação em relação à computação necessária para a
execução da consulta. Além disso, há uma boa eficiência quando não é aplicado o
agrupamento prévio, mas em proporções menores em relação à CAP. Por outro lado, em
consultas com muitos agrupamentos, como a Q4, o acréscimo de servidores reduziu a
eficiência em todas configurações de servidores, devido aos acessos a disco e a computação
necessária para compor o resultado final. Mas, a técnica CAP ajuda a minimizar esse
problema.
Eficiência da consulta Q4
0,7
SAP
0,607
0,6
CAP
0,609
0,5
0,370
0,4
0,362
0,3
0,210
0,2
0,123
0,167
0,1
0,077
0,0
2
4
8
16
Nº servidores de arquivos paralelos
Figura 6-6: Eficiência para a Consulta Q4.
A técnica de agrupamento prévio também se mostra significativa quanto à utilização do
espaço em disco para o armazenamento temporário dos resultados de cada operação da
consulta Q3, conforme ilustra a Figura 6-7.
Apesar da existência de três agrupamentos nessa consulta, o acesso a disco não
influenciou negativamente no tempo de execução da consulta. O espaço em disco requerido
com a técnica CAP foi de 107,7 vezes menor em relação à técnica SAP, um fator de grande
importância porque o acesso a disco ainda é o gargalo em banco de dados. No entanto, este
mesmo comportamento não ocorreu na consulta Q4, que produz 229.245 grupos durante o
primeiro agrupamento. Esse resultado indica, novamente, que a utilização do agrupamento
prévio nesse tipo de consulta não é viável.
77
Tamanho dos arquivos temporários
237,0
SAP
CAP
200,0
Mb
150,0
100,0
50,0
14,7
8,2
2,2
0,0
Q3
Q4
Figura 6-7: Espaço em Disco para os Arquivos Temporários nas Consultas Q3 e Q4.
Técnicas de pipelining podem reduzir os tamanhos dos arquivos temporários utilizados
para o processamento de operações em uma consulta; porém, como o agrupamento é uma
operação unária torna-se mais difícil à aplicação dessa técnica.
Os custos dominantes para a execução das consultas são apresentados no gráfico da
Figura 6-8.
1.600
Junção X Agregação
18,940
Junção
Tempos em segundos
1.400
Agregação
1.200
1.462,408
1.000
800
600
400
219,839
263,576
200
50,164
0
Q3 e SAP
Q3 e CAP
8,837
15,474
Q4 e SAP
2,206
Q4 e CAP
Figura 6-8: Tempos de Execução da Junção e Agregação nas Consultas Q3 e Q4.
Quando a técnica SAP é aplicada, as duas consultas têm o maior custo de execução nas
operações de junção. No entanto, quando a técnica CAP é aplicada na consulta Q3, o maior
custo passa ser o da operação de agregação, mas em proporções menores em relação ao tempo
de execução da junção na técnica SAP. O baixo desempenho da consulta Q4 com a técnica
78
CAP deve-se ao fato de ser gerada uma grande quantidade de grupos durante o primeiro
agrupamento.
6.4. Comparativo entre Consultas com/sem o Filtro Seletivo
Como já foi mencionado, um filtro seletivo é um mecanismo que pode melhorar o
desempenho de uma consulta. No entanto, compreender seu comportamento em situações
diversas pode ajudar durante sua aplicação. Nesta seção serão comparadas as execuções entre
as consultas Q5 e Q6, representadas em SQL a seguir, onde a primeira produz poucos grupos
no primeiro agrupamento e a segunda consulta produz muitos grupos, 30 e 10.781 grupos
respectivamente. As duas consultas possuem uma condição de seleção sobre a tabela de
dimensão FILME, que possibilitará a aplicação do filtro sobre a tabela LOCACAO.
Q5: SELECT
FROM
WHERE
GROUP BY
nomefilme, anoloc, COUNT(*)
Filme, Locacao
idfilme=idfilmeloc AND genero='faroeste'
nomefilme, anoloc
Q6: SELECT
FROM
WHERE
GROUP BY
nomefilme, anoloc, mesloc, dialoc, COUNT(*)
Filme, Locacao
idfilme=idfilmeloc AND genero='faroeste'
nomefilme, anoloc, mesloc, dialoc
A Figura 6-9 apresenta os resultados da execução da Consulta Q5 com e sem a
utilização do filtro seletivo (CFS, SFS), sem envolver falsos positivos. Além disso, são
apresentadas as medições envolvendo as técnicas SAP e CAP para melhor exemplificar o
filtro seletivo.
O bom desempenho alcançado na execução da consulta Q5 com a aplicação do filtro
seletivo (CAP/CFS) já era esperado, pois os grupos que não satisfazem a condição de seleção
(genero='faroeste') são descartados durante o primeiro agrupamento. Desta maneira, reduz-se
ainda mais o custo do agrupamento e da junção.
Em todas configurações de servidores os tempos de execução da consulta Q5 foi melhor
em relação à não aplicação do filtro seletivo. Mas, à medida que se aumenta o número de
servidores, então os ganhos são menores. Esse fato ocorre devido à pouca quantidade de
grupos descartados em cada servidor, uma vez que o aumento do número de servidores
79
contribui para que os agrupamentos no SFS sejam realizados diretamente em partições na
memória principal.
Aplicação do filtro seletivo na consulta Q5
70
SAP/SFS
64,47
CAP/SFS
CAP/CFS
Tempos em segundos
60
50
40
30
34,32
37,46
16,94
20
21,95
8,31
10
10,93
0
1
2
4
5,64
6,34
4,78
8
16
Nº servidores de arquivos paralelos
Figura 6-9: Aplicação do Filtro Seletivo na Consulta Q5.
Na consulta Q6, que produz muitos grupos, o filtro seletivo não melhorou o tempo de
execução da consulta, pois a quantidade de grupos descartados não foi suficiente para
minimizar os acessos a disco, conforme apresentado no gráfico da Figura 6-10.
Aplicação do filtro seletivo na consulta Q6
1.000
976,62
800
Tempos em segudos
SAP/SFS
CAP/SFS
CAP/CFS
804,31
659,29
582,54
600
494,37
400
276,90
200
172,94
141,96
125,60
0
1
127,63
119,56
138,24
129,80
2
4
8
Nº de servidores de arquivos paralelos
145,65
140,00
16
Figura 6-10: Aplicação do Filtro Seletivo na Consulta Q6.
Na análise do comportamento da aplicação do filtro seletivo também é verificado o seu
desempenho em relação à variação do tamanho do vetor de bits. Desta maneira deseja-se
averiguar a ocorrência dos chamados falsos positivos e determinar estratégias para minimizar
este problema. As Figuras 6-11 e 6-12 apresentam os tempos de execução para as consultas
80
Q5 e Q6 envolvendo falsos positivos. Para tanto, o tamanho do vetor de bits foi definido em
N/2, onde N é o tamanho necessário para que não ocorram falsos positivos.
A presença de falsos positivos na consulta Q5
50
46,44
45
Sem falsos positivos
Com falsos positivos
Tempos em segundos
40
35
30
37,46
26,33
25
20
21,95
14,03
15
10
6,73
10,93
5
4,57
6,34
0
1
2
4
4,78
8
16
Nº servidores de arquivos paralelos
Figura 6-11: A Ocorrência de Falsos Positivos na Consulta Q5.
A presença de falsos positivos na consulta Q6
300
298,94
Sem falsos positivos
280
Tempos em segudos
260
Com falsos positivos
276,90
240
220
200
179,25
180
150,82
160
161,24
150,38
140
138,24
120
145,65
127,63
125,60
100
1
2
4
8
16
Nº de servidores de arquivos paralelos
Figura 6-12: A Ocorrência de Falsos Positivos na Consulta Q6.
Quando o filtro seletivo é aplicado usando-se vetores de bits que não mapeiam cada
valor de um atributo de seleção em uma posição do vetor, grupos que deveriam ser
descartadas durante o primeiro agrupamento não o são, elevando o custo de execução da
consulta, conforme ilustra os gráficos das Figuras 6-11 e 6-12.
A capacidade do tamanho do vetor de bits está diretamente relacionada à redução da
quantidade de grupos em uma consulta, conforme ilustra as Figuras 6-13 e 6-14 para as
81
consultas Q5 e Q6, respectivamente. Esses valores levam à conclusão de que, quanto menor
for o tamanho de um vetor de bits, então maiores serão as chances de ocorrer falsos positivos
durante o processamento do agrupamento.
Redução do número de grupos para a consulta Q5
700
640
Grupos no 1º agrupamento
600
Nº de grupos
500
400
300
200
60
100
30
0
CAP
CAP e filtro sem falsos positivos
CAP e filtro com falsos positivos
Figura 6-13: Nº de Grupos para a Consulta Q5 Com/Sem Falsos Positivos.
Redução do número de grupos para a consulta Q6
250.000
229.945
Grupos no 1º agrupamento
Nº de grupos
200.000
150.000
100.000
50.000
10.781
21.565
0
CAP
CAP e filtro sem falsos positivos CAP e filtro com falsos positivos
Figura 6-14: Nº de Grupos para a Consulta Q6 Com/Sem Falsos Positivos.
É desejável aplicar o filtro seletivo sem a ocorrência de falsos positivos. No entanto,
mapear cada valor de um atributo em um vetor de bits pode consumir muita memória quando
os atributos têm um elevado número de valores distintos. Neste caso, se poucos valores
distintos satisfazem a condição de seleção, então muitas posições do vetor de bits não serão
utilizadas, causando desperdício de memória. Logo, em situações como estas deve-se aplicar
estratégias que não anulem o uso do filtro seletivo, por exemplo, utilizar uma lista encadeada
82
para o armazenamento dos valores dos atributos definidos pela condição de seleção. Para
situações onde a condição de seleção define uma quantidade moderada de valores distintos
pode-se utilizar uma árvore binária de busca. Assim, o custo de busca de um valor de
comparação deverá ser menor em relação ao uso de uma lista encadeada.
6.5. Comparativo entre Consultas com/sem um Data Warehouse
Nesta seção deseja-se confrontar os custos de uma consulta executada em dois ambientes
paralelos distintos: um banco de dados tradicional com todos os dados da movimentação da
empresa e um data warehouse construído a partir do banco de dados tradicional com dados
pré-computados. O objetivo deste teste é analisar a relevância da utilização de um data
warehouse sem, no entanto, analisar os custos para sua manutenção.
Para alcançar o objetivo exposto foi construída a visão materializada LOCDIALOJAFILME
a partir da tabela LOCACAO. O plano de execução da consulta Q7 é, praticamente, o mesmo da
consulta Q3, mas o tamanho da visão materializada é menor que o tamanho da tabela de
LOCACAO. A seguir apresenta-se a visão materializada V1 e a consulta Q7.
V1: CREATE MATERIALIZED VIEW LocDiaLojaFilme(idlojadlf, idfilmedlf, anodlf,
mesdlf, diadlf, nfitdlf, slocdlf) AS
SELECT
idlojaloc, idfilmeloc, anoloc, mesloc, dialoc, COUNT(*), SUM(valorlocfita)
FROM
Locacao
GROUP BY idlojaloc, idfilmeloc, anoloc, mesloc, dialoc
REFRESH INCREMENTAL CICLE 1 DAY
Q7: SELECT
FROM
WHERE
GROUP BY
bairro, anodlf, SUM(nfitdlf), SUM(slocdlf)
Loja, LocDiaLojaFilme, Filme
idloja=idlojadlf AND idfilmedlf=idfilme AND genero='drama'
bairro, anodlf
Os tempos de execução das consultas Q3 e Q7 são ilustrados na Figura 6-15. Estas
consultas são processadas sem a aplicação do agrupamento prévio.
O uso de uma visão materializada, consulta Q7, garantiu a redução do tempo de
execução da consulta, pois os grupos já pré-computados são utilizados imediatamente. Assim,
evita-se um processamento a mais durante a execução da consulta, o que ocorreu em todas as
configurações de arquivos paralelos. Mas, essa redução pode ser ainda mais evidente caso
83
outras visões materializadas sejam criadas a partir de V1 ou haja uma mudança na
especificação da própria V1, por exemplo, realizando o agrupamento das locações anualmente
para todos os filmes. Desta maneira, a dimensão tempo irá refletir as locações anuais.
Tempos de execução das Consultas Q3 e Q7
sem agrupamento prévio
1.600
Tempos em segundos
Q3 (Sem DW)
1.483,49
1.400
Q7 (Com DW)
1.200
1.191,31
1.000
800
748,38
600
614,43
400
354,88
218,28
200
74,07
296,29
124,84
0
1
2
4
50,83
16
8
Nº de servidores de arquivos paralelos
Figura 6-15: Tempos de Execução das Consultas Q3 e Q7 sem Agrupamento Prévio.
A seguir será ilustrada a aplicação do agrupamento prévio juntamente com um data
warehouse que também melhorou o desempenho da consulta Q3, conforme apresenta o
gráfico da Figura 6-16.
Tempos de execução das consultas Q3 e Q7
com agrupamento prévio
350
Tempos em segundos
Q3 (Sem DW)
315,82
300
Q7 (Com DW)
250
200
213,13
150
97,72
100
75,81
50
35,71
17,88
9,60
36,02
0
1
2
4
8
21,20
16
10,52
Nº de servidores de arquivos paralelos
Figura 6-16: Tempos de Execução das Consultas Q3 e Q7 com Agrupamento Prévio.
Como pode ser observado, os ganhos obtidos são melhores com um reduzido número de
servidores, pois a aplicação do agrupamento prévio sobre um único servidor reduz
sensivelmente a diferença entre o uso e não do data warehouse e, deste modo, influencia nos
84
resultados quando são acrescidos mais servidores. Outro fato que colabora com este
comportamento é a reduzida quantidade de dados utilizada nos testes devido às limitações
existentes no laboratório.
Embora os resultados apresentados com a utilização do agrupamento prévio não tenham
sido satisfatórios a sua aplicação pode evitar dois problemas existentes em um data
warehouse: o custo necessário de espaço em disco e sua manutenção. Mas, não foram
analisados os custos de concorrência entre essa consulta e as outras operações sobre as tabelas
bases. Assim, um projeto bem cuidadoso determinará a coexistência entre um data warehouse
e a técnica de agrupamento prévio.
O speedup e a eficiência das consultas Q3 e Q7 são apresentadas nas Figuras 6-17 e 618 sem a aplicação do agrupamento prévio.
Speedup das consultas Q3 e Q7 sem agrupamento prévio
Q3 (Sem DW)
Q7 (Com DW)
24
23,436
Tempos em segundos
20
20,029
16
12
9,543
8
4,021
4
1,939
1,982
0
2
6,796
4,180
4
8
16
Nº servidores de arquivos paralelos
Figura 6-17: Speedup das Consultas Q3 e Q7 sem Agrupamento Prévio.
Nota-se que a partir de 4 servidores o speedup aumenta gradativamente quando
utilizado o data warehouse. Isso ocorre porque o acréscimo de servidores aumenta o
paralelismo, há uma melhor distribuição dos dados e, assim, menos processamento será
exigido em cada servidor. Outra questão que colabora com esse comportamento vem do fato
desta consulta produzir poucos grupos e, desta forma, a comunicação não sobrepõe à
computação.
85
Eficiência das consultas Q3 e Q7 sem agrupamento prévio
Q3 (Sem DW)
Q7 (Com DW)
1,5
1,465
1,4
1,3
1,252
1,2
1,193
1,045
1,1
0,991
1,0
0,969
0,9
1,005
0,850
0,8
2
4
8
16
Nº servidores de arquivos paralelos
Figura 6-18: Eficiência das Consultas Q3 e Q7 sem Agrupamento Prévio.
Comparando-se a eficiência com a aplicação do data warehouse nota-se, também, o
ganho a partir de 4 servidores, devido aos mesmos motivos já apresentados.
As Figuras 6-19 e 6-20 ilustram respectivamente, o speedup e a eficiência para c
consulta Q7. O baixo speedup apresentado com a aplicação do agrupamento prévio deve-se
aos mesmos motivos já apresentados quando foram feitas as considerações sobre a Figura 616.
Speedup das consultas Q3 e Q7 com agrupamento prévio
Q3 (Sem DW)
Q7 (Com DW)
36
32,911
Tempos em segundos
32
28
24
20,267
20
17,659
16
12
8
8,844
10,051
3,232
4
2,811
0
2
5,917
4
8
16
Nº servidores de arquivos paralelos
Figura 6-19: Speedup das Consultas Q3 e Q7 com Agrupamento Prévio.
86
Eficiência das consultas Q3 e Q7 com agrupamento prévio
Q3 (Sem DW)
2,4
2,211
Q7 (Com DW)
2,207
2,2
2,057
2,0
1,8
1,616
1,6
1,479
1,4
1,406
1,256
1,267
1,2
1,0
2
4
8
16
Nº servidores de arquivos paralelos
Figura 6-20: Eficiência das Consultas Q3 e Q7 com Agrupamento Prévio.
6.6. Comparativo entre Consultas Variando a Carga de Trabalho
Para obter o tempo de execução de consultas que selecionam quantidades variadas de cargas
de trabalho para os servidores foram definidas as consultas Q8, Q9, Q10, Q11 e Q12. Essas
consultas diferem-se pela condição de seleção sobre o atributo idlojaloc da tabela LOCACAO.
Desta maneira, os servidores relacionados com determinadas lojas são escolhidos para
executar a consulta. As consultas são representadas em SQL conforme a seguir.
Q8: SELECT
FROM
WHERE
GROUP BY
genero, SUM(valorlocfita)
Filme, Locacao
idfilme=idfilmeloc AND idlojaloc =16
genero
Q9: SELECT
FROM
WHERE
GROUP BY
genero, SUM(valorlocfita)
Filme, Locacao
idfilme=idfilmeloc AND idlojaloc >=15
genero
Q10: SELECT
FROM
WHERE
GROUP BY
genero, SUM(valorlocfita)
Filme, Locacao
idfilme=idfilmeloc AND idlojaloc >=13
genero
Q11: SELECT
FROM
WHERE
GROUP BY
genero, SUM(valorlocfita)
Filme, Locacao
idfilme=idfilmeloc AND idlojaloc >=9
genero
87
Q12: SELECT
FROM
WHERE
GROUP BY
genero, SUM(valorlocfita)
Filme, Locacao
idfilme=idfilmeloc AND idlojaloc >=1
genero
A Figura 6-21 apresenta o gráfico com os tempos de execução dessas consultas.
Execução de consultas variando a carga de trabalho
1.500
1.632,405
1 Servidor
2 Servidores
Tempos em Segundos
4 Servidores
1.200
8 Servidores
16 Servidores
880,550
900
600
300
505,285
206,110
303,513
73,254
0
Q8
73,071
Q9
73,486
Q10
73,913
Q11
74,893
Q12
Figura 6-21: Tempo de Execução de Consultas Variando a Carga de Trabalho
O tempo de execução entre as consultas para um único servidor aumenta à medida que
se executam as consultas. Esse fato ocorre porque essas consultas aumentam a carga de
trabalho para o servidor através da seleção de uma quantidade maior de dados. Observa-se,
também, que o mesmo comportamento ocorre para 2, 4 e 8 servidores.
No entanto, algumas consultas apresentam tempos de execução muito próximos para
determinadas configurações de servidores, por exemplo, as consultas Q11 e Q12 para dois
servidores. Isso ocorre porque a carga de trabalho da consulta Q12 é distribuída entre os dois
servidores, mantendo-se, assim, praticamente o mesmo custo da consulta Q11.
Desta forma, conclui-se que o tempo de execução de uma consulta depende de como os
dados estão distribuídos e da condição de seleção envolvida na consulta. Portanto, é
importante que os dados estejam particionado de tal forma que o custo da comunicação não
supere o ganho com o paralelismo.
88
6.7. Considerações Finais
As avaliações de desempenho obtidas com a execução do estudo de caso demonstraram o
potencial existente no FAP. Esse ambiente possibilitou a descoberta do comportamento de
certos tipos de consultas, mesmo considerando as limitações de teste existentes.
Os resultados obtidos durante a execução das consultas com a aplicação do
agrupamento prévio indicaram que essa estratégia permite ganhos de desempenho com
algumas consultas. Para consultas que produzem poucos grupos no primeiro agrupamento,
tem-se um ganho relativamente bom. Se a quantidade de grupos produzidos for grande, o
custo de execução da consulta aumenta.
Um filtro seletivo ajuda a melhorar ainda mais o desempenho da consulta. Mas, sua
aplicação está diretamente relacionada com a condição de seleção da consulta. Assim, deve-se
utilizá-lo quando o custo da consulta possa ser reduzido.
A utilização de tabelas pré-computadas de um data warehouse para a execução de uma
consulta revelou-se muito importante. No entanto, necessita-se realizar novos esforços de
pesquisa evidenciando sua utilização concorrente e seus custos para manutenção.
No próximo capítulo são registradas as conclusões deste trabalho, apresentadas as suas
contribuições e algumas perspectivas para trabalhos futuros.
89
7. Conclusões, Contribuições e Trabalhos Futuros
7.1. Conclusões
O desempenho de consultas com agregados tem se tornado um fator crítico em bancos de
dados com muitas informações, pois o acesso a disco ainda é um grande problema nesses
sistemas. Assim, diversas propostas têm surgido para melhorar o desempenho, como o uso do
paralelismo e a aplicação do agrupamento prévio.
Neste trabalho, foram apresentados resultados favoráveis quanto à utilização do
paralelismo e do agrupamento prévio. Para isso, foi proposto e implementado um ambiente, o
FAP, para a execução de consultas paralelas com agregados que vêm auxiliar na análise do
comportamento de consultas.
Para atingir este objetivo, foi feita uma revisão bibliográfica, que mostrou as principais
estratégias seqüenciais e paralelas utilizadas no processamento de agregados e no
agrupamento prévio. Além disso, foram detalhados os módulos básicos da arquitetura do
FAP.
Para a implementação do FAP foram utilizadas as especificações do CDBS que ajudou
a criação do banco de dados paralelo. Além disso, foi importante o estudo e a utilização de
uma biblioteca com rotinas para a troca de mensagens para o gerenciamento dos dados
paralelos. A escolha da distribuição LAM foi muito apropriada devido ao seu suporte à
linguagem C++ e ao padrão MPI-IO.
Apesar dos resultados favoráveis obtidos quanto à utilização do agrupamento prévio,
deve-se realizar novos estudos para determinar um modelo de estimativas de custos que
auxilie na tomada de decisão quanto à utilização dessa estratégia.
Ao final deste trabalho, conclui-se que o entendimento do comportamento da execução
de consultas não é uma tarefa fácil. Essa dificuldade deve-se aos recursos disponíveis em uma
máquina, aos diferentes tipos de consultas, ao tipo de distribuição dos dados e a quantidade de
90
dados que influenciam as tarefas de um processador de consultas. No entanto, o ambiente
proposto permitiu um melhor entendimento do comportamento da execução de consultas com
agregados.
7.2. Contribuições
Este trabalho apresenta uma série de contribuições envolvendo o processamento de consultas
em ambientes paralelos e distribuídos que serão destacados a seguir.
Foi examinada a bibliografia existente, mostrando um contexto geral do processamento
e otimização de consultas, dando uma atenção especial à operação de agregação. Além disso,
foram apresentados os conceitos do paradigma de troca de mensagens e a descrição de um
ambiente de troca de mensagens com recursos para o acesso a arquivos paralelos.
Foi definido e implementado o FAP, um ambiente de software para o processamento de
consultas que: (i) possibilita a criação de um banco de dados com dados distribuídos; (ii)
oferece um ambiente para testes e coleta de resultados, de maneira que os resultados coletados
visam uma melhor compreensão dos fatores que podem limitar o tempo de execução de uma
consulta; (iii) permite o acréscimo de novas estratégias para a execução das operações de
junção e agregação e (iv) possibilita o acréscimo de outras estratégias para o processamento
paralelo com agregados.
Os resultados mostram o desempenho nas situações propostas neste trabalho, apesar das
limitações existentes no ambiente físico de testes. A análise desses resultados oferece
importantes direções, complementando a avaliação como um todo.
Os resultados analisados ajudaram descobrir que o número de grupos produzidos no
primeiro agrupamento é um fator que limita o desempenho de uma consulta. Desta forma, foi
definida uma estratégia simples, baseada na contagem do número de valores distintos dos
atributos de agrupamento, que evita o uso agrupamento prévio. No entanto, essa estratégia
não constitui uma solução definitiva, pois outras alternativas devem ser estudadas e
comparadas.
91
Como conseqüência natural destes resultados, foi proposto e descrito um filtro seletivo,
que é uma estratégia de otimização a ser utilizada junto com o agrupamento prévio. Desta
forma, reduz-se ainda mais o tempo de execução de uma consulta. Além disso, foram
identificados e mencionados os pontos críticos relacionados a utilização do filtro seletivo.
Um dos problemas que ainda persiste com a execução de uma consulta sobre muitos
dados é o acesso a disco, principalmente, no processamento de agregados. Para consultas que
produzem poucos grupos obteve-se melhor desempenho, pois o processamento é realizado na
memória principal. Por outro lado, quando a consulta produz muitos grupos então são
necessários acessos a disco usando um algoritmo de duas passagens.
Para minimizar este problema, a adoção de um data warehouse paralelo é uma boa
alternativa, pois o uso de dados pré-computados armazenados em visões materializadas ajuda
a reduzir a quantidade de processamento.
Uma outra idéia é o uso de uma estratégia para a fase de mesclagem em algoritmo de
duas passagens destinado ao processamento de agregados. Esta abordagem demonstrou
ganhos em até três vezes para quantidades de dados não muito grandes durante os testes. Uma
outra vantagem é que, para essa estratégia, são necessários apenas três buffers durante o
processamento de uma consulta.
7.3. Trabalhos Futuros
Diversas questões podem ser abordadas em trabalhos futuros e, dentre elas, pode-se enumerar:
•
Implementação de outras estratégias para o processamento do agrupamento prévio
em paralelo avaliando suas características e determinando políticas de utilização;
•
Avaliação do agrupamento prévio usando outros tipos de distribuição de dados, tais
como a distribuição hash e a distribuição circular;
•
Verificação do comportamento de estruturas de dados estáticas e dinâmicas no
processamento de consultas com agregados, tais como vetores, tabelas hash e
árvores, levando em consideração o tamanho da memória principal disponível;
•
Inclusão de técnicas de pipelining durante a execução de consultas e a utilização de
diferentes políticas de buffering e caching para minimizar os acessos a discos;
92
•
Definição de métodos de acesso mais apropriados para um plano de consulta, a fim
de que os recursos disponíveis sejam utilizados da melhor forma possível;
•
Construção de planos de execução para cada servidor de arquivos paralelos, levando
em consideração as informações estatísticas dos dados de cada servidor;
•
Determinação de um modelo de estimativas de custos que defina de maneira
apropriada, a melhor utilização do agrupamento prévio e do filtro seletivo;
•
Avaliação de consultas com outras propriedades de agrupamento prévio, tais como a
invariante e a união generalizada;
•
Construção de uma interface amigável para o processamento de consultas no FAP,
para que o ambiente possa ser utilizado por um maior número de pessoas;
•
Avaliação da estratégia proposta quanto ao esquema de composição dos resultados
usando pares de partições durante a agregação para grandes quantidades de dados; e
•
Adoção de novas políticas de paralelismo para o agrupamento prévio como o
paralelismo particionado e pipelined.
93
Referências Bibliográficas
[Bar95]
Baru, C. K.; Fecteau G.; Goyal A.; Hsiao, H.; Jhingran, A.; Padmanabhan,
S.; Copeland, G. P.; Wilson, W. G. DB2 Parallel Edition. IBM Systems
Journal, v.34, p.292-322, abril/1995.
[Ber91]
Bergsten, M. C.; Valduriez, P. Prototyping DBS3, a Shared-Memory
Parallel Database System, In First International Conference on Parallel and
Distributed Information Systems, p.226-234, Miami Beach, Florida,
dezembro/1991.
[Bit83]
Bitton, D.; Boral, H.; DeWitt, D. J.; Wilkinson, W. K. Parallel Algorithms
for the Execution of Relational Database Operations, ACM Transactions on
Database Systems, v.8, p.324-353, setembro/1983.
[Bor90]
Boral, H.; Clay, L.; Copeland, G.; Danforth, S.; Franklin, M.; Hart, B.;
Smith, M.; Valduriez, P. Prototyping Bubba, A Highly Parallel Database
System. IEEE Transactions on Knowledge and Data Engineering, v.2, p.424, março/1990.
[Cha94]
Chaudhuri, S.; Shim, K. Including Group-By in Query Optimization.
Proceedings of 20th International Conference on VLDB, p.354-366,
Santiago de Chile, Chile, setembro/1994.
[Cha97]
Chaudhuri, S.; Dayal, U. An Overview of Data Warehousing and OLAP
Technology. SIGMOD Record, v.26, p.65-74, março/1997.
[Cha98]
Chaudhuri, S. An Overview of Query Optimization in Relational Systems.
Proceedings of the Seventeenth ACM SIGACT-SIGMOD-SIGART
Symposium on Principles of Database Systems, p.34-43, Seattle,
Washington, junho/1998.
[Cod70]
Codd, E. A Relational Model for Large Shared
Communications of the ACM, v.13, p.377-387, junho/1970.
[Cos01]
Costa Neto, J. C. Considerações sobre a Integração de um Banco de Dados
e um Data Warehouse sobre um Sistema de Arquivos Paralelos. Tese de
doutorado, Escola Politécnica da Universidade de São Paulo, 2001.
[Cro94]
Crowl, L. How to Measure, Present and Compare Parallel Performance.
IEEE Parallel and Distributed Technology, v.2, p.9-25, 1994.
[DeW90]
DeWitt, D. J.; Ghandeharizadeh, S.; Schneider, D.; Bricker, A.; Hsiao, H.;
Rasmussen, R. The Gamma Database Machine Project. IEEE Trans. On
KDE, v.2, p.44-62, março/1990.
[DeW92]
DeWitt, D. J.; Gray, J. Parallel Database Systems: The Future of High
Performance Database Processing. CACM v. 35, p.85-98, junho/1992.
Data
Banks.
94
[Elm00]
Elmasri, R.; Navathe, S. R. Fundamentals of Database Systems. Addison
Wesley, 3ª ed., 2000.
[Eng95]
Englert, S.; Glasstone, R.; Hasan, W. Parallelism and its Price: A Case
Study of NonStop SQL/MP. SIGMOD RECORD, v.24, p.61-71,
dezembro/1995.
[Gar99]
Garcia-Molina, H.; Labio, W. J.; Wiener, L. J.; Zhuge, Y. Distributed and
Parallel Computing Issues in Data Warehousing, 1999. [on line].
<URL: http://www-db.stanford.edu/warehousing/publications.html.
[Gar00]
Garcia-Molina, H.; Ullman, J. D.; Widom, J. Database System
Implementation.Prentice-Hall, Inc., 2000.
[Gei94]
Geist, A.; Beguelin, A.; Dongarra, J.; Jiang, W.; Manchek, R.; Sunderam, V.
PVM: Parallel Virtual Machine – A Users’ Guide And Tutorial for
Networked Parallel Computing, The MIT Press, 1994.
[Gra90]
Graefe, G. Encapsulation of Parallelism in the Volcano Query Processing
System, ACM SIGMOD, v.19, p.102-111, Atlantic City, NJ, USA,
junho/1990.
[Gra93]
Graefe, G. Query Evaluation Techniques for Large Databases, ACM
Computing Surveys v.25, p.73-170, junho/1993.
[Gua99]
Guardia, H. C. Considerações sobre as Estratégias de um Sistema de
Arquivos Paralelos Integrado ao Processamento Distribuído. Tese de
doutorado, Escola Politécnica da Universidade de São Paulo, 1999.
[Has96]
Hasan, W. Optimization of SQL Queries for Parallel Machines. Springer
Verlag, 1996.
[Hon92]
Hong, W. Exploiting Inter-Operation Parallelism in XPRS, ACM
SIGMOD, p.19-28, San Diego, California, junho/1992.
[Jar84]
Jarke, M.; Koch, J. Query Optimization in Database Systems, ACM
Computing Surveys, v.16, p.111-152, junho/1984.
[Kim95]
Kim, W. Modern Database Systems: The Object Model, Interoperability,
and Beyond. Reading, MA, Addison Wesley/ACM Press, 1995.
[Kim98]
Kimball, R. Data Warehouse Tookit. Makron Books, 1998.
[Lar97]
Larson, P. Grouping and Duplicate Elimination: Benefits of Early
Aggregation, Technical Report MSR-TR-97-36, Microsoft Research,
Redmond, dezembro/1997.
95
[Mpi95]
Message Passing Interface Forum. MPI: A Message Passing Interface
Standard, Versão 1.0, junho/1995. [on line].
<URL: http://www.mpi-forum.org/docs/docs.html.
[Mpi97]
Message Passing Interface Forum. MPI-2: Extension to the Message
Passing Interface, Versão 2.0, julho/1997. [on line].
<URL: http://www.mpi-forum.org/docs/docs.html.
[Pat88]
Patterson, D. A.; Gibson, G.; Katz, R. H. A Case for Redundant Arrays of
Inexpensive Disks (RAID). Proc. of the ACM SIGMOD Conf., p.109-116,
Chicago, junho/1988.
[Pau03]
Paula, N. C.; Costa Neto, J. C.; Sato, L. M. Uma Arquitetura para o
Processamento de Consultas com Agregados. WSCAD 2003 – IV
Workshop em Sistemas Computacionais de Alto Desempenho, p.101-108,
São Paulo, novembro/2003.
[Sel79]
Selinger, P. G.; Astrahan, M. M.; Chamberlin, D. D.; Lorie, R. A.; Price, T.
G. Access Path Selection in a Relational Database Management System.
Proc. of the ACM SIGMOD Conf., p.23-34, New York, USA, 1979.
[Sha94]
Shatdal, A.; Naughton, J. F. Processing Aggregates in Parallel Database
Systems, Technical Report CS-TR-94-1233, Computer Sciences
Department, University of Wisconsin, Madison, junho/1994.
[Sha95]
Shatdal, A.; Naughton, J. F. Adaptive Parallel Aggregation Algorithms,
Conference SIGMOD, p.104-114, San Jose, California, 1995.
[Tan95]
Tandem. Query Processing Using NonStop SQL/MP, 1995. [on line].
<URL:http://www.tandem.com.
[Tan00a]
Taniar, D.; Rahayu, J. W. Parallel Processing of Aggregate Queries in a
Cluster Architecture. Proc. of the 7th Australasian Conf. on Parallel and
Real-Time Systems, Springer-Verlag, novembro/2000.
[Tan00b]
Taniar, D.; Liu, K. H.; Jiang, Y.; Leung, C. H. C. Aggregate-Join Query
Processing in Parallel Database Systems, Proc. of the 4th HPCAsia’2000
Int. Conf, v.2, p.824-829, IEEE CS Press, 2000.
[Tan01]
Taniar, D.; Rahayu, J. W. Parallel Processing of "GroupBy-Before-Join"
Queries in Cluster Architecture. 1st International Symposium on Cluster
Computing and the Grid, v.26, p.15-18, março/2001.
[Tha90]
Thakkar, S. S.; Sweiger, M. Performance of an OLP Application on
Symmetric Multiprocessor System. 17th International Symposium on
Computer Architecture, p.228-238, maio/1990.
96
[Tha99]
Thakur, R.; Gropp, W.; Lusk, E. On Implementing MPI-IO Portably and
with High Performance. 6th Workshop on I/O in Parallel and Distributed
Systems, p.23-32, maio/1999.
[Ull97]
Ullman. J. D.; Widom, J. A First Course in Database Systems. PrenticeHall, Inc., 1997.
[Waq96]
Waqar, H.; Florescu, D.; Valduriez, P. Open Issues in Parallel Query
Optimization, SIGMOD Record, v.25, p.28-33, setembro/1996.
[Wei02]
Weininger, A. Efficient Execution of Joins in a Star Schema, ACM
SIGMOD, p.542-545, junho/2002.
[Wil99]
Wilkinson, B.; Allen, M. Parallel Programming: Techniques and
Applications Using Networked Workstations and Parallel Computers.
Prentice-Hall, Inc., 1999.
[Yan94a]
Yan, W. P.; Larson, P. Performing Group-By Before Join, Proceedings of
the IEEE, v.10, p.89-100, Houston, Texas, USA, 1994.
[Yan94b]
Yan, W. P.; Larson, P. Data reduction through early grouping, Proc. of the
1994 IBM CAS Conference, Toronto, Ontario, novembro/1994.
[Yan97]
Yang, Y.; Singhal, M. A Comprehensive Survey of Join Techniques in
Relational Databases, 1997. [on line].
<URL:http://citeseer.nj.nec.com/ yang97comprehensive.html.
[Yu98]
Yu, C. T.; Meng, W. Principles of Database Query Processing for
Advanced Applications. Morgan Kaufmann Publishers, Inc., 1998.
97
Apêndices
Apêndice A. Um Exemplo de uma Aplicação de Banco de
Dados
Neste apêndice encontra-se o exemplo de uma aplicação, o de uma rede de locadoras de
filmes para vídeo-cassete, utilizado no decorrer deste trabalho. Essa aplicação foi proposta em
[Cos01]. Além disso, serão apresentados dois conjuntos de dados também utilizados durante
o trabalho.
As lojas da rede estão distribuídas em dez bairros de uma grande cidade e recebem
remuneração pelos serviços prestados de aluguel de cópias de filmes a seus clientes. A
quantidade de locações feitas pelas lojas da rede a partir de 1992 é muito grande,
considerando o tempo de existência da rede, por volta de onze anos. As relações do banco de
dados da rede de locadoras estão ilustradas pela Figura A-1.
Loja
Cliente
idcli
nomecli
idlojacli
dtnasc
responsavel
rua
num_rua
bairro
cep
fone
Locacao
idloc
idcliloc
idlojaloc
idfilmeloc
dialoc
mesloc
anoloc
valorlocfita
idloja
nomeloja
classe
rua
num_rua
bairro
cep
zona
fone
Filme
idfilme
nomefilme
gênero
censura
produtora
numfitasloja
numfitaslocdia
valorlocdia
Figura A-1: Modelo Lógico da Rede de Locadoras [Cos01, p. 13].
O esquema a seguir apresenta as tabelas do banco de dados da rede de locadoras:
CLIENTE (idcli, nomecli, idlojacli, dtnasc, responsavel, rua, num_rua, bairro, cep, fone),
LOJA (idloja, nomeloja, classe, rua, num_rua, bairro, cep, zona, fone),
FILME (idfilme, nomefilme, genero, censura, produtora, numfitasloja, numfitaslocdia,
valorlocdia),
LOCACAO (idloc, idcliloc, idlojaloc, idfilmeloc, dialoc, mesloc, anoloc, valorlocfita).
98
As tabelas LOJA, CLIENTE, FILME e LOCACAO têm como chave primária os campos
idloja, idcli, idfilme e idloc, respectivamente. Há relacionamentos entre as tabelas através de
chave estrangeira, por exemplo, os atributos idcliloc, idlojaloc e idfilmeloc presentes na tabela
LOCACAO, fazendo ligação com as respectivas tabelas CLIENTE, LOJA e FILME. Devido aos
descontos e promoções periódicos, o valor recebido correspondente à locação de uma fita não
é funcionalmente determinado pela chave primária da tabela FILME (idfilme), por isto é
armazenado na tabela LOCACAO no campo valorlocfita. A tabela LOCACAO determina a ordem
de grandeza do banco de dados porque o movimento das locações de filmes nas lojas da rede
é registrado nesta tabela.
A Tabela A-1 apresenta a massa de dados de exemplos do banco de dados da rede de
locadoras utilizada para exemplificar algumas situações no decorrer do trabalho.
Tabela
Cliente
Loja
Filme
Locação
Nº de
Nº de
Registros Atributos
5.000
10
16
12
2.000
9
1.000.000
9
Comprimento do
Registro (bytes)
93
121
77
44
Tamanho
454,1 (Kb)
1,9 (Kb)
150,4 (Kb)
42,0 (Mb)
Tabela A-1: Massa de Dados de Exemplos.
Outro conjunto de dados foi definido para fazer a avaliação do ambiente conforme está
ilustrado na Tabela A-2.
Tabela
Cliente
Loja
Filme
Locação
Nº de
Nº de
Registros Atributos
5.000
10
16
12
64
9
5.760.000
9
Comprimento do
Registro (bytes)
93
121
77
44
Tabela A-2: Massa de Dados de Testes.
Tamanho
454,1 (Kb)
1,9 (Kb)
4,8 (Kb)
241,7(Mb)
99
Apêndice B. Principais Classes do FAP
Neste apêndice encontra-se a descrição das principais classes implementadas no FAP. A
interface de cada classe está representada pelos seus métodos e atributos principais.
//classe catálogo: gerenciar o catálogo da base dados.
class Catalog {
public:
...
//adicionar servidor de arquivos paralelos
void AddServer(char *server);
//adicionar tabela
void AddTable(char *tablename, int segtype, char *segfield, int reptype, int tabletype);
//adicionar campo de tabela
void AddField(char *tablename, char *fieldname, char *fieldtype, int fieldsize, int is_pk, int is_fk,
char *ref_field, int field_statistic);
//adicionar visao
void AddMatView(char *viewname, int segtype, char *segfield, int reptype, int viewtype, int refreshtype,
int maniptype, char *refreshcycle, char *dependsfrom, double nextrefreshtime);
//adicionar campo de visao
void AddFieldMatView(char *viewname, char *fieldname, char *fieldtype, int fieldsize, int is_pk, int is_fk,
char *ref_field, int iscalc, int func, int is_grp_field, int field_statistic);
//criar o catalogo
void Create();
…
//server: é o nome do servidor de arquivos paralelos.
//tablename: é o nome da tabela.
//segtype: indica o tipo de segmentação (0:nenhuma distribuição; 1:distribuição circular; 2:distribuição
//
por faixa de valores; 3:distribuição por função hashing).
//segfield: indica o campo de segmentação da tabela.
//reptype: indica o tipo de replicação (0:sem replicação; 1:com replicação).
//tabletype: indica o tipo da tabela (1:tabela de fato; 2:tabela de dimensão; 3:outros).
//fieldname: é o nome do campo.
//fieldtype: é o tipo do campo (int, char, long)
//fieldsize: é o tamanho do campo.
//is_pk: indica se o campo é chave primária.
//is_fk: indica se o campo é chave estrangeira.
//ref_field: o nome do campo da tabela da qual ele é chave estrangeira.
//field_statistic: indica se campo participará da coleta estatística.
//viewname: indica o nome da visão materializada.
//viewtype: ver tabletype.
//refreshtype: indica o tipo de atualizacao (0:completo; 1:incremental).
//maniptype: indica se a visao gerara novos registros, sem alterar os antigos, ou recalculara os
//
registros antigo.
//refreshcycle: é o periodo entre um refresh e outro.
//dependsfrom: indica ligacao entre o campo e outro da tabela fonte.
//nextrefreshtime: indica o instante do proximo refresh.
//iscalc: indica se o campo é direto (0) ou calculado (1).
//func: qual funcao de calculo que sera disparada (0:null; 1:sum; 2:count; 3:avg; 4:min; 5:max; etc).
//is_grp_field: se o campo eh de agrupamento.
};
//classe buffer de dados: gerenciar uma área da memória principal para armazenamento temporário dos registros
//que serão processados pelo sistema.
class Buffer_Data {
100
public:
...
int Insert(char *data);
int Get(char *retval);
int Remove(char *retval);
int TableToBuffer(Table *table);
int BufferToTable(Table *table);
int GetLenght();
int GetMaxLenght();
void Free();
...
};
//inserir um registro
//recuperar um registro corrente sem remove-lo do buffer e avançar o ponteiro
//recuperar um registro corrente removendo-a do buffer e avançar o ponteiro
//ler os registros de table da posicao corrente e armazena-los no buffer
//gravar os registros do buffer para a table a partir da posição corrente
//obter a quantidade de rgistros armazenados no buffer
//obter a capacidade maxima do buffer
//liberar os dados do buffer
//classe campo de uma tabela: gerenciar cada campo de uma tabela.
class Field {
public:
…
//inserir as informacoes de um campo
void Insert(char *tablename, char *fieldname, char *fieldtype, int fieldsize, int is_pk, int is_fk, char *ref_field,
int is_statistic);
//inserir as informações de uma tabela/visao
void Insert(char *tablename, char *fieldname, char *fieldtype, int fieldsize, int is_pk, int is_fk, char *ref_field, int iscalc,
int func, int is_grp_field, int is_statistic);
//definir a ordem do campo no registro
void SetOrder(int ord);
//definir a posicao dos bytes de gravacao no registro (inic:posicao onde inicia o registro;
fin:posicao onde termina o registro)
void SetBytes(int inic, int fin);
…
//para mais informacoes sobre os argumentos dos métodos ver a classe catálogo.
};
//classe tabela: gerenciar cada tabela do sistema.
class Table {
public:
//metodos
…
//inserir uma tabela.
void Insert(char *tablename, int segtype, char *segfield, int reptype, int tabletype, char tableflag);
//inserir uma visao.
void Insert(char *viewname, int segtype, char *segfield, int reptype, int viewtype, int refreshtype, int maniptype,
char *refreshcycle, char *dependsfrom, double nextrefreshtime, char tableflag);
void InsertField(Field *f); //inserir um campo na tabela
ListObject *GetFields(); //obter todos os campos.
char *GetTableName(); //obter o nome da tabela.
Field *FindField(char *fieldname); //devolver o objeto Field se existir da tabela, caso contrario NULL,
//pesquisando o fieldname, usar a tabela hash.
void Create(char *name,char *modo);
//criar.
void Open(char *name,char *modo);
//abrir.
void Close();
//fechar .
void InsertRecord(RECORD r);
//inserir um registro.
void UpDateRecord(RECORD r);
//atualizar o registro corrente.
void DeleteRecord(RECORD r);
//apagar logicamente (colocar uma marca) o registro corrente.
void PackRecords();
//apagar fisicamente os registros marcados.
void WriteBufferToTable(ListString *buffer); //gravar todos os registros que estao no buffer na tabela.
void SeekRecord(int origin);
//posicionar o ponteiro da tabela em origin.
int GetRecord(RECORD r);
//obter o registro corrente.
101
...
private:
//atributos
…
#ifdef EXECUTION_PARALLEL
File_MPI *ofile; //ponteiro para arquivo paralelo.
#else
File_Text *ofile; //ponteiro para arquivo seqüencial.
#endif
oHash h_fields; //os objetos campos da tabela em um hash.
ListObject l_fields; //os objetos campos da tabela em uma lista encadeada (mantém a ordem do catálogo).
};
//classe abstrata arquivo: gerenciar o acesso a disco através de classes derivadas.
class File {
public:
//metodos
...
virtual void Create(char *nome,char *modo)=0; //criar (nome: nome do arquivo; modo: modo de criação,
//ver fopen do C++).
virtual void Close()=0;
//fechar.
virtual void Open(char *nome,char *modo)=0;
//abrir (ver Create).
virtual int IsOpenFile()=0;
//verificar se esta aberto.
virtual int long GetOffSet()=0;
//obter o offset.
virtual char *ReadAll()=0;
//devolver todo o conteudo.
virtual int ReadRecord(RECORD r)=0;
//ler o registro corrente r.
virtual void WriteRecord(RECORD r)=0;
//gravar um registro r.
virtual void UpDateRecord(RECORD r)=0;
//atualizar o registro corrente.
virtual void DeleteRecord(RECORD r)=0;
//apagar logicamente (colocar uma marca) o registro corrente.
virtual void PackRecords()=0;
//apagar fisicamente os registros marcados.
virtual void Seek(long int offset,int origin)=0;
//posicionar o ponteiro (ver fseek do C++).
virtual int FEof()=0;
//verificar se atingiu final do arquivo.
…
//atributos
char path_filename[1000]; //path de leitura/gravacao do arquivo.
char mode[10];
//modo de criação/abertura do arquivo.
FILE *ptr_f;
//ponteiro para arquivos seqüenciais.
MPI_File fh;
//ponteiro para arquivos paralelos.
...
};
//classe arquivo padrao do tipo texto: gerenciar o acesso a disco através de um arquivo do tipo texto.
class File_Text : public File {
public:
…
void Create(char *nome,char *modo);
void Close();
void Open(char *nome,char *modo);
int IsOpenFile() {return(ptr_f!=NULL);};
long GetOffSet();
char *ReadAll();
int ReadRecord(RECORD r);
void WriteRecord(RECORD r);
void UpDateRecord(RECORD r);
void DeleteRecord(RECORD r);
void PackRecords();
void Seek(long offset,int origin);
102
int FEof();
…
//para mais informacoes ver a classe File
};
//classe arquivo do MPI/IO: gerenciar o acesso a disco através das rotinas do MPI/IO.
class File_MPI : public File {
public:
…
void Create(char *nome,char *modo);
void Close();
void Open(char *nome,char *modo);
int IsOpenFile() { return(fh!=NULL); };
int long GetOffSet();
char *ReadAll() { return(NULL); };
int ReadRecord(RECORD r);
void WriteRecord(RECORD r);
void UpDateRecord(RECORD r);
void DeleteRecord(RECORD r);
void PackRecords();
void Seek(long int offset,int whence);
int FEof();
…
//para mais informacoes ver a classe File
};
//classe base de dados: classe principal do sistema para gerenciar todos os eventos referentes ao acesso ao banco de
//dados entre os processos cliente e servidores de arquivos paralelos.
class DbFap {
public:
DbFap(char *basename);
//construtor seqüencial.
DbFap(char *basename,Host *host); //construtor paralelo.
void Init();
//inicializacoes.
~DbFap();
//destrutor.
//inserir um servidor de arquivos paralelos.
void AddServer(char *Server);
//inserir uma tabela.
void AddTable(char *tablename, int segtype, char *segfield, int reptype, int tabletype);
//inserir um campo de uma tabela.
void AddFieldTable(char *tablename, char *fieldname, char *fieldtype, int fieldsize, int is_pk, int is_fk, char *ref_field,
int field_statistic);
//inserir uma visao.
void AddMatView(char *viewname, int segtype, char *segfield, int reptype, int viewtype, int refreshtype, int maniptype,
char *refreshcycle, char *dependsfrom, double nextrefreshtime);
//inserir um campo de uma visao.
void AddFieldMatView(char *viewname, char *fieldname, char *fieldtype, int fieldsize, int is_pk, int is_fk, char *ref_field,
int iscalc, int func, int is_grp_field, int field_statistic);
//criar o catalogo no path definitivo.
void CreateCatal();
Table *GetTable(char *tablename); //obter uma tabela pelo tablename.
void Create();
//criar o banco de dados.
void Open();
//abrir o banco de dados.
void Close();
//fechar o banco de dados.
void InsertRecord(char *tablename,RECORD r);
//inserir um registro na tabela tablename.
void UpDateRecord(char *tablename,RECORD r); //atualizar o registro corrente na tabela tablename.
void DeleteRecord(char *tablename,RECORD r);
//apagar logicamente (colocar uma marca) no registro corrente
//na tabela tablename.
103
void PackRecords (char *tablename,RECORD r); //apagar fisicamente os registros com marca na tabela tablename.
void SeekRecord(char *tablename,int whence); //posicionar o ponteiro a partir de whence para a tabela
//tablename (whence: ver fseek do C++).
int GetRecord(char *tablename,RECORD r);
//obter o registro corrente.
void CreateStatistic();
//criar a estatistica das tabelas.
void StatisticToMem();
//transfere a estatistica para cada campo de uma tabela.
void SetQueryName(char *name);
//definir um nome para uma consulta.
void Query(char *query);
//executar uma consulta sql (query: a consulta em sql).
void MatView(char *viewname,char *query);//executar uma visao, materializando em disco (viewname: nome da visao,
//query:a consulta).
//aplicar ou nao o agrupamento prévio.
int ApplyGroupByBeforeJoin_Yes();
//sim.
int ApplyGroupByBeforeJoin_No();
//nao.
//aplicar ou nao o Filtro Seletivo
int ApplyFilterGroupByBeforeJoin_Yes(); //sim.
int ApplyFilterGroupByBeforeJoin_No(); //nao.
//definir as tecnicas para o processamento das consultas.
int SetTechnical_Join_Hash();
//juncao hash.
int SetTechnical_Join_LoopAninhate();
//juncao laco aninhado.
int SetTechnical_Join_Merge();
//juncao merge (sem sort).
int SetTechnical_GroupBy_Hash();
//agrupamento hash.
int SetTechnical_GroupBy_Tree();
//agrupamento arvore binaria.
int SetTechnical_GroupBy_BPlus();
//agrupamento arvore B+.
int SetTechnical_GroupBy_Scan();
//agrupamento com varredura com ordenacao.
int SetTechnical_GroupBy_ScanRepeated();
// agrupamento varredura com repeticao
int SetTechnical_GroupBy_UnionRepeated();
// agrupamento uniao com repeticao
//apoio ao MPI
int GetSegment(Table *t, RECORD r);
//verifica se o registro a ser gravado pertence ao segmento.
void ReplicateCatal(char *name_catal); //enviar o catalogo para os servidores.
void RecvCatal();
//Os servidores recebem o catalogo.
void SendStatistic();
//Os servidores enviam a sua estatistica para o cliente.
void RecvStatistic();
//cliente cria um arquivo de estatistica para cada servidor.
void ClearFileLogs();
//apagar todos os arquivos de logs.
...
//para mais informacoes sobre os argumentos dos métodos ver a classe catálogo, tabela ou campo.
};
//classe sql: gerenciar as consultas escritas em sql para serem executadas no sistema.
class Sql {
public:
//metodos
...
void Query(DbFap *db,char *query); //executar a consulta (db: objeto banco de dados; query: consulta em sql).
int ParserQuery();
//analisar lexicamente, sintaticamente a consulta
void MakePlanInitial();
//construir o plano de consulta inicial
void MakePlanExec();
//construir o plano de execucao da consulta
void MakePlanAloc();
//construiro plano de alocacao de recursos (servidores de arquivos)
void MakeBitVector();
//construir vetores de bits para cada atributo de selecao
//aplicar otimizacoes
void OptimizationHeuristic();
//otimizacao heuristica
void OptimizationGroupByBeforeJoin(); //otimizacao GroupByBeforeJoin
void OptimizationEstimCustToGBBJ();
//aplicar estimativa de custo basico para o GBBJ
int ApplyFilterGBBJ(Table *pt_table,RECORD r); //aplicar o filtro no GBBJ
void Execute();
//executar a consulta
//executar a projecao.
Table *_ExecutePI(char *tablename_in,
//tabela de entrada.
int n_fields,
//número de campos projetados.
char *fields[],
//campos projetados.
104
};
char *tablename_out);
//tabela de saida.
//executar a selecao.
Table *_ExecuteSIGMA(char *tablename_in, //tabela de entrada.
char *field_1,
//primeiro operando.
char *field_2,
//segundo operando.
char *operador,
//operador de condicao.
char *tablename_out); //tabela de saída.
//executar uma junção de laço aninhado.
Table *_ExecuteJOIN_LoopAninhate(char *table_1,
//primeira tabela de entrada.
char* field_1,
//campo da primeira tabela de entrada.
char *table_2,
//segunda tabela de entrada.
char* field_2,
//campo da segunda tabela de entrada.
char *operador,
//operador de condicao.
char *tablename_out); //tabela de saida.
//executar uma junção hash.
Table _ExecuteJOIN_Hash(/*ver juncao laço aninhado*/);
//executar uma junção merge.
Table *_ExecuteJOIN_Merge(/*ver juncao laço aninhado*/);
//executar uma agregação
Table *_ExecuteGAMA(char *tablename_in,
//tabela de entrada.
int n_fields,
//número de campos de agrupamento.
char *fields[],
//campos de agrupamento.
char *tablename_out,
//tabela de saída.
LEFT_DEEP_TREE *plan); //plano de execução.
//apoio ao MPI
char *QueryPlanCod();
//transformar o plano em string para ser enviado aos servidores para ser executado.
void CoordExecQuery(int id_query); //coordena as atividades para a execucao da consulta.
int ReceptionResults();
//cliente faz a recepcao dos resultados.
void SendResult(Table *t);
//servidores enviam seus resultados para o cliente.
...
//atributos
PlanQuery *plan; //o objeto plano de consulta
DbFap *db;
//o objeto banco de dados
...
//classe de vetor bits utilizada no filtro seletivo: gerenciar a construção e verificação do filtro seletivo no sistema.
class BitVector {
public:
BitVector(int size);
//construtor (size: capacidade do vetor)
~BitVector();
//destrutor
void Insert(int key);
//marcar um bit baseado na key
int Find(int key);
//verificar se o bit esta marcado baseado para a key
...
};
105
Apêndice C. Estrutura de Diretórios do FAP
O FAP foi implementado na estrutura de diretórios ilustrada pela Figura C-1. O
diretório "fap_db", o diretório padrão, contém o código fonte e o arquivo executável da
aplicação.
fap_db
<basename>
catalog
performances
plans
Figura C-1: Estrutura de Diretórios usada pelo FAP
O diretório "<basename>" contém as tabelas do banco de dados do sistema e os arquivos
com os resultados das consultas. Além disso, é o diretório utilizado para o armazenamento
dos arquivos temporário criados durante a execução das consultas. O nome desse diretório
será fornecido diretamente pela aplicação durante a criação do objeto da classe DbFap.
O diretório "catalog" contém o arquivo de catálogo "CatalogDb" utilizado pela aplicação
para consultar e gravar os dados nas tabelas. Neste diretório também são gravadas as
estatísticas das tabelas do banco de dados no arquivo "StatisticDb" que serão utilizadas na
otimização das consultas.
O diretório "performances" contém os arquivos com os resultados de desempenho das
consultas executadas no FAP.
O diretório "plans" contém os planos de consulta criados durante a otimização das
consultas. No processo cliente é construído os seguintes planos: inicial, heurístico,
agrupamento prévio, execução e codificado. Os servidores decodificam o plano recebido do
processo cliente.
106
Apêndice D. Catálogo do Banco de Dados para o Estudo de
Caso
Neste apêndice encontram-se as informações do catálogo utilizado durante a execução
do estudo de caso. A estrutura do catálogo especificada e detalhada em [Cos01] passou por
duas alterações. Uma para possibilitar a realização da estatística dos dados das tabelas e a
outra para aplicar o filtro seletivo.
A primeira alteração é o acréscimo do campo field_statistic na definição das
informações dos campos de uma tabela (cat_t_fields) ou visão materializada (cat_t_views). Os
valores possíveis nesse novo campo são 0 e 1 que correspondem respectivamente não realizar
ou realizar a estatística para o campo especificado.
A segunda alteração corresponde no acréscimo do campo tabletype na definição das
informações da tabela (cat_tables) que possui como possíveis valores: 1 que classifica uma
tabela como tabela de fatos e 2 como de dimensão.
A seguir é apresentada a estrutura do catálogo com esse novo acréscimo.
cat_sites
sites
host_0
host_1
host_2
host_3
cat_tables
tablename
loja
cliente
filme
locacao
//servidores de arquivos paralelos
//tabelas
segtype segfield
0
null
2
idlojacli
0
null
2
idlojaloc
reptyle
1
0
1
0
cat_t_fields
//campos das tabelas
tablename fieldname fieldtype fieldsize
loja
idlojalj
int
4
loja
nomeloja char
15
loja
classe
char
15
loja
rualj
char
15
loja
numrualj int
6
loja
bairrolj
char
15
loja
ceplj
char
10
tabletype
2
2
2
1
is_pk
1
0
0
0
0
0
0
is_fk
0
0
0
0
0
0
0
ref_field
null
null
null
null
null
null
null
field_statistic
1
0
1
0
0
1
0
107
loja
loja
loja
loja
loja
cliente
cliente
cliente
cliente
cliente
cliente
cliente
cliente
cliente
cliente
filme
filme
filme
filme
filme
filme
filme
filme
filme
locacao
locacao
locacao
locacao
locacao
locacao
locacao
locacao
locacao
zona
fonelj
cliinic
qtcli
deletedlj
idcli
nomecli
idlojacli
dtnasc
respons
ruacli
numruacli
bairrocli
fonecli
deletedcli
idfilmefil
nomefilme
idgenfil
genero
censura
produtora
nfitasloja
vrlocdia
deletedfil
idloc
idcliloc
idlojaloc
idfilmeloc
dialoc
mesloc
anoloc
vrlocfita
deletedloc
char
char
int
int
int
int
char
int
long
int
char
int
char
long
int
int
char
int
char
int
char
int
long
int
long
int
int
int
int
int
int
long
int
10
10
4
4
1
6
16
4
8
6
16
6
12
8
1
4
16
2
16
4
16
4
5
1
8
6
4
4
2
2
4
3
1
0
0
0
0
0
1
0
0
0
0
0
0
0
0
0
1
0
0
0
0
0
0
0
0
1
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
1
0
1
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
1
1
1
0
0
0
0
0
null
null
null
null
null
null
null
idlojalj
null
idcli
null
null
null
null
null
null
null
null
null
null
null
null
null
null
null
idcli
idlojalj
idfilmefil
null
null
null
null
null
cat_views
//visão materializada
viewname segtype segfield reptyle viewtype refreshtype
nextrefrestime
locdialjf
2
idlojadlf 0
1
1
cat_v_fields //campos da visão materializada
viewname fieldname fieldtype fieldsize is_pk
locdialjf
idlojadlf int
4
1
locdialjf
idfilmedlf int
4
1
locdialjf
anodlf
int
4
1
locdialjf
mesdlf
int
2
1
locdialjf
diadlf
int
2
1
locdialjf
nfitdlf
int
10
0
locdialjf
slocdlf
long
10
0
is_fk
1
1
1
1
1
0
0
1
0
0
0
0
1
0
1
1
1
0
0
1
0
0
1
0
1
1
1
1
0
0
0
0
1
1
1
1
1
1
0
0
manitype refreshcycle
dependsfrom
1
locacao
ref_field
idlojaloc
idfilmeloc
anoloc
mesloc
dialoc
null
vrlocfita
day
is_calc
0
0
0
0
0
1
1
func
0
0
0
0
0
2
1
is_grp_field
1
1
1
1
1
0
0
0
field_statistic
1
1
1
1
1
0
0
108
Apêndice E. Código Fonte utilizado no Estudo de Caso
Neste apêndice encontra-se o código fonte das principais rotinas utilizadas para
executar o estudo de caso no FAP.
// ===========================================================================================
// SQL DAS CONSULTAS
// ===========================================================================================
//Define a quantidade de fitas locadas e o valor faturado com locacoes,
//por bairro, anualmente, para filmes do genero 'drama'.
void Q3(DbFap *db)
{
Rotinas time;
time.SetTimeInit();
db->Query("SELECT loj.bairrolj, loc.anoloc, COUNT(*), SUM(loc.vrlocfita)
FROM loja as loj, locacao as loc, filme as film
WHERE loj.idlojalj == loc.idlojaloc AND loc.idfilmeloc == film.idfilmefil AND film.genero == 'drama'
GROUP_BY loj.bairrolj, loc.anoloc");
printf("\nTempo de execucao:%fs",time.GetTimePassed());
}
//Define a quantidade de fitas locadas diariamente, para filmes do genero 'faroeste'.
void Q4(DbFap *db)
{
Rotinas time;
time.SetTimeInit();
db->Query("SELECT f.nomefilme, l.anoloc, l.mesloc, l.dialoc, COUNT(*)
FROM filme as f, locacao as l
WHERE f.genero == 'faroeste' AND f.idfilmefil == l.idfilmeloc
GROUP_BY f.nomefilme, l.anoloc, l.mesloc, l.dialoc");
printf("\nTempo de execucao:%fs",time.GetTimePassed());
}
//Define a quantidade de fitas locadas anualmente, para filmes do genero 'faroeste'.
void Q5(DbFap *db)
{
Rotinas time;
time.SetTimeInit();
db->Query("SELECT f.nomefilme, l.anoloc, COUNT(*)
FROM filme as f, locacao as l
WHERE f.genero == 'faroeste' AND f.idfilmefil == l.idfilmeloc
GROUP_BY f.nomefilme, l.anoloc");
printf("\nTempo de execucao:%fs",time.GetTimePassed());
}
//Define a quantidade de fitas locadas diariamente, para filmes do genero 'faroeste'.
void Q6(DbFap *db)
{
Rotinas time;
}
time.SetTimeInit();
db->Query("SELECT f.nomefilme, l.anoloc, l.mesloc, l.dialoc, COUNT(*)
FROM filme as f, locacao as l
WHERE f.genero == 'faroeste' AND f.idfilmefil == l.idfilmeloc
GROUP_BY f.nomefilme, l.anoloc, l.mesloc, l.dialoc");
printf("\nTempo de execucao:%fs",time.GetTimePassed());
109
//Define a quantidade de locacoes e o valor faturado com locacoes, diariamente, filme por filme,
//para cada loja.
void V1(DbFap *db)
{
db->MatView("locdialjf","SELECT l.idlojaloc, l.idfilmeloc, l.anoloc, l.mesloc, l.dialoc, COUNT(*), SUM(l.vrlocfita)
FROM locacao as l
GROUP_BY l.idlojaloc, l. idfilmeloc, l.anoloc, l.mesloc, l.dialoc");
db->CreateStatistic(); //criar novas estatisticas
db->StatisticToMem(); //atualizar estruturas com as novas estatisticas
}
//Define a quantidade de fitas locadas e o valor faturado com locacoes,
//por bairro, anualmente, para filmes do genero 'drama'.
void Q7(DbFap *db)
{
Rotinas time;
time.SetTimeInit();
db->Query("SELECT loj.bairrolj, loc.anodlf, SUM(loc.nfitdlf), SUM(loc.slocdlf)
FROM loja as loj, locdialjf as loc, filme as film
WHERE loj.idlojalj == loc.idlojadlf AND loc.idfilmedlf == film.idfilmefil AND film.genero == 'drama'
GROUP_BY loj.bairrolj, loc.anodlf");
printf("\nTempo de execucao:%fs",time.GetTimePassed());
}
//Define o valor faturado com locacoes por genero para loja com idlojaloc=16
void Q8(DbFap *db)
{
Rotinas time;
time.SetTimeInit();
db->Query("SELECT f.genero, SUM(l.vrlocfita)
FROM filme as f, locacao as l
WHERE f.idfilmefil == l.idfilmeloc AND l.idlojaloc == 16
GROUP_BY f.genero");
printf("\nTempo de execucao:%fs",time.GetTimePassed());
}
//Define o valor faturado com locacoes por genero para loja com idlojaloc>=15
void Q9(DbFap *db)
{
Rotinas time;
time.SetTimeInit();
db->Query("SELECT f.genero, SUM(l.vrlocfita)
FROM filme as f, locacao as l
WHERE f.idfilmefil == l.idfilmeloc AND l.idlojaloc >= 15
GROUP_BY f.genero");
printf("\nTempo de execucao:%fs",time.GetTimePassed());
}
//Define o valor faturado com locacoes por genero para loja com idlojaloc>=13
void Q10(DbFap *db)
{
Rotinas time;
time.SetTimeInit();
db->Query("SELECT f.genero, SUM(l.vrlocfita)
FROM filme as f, locacao as l
WHERE f.idfilmefil == l.idfilmeloc AND l.idlojaloc >= 13
GROUP_BY f.genero");
printf("\nTempo de execucao:%fs",time.GetTimePassed());
}
110
//Define o valor faturado com locacoes por genero para loja com idlojaloc>=9
void Q11(DbFap *db)
{
Rotinas time;
time.SetTimeInit();
db->Query("SELECT f.genero, SUM(l.vrlocfita)
FROM filme as f, locacao as l
WHERE f.idfilmefil == l.idfilmeloc AND l.idlojaloc >= 9
GROUP_BY f.genero");
printf("\nTempo de execucao:%fs",time.GetTimePassed());
}
//Define o valor faturado com locacoes por genero para loja com idlojaloc>=1
void Q12(DbFap *db)
{
Rotinas time;
time.SetTimeInit();
db->Query("SELECT f.genero, SUM(l.vrlocfita)
FROM filme as f, locacao as l
WHERE f.idfilmefil == l.idfilmeloc AND l.idlojaloc >= 1
GROUP_BY f.genero");
printf("\nTempo de execucao:%fs",time.GetTimePassed());
}
// ===========================================================================================
// EXECUCAO DAS CONSULTAS
// ===========================================================================================
void Execute(DbFap *db)
{
char *ranks[20];
int i, nr_hosts=17;
//determinar os hosts
for(i=0;i<nr_hosts;i++) {
ranks[i]=new char[10];
sprintf(ranks[i],"host_%d",i);
}
CreateCatalog(db,ranks,nr_hosts);
db->Create();
db->Open();
InserirRegistros(db);
//criar o catalogo do banco de dados
//criar o banco de dados
//abrir o banco de dados
//inserir os registro na banco de dados
db->ClearFileLogs();
//apagar os arquivos de log
db->SetTechnical_Join_Hash();
//definir a tecnica HASH para a juncao
db->SetTechnical_GroupBy_Hash(); //definir a tecnica HASH para o agrupamento
V1(db);
//executar a visao materializada 1
db->ApplyGroupByBeforeJoin_No();
db->ApplyFilterGroupByBeforeJoin_No();
db->SetQueryName("Q3NN");
Q3(db);
db->SetQueryName("Q4NN");
Q4(db);
//aplicar o agrupamento previo? (Nao)
//aplicar o filtro seletivo? (Nao)
//nomear a consulta
//executar a consulta 3
//nomear a consulta
//executar a consulta 4
db->ApplyGroupByBeforeJoin_Yes();
db->ApplyFilterGroupByBeforeJoin_No();
//aplicar o agrupamento previo? (Sim)
//aplicar o filtro seletivo? (Nao)
111
db->SetQueryName("Q3YN");
Q3(db);
db->SetQueryName("Q4YN");
Q4(db);
//nomear a consulta
//executar a consulta 3
//nomear a consulta
//executar a consulta 4
db->ApplyGroupByBeforeJoin_Yes();
db->ApplyFilterGroupByBeforeJoin_No();
db->SetQueryName("Q5YN");
Q5(db);
db->SetQueryName("Q6YN");
Q6(db);
//aplicar o agrupamento previo? (Sim)
//aplicar o filtro seletivo? (Nao)
//nomear a consulta
//executar a consulta 5
//nomear a consulta
//executar a consulta 6
db->ApplyGroupByBeforeJoin_Yes();
db->ApplyFilterGroupByBeforeJoin_Yes();
db->SetQueryName("Q5YY");
Q5(db);
db->SetQueryName("Q6YY");
Q6(db);
//aplicar o agrupamento previo? (Sim)
//aplicar o filtro seletivo? (Sim)
//nomear a consulta
//executar a consulta 5
//nomear a consulta
//executar a consulta 6
db->ApplyGroupByBeforeJoin_No();
db->ApplyFilterGroupByBeforeJoin_No();
db->SetQueryName("Q7NN");
Q7(db);
//aplicar o agrupamento previo? (Nao)
//aplicar o filtro seletivo? (Nao)
//nomear a consulta
//executar a consulta 7
db->ApplyGroupByBeforeJoin_Yes();
db->ApplyFilterGroupByBeforeJoin_No();
db->SetQueryName("Q7YN");
Q7(db);
//aplicar o agrupamento previo? (Sim)
//aplicar o filtro seletivo? (Nao)
//nomear a consulta
//executar a consulta 7
db->ApplyGroupByBeforeJoin_Yes();
db->ApplyFilterGroupByBeforeJoin_No();
db->SetQueryName("Q8YN");
Q8(db);
db->SetQueryName("Q9YN");
Q9(db);
db->SetQueryName("Q10YN");
Q10(db);
db->SetQueryName("Q11YN");
Q11(db);
db->SetQueryName("Q12YN");
Q12(db);
//aplicar o agrupamento previo? (Sim)
//aplicar o filtro seletivo? (Nao)
//nomear a consulta
//executar a consulta 8
//nomear a consulta
//executar a consulta 9
//nomear a consulta
//executar a consulta 10
//nomear a consulta
//executar a consulta 11
//nomear a consulta
//executar a consulta 12
db->Close();
//fechar o banco de dados
//liberar memoria
for(i=0;i<nr_hosts;i++)
delete ranks[i];
}