Utilizando TimeDB na implementação de bancos de dados temporais Carlos Eduardo Santin1 , Willian Bruno Gomes Alves1 1 Instituto de Informática – Universidade Federal do Rio Grande do Sul (UFRGS) Caixa Postal 15.064 – 91.501-970 – Porto Alegre – RS – Brazil {cesantin,wbgalves}@inf.ufrgs.br Abstract. Most of the current applications uses databases that just represent one state of the real world. However, more and more we noticed the need of work with information referring to several points in the time. For that, we needed to access databases that store data in its current state, as also in the past and in some cases in the future. For this objective appeared temporal databases. The temporal control of a database can be implemented directly in the application or really creating a new database or using a layer on an existent database that allows the translation of temporal operations for SQL default. In this last model is the TimeDB, a tool that makes possible the use of commercial databases as if they were temporal databases, however this tool still presents the lack of some resources. Resumo. A maioria das aplicações atuais utilizam bancos de dados que representam apenas um estado do mundo real. No entanto, cada vez mais notamos a necessidade de trabalharmos com informações referentes a diversos pontos no tempo. Para isso, necessitamos acessar bancos de dados que armazenem dados em seu estado atual, como também no passado e em alguns casos no futuro. Com este objetivo surgiram os bancos de dados temporais. O controle temporal de um banco de dados pode ser implementado diretamente na aplicação ou criando realmente um novo banco de dados ou ainda utilizando uma camada sobre um banco já existente que permita a tradução de operações temporais para operações SQL padrão. Neste último modelo enquadra-se o TimeDB, uma ferramenta que possibilita a utilização de bancos comerciais como se fossem bancos temporais, no entanto esta ferramenta ainda apresenta a carência de alguns recursos. 1. Introdução A grande maioria das aplicações que utilizam bancos de dados têm acesso apenas a um único estado do mundo real, geralmente o estado mais atual do banco, e uma atualização do mesmo resulta na perda dos dados antigos. Existem, no entanto, muitas aplicações em que é necessária a manipulação de outros estados do banco, como estados passados e até mesmo estados futuros. Exemplos dessas aplicações são: controle de estoque, sistemas de reserva, sistemas de suporte à decisão, etc. Com isso, surgem os bancos de dados temporais, que permitem armazenar todos os estados de uma aplicação, registrando sua evolução com o passar do tempo. Na seção 2 é feita uma breve apresentação de bancos de dados temporais, sendo mostradas algumas caracterı́sticas de um banco de dados temporal especı́fico, o TimeDB, na seção 3. A seção 4 apresenta um estudo de caso utilizando o TimeDB e o Oracle 10g, e nas seções que seguem são exibidas algumas questões atuais, tendências futuras e as conclusões deste trabalho. 2. Bancos de Dados Temporais Como dito anteriomente, os bancos de dados não-temporais apenas dão suporte ao acesso de apenas um único estado do mundo real, geralmente o estado mais recente, e uma atualização nas informações desse banco significa a perda dos dados antigos. Contudo, existe um grande número de aplicações que necessitam ter acesso a não apenas o estado mais recente do banco, mas também a estados passados e futuros. Um dos primeiros passos na construção de bancos de dados temporais é a associação de informação de tempo aos dados, permitindo a distinção entre diferentes estados [Steiner 1999]. Para isso, diferentes noções do tempo são relevantes para a construção de bancos de dados temporais. O tempo de validade (valid time), que é o tempo no qual os dados são válidos no mundo real, e o tempo de transação (transaction time), que é o tempo em que os dados são inseridos no banco. Essas diferentes noções de tempo permitem a distinção entre tipos de bancos de dados temporais: bancos de dados de tempo de validade, bancos de dados de tempo de transação e bancos de dados bitemporais. Os bancos de dados convencionais são também conhecidos como snapshot database, por armazenarem um único estado do mundo real, geralmente o estado mais recente. São exemplos de aplicações que lidam com dados temporais: aplicações financeiras, sistemas de reserva, sistemas de gerenciamento de informações médicas, sistemas de suporte à decisão, etc. [Steiner 1999] afirma, que de fato, é difı́cil identificar domı́nios de aplicações que não envolvam o gerenciamento de dados temporais. 2.1. Implementação de Bancos de Dados Temporais [Steiner 1998] discute diferentes soluções para gerenciar dados temporais. Eles identificam quatro possibilidades: (i) utilizar o tipo DATE fornecido por SGBDs não temporais e construir todo o suporte temporal na própria aplicação, (ii) implementar um tipo abstrato de dado para o tempo, (iii) estender um modelo de dados não temporal para um modelo temporal, e (iv) generalizar um modelo de dados não-temporal para um modelo temporal. 3. TimeDB O TimeDB funciona como uma camada acoplada a bancos de dados comerciais, traduzindo expressões temporais para expressões SQL padrão. Desta forma é possı́vel fazer uso de caracterı́sticas já existentes em bancos de dados, como a persistência e concorrência, sem a necessidade de reimplementá-las. Com o TimeDB é possı́vel armazenar e manipular diversos estados de uma base de dados. A grande vantagem de sua utilização é que bases de dados já existentes, armazenadas em SGBD comerciais, e aplicações que acessam estes dados podem continuar sendo utilizadas enquanto que novas aplicações que tratam dados temporais podem ser adicionadas. O TimeDB utiliza a linguagem ATSQL2 que é um linguagem de pesquisa temporal baseada na linguagem SQL, que suporta alterações, visões, declarações e restrições temporais. Por ter sido baseada em SQL, qualquer expressão construı́da utilizando SQL padrão, também será suportada pela linguagem ATSQL2. Na versão 1.0 do TimeDB eram suportadas consultas, inserções, alterações, exclusões, criação de tabelas e visões, tudo isso de forma temporal, além de declarações e restrições temporais em tabelas. Nesta versão também era suportado tempo de validade e tempo de transação. O TimeDB foi reimplementado utilizando-se a linguagem de programação Java, tornando-se independente de plataforma. Nesta nova implementação algumas diferenças surgiram em relação a versão 1.0: • TimeDB 2.0 utiliza JDBC, permitindo a conexão com diferentes bancos de dados; • TimeDB 2.0 possui uma interface gráfica que permite a execução de consultas de uma forma mais fácil; • TimeDB 2.0 é otimizado em relação a construção de tabelas auxiliares; • TimeDB 2.0 possui uma interface de comunicação nativa que pode ser usada por aplicações Java para execução de expressões ATSQL2. Além disso, a versão 2.0 acrescentou a possibilidade de utilização de funções de agregação, cláusulas GROUP BY, cláusulas HAVING e restrições de colunas e tabelas, no entanto algumas caracterı́sticas presentes na versão 1.0 não são mais suportadas, como as operações de alteração e operações de tempo de transação e bitemporais. Atualmente o TimeDB é compatı́vel com os bancos Oracle, Sybase e IBM Cloudscape. 3.1. ATSQL2 Nesta seção mostraremos a sintaxe utilizada pelo ATSQL2 para criação, pesquisa e manutenção dos dados e na seção seguinte faremos uso dos comandos aqui exibidos para realização de um estudo de caso. Um exemplo da sintaxe do ATSQL2 pode ser visto na tabela 1. 3.2. Tipos especiais de dados O TimeDB trabalha com alguns tipos especiais de dados voltados para questões temporais que são o interval, o period e o date. O tipo interval permite especificar um intervalo de tempo que pode englobar dias, meses e anos (e.g., interval 3 year 2 month). O tipo period permite a especificação de perı́odos entre dois pontos no tempo (e.g., period [1990-1993)). O tipo date especifica que um determinado dado é uma data (e.g., date ’1981-03-09’). 4. Estudo de Caso Com objetivo de exemplificar o funcionamento do TimeDB para implementação de um banco de dados temporal, é mostrado nesta seção um cenário onde os dados podem ser modelados de forma temporal e uma implementação deste cenário utilizando o TimeDB em conjunto com o banco de dados Oracle 10g. Criação de Tabelas CREATE TABLE nomeTabela(campo1 tipo, ..., campoN tipo) AS VALIDTIME; /* Aceita somente tempo de validade */ Inserção de Dados VALIDTIME PERIOD [tempoInicial-TempoFinal) INSERT INTO nomeTabela VALUES (valor1, ..., valorN); /* TempoInicial e TempoFinal podem assumir os valores beginning e forever respectivamente para denotar infinito */ Consulta de Dados NONSEQUENCED VALIDTIME SELECT * FROM nomeTabela; /* Retorna os dados da tabela sem levar em consideração o tempo de validade */ VALIDTIME SELECT * FROM nomeTabela; /* Retorna os dados da tabela levando em consideração o tempo de validade */ VALIDTIME (SELECT * FROM nomeTabela) (PERIOD); /* Retorna as instâncias de um mesmo registro que são continuidade uma da outra em função do tempo em um único registro */ VALIDTIME PERIOD [tempoInicial-tempoFinal) SELECT * FROM nomeTabela; /* Retorna os dados compreendidos entre um tempo inicial e um tempo final */ Exclusão de Dados DELETE FROM nomeTabela WHERE condicao; /* Ao excluir um registro com tempo final igual a “forever”, este receberá como tempo final a data e horário da exclusão, não sendo fisicamente excluı́do */ Table 1. Comandos ATSQL2 4.1. Cenário Neste artigo é proposto como cenário um sistema para controle do departamento pessoal de uma empresa. O departamento pessoal mantém um cadastro dos funcionários que trabalham atualmente na empresa, bem como os que já trabalharam. No cadastro do funcionário é armazenado o seu nome, um código identificador único, seu cpf e rg, o seu salário, a data de sua admissão, seu cargo e o departamento ao qual pertence. O sistema também possui um cadastro de departamentos que apresenta o código único do departamento e o seu nome. Com o sistema atualmente implementado esta empresa passa pelo problema de perder informações antigas dos seus funcionários, informações essas que não são mais atualmente verdadeiras mas que são úteis para geração de algumas estatı́sticas. O usuário necessita que o salário anterior do funcionário não seja perdido após uma alteração de seu valor para que dessa forma possa ser realizada uma estatı́stica do aumento ocorrido durante sua permanência na empresa. Também é necessário manter um histórico dos cargos que já foram assumidos pelo funcionário bem como os departamentos pelo qual ele passou. No primeiro momento o sistema deve apresentar a possibilidade de obtenção das seguintes informações: • Dado o código de um funcionário, obter todos os cargos que ele já possuiu dentro da empresa; • Dado o código de um funcionário, obter todos os departamentos nos quais ele já trabalhou; • Obter a média de salário do funcionário durante todo o tempo em que esteve empregado; • Obter o número de funcionários que trabalham atualmente na empresa; • Obter o maior e o menor salário pago atualmente na empresa; • Obter o maior e o menor salário já pago na empresa; • Listar os departamentos existentes na empresa e os maiores e menores salários atuais de cada departamento; • Listar o número de funcionários existentes atualmente em cada departamento. Posteriormente novas consultas poderão ser necessárias. 4.2. Modelagem do banco de dados Para a implementação do sistema explicado na seção anterior, foi gerado o modelo ER exibido na figura 1. Figure 1. Modelo ER para o sistema de controle de funcionários 4.3. Implementação utilizando TimeDB e Oracle 10g Para a implementação foi utilizado o TimeDB versão 2.2 e a interface gráfica que o acompanha, através da qual foi feita a criação do banco de dados, operações de manutenção e consultas. Para possibilitar a criação de tabelas através da interface gráfica, a primeira coisa que deve ser feita é acessar o menu TimeDB e executar a opção Create DB. Ao realizar isso serão criadas cinco tabelas para o usuário no oracle, as tabelas ASSERTIONS, KEYS, TABLE TYPES, TABLE VIEW SCHEMES e VIEWS. Elas são utilizadas internamente pelo TimeDB para controle das informações temporais. A tabela “Funcionario” foi criada de forma temporal com o objetivo de permitir que dados do funcionário não sejam perdidos após uma alteração, como por exemplo, um aumento de salário. Para a criação das tabelas foi executado o seguinte script SQL: CREATE TABLE Departamento (codigo INTEGER PRIMARY KEY, nome VARCHAR(40)); CREATE TABLE Cargo (codigo INTEGER PRIMARY KEY, nome VARCHAR(40)); CREATE TABLE CargoDep (codigoCargoDep INTEGER PRIMARY KEY, codigoCargo INTEGER, codigoDep INTEGER, FOREIGN KEY (codigoCargo) REFERENCES Cargo(codigo),FOREIGN KEY (codigoDep) REFERENCES Departamento(codigo)); CREATE TABLE Funcionario (codigo INTEGER PRIMARY KEY, nome VARCHAR(40), cpf VARCHAR(14), rg VARCHAR(10), salario FLOAT, admissao DATE, codigoCargoDep INTEGER, FOREIGN KEY (codigoCargoDep) REFERENCES CargoDep(codigoCargoDep)) AS VALIDTIME; Ao criar a tabela Funcionario de forma temporal, o TimeDB automaticamente acrescentou duas colunas à tabela, a coluna de tempo de validade inicial e a coluna de tempo de validade final, demonstrado na figura 2 através dos campos VTS TIMEDB e VTE TIMEDB respectivamente. Figure 2. Tabela Funcionario Tendo as tabelas criadas, o próximo passo foi populá-las com dados para posterior realização de consultas. Foram criados quatro departamentos: Testes, Desenvolvimento, Análise, Gerência. Também foram criados sete cargos: Estagiário, Testador, Programador Júnior, Programador Sênior, Analista de Sistemas Júnior, Analista de Sistemas Sênior e Gerente de Projetos. A relação entre os cargos e departamentos pode ser visualizada na tabela 2. Cargo Estagiário Estagiário Estagiário Testador Programador Júnior Programador Sênior Analista de Sistemas Júnior Analista de Sistemas Sênior Gerente de Projetos Departamento Testes Desenvolvimento Análise Testes Desenvolvimento Desenvolvimento Análise Análise Gerência Table 2. Relação Cargos X Departamentos A tabela Funcionario foi populada com dados que permitissem a realização das consultas necessárias citadas na definição do cenário. Logo após as seguintes consultas foram criadas: Dado o código de um funcionário, obter todos os cargos que ele já possuiu dentro da empresa: SELECT c.nome FROM cargo c WHERE EXISTS (SELECT cd.codigoCargo FROM cargoDep cd WHERE cd.codigoCargo = c.codigo AND EXISTS (VALIDTIME SELECT f.codigoCargoDep FROM funcionario f WHERE f.codigo = :CODIGO AND f.codigoCargoDep = cd.codigoCargoDep)); A necessidade da criação de subselects foi devido a não aceitação por parte do TimeDB de realizar um VALIDTIME SELECT em tabelas que não foram criadas de forma temporal. Dado o código de um funcionário, obter todos os departamentos nos quais ele já trabalhou: SELECT d.nome FROM departamento d WHERE EXISTS (SELECT cd.codigoCargo FROM cargoDep cd WHERE cd.codigoDep = d.codigo AND EXISTS (VALIDTIME SELECT f.codigoCargoDep FROM funcionario f WHERE f.codigo = :CODIGO AND f.codigoCargoDep = cd.codigoCargoDep)); Obter a média de salário do funcionário durante todo o tempo em que esteve empregado: NONSEQUENCED VALIDTIME SELECT AVG(salario) FROM Funcionario WHERE codigo = :CODIGO; Obter o número de funcionários que trabalham atualmente na empresa: NONSEQUENCED VALIDTIME SELECT COUNT(f.codigo) FROM funcionario f WHERE (END(VALIDTIME(f)) = FOREVER); Obter o maior e o menor salário pago atualmente na empresa: NONSEQUENCED VALIDTIME SELECT MAX(f.salario) FROM Funcionario f WHERE (END(VALIDTIME(f)) = FOREVER); NONSEQUENCED VALIDTIME SELECT MIN(f.salario) FROM Funcionario f WHERE (END(VALIDTIME(f)) = FOREVER); Obter o maior e o menor salário já pago na empresa: NONSEQUENCED VALIDTIME SELECT MAX(f.salario) FROM Funcionario f; NONSEQUENCED VALIDTIME SELECT MIN(f.salario) FROM Funcionario f; Listar os departamentos existentes na empresa e os maiores e menores salários atuais de cada departamento: SELECT cd.codigoDep, d.nome, MAX(f.salario) FROM CargoDep cd, Departamento d, Funcionario f WHERE f.codigoCargoDep = cd.codigoCargoDep AND cd.codigoDep = d.codigo GROUP BY cd.codigoDep, d.nome; SELECT cd.codigoDep, d.nome, MIN(f.salario) FROM CargoDep cd, Departamento d, Funcionario f WHERE f.codigoCargoDep = cd.codigoCargoDep AND cd.codigoDep = d.codigo GROUP BY cd.codigoDep, d.nome; Listar o número de funcionários existentes atualmente em cada departamento: SELECT cd.codigoDep, d.nome, COUNT(f.codigo) FROM CargoDep cd, Departamento d, Funcionario f WHERE f.codigoCargoDep = cd.codigoCargoDep AND cd.codigoDep = d.codigo GROUP BY cd.codigoDep, d.nome; 5. Questões Atuais Atualmente é difı́cil encontrar um suporte à informações temporais em SGBDs comerciais, o que dificulta bastante a construção de aplicações que necessitam manipular dados temporais por motivos já mostrados nas seções anteriores. O que é encontrado hoje são extensões de SGBDs que dão suporte à manipulação de dados temporais, porém em tais extensões os esforços são geralmente concentrados em algumas caracterı́sticas especiais como estruturas de dados temporais, projeto da linguagem de consulta, álgebra temporal ou restrições de integridade temporal. Por esse motivo, [Steiner 1998] argumenta que esta abordagem está a “metade do caminho” da abordagem ideal, que seria a generalização de um modelo de dados. 6. Conclusões e Tendências Futuras A tendência natural é que seja criado um novo modelo de dados que tenha suporte à manipulação de informações temporais. Pois apesar das extensões de modelos de dados não-temporais proporcionarem essa manipulação, existem restrições as quais só podem ser eliminadas com a construção de um novo modelo. Com respeito a generalização das operações da álgebra temporal, um passo já foi tomado sendo definido o conceito de completeza temporal (temporal completeness) [Böhlen and Marti 1994] que introduz requerimentos proveitosos a respeito de dados e consultas temporais. Neste trabalho foi estudado o conceito de banco de dados temporais e a ferramenta TimeDB que serve como uma camada para tradução de SQLs temporais em SQLs padrões. O TimeDB mostrou-se uma ferramenta de grande valia no auxilio da implementação de aplicações temporais, no entanto algumas necessidades foram sentidas, como por exemplo, ao incluir um novo registro com o mesmo valor de chave primária de um registro com tempo final de validade “forever”, este não é finalizado. A finalização dos registros com o tempo final em aberto só foi realizada, em nossos testes, através do comando de exclusão. Ou seja, o TimeDB possibilita a realização de operações temporais em um banco de dados, no entanto em alguns casos é necessário que o programador interfira criando conjuntos de operações para atingir um estado do banco que poderia ser atingido de forma automática. References Böhlen, M. and Marti, R. (1994). On the completeness of temporal database query languages. In Gabbay, D. M. and Ohlbach, H.-J., editors, Temporal Logic: 1st International Conference (ICTL’94), pages 283–300. Springer, Berlin, Heidelberg. Steiner, A. (1998). A Generalisation Approach to Temporal Data Models and their Implementations. PhD thesis, Swiss Federal Institute of Technology. Steiner, A. (1999). TimeDB 2.0. http://www.timeconsult.com. Acessado em junho de 2006.