Você está na página 1de 59

Sistemas de Base de Dados

Análise do SGBD PostgreSQL

Bruno Barão nº28061


Fábio Afonso nº30218
Hugo Fernandes nº28062
Quarta-Feira, 9 de Dezembro de 2009 SBD: Análise do SGBD PostgreSQL

Índice de Conteúdos
Índice de Conteúdos............................................................................................... ii
Introdução.............................................................................................................. 1
Introdução Histórica.......................................................................................... 1
Cobertura SQL....................................................................................................... 2
Tipos de Dados...................................................................................................3
Tipos Numéricos............................................................................................3
Tipo Monetário.............................................................................................. 3
Tipos Carácter............................................................................................... 3
Tipos de Dados Binários................................................................................ 3
Tipo Data/Hora.............................................................................................. 4
Tipo Booleano................................................................................................ 4
Tipos Geométricos......................................................................................... 4
Tipo Endereço de Rede..................................................................................5
Tipo UUID......................................................................................................5
Arrays............................................................................................................ 5
Tipos Compostos............................................................................................6
Tipo Identifcador de Objectos (OID).............................................................6
Pseudo-Tipos..................................................................................................7
DML (Data Manipulation Language).................................................................8
Select.............................................................................................................8
Insert............................................................................................................. 8
Update........................................................................................................... 8
Delete............................................................................................................ 9
DDL (Data Defnition Language)......................................................................10
Create Table................................................................................................ 10
Alter Table................................................................................................... 10
Drop Table................................................................................................... 11
Restrições.................................................................................................... 11
Chave-Primária (Primary Key)................................................................ 11
Chave Estrangeira...................................................................................12
Unique.....................................................................................................12
Check...................................................................................................... 13
Not-Null.................................................................................................. 14
Herança...................................................................................................15
With.........................................................................................................15
Triggers...................................................................................................15
Assertion................................................................................................. 16
Armazenamento e File Structure......................................................................... 17
Database File Layout....................................................................................... 17
Toast (The Oversized-Attribute Storage Technique.........................................19
Free Space Map (FSM).................................................................................... 20
Visibility Map (VM).......................................................................................... 20
Database Page Layout......................................................................................20
Indexação e Hashing............................................................................................ 22
Tipos de Índices............................................................................................... 24
B-tree...........................................................................................................24
Hash............................................................................................................ 24
GiST............................................................................................................. 24
Índices Multi-Coluna........................................................................................ 25

ii
Quarta-Feira, 9 de Dezembro de 2009 SBD: Análise do SGBD PostgreSQL

Índices e ORDER BY........................................................................................ 26


Combinação de Múltiplos Índices.................................................................... 27
Unicidade......................................................................................................... 28
Índices em Expressões.....................................................................................29
Índices Parciais................................................................................................ 29
Classes de Operadores e Famílias de Operadores........................................... 30
Análise de Uso dos Índices.............................................................................. 31
Processamento e Optimização de Perguntas........................................................32
Representação Interna das Perguntas............................................................. 34
Reescrita de Perguntas.................................................................................... 35
Optimização e Planeamento.............................................................................36
Transformação de Perguntas.......................................................................36
Análise de Perguntas................................................................................... 37
Geração de Planos....................................................................................... 38
Algoritmos de Junção...................................................................................38
Modelo de Custo..........................................................................................39
Gestão de transacções e controlo de concorrência.............................................. 41
Savepoints........................................................................................................42
Lidar com a consistência..................................................................................43
Isolamento das transacções............................................................................. 43
Nível de Isolamento: Read Committed........................................................ 44
Nível de Isolamento: Serializable................................................................ 45
Locks................................................................................................................46
Locks ao nível da tabela.............................................................................. 46
Locks ao nível das linhas............................................................................. 49
Deadlocks.........................................................................................................49
Advisory Locks................................................................................................. 50
Suporte para Bases de Dados Distribuídas.......................................................... 51
Outras características do sistema estudado.........................................................52
Stored Functions..............................................................................................52
Triggers........................................................................................................... 52
Database Connectivity..................................................................................... 53
Suporte para XML............................................................................................53
Ferramentas.....................................................................................................54
Conclusão............................................................................................................. 55
Bibliografa........................................................................................................... 56

iii
Quarta-Feira, 9 de Dezembro de 2009 SBD: Análise do SGBD PostgreSQL

Introdução
Neste trabalho iremos abordar o sistema de gestão de bases de
dados PostgreSQL, focando alguns pontos considerados essenciais
no mesmo. Assim, é nosso objectivo contribuir positivamente para a
compreensão dos seguintes temas: Cobertura do SQL,
Armazenamento e File Structure, Indexação e Hashing,
Processamento e Optimização de Perguntas, Gestão de Transacções
e Controlo de Concorrência, Suporte para Bases de Dados
Distribuídas e algumas outras características dos sistema em foco.
De realçar, ainda, que escolhemos este SGBD, dada a sua
aplicação no mercado e, pelo facto, de ser um sistema de código
aberto.

Introdução Histórica
O PostgreSQL é um Sistema de Gestão de Bases de Dados de
código aberto. O seu início aconteceu em 1986, na Universidade de
Berkeley, na California, pela mão de Michael Stonebraker, líder do
projecto. O PostgreSQL começou, no entanto, a ser pensado uns
anos antes. Na verdade, este SGBD é uma evolução do Ingres. O
Ingres, foi outro projecto liderado por Michael Stonebraker que
ainda tentou a sua comercialização após abandonar,
temporariamente, a universidade. Contudo, acabou por retomar a
mesma e criar, então, o PostgreSQL, tendo em vista resolver
problemas com o modelo anterior, o Ingres. Na verdade, o nome
que resultou da evolução do Ingres foi Postgres e, só mais tarde,
em 1996, se passou a chamar PostgreSQL, tendo como objectivo
refectir a nova linguagem de consulta à base de dados, o SQL. A
primeira versão do PostreSQL, a 6.0, foi disponibilizada em 1997 e,
desde então, conta com milhares de contribuidores em todo o
mundo.
À data da realização deste trabalho, a versão mais actual do
PostgreSQL é a 8.4.1.

1
Quarta-Feira, 9 de Dezembro de 2009 SBD: Análise do SGBD PostgreSQL

Cobertura SQL
O PostgresSQL, tal como a maioria dos sistemas de bases de
dados, procede à implementação de um subconjunto estendido do
SQL. Neste caso concreto é denominado de PL/pgSQL (Procedural
Language/PostgreSQL Structured Query Language). Esta é
baseada na linguagem PL/SQL da Oracle, no entanto nem sempre
foi assim. Nos seus primórdios para interrogar e gerir a base de
dados utilizava-se uma linguagem de nome POSTQUEL. Somente a
partir de 1995 é que esta alteração surgiu pelas mãos de dois
estudantes de doutoramento dos laboratórios da Stonebraker,
Andrew Yu e Jolly Chen.
Além de ser possível escrever consultas de SELECT, manipular
objectos DDL e dados DML em PL/pgSQL, podemos ainda integrar
a base de dados com outras linguagens procedurais tais como
PL/TCL, PL/Perl ou PL/Python.
Passamos a enunciar os tipos de dados suportados por este
sistema de gestão de base de dados, bem como comandos
disponíveis no PL/pgSQL.

2
Quarta-Feira, 9 de Dezembro de 2009 SBD: Análise do SGBD PostgreSQL

Tipos de Dados
São suportados todos os tipos básicos do SQL, no entanto neste
SGBD foram ainda incluídos tipos e mecanismos mais elaborados,
tais como vectores, funções e a noção de herança.

Tipos Numéricos

Tipo Monetário

Tipos Carácter

Tipos de Dados Binários

3
Quarta-Feira, 9 de Dezembro de 2009 SBD: Análise do SGBD PostgreSQL

Tipo Data/Hora

Tipo Booleano

Tipos Geométricos

4
Quarta-Feira, 9 de Dezembro de 2009 SBD: Análise do SGBD PostgreSQL

Tipo Endereço de Rede

Tipo UUID
Os Universally Unique Identifers ou Global Unique Identifers não
são mais do que uma sequência de 128-bits que pretende
identifcar um objecto de forma inequívoca. Poderá parecer uma
redundância se tivermos em conta as sequências, mas estas apenas
permitem a identifcação única exclusivamente na base de dados.
Para tais sequências o PostgreSQL aceita a defnição de qualquer
um deste tipo, equivalente, de sequências:
• a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11
• A0EEBC99-9C0B-4EF8-BB6D-6BB9BD380A11
• {a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11}
• a0eebc999c0b4ef8bb6d6bb9bd380a11
• a0ee-bc99-9c0b-4ef8-bb6d-6bb9-bd38-0a11
• {a0eebc99-9c0b4ef8-bb6d6bb9-bd380a11}

Embora no seu core não tenha um algoritmo de geração de


UUID’s, a extensão contrib/uuid-ossp fornece essa capacidade.

Arrays
Podem ser defnidos vectores de qualquer tipo suportado por este
SGBD ou criados pelo utilizador, no entanto não existe ainda
suporte para vectores de domínios.
Podemos criar este tipo de dados de duas formas distintas, como
podemos ver a baixo, sendo que estas são equivalentes, pois o
PostgreSQL trata todos os vectores adoptando a segunda defnição.

5
Quarta-Feira, 9 de Dezembro de 2009 SBD: Análise do SGBD PostgreSQL

Sintaxe:
field_name field_type ARRAY[array_length]
ou
field_name field_type ARRAY

Tipos Compostos
Representam a estrutura de uma linha ou um registo. Podemos
utilizar este tipo de dados exactamente da mesma forma que um
qualquer tipo nativo disponibilizado.
Sintaxe:
CREATE TYPE complex_name AS (
field_name field_type,
field_name field_type
);

Tipo Identifcador de Objectos (OID)


Os identifcadores de objecto são utilizados internamente pelo
PostgreSQL como chaves primárias para várias tabelas do sistema.
Somente são associados a tabelas criadas pelo utilizador se, a
quando da criação da tabela, a opção WITH OID seja explicitada, ou
caso se encontre activa a variável de sistema DEFAULT_WITH_OIDS
(BOOLEAN).
Estes são defnidos como um inteiro de quatro bytes sem sinal,
dessa forma não poderão ser considerados sufcientemente grandes
para que seja possível garantir unicidade a todos os elementos de
uma base de dados, ou mesmo a tabelas num domínio
relativamente grande, assim sendo apenas deverão ser utilizados
para identifcar componentes do sistema.

6
Quarta-Feira, 9 de Dezembro de 2009 SBD: Análise do SGBD PostgreSQL

Pseudo-Tipos
O PostgreSQL contém um certo número de entradas especiais que
são colectivamente chamadas de pseudo-tipos. Estes podem ser
utilizados para declarar um argumento de uma função ou o seu tipo
de retorno. Cada um destes tipos de dados disponíveis tornam-se
bastante úteis em situações onde o comportamento de uma função
não corresponde a simplesmente aceitar ou devolver um valor de
um determinado tipo de dados SQL.

7
Quarta-Feira, 9 de Dezembro de 2009 SBD: Análise do SGBD PostgreSQL

DML (Data Manipulation Language)


A linguagem de manipulação de dados do SQL inclui comandos
para seleccionar, actualizar, inserir e apagar registos.

Select
Retorna linhas de zero ou mais tabelas
Sintaxe:
SELECT [ALL | DISTINCT [ON (expression [,...])]]*
| expression [[AS] output_name] [, ...]
[FROM from_item [,...]]
[WHERE condition]
[GROUP BY expression [,...]]
[HAVING condition [,...]]

Insert
Insere novos registos numa tabela. Caso sejam especifcados por
valor irão ser inseridas uma ou mais linhas, se estes advirem de
uma consulta poderão ser inseridas várias linhas ou nenhuma,
dependendo do resultado desta.
Sintaxe:
INSERT INTO table [(column [,...])]
{DEFAULT VALUES | VALUES ({xpression | DEFAULT}
[, ...]) [, ...] | query}
[RETURNING * | output_expression [[AS] output_name]
[,...]]

Update
Altera os valores de todas as linhas da coluna indicada que
satisfaçam a condição enunciada.
Sintaxe:
UPDATE [ONLY] table [[AS] alias]
SET {column = {expression | DEFAULT} | (column
[, ...]) = ({expression | DEFAULT}[, …])} [, …] [FROM fromlist]
[WHERE condition | WHERE CURRENT OF cursor_name]
[RETURNING * | output_expression
[[AS] output_name] [,...]]

8
Quarta-Feira, 9 de Dezembro de 2009 SBD: Análise do SGBD PostgreSQL

Delete
Remove os tuplos da tabela enunciada que satisfaçam a cláusula
where. Caso esta seja omissa toda a tabela é apagada sendo
retornada uma vazia.
Sintaxe:
DELETE FROM [ONLY] table [[AS] alias]
[USING usinglist]
[WHERE condition | WHERE CURRENT OF cursor_name]
[RETURNING * | output_expression [[AS] output_name] [,...] ]

9
Quarta-Feira, 9 de Dezembro de 2009 SBD: Análise do SGBD PostgreSQL

DDL (Data Defnition Language)


De forma a ser possível a manipulação de tabelas, a linguagem de
defnição de dados SQL possui as funções a baixo sucintamente
descritas.

Create Table
Cria uma nova tabela vazia na base de dados. Esta tabela pode
ainda ser temporária ou persistente. Caso se enquadre na segunda
opção poderá ser criada segundo um schema pré-defnido pelo
utilizador, ou utilizara o corrente caso nenhum seja explicitado. Já
as tabelas temporárias são sempre criadas obedecendo a um
schema especial.
Sintaxe:
CREATE [[GLOBAL | LOCAL] {TEMPORARY | TEMP}] TABLE table_name
([{column_name data_type [DEFAULT default_expr] [column_constraint
[...]]
| table_constraint | LIKE parent_table
[{INCLUDING | EXCLUDING} {DEFAULTS | CONSTRAINTS
| INDEXES}] ...} [,...]])
[INHERITS (parent_table [,...])]
[WITH (storage_parameter [=value] [,...]) | WITH OIDS
| WITHOUT OIDS]
[ON COMMIT {PRESERVE ROWS | DELETE ROWS | DROP}]
[TABLESPACE tablespace]

Alter Table
Modifca a forma como uma tabela existente na base de dados foi
previamente defnida.
Sintaxe:
ALTER TABLE [ONLY] name [*]
action [,... ]

ALTER TABLE [ONLY] name [*]


RENAME [COLUMN] column TO new_column
ALTER TABLE name
RENAME TO new_name
ALTER TABLE name
SET SCHEMA new_schema

10
Quarta-Feira, 9 de Dezembro de 2009 SBD: Análise do SGBD PostgreSQL

Drop Table
Procede à remoção de tabelas da base de dados. Apenas os seus
donos as podem remover.
Caso se deseje somente apagar as linhas da tabela deveremos
utilizar a função DELETE ou TRUNCATE, sendo esta última uma
extensão do PostgresSQL.
Sintaxe:
DROP TABLE [IF EXISTS] name [,...] [CASCADE | RESTRICT]

Restrições

Chave-Primária (Primary Key)


A restrição chave primária pode ser visto como a conjugação de
duas outras, NOT NULL com UNIQUE, assim sendo esta não é mais
do que uma especifcação que obriga a existência de valores únicos
e não nulos numa coluna (ou colunas) de uma determinada tabela.
Cada tabela somente pode ter uma chave primária, sendo
indiferente que esta seja defnida como uma restrição de coluna ou
de tabela.
Passaremos a demonstrar as sintaxes utilizadas para criar uma
chave primária a aquando da criação de uma tabela bem como ao
alterar uma previamente existente.
• Na criação de uma tabela
CREATE TABLE table_name (
...
field_name field_type PRIMARY KEY
...
);

• Alteração de uma tabela existente


ALTER TABLE table_name ADD CONSTRAINT constraint_name PRIMARY KEY
(field_name);

11
Quarta-Feira, 9 de Dezembro de 2009 SBD: Análise do SGBD PostgreSQL

Chave Estrangeira
Uma Chave Estrangeira corresponde a uma ou mais colunas que
servirá para estabelecer uma ligação entre dados de duas tabelas.
Esta restrição é defnida a quando da criação de uma nova tabela,
ou quando se procede a uma alteração numa existente.
Uma chave estrangeira existe na tabela (T2) quando a chave
primária de uma tabela (T1) é referenciada nesta. Será ainda criada
uma restrição deste tipo se, em vez de ser referenciada a chave
primária de T1 sejam referenciadas colunas desta do tipo UNIQUE.
Dependendo da forma de correspondência de padrões poderão
existir valores nulos nestes campos. No caso de ser Match Full só
existirão valores nulos numa coluna caso todos os valores das
colunas da chave estrangeira sejam nulos. Caso seja Match Simple
o critério é menos rígido, pois permite que algumas das colunas da
chave estrangeira sejam nulas e outras sejam não nulas.
• Na criação de uma tabela
CREATE TABLE table_name (
...
field_name field_type REFERENCES other_table_name
(other_field_name)
...
);

• Alteração de uma tabela existente


ALTER TABLE table_name ADD CONSTRAINT constraint_name FOREIGN KEY
(field) REFERENCES other_table_name(other_field_name);

Unique
A restrição UNIQUE especifca um grupo de uma ou mais colunas da
tabela referida somente poderá conter valores únicos. O
comportamento da restrição de tabela é exactamente igual ao de
coluna, com a diferença de no primeiro pode abranger várias
colunas simultaneamente.
Para efeitos de uma restrição de unicidade os valores nulos não
são considerados iguais.
Cada restrição da tabela original deve nomear um conjunto de

12
Quarta-Feira, 9 de Dezembro de 2009 SBD: Análise do SGBD PostgreSQL

colunas que é diferente do conjunto de colunas abrangido por uma


restrição exclusiva ou outra chave primária defnida para a tabela.
Caso tal não se verifcasse apenas teríamos a mesma restrição
listada duas vezes.
• Na criação de uma tabela
CREATE TABLE table_name(
...
field_name field_type,
...
UNIQUE (field_name)
);

ou

CREATE TABLE table_name(


...
field_name field_type CONSTRAINT constraint_name
UNIQUE (field_name)
);

• Alterar uma tabela existente


ALTER TABLE table_name ADD CONSTRAINT
constraint_name UNIQUE (feld_name);

Check
A cláusula CHECK pode ser vista como uma função booleana que as
novas linhas a serem inseridas na tabela têm de satisfazer de forma
à operação ser bem sucedida. Somente as expressões que retornam
FALSE não têm sucesso, assim sendo resultados como TRUE e
UNKNOWN são vistos como aceitáveis.
Uma restrição deste tipo especifcada para uma coluna apenas
deve verifcar o valor desta, caso seja declarada a quando da
criação da tabela poderá referenciar várias.
Na actualidade expressões deste tipo não podem referir colunas
de diferentes linhas nem conter sub-consultas.

13
Quarta-Feira, 9 de Dezembro de 2009 SBD: Análise do SGBD PostgreSQL

• Na criação de uma tabela


CREATE TABLE table_name(
...
field_name field_type CHECK (logic_expression)
);

ou

CREATE TABLE table_name(


...
field_name field_type CONTRAINT constraint_name CHECK
(logic_expression)
);

• Alterar uma tabela existente


ALTER TABLE table_name ADD CONSTRAINT constraint_name CHECK
(logic_expression);

Not-Null
A restrição de não nulidade obriga a que uma ou mais colunas não
possam tomar valores nulos. Esta não é mais do que uma restrição
de CHECK(feld_name NOT NULL), mas neste sistema de base de
dados é bem mais efciente criar campos que não podem assumir
valores nulos desta forma.
Existe uma restrição inversa a esta denominada de NULL, isto não
signifca que todos os elementos da tabela têm de ser nulos, mas
sim que o seu valore por defeito é esse. Este tipo não está presente
no SQL standard apenas foi adicionado ao PostgresSQL por uma
questão de compatibilidade com outros sistemas de bases de dados,
devido a isso não deve ser usados em sripts que assumam
portabilidade.
Ambas as restrições podem ser defnidas tanto na criação de uma
nova tabela, mas somente a de não nulidade pode ser defnida na
alteração de uma tabela existente.

14
Quarta-Feira, 9 de Dezembro de 2009 SBD: Análise do SGBD PostgreSQL

• Na criação de uma tabela


CREATE TABLE table_name(
...
field_name field_type NOT NULL
...
);

CREATE TABLE table_name(


...
field_name field_type NULL
...
);

• Alterar uma tabela existente


ALTER TABLE [ONLY] table_name [*]

ALTER [COLUMN] column_name {SET | DROP} NOT NULL

Herança
O mecanismo de herança múltipla é disponibilizado como uma
extensão ao standard SQL. Este não é mais do que o mecanismo de
herança singular, mas com diferente sintaxe.

With
Esta cláusula é uma extensão feita pelo sistema de gestão de base
de dados ao SQL standard. Tal tornou-se necessário para, por
exemplo, permitir algum controlo aos identifcadores de objectos
gerados a quando da criação de uma tabela.

Triggers
Um TRIGGER é uma especifcação da base de dados que executa
automaticamente uma determinada função sempre que um
determinado tipo de operação é desencadeada. Este pode ser
defnido para ser executado, uma vez por linha ou uma vez por

15
Quarta-Feira, 9 de Dezembro de 2009 SBD: Análise do SGBD PostgreSQL

instrução SQL, antes ou depois de qualquer operação de INSERT,


UPDATE ou DELETE.
A função deste deve ser criada antes dele próprio, esta não recebe
argumentos e retorna o tipo TRIGGER. Poderá ser escrita em
qualquer linguagem procedural.
Sintaxe:
CREATE TRIGGER name {BEFORE | AFTER} {event [OR...]} ON table
[FOR [EACH] {ROW | STATEMENT}] EXECUTE PROCEDURE function_name
(arguments)

Assertion
O PostgresSQL não suporta a criação de asserções, no entanto é
possível garantir a mesma integridade oferecida por estes
mecanismos através das restrições a cima enunciadas.

16
Quarta-Feira, 9 de Dezembro de 2009 SBD: Análise do SGBD PostgreSQL

Armazenamento e File Structure

Database File Layout


Começaremos por descrever o armazenamento ao nível de
fcheiros e directorias.
O SGBD PostgreSQL procede ao armazenamento dos seus dados
em fcheiros assente no sistema de fcheiros gerido pelo sistema
operativo anftrião. Os dados são guardados numa directoria
denominada PGDATA, sendo que esta por omissão aponta para
/var/lib/pgsql/data. Aqui serão encontrados todos os fcheiros e
directorias necessários para o sistema armazenar e gerir os dados,
bem como alguns fcheiros de confguração. Passa-mos então a
explicitar o conteúdo da directoria PGDATA.

Caso a base de dados seja portadora de clusters irá ser criado um


subdirectório de nome PGDATA/BASE, herdando este o nome do OID
da base de dados presente em PG_DATABASE.
Cada tabela e índice são armazenados num fcheiro distinto, sendo
que, ao excederem o tamanho de um gigabyte o PostgreSQL
procede automaticamente à divisão deste em pedaços de tamanho
mais reduzido. Enquanto o primeiro pedaço é baptizado com o
nome do fcheiro (FILENODE), as restantes partes herdam o mesmo
nome recebendo o número de partição após um ponto (FILENODE.N,
de onde N é o número de partição do fcheiro que varia entre um e

17
Quarta-Feira, 9 de Dezembro de 2009 SBD: Análise do SGBD PostgreSQL

número total de partições do fcheiro de nome FILENODE). Isto é


necessário pois alguns sistemas não puderem suportar fcheiros de
tamanho elevado.
Qualquer tabela com atributos potencialmente grandes terá uma
tabela TOAST associada. Esta possibilita o armazenamento de
valores fora das linhas da tabela original (seguidamente tal será
explicado em mais detalhe).
Ficheiros temporários, como os usados para ordenar dados que
não cabem em memória, são criados em PGDATA/BASE/PGSQL_TEMP ou
dentro de uma subdirectoria sua.

18
Quarta-Feira, 9 de Dezembro de 2009 SBD: Análise do SGBD PostgreSQL

Toast (The Oversized-Attribute


Storage Technique
O PostgreSQL usa um tamanho de página fxo, por norma de oito
kilobytes, sendo que cada tuplo não pode ultrapassar uma página.
Assim sendo, não é possível armazenar directamente linhas com
atributos muito grandes. De forma a ser possível ultrapassar esta
limitação o sistema comprime ou divide atributos grandes em
enumeras linhas físicas. De notar ainda que este fenómeno
acontece transparentemente para o utilizador.
Esta técnica somente é utilizada quando o tamanho de um tuplo é
superior a um quarto do tamanho do bloco. Nesses casos procede-
se à redução, por compressão dos campos, do tamanho da linha. Se
tal falhar, ou seja, a compressão foi insufciente, o sistema procede
ao armazenamento dos dados numa outra tabela (OUT_OF_LINE),
sendo armazenada uma referência na tabela original. A aplicação
destas técnicas é feita de forma cíclica até se obter o resultado
desejado ou este seja o melhor possível.
Tais características tornam este método bastante útil e vantajoso
em relação com outras aproximações pois, ao ter um tamanho
reduzido a tabela principal e os dados referenciados somente são
acedidos após cada operação, pode-mos concluir que certas
operações, tais como ordenações, serão facilitadas.

19
Quarta-Feira, 9 de Dezembro de 2009 SBD: Análise do SGBD PostgreSQL

Free Space Map (FSM)


Cada pilha e índice relacional, excepto os índices de hash,
possuem um mapa de espaço livre de forma a terem a noção do
restante espaço disponível. Este é guardado conjuntamente com os
dados principais sob o nome FILENODE_FSM, sendo que o nome do
fcheiro principal é FILENODE.
O FSM encontra-se organizado numa estrutura de árvore.
Enquanto os níveis superiores armazenam informação referentes
aos níveis inferiores, o último nível guarda o restante espaço livre
para cada pilha ou índice.

Visibility Map (VM)


Todas as pilhas relacionais possuem um mapa de visibilidade para
terem a noção de quais os tuplos visíveis para cada transacção em
cada instante. Esta encontra-se armazenada com a relação
principal tendo o nome de FILENODE_VM, sendo o nome de fcheiro é
FILENODE. De notar que os índices não são possuidores deste tipo de

estruturas.
O VM apenas guarda um bit para cada página da pilha. A
defnição de um conjunto de bits signifca que todos os tuplos
devem ser visíveis para todas as transacções, o mesmo é dizer que
não é preciso proceder à aspiração (VACCUM) dos mesmos.
Futuramente podemos ainda utilizar esta estrutura para evitar
visitas à página com o intuito de fazer verifcações de visibilidade.
No entanto, a exploração do mapa apenas no permite concluir que
a condição é verdadeira caso o bit esteja defnido, caso contrario
nada podemos concluir.

Database Page Layout


Finalmente iremos descrever a forma de armazenamento das
tabelas e dos índices. De registar que tanto as tabelas TOAST como
as de sequência seguem o mesmo formato.
Cada fcheiro procederá ao armazenamento da informação

20
Quarta-Feira, 9 de Dezembro de 2009 SBD: Análise do SGBD PostgreSQL

relativa a índices ou tabelas. No caso das tabelas será guardada


informação referente às linhas, enquanto nos índices iremos
guardar as suas entradas. Abstendo-nos das diferenças entre
ambos vamos apelida-los de itens.
O fcheiro é constituído por um vector de páginas, sendo que cada
uma delas vai conter os itens a ser armazenados. Nos índices existe
uma ligeira diferença, pois a primeira página encontra-se reservada
para o armazenamento de informação respeitante aos dados de
controlo deste.
A tabela a baixo contém a informação correspondente às várias
parcelas das páginas dos fcheiros de armazenamento.

21
Quarta-Feira, 9 de Dezembro de 2009 SBD: Análise do SGBD PostgreSQL

Indexação e Hashing
Numa base de dados, a criação de índices são uma forma de as
bases de dados melhorarem a performance. Isto é, através dos
índices é possível, numa tabela, encontrar, mais rapidamente, as
linhas, que nos interessam. No entanto, a utilização deste recurso
acrescenta overhead ao sistema de base de dados.

Os índices numa base de dados assemelham-se aos índices


remissivos dos livros. Nestes, os leitores podem navegar pelas
diversas páginas, indo de encontro ao que procuram, sem terem
que ler o livro todo. Já na base dados, signifca que o sistema não
necessita de percorrer a tabela toda.

Suponhamos ter a seguinte tabela:


CREATE TABLE test1 (
id integer,
content varchar
);

Se a aplicação fzer muitas perguntas da seguinte forma:


SELECT content FROM test1 WHERE id = constant;

Sem nenhum tipo de preparação o sistema teria que percorrer a


tabela test1, linha por linha, para encontrar todas entradas que
satisfazem a pergunta. Se se der o caso de ser uma tabela com
muitas linhas e em que apenas algumas (poderão até ser 0 ou 1)
sejam retornadas pela pergunta, este método é, claramente,
inefciente.

Assim, para se criar um índice sobre a coluna id, deve-se usar o


seguinte comando:
CREATE INDEX test1_id_index ON test1 (id);

22
Quarta-Feira, 9 de Dezembro de 2009 SBD: Análise do SGBD PostgreSQL

De modo análogo, para se remover um índice, o comando a usar é


DROP INDEX.

Uma vez criados, os índices não necessitam de intervenção uma


vez que o sistema automaticamente os actualiza quando a tabela é
modifcada e os usa em perguntas quando achar que as torna mais
efcientes. Neste último caso o sistema usa estatísticas que lhe
permitem tomar decisões “fundamentadas” (educated decisions).
Deste modo, é útil que regularmente se corra o comando ANALYZE
para actualizar as referidas estatísticas.
Para além de aumentar a performance nas situações acima
referidas, os índices podem ainda melhora-la nas instruções de
UPDATE, DELETE ou mesmo de JOIN.

Contudo, a criação de índices também tem desvantagens como a


demora na criação dos mesmos sobre grandes tabelas. Por defeito,
o PostgreSQL permite leituras (operação SELECT) em paralelo com
a criação do índice. No entanto, bloqueia todas as operações de
escrita (INSERT, UPDATE, DELETE) enquanto a indexação não
termina. A juntar a isto, o facto de o sistema manter o índice
sincronizado com a tabela acrescenta overhead às operações de
manipulação dos dados. Assim, índices raramente ou nunca usados
devem ser eliminados.

23
Quarta-Feira, 9 de Dezembro de 2009 SBD: Análise do SGBD PostgreSQL

Tipos de Índices
O PostgreSQL oferece quatro tipos diferentes de estruturas para
indexação. São elas: B-tree, Hash, GiST e GIN. Cada um dos tipos
usa diferentes algoritmos apropriados a distintos tipos de
perguntas.

B-tree
Por defeito, o comando CREATE INDEX cria índices B-tree. Em
particular, o PostgreSQL utiliza B-tree quando a coluna indexada
está envolvida em comparações que utilizam os seguintes
operadores: <, <=, = >=, >. Construções equivalentes como
BETWEEN e IN poderão também usar este tipo de estrutura. É
ainda possível possível utilizar B-tree com a condição IS NULL
sobre a coluna a indexar.

Hash
Ao contrário das B-tree, os índices Hash só conseguem lidar com
comparações de igualdade. Deste modo, poderá ser útil usar esta
estrutura quando a coluna a indexar está envolvida em
comparações que usem o operador =. Opostamente às B-tree, os
índices Hash não suportam pesquisas IS NULL.
Para se usar, explicitamente, a estrutura Hash terá que se fazer o
seguinte comando:
CREATE INDEX name ON table USING hash (column);

GiST
GiST (Generalized Search Tree) é uma estrutura em árvore usada
para construir diferentes esquemas de indexação, como as árvores
B e R.
Na distribuição standard do PostgreSQL a classe GiST suporta
perguntas que usem os seguintes operadores: <<, &<, &>, >>,
<<|, &<|, |&>, |>>, @>, <@, ~= e &&.

24
Quarta-Feira, 9 de Dezembro de 2009 SBD: Análise do SGBD PostgreSQL

GIN são índices invertidos que suportam valores com mais de uma
chave (vectores, por exemplo). Como o GiST, os índices GIN
suportam diferentes tipos de estratégias de indexação defnidas
pelo utilizador.

Índices Multi-Coluna
Como o nome sugere, índices multi-coluna, são índices defnidos
sobre mais do que uma coluna da tabela. Consideremos a seguinte
tabela:
CREATE TABLE test2 (
major int,
minor int,
content varchar
);

Suponhamos, ainda, que recorrentemente fazemos perguntas


como a seguinte:
SELECT name FROM test2 WHERE major = constant AND minor = constant;

Neste caso, poderá ser apropriado defnir um índice sobre as


colunas major e minor:
CREATE INDEX test2_mm_idx ON test2 (major, minor);

Actualmente, apenas índices B-tree, GiST e GIN suportam


indexação multi-coluna. O limite, por defeito, são 32 colunas,
contudo, é possível alterá-lo.

Os índices multi-coluna B-tree podem ser usados com perguntas


que envolvam qualquer subconjunto das colunas indexadas mas o
índice torna-se mais efciente quando existem restrições na coluna
mais à esquerda. A regra exacta é que restrições de igualdade na
coluna mais à esquerda, juntamente com restrições de
desigualdade na primeira coluna que não tem restrição de
igualdade, serão usadas para limitar a porção do índice que será

25
Quarta-Feira, 9 de Dezembro de 2009 SBD: Análise do SGBD PostgreSQL

lido.

Os índices multi-coluna GiST, à semelhança do anterior, também


podem ser usados com perguntas que envolvam qualquer
subconjunto das colunas indexadas. Condições em colunas
adicionais restringem o número de tuplos retornados pelo índice
mas a condição na primeira coluna é a mais importante para
determinar quanto do índice necessita ser lido. Se a primeira
coluna do índice tiver apenas alguns valores distintos, mesmo que
nas outras colunas isto não se verifque, a utilização do GiST é algo
inefcaz.

Não fugindo à regra, os índices GIN também podem ser usados


em perguntas que envolvam qualquer subconjunto das colunas
indexadas. No entanto, ao contrário dos índices anteriores, a
efcácia do mesmo não está dependente das colunas usadas nas
restrições da querie.

Índices e ORDER BY
Por vezes necessitamos que o resultado de uma pergunta respeite
uma determinada ordem. Assim, os índices deverão ter essa mesma
capacidade. Isto poderá ser obtido usando a cláusula ORDER BY.
Actualmente, no PostgreSQL, apenas os índices B-tree conseguem
produzir um resultado de saída ordenado.
Dependendo de alguns factores, o programador deverá considerar
usar a cláusula ORDER BY num índice existente ou percorrer a
tabela física e fazer uma ordenação explícita. Assim, numa
pergunta que necessite ler uma grande parte da tabela, um
ordenação explícita tenderá a ser mais rápida do que a utilização
do índice porque requer menos I/O no disco. Os índices são mais
úteis quando apenas algumas linhas precisam de ser utilizadas. Um
exemplo importante é a utilização de ORDER BY com LIMIT n.
Neste caso, numa ordenação explícita sobre a tabela seria
necessário processar todas as linhas para identifcar as primeiras

26
Quarta-Feira, 9 de Dezembro de 2009 SBD: Análise do SGBD PostgreSQL

n. Ao invés, se houver um índice que respeite a cláusula ORDER BY,


será apenas necessário retornar as primeira n linhas sem termos
que percorrer as restantes.

Por defeito os índices B-tree guardam as entradas de forma


ascendente. Ou seja, o índice assume o seguinte: ORDER BY x ASC
NULLS LAST. Podem ainda ser percorridos de trás para a frente, o
que corresponde a ter ORDER BY x DESC NULLS FIRST.
É ainda possível ajustar a ordem de um índice B-tree, aquando da
sua criação, usando as seguintes opções: ASC, DESC, NULLS
FIRST e/ou NULLS LAST. Vejamos os seguintes exemplos:
CREATE INDEX test2_info_nulls_low ON test2 (info, NULLS FIRST);
CREATE INDEX test3_desc_index ON test3 (id DESC NULLS LAST);

À partida todas estas opções poderão parecer redundantes


quando consideramos índices de uma coluna. Contudo, se
utilizarmos índices multi-coluna constatamos que não é assim.
Consideremos o índice sobre duas colunas x e y. ORDER BY x, y
poderá ser satisfeito se percorrermos o índice por ordem ou, caso
percorramos inversamente, satisfazemos a condição ORDER BY
DESC x, y. No entanto, poderemos querer percorrer x
ascendentemente e y descendentemente e, nesse caso, teremos de
tirar proveito das capacidades de ordenação fornecidas utilizando
(x ASC, y DESC).

Combinação de Múltiplos Índices


Para a que seja feita uma única leitura no índice, só é possível
usar clausulas nas perguntas que usem as colunas do índice com
operadores da sua classe e juntos com AND. Por exemplo, se
tivermos um índice (a, b), uma pergunta do tipo WHERE a = 5 AND
b = 6 poderia usar o índice. Contudo, um pergunta como WHERE a
= 5 OR b = 6 já não podia directamente usar o índice.
Para lidar com situações em que não é possível satisfazer a
pergunta com uma única leitura do índice, o PostgreSQL cria

27
Quarta-Feira, 9 de Dezembro de 2009 SBD: Análise do SGBD PostgreSQL

condições de AND e OR sobre as várias leituras do índice. Por


exemplo, uma pergunta do tipo WHERE x = 42 OR x = 47 OR x =
53 OR x = 99, poderá ser partida em quatro leituras distintas do
índice, cada uma usando uma das cláusulas. O resultado fnal é
calculado fazendo um OR sobre os quatro resultados intermédios
obtidos. O procedimento é análogo para a intersecção (AND).
Internamente, para realizar estas operações, o PostgreSQL lê
cada índice que será necessário e prepara um bitmap em memória
dando a localização das linhas da tabela que correspondem às
condições do índice. Depois, são feitas operações de OR e AND
conforme a pergunta pedida. Por fm, as linhas da tabela são
visitadas e retornadas pela ordem com que são lidas. Ou seja,
qualquer ordem dos índices originais é perdida e será necessário
reordenar, no fm, caso a pergunta tenha a cláusula ORDER BY.
Uma vez que estas operações poderão ser demoradas e consumir
recursos importantes é necessário que o programador analise, por
exemplo, se compensa utilizar esta técnica ou fazer uso dos índices
multi-coluna. Por exemplo, se a maior parte das perguntas envolve
apenas a coluna x, ou a coluna e por vezes as duas, talvez seja
aconselhável criar dois índices separados (para x e y) e utilizar,
quando necessário, a técnica acima descrita.

Unicidade
Os índices poderão ser usados para reforçar a unicidade de
valores numa coluna ou a unicidade da combinação de valores de
várias colunas. Para tal, utiliza-se a seguinte instrução:
CREATE UNIQUE INDEX name ON table (column [, …]);

Actualmente, apenas os índices B-tree suportam esta


funcionalidade.
O PostgreSQL cria automaticamente um índice deste tipo quando
é declarado, na tabela, um campo como UNIQUE ou como chave
primária.

28
Quarta-Feira, 9 de Dezembro de 2009 SBD: Análise do SGBD PostgreSQL

Índices em Expressões
Um índice não precisa apenas de ser uma coluna da tabela “mãe”.
Poderá, também, ser uma expressão calculada a partir de uma ou
mais colunas da tabela. Assim é possível aceder rapidamente a
estes resultados já computados.
Vejamos o exemplo que se segue:
SELECT * FROM test1 WHERE lower(col1) = 'value';

Esta pergunta poderia usar um índice caso este já estivesse


calculado:
CREATE INDEX test1_lower_col1_idx ON test1 (lower(col1));

Para além disso, se defníssemos este índice como UNIQUE,


estaríamos a garantir que não seriam criadas linhas cujos valores
de col1 apenas diferissem no facto de serem maiúsculas ou
minúsculas.

Índices Parciais
Um índice parcial, é um índice construído sobre apenas um
subconjunto da tabela. Esse subconjunto é defnido por uma
expressão condicional chamada predicado do índice parcial. Deste
modo, o índice contém apenas entradas para as linhas da tabela
que satisfazem esse predicado.
Exemplo da criação de um índice parcial para excluir valores
muito comuns:
Consideremos a seguinte tabela:
CREATE TABLE access_log (
url varchar,
client_ip inet,

);

29
Quarta-Feira, 9 de Dezembro de 2009 SBD: Análise do SGBD PostgreSQL

Criemos então o índice parcial:


CREATE INDEX access_log_client_ip_ix ON access_log (client_ip)
WHERE NOT (client_ip > inet '192.168.100.0' AND
client_ip < inet '192.168.100.255');

Um possível exemplo de uma pergunta que usaria o índice é:


SELECT * FROM access_log
WHERE url = '/index.html' AND client_ip = inet '212.78.10.32';

Contudo, a seguinte pergunta não poderia usar o índice uma vez


que o ip pedido foi excluído do índice aquando da sua criação:
SELECT * FROM access_log
WHERE client_ip = inet '192.168.100.23';

A criação deste tipo de índices também pode ser útil para


seguintes situações:
• Excluir valores que não interessam. Isto é, valores que apesar
de poderem estar em menor percentagem na tabela, são os
mais acedidos.
• Quando queremos assegurar a unicidade. Suponhamos ter
uma tabela que descreve os resultados de alguns testes e
queremos assegurar que há apenas uma entrada que obteve
sucesso dada a combinação do assunto e do objectivo apesar
de haver inúmeras entradas sem sucesso.

Classes de Operadores e Famílias de


Operadores
Ao criarmos um índice é possível defnirmos uma classe de
operador para cada coluna de índice. Tal é feito da seguinte forma:
CREATE INDEX name ON table (cloumn opclass [sort options] [, …]);

As classes de operadores servem para modifcarmos o


comportamento padrão adoptado pelo PostgreSQL aquando da

30
Quarta-Feira, 9 de Dezembro de 2009 SBD: Análise do SGBD PostgreSQL

criação de um índice. Isto é, podemos querer que os valores objecto


de comparação sejam comparados de uma ou outra maneira.
Tomemos como exemplo a ordenação de um número complexo.
Neste caso, poderemos querer ordenar pela parte inteira ou pela
parte fraccionária.

Análise de Uso dos Índices


O PostgreSQL não exige manutenção dos índices. No entanto, é
importante ir verifcando quais os índices realmente usados.
Apesar de haverem algumas dicas possíveis de seguir, não existe
nenhum procedimento “correcto” para determinar quais os índices
a criar.

31
Quarta-Feira, 9 de Dezembro de 2009 SBD: Análise do SGBD PostgreSQL

Processamento e Optimização de
Perguntas
Segundo Silberschatz, Korth e Sudarshan em Database System
Concepts, a optimização de perguntas é o processo de selecção do
plano mais efciente, de entre várias estratégias alternativas
possíveis, para a execução de uma dada interrogação.

Vejamos primeiro, em imagem, a sequência de actividades de


processamento de perguntas no PostgreSQL.

Como se vê na fgura, quando o PostgreSQL recebe uma nova


pergunta procede à sua análise léxica, sintáctica e semântica.
Durante a fase da análise léxica, é feita uma leitura sequencial dos
caracteres que constituem a interrogação, separam-se os
caracteres em palavras e o faz-se o reconhecimento dos vocábulos
representados por cada palavra (ex.: cláusula SELECT, nome de
uma coluna, etc.). Na fase de análise sintáctica verifca-se se a
sintaxe da consulta respeita as regras sintácticas da linguagem
(por exemplo, SQL). No decorrer desta fase é criada uma
representação interna da consulta, através de um modelo em
árvore.
Com base nesta árvore, o sistema de reescrita verifca se existem

32
Quarta-Feira, 9 de Dezembro de 2009 SBD: Análise do SGBD PostgreSQL

regras (guardadas em catálogos do sistema) aplicáveis a esta


árvore. Caso existam, então a árvore é alterada de forma a refectir
as alterações indicadas nas regras. Os utilizadores podem defnir
regras cuja activação seja despoletada pelas operações: UPDATE,
DELETE, INSERT e SELECT. As vistas encontram-se
implementadas através de regras SELECT. Quando o SGBD recebe
uma pergunta sobre uma vista, a regra SELECT correspondente é
despoletada e a pergunta original é reescrita de acordo com a
regra. O sistema de regras lida, em primeiro lugar, com as regras
UPDATE, DELETE e INSERT, e só depois com as regras SELECT.
Note-se que as operações de escrita também podem conter
operações SELECT embebidas. Uma vez que após a reescrita de
uma pergunta podem ser despoletadas novas regras, o sistema
processa, iterativamente, o conjunto de regras até que mais
nenhuma seja aplicável.
Uma vez terminada a chamada fase de reescrita, a pergunta passa
à fase de optimização e planeamento.
O optimizador do PostgreSQL baseia-se, essencialmente, na
estimativa do custo de execução para determinar o melhor plano.
Inicialmente são gerados todos os caminhos que forneçam o
mesmo resultado. Isto é, por exemplo, se existir um índice sob uma
relação a pesquisar, existem duas possibilidades: o uso ou não do
índice. De seguida o custo de cada plano é estimado e escolhe-se
aquele que apresentar menor custo. Este é, então, expandido num
plano completo.
Existem dois algoritmos para a geração do plano óptimo:
algoritmo de programação dinâmica, usado por omissão, e o
algoritmo genético, usado sempre que o número de tabelas
referenciadas numa operação SQL seja elevado. Mais à frente
falaremos sobre eles.
Com o resultado da fase de planeamento e optimização obtém-se o
plano óptimo de execução da pergunta.

33
Quarta-Feira, 9 de Dezembro de 2009 SBD: Análise do SGBD PostgreSQL

Representação Interna das Perguntas


Como referido anteriormente o PostgreSQL representa,
internamente, as perguntas através de um modelo em árvore. A
árvore contém os seguintes nós principais: tipo do comando, lista
das tabelas, tabela do resultado, lista das colunas, expressão de
selecção, sub-árvore de junção.
Analisemos, então, cada um destes nós:
• Tipo do comando – identifca a operação SQL usada pelo
utilizador e pode ter um dos seguintes valores: UPDATE,
DELETE, INSERT e SELECT;
• Lista das tabelas – contém uma lista de todas as tabelas
usadas na pergunta. Numa operação SELECT, este nó contém
todas as tabelas da cláusula FROM, cada uma representada
por um número único;
• Tabela do resultado – representa a tabela onde vai ser
colocado o resultado;
• Lista das colunas – contém uma lista de expressões que
representa o resultado da pergunta. Por exemplo, quando é
usada uma operação SELECT, o nó contém as colunas a partir
das quais deve ser feita a projecção. Na operação INSERT,
representa as expressões presentes na cláusula VALUES ou
na cláusula SELECT. Na operação UPDATE, contém as
expressões usadas para obter os novos valores dos atributos,
envolvendo, apenas, constantes ou atributos da tabela do
resultado. No caso da operação DELETE, este nó não é
usado, uma vez que não são produzidos novos registos;
• Expressão de selecção – representa o conteúdo da cláusula
WHERE numa instrução SQL;
• Árvore de junção – mostra a estrutura da cláusula FROM.
Consideremos a seguinte pergunta: SELECT * FROM a,b,c,d.
Neste caso, a árvore de junção teria apenas a lista de tabelas
da cláusula FROM.

34
Quarta-Feira, 9 de Dezembro de 2009 SBD: Análise do SGBD PostgreSQL

A fgura seguinte representa um exemplo da representação


interna de uma pergunta:

Reescrita de Perguntas
O sistema de regras do PostgreSQL permite aos utilizadores
defnir regras de reescrita de perguntas no servidor da base de
dados. A sintaxe usada é a seguinte:
CREATE RULE regra AS ON { SELECT | INSERT | UPDATE | DELETE } TO
tabela [ WHERE expressão_de_selecção ] DO [ INSTEAD ]{ NOTHING |
comando | ( comando; comando … )};

As vistas são implementadas sobre o sistema de regras. Assim, o


seguinte comando:
CREATE VIEW vista as SELECT * FROM tabela;

35
Quarta-Feira, 9 de Dezembro de 2009 SBD: Análise do SGBD PostgreSQL

É transformado em:
CREATE TABLE vista (lista das colunas da tabela) CREATE RULE “_RETURN” AS
ON SELECT TO vista DO INSTEAD SELECT * FROM tabela;


As regras SELECT são aplicadas como o último passo na


transformação das perguntas, mesmo que o comando SQL usado
seja: INSERT, UPDATE ou DELETE. Ao contrário das regras sobre
operações de escrita, as SELECT modifcam a árvore da
interrogação localmente, em vez de criarem uma nova.

Optimização e Planeamento
Como refere T. Lane em Recent PostgreSQL Optimizer
Improvements, a tarefa de planeamento está dividida em três
passos: transformação da pergunta, análise e geração de planos.
No passo da transformação, a pergunta é convertida numa forma
equivalente mais efciente. Durante a fase da análise extrai-se
informação implícita sobre a pergunta. Terminado o pré-
processamento, são analisados todos os planos alternativos de
execução, sendo escolhido o plano de menor custo.

Transformação de Perguntas
O principal objectivo desta fase é converter as perguntas
“aninhadas” em perguntas simples.
A existência de perguntas aninhadas limita o número de ordens de
junção possíveis. Considere-se a tabela ‘bolsas(aid:string,
montante:real)’, que guarda informação sobre os alunos que têm
bolsas de estudo. Se pretendermos saber a que cadeiras estão
inscritos os alunos com bolsas de estudo, podemos utilizar a
seguinte pergunta:
SELECT v_inscricoes.aid, v_inscricoes.nome, v_inscricoes.cid FROM
v_inscricoes, bolsas WHERE v_inscricoes.aid = bolsas.aid;

36
Quarta-Feira, 9 de Dezembro de 2009 SBD: Análise do SGBD PostgreSQL

Após a expansão da vista obtém-se a seguinte pergunta:


SELECT v_inscricoes.aid, v_inscricoes.nome, v_inscricoes.cid FROM
(SELECT a.aid, a.nome, i.cid FROM alunos a, inscricoes i WHERE
a.aid = i.aid) v_inscricoes, bolsas; WHERE v_inscricoes.aid =
bolsas.aid;

Nesta forma não é possível considerar a junção entre a tabela


‘bolsas’ e qualquer uma das tabelas da pergunta interior: ‘alunos’ e
‘inscricoes’. Após a conversão, passa a ser possível considerar
ordens de junção que envolvam as três tabelas:
SELECT alunos.aid, alunos.nome, inscricoes.cid FROM alunos,
inscricoes, bolsas WHERE inscricoes.aid = alunos.aid AND
inscricoes.aid = bolsas.aid;

Análise de Perguntas
Na fase de análise de interrogações são realizadas,
essencialmente, duas operações de optimização: dedução da
igualdade implícita e a aplicação antecipada dos predicados
(predicate push-down).
Ao analisarmos as condições de igualdade na cláusula WHERE,
conseguimos outras condições de igual implícitas. Vejamos o
seguinte exemplo:
SELECT alunos.aid, alunos.nome, inscricoes.cid FROM alunos,
inscricoes, bolsas WHERE inscricoes.aid = alunos.aid AND
inscricoes.aid = bolsas.aid;

Com base nas duas condições de igualdade: inscricoes.aid =


alunos.aid e inscricoes.aid = bolsas.aid, é possível deduzir uma
terceira igualdade implícita: alunos.aid = bolsas.aid. Esta terceira
igualdade permite juntar as tabelas ‘alunos’ e ‘bolsas’ primeiro.
A aplicação antecipada dos predicados permite que as expressões
de selecção sejam avaliadas tão cedo quanto possível. Esta regra de
optimização é considerada uma heurística visto que normalmente,
mas nem sempre, reduz o custo de execução do plano.

37
Quarta-Feira, 9 de Dezembro de 2009 SBD: Análise do SGBD PostgreSQL

Geração de Planos
Existem dois algoritmos para a geração do plano óptimo:
algoritmo de programação dinâmica, usado por omissão, e o
algoritmo genético, usado sempre que o número de tabelas
referenciadas numa operação SQL seja elevado.
O algoritmo de programação dinâmica caracteriza-se por, numa
primeira fase, determinar os melhores planos de acesso às tabelas.
De seguida, são encontrados os melhores planos para juntar grupos
de duas tabelas do bloco da pergunta. Na fase seguinte, são
encontradas as melhores estratégias para juntar grupos de três
tabelas, com base nos melhores planos para juntar duas tabelas,
determinados anteriormente. O algoritmo termina quando for
encontrado o bom plano para executar o actual bloco da pergunta.
É devido a todo este processo que quando o número de tabelas
referenciadas é muito grande, o algoritmo se torna dispendioso.
Uma alternativa ao algoritmo de programação dinâmica é o
algoritmo genético (GenEtic Query Optimizer, GEQO, no
PostgreSQL). Este algoritmo, inicialmente idealizado para resolver
o conhecido problema do caixeiro viajante, pensa-se ser mais efcaz
que o algoritmo de programação dinâmica quando o número de
tabelas na cláusula FROM ronda as quarenta e cinco.

Algoritmos de Junção
O PostgreSQL implementa três algoritmos para a junção de
tabelas. São eles: nested-loops-join, sort-merge-join e hash-join.
Para efeitos explicativos, considere-se a junção da tabela A B. No
algoritmo nested-loops-join a tabela B (interior) é percorrida na
totalidade para cada registo da tabela A (exterior). Para cada par
de registos é então verifcada se a condição imposta é satisfeita e
caso tal aconteça, adiciona-se o registo composto ao resultado. Tal
como o algoritmo de pesquisa linear, o nested-loops-join não
depende da existência de índices e pode ser usado
independentemente da condição de selecção. Uma vez que a
relação interior é lida sempre que um novo registo é acedido,
torna-se conveniente que seja a mais pequena das duas tabelas.

38
Quarta-Feira, 9 de Dezembro de 2009 SBD: Análise do SGBD PostgreSQL

Caso a relação interior caiba totalmente em memória, necessita ser


lida apenas uma vez. Se existir um índice sobre a relação interior,
então as pesquisas lineares podem ser substituídas por pesquisas
em índices. Para cada registo exterior, o índice é usado para
encontrar os registos interiores que satisfaçam a condição de
selecção.
O algoritmo sort-merge-join pode ser usado em junções naturais e
de igualdade. Considerando a junção natural entre duas tabelas A e
B, se as tabelas já estiverem ordenadas segundo os atributos
comuns, então o processo de junção assemelha-se ao merge do
algoritmo merge-sort. Caso contrário, é necessário ordenar
primeiro, utilizando o algoritmo merge-sort.A excepção acontece
quando, por exemplo, existe um índice sobre os atributos de junção
de A. Neste caso, não é necessário proceder à ordenação dos
registos.
O algoritmo hash-join, à semelhança do algoritmo sort-merge-join,
é usado em junções naturais e de igualdade sendo uma boa opção
quando não existem índices. Neste caso, o algoritmo,
primeiramente, cria um índice hash, em memória, para a tabela
interior (mais pequena). De seguida percorre a tabela exterior e
para cada registo desta, os atributos de junção são usados para
pesquisar o índice hash já criado.

Modelo de Custo
Como foi já referido anteriormente, o PostgreSQL, para
determinar o plano óptimo, estima o custo de execução de cada
plano gerado. Ora, a fórmula usada é a seguinte: C = P + W * R,
onde ‘C’ representa o custo total, ‘P’ o número de páginas
transferidas, que corresponde ao custo de I/O, ‘R’ representa o
número de registos examinados, que corresponde ao custo de
processamento pelo CPU, e ‘W’ indica o peso relativo entre o custo
de I/O e o custo de processamento.
As fórmulas de estimativa de custo para as estratégias de junção
são função do tamanho, em termos de páginas e registos, das
tabelas interior e exterior. Para estimar o tamanho de uma tabela, o

39
Quarta-Feira, 9 de Dezembro de 2009 SBD: Análise do SGBD PostgreSQL

SGBD multiplica o tamanho original da tabela pelo factor de


selectividade associado aos predicados. Este, representa a fracção
dos registos, pertencentes ao produto cartesiano das tabelas
envolvidas, que se espera satisfaçam a condição de junção. A
informação estatística usada na estimativa de custo é actualizada,
periodicamente, pelo SGBD e, manualmente, sempre que se
execute a operação ANALYZE.

Eis uma tabela de estimativa do custo de junções:

Custo das Junções

Nested-loops-join C +N *C
ext ext int

Sort-merge-join C +C +C +C
ext ord_ext int ord_int

Hash-join C +C +N *C
ext const_hash ext hash

Onde:
C : custo para aceder à tabela exterior
ext

C : custo para aceder à tabela interior


int

C : custo para ordenar a tabela exterior (igual a zero, caso


ord_ext

já esteja ordenada)
C : custo para ordenar a tabela interior (igual a zero, caso
ord_int

já esteja ordenada)
C : custo para construir o índice hash sobre a tabela
const_hash

interior
C : custo de uma pesquisa através do índice hash
hash

N : tamanho da tabela exterior


ext

40
Quarta-Feira, 9 de Dezembro de 2009 SBD: Análise do SGBD PostgreSQL

Gestão de transacções e controlo


de concorrência
O PostgreSQL garante a consistência dos dados usando um
modelo MVCC (Multiversion Concurrency Control) oferecendo
assim a cada transacção uma visão da base de dados como esta se
encontrava num momento, do passado, independentemente do
estado actual dos dados. Este sistema garante a todas as sessões
isolamento uma vez que oferece a cada sessão uma snapshot da
base de dados onde não é visível as alterações provocadas pelas
outras sessões. A principal vantagem em utilizar transacções em
vez de utilizar locks reside no facto de as escritas não bloquearem
as leituras e as leituras não bloquearem as escritas. No entanto os
locks são também disponibilizados para aplicações que não se
adaptem facilmente ao modelo transaccional.

No PostgreSQL as transacções estão defnidas implicitamente


para cada instrução realizada, ou seja cada instrução tem
autocommit. Mas para blocos de comandos é necessário explicitar
que se quer realizar uma transacção. Isto faz-se ao preceder uma
sequência de comandos SQL por BEGIN (ou START
TRANSACTION), defnindo opcionalmente o modo da transacção. E
ao colocar no fnal do bloco de comandos COMMIT.

A sintaxe do BEGIN é a seguinte:


BEGIN [ WORK | TRANSACTION ] [ transaction_mode [, ...] ]

where transaction_mode is one of:

ISOLATION LEVEL { SERIALIZABLE | REPEATABLE READ | READ COMMITTED


| READ UNCOMMITTED }
READ WRITE | READ ONLY

41
Quarta-Feira, 9 de Dezembro de 2009 SBD: Análise do SGBD PostgreSQL

Um exemplo poderia ser:


BEGIN;
UPDATE accounts SET balance = balance - 100.00
WHERE name = 'Alice';
UPDATE branches SET balance = balance - 100.00
WHERE name = (SELECT branch_name FROM accounts WHERE name =
'Alice');
UPDATE accounts SET balance = balance + 100.00
WHERE name = 'Bob';
UPDATE branches SET balance = balance + 100.00
WHERE name = (SELECT branch_name FROM accounts WHERE name =
'Bob');
COMMIT;

Savepoints
É possível controlar com maior granularidade as instruções dentro
de um bloco transaccional utilizando savepoints. Os savepoints
permitem que se grave toda a transacção até um ponto, e é possível
voltar a esse estado a qualquer momento (desde que se esteja
ainda dentro do mesmo bloco) utilizando um ROLLBACK TO, que
descarta todas as instruções executadas deste esse savepoint. Um
savepoint depois de ser utilizado para rollback, continua defnido e
pode ser reutilizado quantas vezes for necessário.
O PostgreSQL não suporta nested transactions por defeito, pois ao
iniciar uma transacção dentro de outra transacção o sistema
retorna um warning, mas é possível simular as nested transactions
utilizando os savepoints.
Tudo isto é apenas válido dentro do bloco transaccional, por isso
não é visível para as outras sessões na base de dados. Quando o
commit é feito, as alterações fcam visíveis para as outras sessões,
e por outro lado se for feito um rollback a todas as instruções,
nenhuma alteração fca visível nas outras sessões.

42
Quarta-Feira, 9 de Dezembro de 2009 SBD: Análise do SGBD PostgreSQL

Exemplo:
BEGIN;
UPDATE accounts SET balance = balance - 100.00
WHERE name = ’Alice’;
SAVEPOINT my_savepoint;
UPDATE accounts SET balance = balance + 100.00
WHERE name = ’Bob’;
ROLLBACK TO my_savepoint;
UPDATE accounts SET balance = balance + 100.00
WHERE name = ’Wally’;
COMMIT;

Neste exemplo as alterações que são realizadas são: o débito de


100 unidades na conta da Alice; e o crédito de 100 unidades na
conta do Wally. Sendo que a conta do Bob não é alterada.

Lidar com a consistência


É possível ao criar uma restrição, defnir se a sua avaliação pode
ser deferida (DEFERRABLE) para o fnal da transacção ou não.
Depois dentro da transacção podemos utilizar o seguinte comando:
SET CONSTRAINTS { ALL | name [, ...] } { DEFERRED | IMMEDIATE }

Para deferir ou forçar a avaliação imediata de uma, várias, ou


todas as restrições que estejam envolvidas na transacção.

Isolamento das transacções


O standard do SQL defne quatro níveis de isolamento nas
transacções, onde três acontecimentos não podem decorrer em
transacções concorrentes. Que são: dirty read, uma transacção lê
dados de uma transacção que ainda não está commited;
nonrepeatable read, uma transacção volta a ler informação que já
tinha lido anteriormente, e descobre que essa informação foi
alterada por outra transacção; e phantom read, onde uma
transacção após executar uma query idêntica pela segunda vez
recebe um resultado diferente do anterior, mostrando que outra
transacção alterou os dados presentes na base de dados. Os quatro

43
Quarta-Feira, 9 de Dezembro de 2009 SBD: Análise do SGBD PostgreSQL

níveis de isolamento das transacções e o seu comportamento está


descrito na seguinte tabela:

Isolation Level Dirty Read Nonrepeatable Phantom Read


Read
Read Possible Possible Possible
uncommitted
Read committed Not possible Possible Possible
Repeatable read Not possible Not possible Possible
Serializable Not possible Not possible Not possible

No PostgreSQL é possível especifcar para uma transacção


qualquer dos quatro níveis de isolamento, mas na verdade apenas
existem dois níveis: Read Committed e Serializable. Sendo que o
Read Uncommitted é mapeado internamente para o Read
Committed e o Repeatable Read para o Serializable. Isto é
permitido pelo standard do SQL, pois ao escolhermos um nível de
isolamento apenas estamos a defnir os fenómenos que não
queremos que aconteçam, e não o contrário.

Nível de Isolamento: Read Committed


Este é o nível predefnido pelo PostgreSQL. Quando uma
transacção utiliza este nível de isolamento, uma query apenas vê os
dados “committed” antes da query ter começado. No entanto as
queries vêm todas as actualizações previas realizadas dentro do
seu bloco transaccional, mesmo embora ainda não tenha sido feito
o seu commit.
Uma utilização mais complexa, pode obter resultados não
desejados neste nível de isolamento. Tomemos como exemplo a
tabela website que apenas contem duas linhas com o campo hits
igual a 9 e 10 respectivamente:
BEGIN;
UPDATE website SET hits = hits + 1;
-- run from another session: DELETE FROM website WHERE hits = 10;
COMMIT;

44
Quarta-Feira, 9 de Dezembro de 2009 SBD: Análise do SGBD PostgreSQL

O DELETE não terá nenhum efeito, pois mesmo tendo em conta


que uma das linhas anteriores tinha o valor 10, por causa do
UPDATE é obtido um lock, e depois o valor já é 11. E o valor que
anteriormente era 9, para o DELETE não é 10, então salta para a
próxima linha.
Este nível de isolamento, é adequado para a maioria das
aplicações, além que é rapido e fácil de utilizar. E como não é
sufciente para todos os casos, aplicações mais complexas podem
utilizar um nível de isolamento diferente, ou locks.

Nível de Isolamento: Serializable


Este nível de isolamento é o mais estrito de todos. É com este
nível que a base de dados emula a execução de transacção em
série, como se as transacções tivessem sido executadas uma após a
outra, em vez de executá-las paralelamente. No entanto as
aplicações que utilizem este nível de isolamento têm de estar
preparadas para repetir as transacções devido à falha na
serialização.
Uma transacção que utilize este isolamento, as suas queries
apenas vêm os dados que estavam committed antes da transacção
começar. Uma query nunca vê dados uncommitted ou alterações
feitas por outras transacções, no entanto todas as alterações feitas
dentro do seu bloco transaccional são vísiveis, mesmo que ainda
não estejam committed. A grande alteração para o nível de
isolamento anterior, é que em vez de ser feito um snapshot antes da
execução de uma query, é feito um snapshot no inicio da
transacção, e todas as queries partilham essa snapshot, isto
provocando que se dentro da transacção sejam executadas duas
queries de consulta identicas, mesmo que tenham sido feitas por
outras transacções, estas vão retornar os mesmos dados.
No caso de, pelo menos, uma entrada na base de dados ter sido
alterada após o inicio de uma transacção com este nível de
isolamento, e esta transacção pretende alterar uma dessas
entradas, o UPDATE vai fazer ROLLBACK com a seguinte
mensagem de erro:

45
Quarta-Feira, 9 de Dezembro de 2009 SBD: Análise do SGBD PostgreSQL

ERROR: could not serialize access due to concurrent update

Quando uma aplicação recebe esta mensagem de erro, deve


abortar a transacção por completo, e recomeçar desde o inicio.
Esta mensagem de erro apenas pode ser obtida em transacções que
alterem dados, as transacções que apenas consultem dados (read-
only) nunca vão obter confitos de serialização.
Este nível de isolamento é adequado quando o nível anterior não é
sufciente, e é necessário que cada transacção tenha uma visão
consistente da base de dados. Mas tal como já foi referido
anteriormente, a aplicação tem de estar preparada para voltar a
tentar a transacção no caso de receber a mensagem de erro acima
referida.

Locks
O PostgreSQL oferece vários modos para trancar/controlar o
acesso aos dados nas tabelas. Estes mecanismos poderão ser
utilizados em sítuações onde o modelo transaccional não oferece o
comportamento desejado.
Alguns dos comandos do PostgreSQL adequirem automaticamente
locks para garantir que por exemplo uma tabela não é eliminada
enquando o comando executa com o intuito de provocar alterações
ou leituras nessa tabela.

Locks ao nível da tabela


A lista seguinte mostra todos os locks que existem para as tabelas
e que podem ser especifcados manualmente com o comando
LOCK, e as condições em que o PostgreSQL os utiliza
automaticamente.
Duas transacções podem obter locks sobre o mesmo recurso
desde que estes locks não entrem em confito. O mesmo não se
passa para uma única transacção onde, apesar de ter obtido um
determinado tipo de lock, pode sempre tentar obter outro que entre
em confito com o anterior.

46
Quarta-Feira, 9 de Dezembro de 2009 SBD: Análise do SGBD PostgreSQL

• ACCESS SHARE: Este lock é adquirido quando um SELECT


referencia uma tabela. Geralmente numa query onde apenas
é lida informação.
• ROW SHARE: Os comandos SELECT FOR UPDATE e
SELECT FOR SHARE utilizam automaticamente este lock nas
tabelas destino.
• ROW EXCLUSIVE: Os comandos UPDATE, DELETE, e
INSERT adquirem automaticamente este lock na tabela
destino. Normalmente este lock é utilizado sempre que um
comando modifca uma tabela.
• SHARE UPDATE EXCLUSIVE: Este modo protege contra
alterações no schema da tabela e VACUUMs concorrentes.
Utilizadas quando são executados: VACUUM (sem o modo
FULL); ANALYZE; e CREATE INDEX CONCURRENTLY.
• SHARE: Este modo protege contra alterações concorrentes à
informação de uma tabela.
• SHARE ROW EXCLUSIVE: Este modo não é utilizado
automaticamente por nenhum comando do PostgreSQL.
• EXCLUSIVE: Tal como o modo anterior, este modo apenas
pode ser utilizado pela aplicação ou utilizador.
• ACCESS EXCLUSIVE: Adquirido pelos comandos ALTER
TABLE, DROP TABLE, TRUNCATE, REINDEX, CLUSTER e
VACUUM FULL. É também adqurido pelo comando LOCK
TABLE por defeito, quando não é especifcado um modo.

Tal como já foi referido anteriormente, a unica diferença entre os


locks, é a sua ligação de confitos com outros locks.

47
Quarta-Feira, 9 de Dezembro de 2009 SBD: Análise do SGBD PostgreSQL

A seguinte tabela representa os locks que entram em confito


quando utilizadas em conjunto:

Current Lock Mode


Requ SHAR
ested ACC SHAR
E ACCE
Lock ESS ROW ROW E
UPDA SHAR EXCL SS
SHAR EXCL ROW
Mode SHAR TE E USIVE EXCL
E USIVE EXCL
E EXCL USIVE
USIVE
USIVE
ACCE
SS
X
SHAR
E
ROW
SHAR X X
E
ROW
EXCL X X X X
USIVE
SHAR
E
UPDA
X X X X X
TE
EXCL
USIVE
SHAR
X X X X X
E
SHAR
E
ROW X X X X X X
EXCL
USIVE
EXCL
X X X X X X X
USIVE
ACCE
SS
X X X X X X X X
EXCL
USIVE

48
Quarta-Feira, 9 de Dezembro de 2009 SBD: Análise do SGBD PostgreSQL

Locks ao nível das linhas


Além de ser possível bloquear/trancar tabelas, também é possível
fazê-lo para linhas de uma tabela. O PostgreSQL oferece SHARED e
EXCLUSIVE locks. Os locks SHARED são adquiridos quando uma
transacção tenta consultar os dados. Os locks EXCLUSIVE são
utilizados automaticamente quando os dados são alterados. Estes
locks serão libertados quando a transacção chega ao fm, quer com
sucesso, quer com erro, ou até a um ROLLBACK anterior à
obtenção do lock.

Deadlocks
Com a utilização explícita de locks, também aumentamos a
possibilidade de obter um deadlock. Isto acontece quando pelo
menos duas transacções mantêm locks que a outra (ou outras)
querem obter.
Exemplo: Temos duas transacções, 1 e 2. A transacção 1 adquire
um exclusive lock na tabela A e em seguida tenta obter um
exclusive lock na tabela B. Isto decorreu enquanto a transacção 2
já tinha obtido um exclusive lock na tabela B e agora quer obter um
exclusive lock na tabela A. Chegamos então a um deadlock, onde
nenhuma das transacções consegue avançar.
O PostgreSQL detecta automaticamente uma situação de
deadlock, e resolve-a ao abortar uma das transacções (não é
possível prever qual das transacções envolvidas será abortada),
permitindo assim que a outra consiga completar a sua execussão.
Os deadlocks tal como numa sítuação envolvendo tabelas, também
pode acontecer com locks de linhas de uma tabela.

A melhor defesa contra deadlocks normalmente é fazer com as


aplicações que utilizam a base de dados, adquira os locks de uma
maneira/ordem consistente. Se no exemplo em cima, ambas as
transacções começassem por adquirir o lock na tabela A e em
seguida na tabela B, não teria existido um deadlock. E como um
lock permanece até ao fm da transacção, não é aconselhado deixar

49
Quarta-Feira, 9 de Dezembro de 2009 SBD: Análise do SGBD PostgreSQL

a transacção aberta durante um longo período de tempo (por


exemplo, enquanto se aguarda input do utilizador), pois se outra
transacção também necessita de um lock que já esteja nessa
transacção, a transacção vai fcar suspensa até o utilizador der
input.

Advisory Locks
O PostgreSQL também fornece uma variante de locks,
denominada de advisory locks. Este tipo de locks são criados e
utilizados por uma aplicação que conhece o seu signifcado, isto é,
o PostgreSQL não obriga o uso deste tipo de locks, cada aplicação é
que tem de o interpretar e utilizar à sua maneira.
Quando é adquirido um lock deste tipo, irá permanecer activo até
ao fnal da sessão ou até ser explicitamente removido.
Tal como todos os outros locks no PostgreSQL, uma lista completa
de todos os advisory locks que pertençam a qualquer sessão podem
ser obtidos a partir da view de sistema pg_locks.

50
Quarta-Feira, 9 de Dezembro de 2009 SBD: Análise do SGBD PostgreSQL

Suporte para Bases de Dados


Distribuídas
Com a evolução global da internet tornou-se necessário expandir
as bases de dados para se providenciar um acesso a estas de forma
mais rápida e independente da localização, quer da sua como da do
cliente.
Como exemplo típico deste cenário temos as transacções
bancárias que são realizadas mundialmente sem qualquer
problema. Isto só é possível devido à replicação dos dados do banco
em questão, ou seja, o banco possui vários servidores em cada
dependência e esses servidores terão de comunicar com outro/s
servidor/es presentes na sede de forma a aceder aos dados de um
cliente de Portugal a fazer compras em Itália, para os dados da sua
conta não fcarem inconsistentes.
Podemos proceder à replicação dos dados de forma heterogénea,
ou de forma homogénea. A segunda pressupõe que todas as bases
de dados estão assentes sobre o mesmo sistema de gestão de bases
de dados. Já a segunda permite-nos que cada base de dados esteja
num sistema diferente, o que obriga a que estas disponibilizem uma
forma de comunicação entre si global a todos os sistemas
utilizados.
Torna-se então evidente uma consulta distribuída terá muitas mais
etapas e difculdades do que uma localizada, mas que estes
mecanismos são muito importantes e úteis para todos nós no dia-a-
dia.
Infelizmente o PostgresSQL não implementa de forma nativa
qualquer forma de replicação de dados, somente poderemos fazê-lo
se recorrermos a módulos externos, tais como o Postgres-R1 e
Slony-I2.

1http://www.postgres-r.org/
2http://slony.info/

51
Quarta-Feira, 9 de Dezembro de 2009 SBD: Análise do SGBD PostgreSQL

Outras características do sistema


estudado

Stored Functions
O PostgreSQL tal como outros SGBD, suporta a criação e
armazenamento de funções na base de dados. A grande diferença,
é que normalmente a esta funcionalidade chama-se Stored
Procedures, mas no PostgreSQL chama-se Stored Functions, pois
tal como na programação uma função restorna sempre algo (ou
void), e um procedimento não retorna nada.
A sintaxe básica é a seguinte:
CREATE FUNCTION my_function() RETURNS integer AS $$
DECLARE
-- declarations
BEGIN
-- body of the function
END;
$$ LANGUAGE plpgsql;

Como pode ser visto no fnal, é possível específcar qual é a


linguagem procedurais como: PL/pgSQL; PL/TCL; PL/Perl;
PL/Python.

Triggers
Também no PostgreSQL é possivel utilizar triggers para executar
operações quando, por exemplo, é adicionada uma nova entrada
numa tabela.
Exemplifcando:
CREATE FUNCTION emp_stamp() RETURNS trigger AS $emp_stamp$
BEGIN
-- Check that empname and salary are given
IF NEW.empname IS NULL THEN
RAISE EXCEPTION 'empname cannot be null';
END IF;
IF NEW.salary IS NULL THEN
RAISE EXCEPTION '% cannot have null salary', NEW.empname;

52
Quarta-Feira, 9 de Dezembro de 2009 SBD: Análise do SGBD PostgreSQL

END IF;

-- Who works for us when she must pay for it?


IF NEW.salary < 0 THEN
RAISE EXCEPTION '% cannot have a negative salary',
NEW.empname;
END IF;

-- Remember who changed the payroll when


NEW.last_date := 'now';
NEW.last_user := current_user;
RETURN NEW;
END;
$emp_stamp$ LANGUAGE plpgsql;

CREATE TRIGGER emp_stamp BEFORE INSERT OR UPDATE ON emp


FOR EACH ROW EXECUTE PROCEDURE emp_stamp();

Simplesmente temos de criar uma stored function que retorne um


trigger, e associar essa função com um trigger utilizando o
CREATE TRIGGER.

Database Connectivity
O PostgreSQL suporta ODBC, se for compilado para ter suporte.
Mas não fornece directamente as interfaces para os clientes. Estas
têm de ser obtidas, por exemplo a partir do site do PostgreSQL3 ou
do PgFoundry4.
Também pode suportar ligação por JBDC instalando um driver
externo5.

Suporte para XML


O PostgreSQL tem um tipo de dados xml que pode ser utilizado
para guardar dados XML, sejam documentos completos, ou apenas
fragmentos. A vantagem a usar este tipo de dados, em vez de um
tipo de texto, é que utilizando o tipo xml, o PostgreSQL valida se o
XML está bem formado.

3 http://www.postgresql.org/download/product-categories
4 http://pgfoundry.org/search/...odbc...
5 http://jdbc.postgresql.org/download.html

53
Quarta-Feira, 9 de Dezembro de 2009 SBD: Análise do SGBD PostgreSQL

A importação de XML pode ser feita utilizando o XMLPARSE e a


sua exportação utilizando o XMLSERIALIZE:
XMLPARSE ( { DOCUMENT | CONTENT } value)

XMLSERIALIZE ( { DOCUMENT | CONTENT } value AS type )

Ferramentas
Existe um enorme repositório de ferramentas no site do
PostgreSQL6. Onde entre de aplicações comerciais e open-source
podemos encontrar também modulos e extensões para o
PostgreSQL, como linguagens procedimentais.
Entre as ferramentas de administração, gostariamos de destacar o
PGAdmin7 que é uma ferramenta de administração open-source e
web-based, onde podemos administrar, visualizar a base de dados,
realizar operações de manutenção, tudo remotamente utilizando
apenas um browser.

6 http://www.postgresql.org/download/product-categories
7 http://www.pgadmin.org

54
Quarta-Feira, 9 de Dezembro de 2009 SBD: Análise do SGBD PostgreSQL

Conclusão
O estudo que efectuamos durante a elaboração deste relatório,
mostra que o SGBD PostgreSQL tem as funcionalidades necessárias
para ser “levado a sério” e poder concorrer contra SGBD's
comerciais. Sendo também open-source, permite que alguma
necessidade mais exótica de um cliente possa ser mais facilmente
satisfeita, pois é possível alterar o código-fonte do PostgreSQL
consoante as necessidades.

55
Quarta-Feira, 9 de Dezembro de 2009 SBD: Análise do SGBD PostgreSQL

Bibliografa
[1] D. Bastos, “Processamento e Otimização de Consultas em
PostgreSQL.”
[2] “Manual PostgreSQL.”

56

Você também pode gostar