Вы находитесь на странице: 1из 59

Departamento de Informtica

Relatrio de comparao de SGBDs


Mestrado em Engenharia Informtica Sistemas de Bases de Dados - 2011/12

Processamento e Optimizao de Queries Oracle, MySQL e PostGreSQL - G13

Bruno Sampaio (no 35101) Joo Gouveia (no 35100) Pedro Marques (no 30227)

Professor: Jos Alferes

Contedo
1 Introduo 1.1 Enquadramento . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1.2 Escolha e Objectivos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1.3 Estrutura do Relatrio . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2 Linguagens Intermdias 2.1 MySQL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2.2 PostGreSQL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3 Processamento de Queries 3.1 MySQL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3.2 PostGreSQL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4 Algoritmos Usados em Operaes 4.1 MySQL . . . . . . . . . . . . . . . . . . . . . 4.1.1 Algoritmo de ordenao FILESORT 4.1.2 Algoritmos de Juno . . . . . . . . 4.2 PostreSQL . . . . . . . . . . . . . . . . . . . . 4.2.1 Operao de seleco . . . . . . . . 4.2.2 Operao de ordenao . . . . . . . 4.2.3 Algoritmos de juno . . . . . . . . 3 3 3 4 5 5 5 6 7 8 9 9 9 10 12 12 13 14

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

5 ndices 15 5.1 MySQL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15 5.2 PostGreSQL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16 6 Expresses Complexas 18 6.1 MySQL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18 6.2 PostGreSQL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18 7 Transformaes de Queries 7.1 MySQL . . . . . . . . . . . . . . . . . . . . . . . . . . 7.1.1 Optimizao de Intervalos . . . . . . . . . . 7.1.2 Optimizao por Fuso de ndices . . . . . 7.1.3 Engine Condition Pushdown Optimization . 7.1.4 Index Condition Pushdown Optimization . . 7.1.5 Optimizao do IS NULL . . . . . . . . . . . 7.1.6 Optimizao de LEFT JOIN e RIGHT JOIN . 7.1.7 Optimizao do ORDER BY . . . . . . . . . . 20 20 20 25 26 27 28 29 30

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

CONTEDO

7.1.8 Optimizao do GROUP BY 7.1.9 Optimizao do DISTINCT . 7.1.10 Optimizao de Subqueries . 7.2 PostGreSQL . . . . . . . . . . . . . . . 7.2.1 Optimizao Geral . . . . . . 7.2.2 Genetic Query Optimizer . . . 8 Planos de Execuo de Queries 8.1 Uso do EXPLAIN . . . . . . . 8.1.1 MySQL . . . . . . . . 8.1.2 PostGreSQL . . . . . 8.2 Output do EXPLAIN . . . . . 8.2.1 MySQL . . . . . . . . 8.2.2 PostGreSQL . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

31 32 33 35 36 36 38 38 38 39 40 40 45 47 47 47 48 48 49 55 56

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

9 Estimativas 9.1 MySQL . . . . . . . . . . . . . 9.1.1 Query Performance . . 9.2 PostGreSQL . . . . . . . . . . . 9.2.1 Analyze . . . . . . . . 9.2.2 Estimativas de Linhas 10 Concluso Bibliograa

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

Captulo 1

Introduo
1.1 Enquadramento

Este relatrio foi escrito no contexto da disciplina de Sistemas de Bases de Dados do Mestrado em Engenharia Informtica da Faculdade de Cincias e Tecnologia da Universidade Nova de Lisboa. No contexto desta disciplina aprendemos de forma mais aprofundada algumas das caractersticas do Sistema de Gesto de Bases de Dados (SGBD) da Oracle. No entanto existem muitos outros SGBDs actualmente e todos eles tm caractersticas diferentes, tornando-se assim importante conhecer as diferenas entre estes e o que os torna melhores para umas situaes e piores para outras. Desta forma de grande importncia realizar um estudo aprofundado sobre alguns destes SGBDs, sendo ai que se assenta o objectivo deste trabalho.

1.2

Escolha e Objectivos

O objectivo deste trabalho realizar um estudo, de um determinado grupo de funcionalidades, de dois SGBDs diferentes de forma a poder compar-los entre si e tambm com, o nosso j conhecido, Oracle 10g [1]. Para a realizao do trabalho escolhemos o tema de Processamento e Optimizao de Queries e os sistemas que escolhemos analisar dentro desse tema so o MySQL 5.6 [2] e o PostGreSQL 9.1 [3]. As razes que nos levaram a esta escolha so as seguintes: So ambos sistemas open source e gratuitos; Esto ambos disponveis para vrias plataformas; Documentao bastante completa disponvel online; J lidmos com ambos no passado e gostaramos de os conhecer melhor. Dentro do tema referido iremos analisar questes como: Linguagens intermdias utilizadas por estes sistemas; Implementao das operaes bsicas de seleco, juno, ordenao, entre outras;

Algoritmos suportados para cada operao, como fazem uso dos ndices quando existem e que tipo de ndices suportam; Mecanismos para expresses complexas, como, materializao, pipelining e paralelizao; Transformaes de queries suportadas; Existncia ou no de comandos para parametrizar a construo e uso de estimativas; Mecanismos fornecidos para ver planos de queries.

1.3

Estrutura do Relatrio

O relatrio est estruturado em vrias seces principais, dentro de cada seco h uma referente ao MySQL e outra referente ao PostGreSQL. Comeamos por apresentar as linguagens intermdias de cada um na seco 2. Na seco 3, apresentamos a forma como ambos processam queries. Na seco 4, descrevemos alguns dos algoritmos disponveis para seleco, junes, ordenaes, entre outros. Na seco 5, falamos dos tipos de ndices que cada um suporta. Na seco 6, falamos dos vrios algoritmos disponveis para avaliao de perguntas (materializao, pipelining e paralelizao). Na seco 7, falamos de alguns dos tipos de optimizao interna disponibilizados por ambos. Na seco 8, apresentamos o comando EXPLAIN e a forma como este usado para ajudar na optimizao de queries. Na seco 9, mostramos algumas das estimativas disponveis. E nalmente, na seco 10 temos as concluses a que chegamos com este trabalho.

Captulo 2

Linguagens Intermdias
O Oracle, o MySQL e o PostGreSQL foram escritos em diferentes linguagens, mas so todos eles baseados em SQL [4], linguagem desenhada para a gesto de dados em Sistemas de Gesto de Bases de Dados Relacionais (SGBDR). Embora a base seja a mesma existem vrias diferenas entre os trs, pois cada um deles utilizada extenses diferentes da linguagem SQL. Isto signica que para alm das operaes existentes no SQL, tm outras especicas da extenso que usam. Muitas dessas operaes podem at mesmo ter os mesmo objectivos, mas tm sintaxes diferentes.

2.1

MySQL

O MySQL [5] est escrito em C e C++, o parser de SQL est escrito em yacc (explicado em maior detalhe na seco 3.1) e a extenso SQL que utiliza o SQL/PSM (SQL/Persistent Stored Module) [6]. Esta extenso adiciona ao SQL, uxo de controlo, manipulao de condies, cursores e variveis locais, e atribuio de expresses a variveis e parmetros.

2.2

PostGreSQL

O PostGreSQL [7] est escrito em C e utiliza a extenso PL/pgSQL (Procedural Language/PostGreSQL Structured Query Language) [8] do SQL. Esta extenso baseada na utilizada pelo Oracle, o PL/SQL (Procedural Language/SQL), que por sua vez baseado na linguagem Ada. O PL/pgSQL foi desenvolvido com o objectivo de permitir a realizao de operaes e computaes mais complexas que o SQL, sendo ao mesmo tempo simples de usar. Esta extenso fornece a possibilidade de utilizar ciclos e outras estruturas de controlo. Uma funo criada nesta linguagem pode ser chamada numa operao SQL ou como a aco realizada por um trigger.

Captulo 3

Processamento de Queries
Quando uma query enviada para o servidor, tanto o MySQL, como o PostGreSQL, passam por uma fase de parsing. O mesmo acontence no caso do Oracle. Esta fase , no entanto, diferente em cada uma das tecnologias. Neste captulo ser explicado como esse processamento se faz, assim como algumas das funes que so usadas para a optimizao das queries. Para a fase de parsing o Oracle [9], de forma a limitar o nmero de dados que so reconstrudos, utiliza uma rea de memoria partilhada chamada shared pool. Nesta rea o Oracle mantem instrues SQL, pacotes, informao de outros objectos, entre outras coisas. Esta memoria mantida em funcionamento mesmo quando um utilizador acaba uma aco que a utiliza. Esta informao, mantida em sesso poder ser utilizada por outra, mas o Oracle no sabe priori se um determinado dado ser til ou no para outra sesso, mantendo tudo o que iniciado, mesmo que isso signique remover informao antiga para ter espao para a nova. As reas mais interessantes para a funcionalidade de parsing so as seguintes: dictionary cache Esta rea contm copias do dicionrio do Oracle que foram utilizadas em instrues SQL anteriores e outros objectos da cache da biblioteca; library cache Esta rea guarda metadata acerca de tabelas, ndices, vistas, sinnimos entre outros objectos da base de dados. Contm tambm grafos de dependncias e outras relaes entre objectos, incluindo SQL e PL/SQL; SQL rea Esta rea contm a forma binria, executvel pelo Oracle dos cursores SQL e PL/SQL. Durante a operao de parse o Oracle primeiro valida a syntax da instruo SQL, de seguinda valia a semntica, isto , se os objectos so vlidos, se existe alguma ambiguidade, se o utilizador tem privilgios para os aceder, etc. Aps esta vericao segue-se uma pesquisa shared pool. Nesta pesquisa o Oracle verica se os resultados j esto guardados e se os objectos e ambiente de execuo so idnticos. Em caso negativo, a informao da nova query alocada na memoria. De seguida, so retirados os valores das variveis e vericados se todos encaixam nas colunas a que se referem. Antes da construo da rvore de parse feita uma optimizao query. Por m, a rvore guardada na shared pool. Nas seces seguintes sero apresentados como o parse e a optimizao so feitos, tanto no MySQL como no PostGreSQL. 6

3.1

MySQL

Na Figura 3.1 retirada de [10] possvel ver o caminho de uma query MySQL no cdigo fonte.

Figura 3.1: Vista do caminho de uma query. O cdigo est dividido em 4 seces: a SQL Interface, que tem como funo abrir conexes e receber os comandos, o Query Parser que faz o parse da query recebida, o Query Optimizer, optimiza a query de forma a simplica-la e torna-la mais eciente e, por m, no Query Execution que a query executada. Para este trabalho demos maior nfase s seces relacionadas com o processamento das queries (Query Parser e Query Optimizer). Em primeiro lugar vericado se a query a ser analisada j existe em cache e, em caso armativo, os resultados so imediatamente retornados sem passar por mais nenhum tipo de processamento. Caso contrrio criada uma nova estrutura LEX que contm a representao interna da query. A estrutura depois preenchida com o Lex/YACC parser. O Lex serve para identicar tokens, literais, assim como sintaxe de uma linguagem, o YACC usado para construir o cdigo que interage com o cdigo fonte do MySQL. Aps o parse da query entra a fase de optimizao, que explicada em maior detalhe na seco 7.1. Esta fase constituda por uma coleco de funes e controlos de uxo desenhados para encontrar o caminho mais rpido para executar a query. O Optimizer utiliza uma combinao de boas prticas com uma seleco baseada em custos. Iremos agora exemplicar algumas dessas boas prticas. Propagao Constante Remoo de conjunes transitivas utilizando constantes. Por exemplo, com a = b = c, possvel concluir que a = c. Portanto numa query com WHERE column1 = column2 AND column1 = x seria transformada para WHERE column1 = x AND column2 = x; Eliminao de cdigo morto Remoo de condies que so sempre verdadeiras. Por exemplo, WHERE 0 = 0 AND column1 = x caria apenas WHERE column1 = x. O mesmo acontece para condies que so sempre falsas e podem ser removidas sem afectar o resto da query. Por exemplo,

WHERE column1 = 12 AND column2 = 12 AND column1 > column2 seria modicado para WHERE column1 = 12 AND column2 = 13;
Folding Constants Uma expresso com a clusula WHERE column1 = 1 + 2 transformada em WHERE column1 = 3.

Aps feita a optimizao, como foi explicado anteriormente, o cdigo entra na fase de execuo. aqui que a query executada e os dados, depois, enviados para o cliente.

3.2

PostGreSQL

Em relao ao PostGreSQL, como pode ser visto em [11], aps a conexo com o servidor ser realizada e este receber a query, comea a etapa de parse. Aqui vericado se a query contm algum erro de sintaxe e, em caso negativo, criada a rvore da query. De seguida, o sistema de reescrita procura por quaisquer regras que possam ser aplicadas rvore e efectua as transformaes que sejam necessrias. Por exemplo, caso exista uma query que utilize uma view, o sistema transforma essa query de forma a referenciar as tabelas existentes na view. agora que comea o processo de optimizao. O planner/optimizer pega na rvore e aplica-lhe um plano que ser utilizado como input para o executor. Para a criao do plano, primeiro so criados todos os caminhos possveis que levam ao mesmo resultado. De seguida, so estimados os custos de execuo de cada caminho e o mais barato escolhido. Este expandido para um plano completo de forma a que o executor o consiga utilizar. Finalmente, aps a recepo da rvore com o plano, o executor vai buscar as linhas que so representadas pelo plano. Ele utiliza o sistema de armazenamento enquanto analisa as relaes, efectua os joins e sorts necessrios e avalia qualicaes. Tal como foi explicado acima o parser [12] verica primeiro se a string (texto ASCII) vlida. Caso seja, criada uma rvore de parse e um lexer. Ambos so implementados usando as ferramentas Unix, bison e ex. O lexer responsvel por reconhecer identicadores, palavras chave de SQL, etc. Para cada palavra ou identicador encontrados, um token gerado e enviado para o parser. O parser consiste num conjunto de regras gramaticais e aces que so executadas sempre que uma regra disparada. O cdigo das aces (geralmente em linguagem C) utilizado para construir a rvore. Aps a rvore estar construda, ela enviada para o processo de transformao que realiza a interpretao semntica necessria para compreender quais as tabelas, funes e operadores que so referenciados pela query. ento construda uma rvore da query. Esta rvore estruturalmente parecida rvore de parse, no entanto, contm diferenas nos detalhes. Por exemplo, informao acerca dos tipos de dados das colunas e dos resultados das expresses adicionada rvore. Como j foi explicado, aps a construo desta rvore, inicia-se o processo de optimizao. Todas as formas possveis de execuo de uma query so examinadas de forma a determinar qual o caminho mais rpido. No entanto, em certas situaes este processo consome excessivas quantidades de tempo e memoria, tornando o processo intil, uma vez que, o objectivo aumentar a performance computacional. Isto ocorre, por exemplo, quando a query contm um grande nmero de operaes de juno. De forma a determinar um plano razovel numa quantidade de tempo, tambm, razovel, o PostGreSQL utiliza o Genetic Query Optimizer [13]. O processo de optimizao explicado em maior detalhe na seco 7.2.

Captulo 4

Algoritmos Usados em Operaes


4.1
4.1.1

MySQL
Algoritmo de ordenao FILESORT

O MySQL faz uso de dois algoritmos para ordenao de resultados [14], o mtodo original ORDER BY usa apenas o valor do atributo que lhe dado como parmetro, no mtodo modicado, no s usado o valor do tributo chave como tambm de todas os atributos que so usados na query. O mtodo original funciona do seguinte modo : Ler todas a linhas da que esto de acordo com a chave, ou ler a tabela por completo, os itens que no fazem parte da clusula WHERE so descartados. Para cada linha armazenado um par de valores (chave, apontador da linha), estes valor so armazenados num buffer cujo tamanho denido pela varivel de sistema sort_buffer_size Quando termina o espao no buffer o algoritmo executa um quicksort e armazena o resultado num cheiro temporrio e guarda o apontador para o bloco ordenado. Todos os passos acima descritos so repetidos at todos os tuplos da tabela serem processados. feito um multi-merge de 7 blocos para um cheiro temporrio, este processo repetido at todos os blocos do primeiro cheiro existirem no segundo O processo anterior repetido at que restem menos de 15 blocos. No ultimo multi-merge efectuado, apenas o apontador do tuplo escrito como resultado para um cheiro Por m os tuplos so lidos de forma ordenada usando os apontadores dos tuplos j anteriormente guardados no cheiro. Para optimizar este processo lido um grande bloco de apontadores que so ordenados e posteriormente usados para ler os tuplos ordenadamente para um buffer. 9

Um problema inerente abordagem acima, consiste no facto de ser necessrio efectuar mais do que um acesso tabela para leitura, neste caso em concreto sero necessrios dois acessos, numa primeira altura para identicar os tuplos coincidentes com o estabelecido na clusula WHERE , e novamente aps ter sido ordenados os valores (chave, apontador de tuplo), para consulta dos tuplos respectivos. O algoritmo modicado incorpora uma optimizao que regista no o valor da chave de ordenao e a posio do tuplo como tambm todas os atributos necessrias query. Isto evita ler os tuplos mais do que uma vez. O algoritmo modicado funciona da seguinte forma: L os tuplos que esto de acordo com a clusula WHERE Para cada linha, regista o tuplo com os valores da chave de ordenao , posio da linha e as colunas necessrias para a query. Faz a ordenao dos tuplos anteriormente registados, esta ordenao feita pelo valor da chave. Devolve as linhas j ordenadas, e l as colunas diretamente dos tuplos ordenados, evitando assim um novo acesso tabela. No algoritmo modicado os tuplos so maiores que os pares de valores usados no algoritmos tradicional, assim sendo o nmero de tuplo que existentes no buffer de ordenao menor. Como resultado possvel que o extra I/O gerado torne esta abordagem mais lenta, o que no de todo desejado. Para evitar esta situao a optimizao s usada se o tamanho total das colunas extra no tuplo, no exceder o valor da varivel de sistema max_length_for_sort_data.

4.1.2

Algoritmos de Juno

Para operaes de juno entre tabelas o MySQL utiliza o Nested-Loop Join ou variaes do mesmo. Nested-loop Join O algoritmo Nested-Loop [15] verica as linhas da primeira coluna e faz esta operao em ciclo num determinado nmero de tempo, colocando cada linha num outro nested-loop que processa a prxima tabela existente na operao de juno. Assume-se que a juno entre as tabelas t1, t2 e t3 executada usando os tipos de juno na Tabela 4.1: Tabela 4.1: Tipos de juno. Table t1 t2 t3 Join Type range ref ALL

Se for aplicado o algoritmo Nested-Loop a juno processada da seguinte forma:

10

for each row in t1 matching range { for each row in t2 matching reference key { for each row in t3 { if row satisfies join conditions, send to client } } }

Como o algoritmo Nested-loop faz a leitura linha a linha , dos loops exteriores para loops interiores, tipicamente processa as tabelas nos loops internos vrias vezes. Block Nested-Loop Join Neste algoritmo so usados buffers de linhas, para reduzir o nmero de vezes que a tabela lida no inner loop. i.e. Se por exemplo dez linhas de uma determinada tabela, forem lidas para um buffer, e se o buffer for passado para o prximo inner loop, cada nova linha lida no inner loop, poder ser comparada com as 10 linhas existentes no buffer, isto reduz o nmero de vezes que a tabela interna ser lida. O MySQL usa join buffering nas seguintes condies: A variavl join_buffer_size permite denir o tamanho do buffer a ser usado no join. O join buffering pode ser usado, quando a juno do tipo ALL ou INDEX, de outra forma quando no e possvel recorrer ao uso de chaves para executar o mesmo e feito executando um scan completo s linhas da tabela. alocado um buffer para cada join, ou seja uma determinada consulta poder estar a usar mltiplos buffers. O buffer alocado priori e libertado aps a execuo da consulta. Apenas as colunas pertinentes para a execuo da operao de join sero colocadas no buffer. Exemplo de execuo de um Neste-loop join recorrendo ao uso de um buffer.

for each row in t1 matching range { for each row in t2 matching reference key { store used columns from t1, t2 in join buffer if buffer is full { for each row in t3 { for each t1, t2 combination in join buffer { if row satisfies join conditions,

11

send to client } } empty buffer } } } if buffer is not empty { for each row in t3 { for each t1, t2 combination in join buffer { if row satisfies join conditions, send to client } } }

Se S for o tamanho da combinao de t1 e t2 no buffer de juno e c o nmero de combinaes presentes no buffer, o nmero de vezes que a tabela t3 lida, nos dado por:

(S C )/ join_ bu f f er _size + 1

Quanto maior o valor da varivel join_buffer_size menor ser o nmero de vezes em que a tabela 3 ser lida, at ao ponto em que join_buffer_size tem tamanho suciente para guardar todas as combinaes. A partir deste valor deixa de haver ganho no desempenho, em tornar maior o valor de join_buffer_size.

4.2
4.2.1

PostreSQL
Operao de seleco

No PostGreSQL podemos encontrar os seguintes algoritmos de seleco, referidos em [16]: Sequential Scan comea na primeira linha da tabela e percorre toda a tabela, linha a linha at satisfazer a condio denida, ou at ao limite da tabela. De notar que no Sequential Scan pode ser denido o nmero limite de linhas que podem ser vericadas. Bitmap Scan este tipo de operao usada quando se pretende obter apenas um conjunto de tuplos que satisfazem determinada condio, Esta opo aumenta o nmero de acessos feitos ao disco, sendo assim mais vantajoso nas operaes onde apenas necessita de seleccionar pequenos blocos de linhas.

12

Index Scan [17] Este tipo de acesso devolve os TIDs (Identicador do Tuplo) de cada tuplo que coincide com as chaves da relao. Este tipo de Scan no tem como objectivo devolver os tuplos que coincidem com a chave da relao.

4.2.2

Operao de ordenao

Quando produzido um resultado, aps a operao SELECT ser processada, o mesmo resultado poder ser ordenado opcionalmente, se esta opo no for escolhida o resultado ser mostrado consoante o tipo de SCAN utilizado , o tipo de join bem como ordem dos resultados em disco. Para ser feita uma ordenao dos resultados necessrio explicitar esse opo na query a realizar como mostra a sintaxe:

SELECT select_list FROM table_expression ORDER BY sort_expression1 [ASC | DESC] [NULLS { FIRST | LAST }] [, sort_expression2 [ASC | DESC] [NULLS { FIRST | LAST }] ...]

Neste exemplo as variveis sort_expression1 e sort_expression2 podem representar apenas atributos ou simplesmente ser uma expresso que use atributos j existentes na clusula SELECT assim sendo um exemplo para uma expresso usando ORDER BY poderia ser a seguinte:

SELECT a , b FROM table1 ORDER BY a, a+b ;

Quando mais do que uma expresso for especicada na clusula ORDER BY, a segundo valor (expresso2 usada para ordenar as linhas ou tuplos que so iguais de acordo com o valor usado na expresso1. Cada expresso pode ser seguida pelo opo ASC ou DESC denindo assim a classicao da ordenao para ascendente ou descendente, por omisso utilizada a ordem ASC. A opo NULLS FIRST e NULLS LAST determina quando um valor NULL aparece antes ou depois de um valor no nulo, na ordenao. Por omisso a ordenao de valores NULL e feita sendo este tipo de valores NULL maior do que qualquer outro tipo de valor no nulo, assim sendo NULLS FIRST tem o mesmo signicado que DESC e NULLS LAST signica ordenao ASC. Actualmente o PostGreSQL utilizador operadores do tipo B-tree para determinar o tipo de ordenao ascendente ou descendente.

13

4.2.3

Algoritmos de juno

No PostGreSQL, podemos encontrar trs diferentes algoritmos de juno, referidos em [16]. Nested-loop join A relao direita do JOIN vericada uma vez para cada tuplo encontrado na relao da esquerda. Este procedimento sendo fcil de implementar, no eciente, tornando-se um algoritmo muito demorado. Merge join cada relao ordenada com base nos atribudos chave antes do incio da juno, Em seguida as duas relaes so vericadas simultaneamente, e os tuplos em comum so agregados. Este tipo de algoritmo, torna-se mais atractivo por cada relao no JOIN apenas vericada um vez. A ordenao requerida pode ser obtida atravs por uma operao explcita de ordenao, ou ento vericando a relao pela ordem correcta usando um ndice para a chave de juno. Hash Join a relao da direita vericada e de seguida colocada numa HASHTABLE usando os atributos da juno como chave de HASH, por sua vez a relao da esquerda vericada e para cada tuplo encontrado o mesmo utilizado como chave de hash para localizar os tuplos correspondentes na tabela.

14

Captulo 5

ndices
5.1 MySQL

Em MySQL os ndices [18] so usados na generalidade para encontrar registos com os valores da coluna especica com maior rapidez. Sem recorrer ao uso de ndices o MySQL ter de comear no primeiro registo fazer uma leitura sequencial de todos os registos da tabela para encontrar o valor especco. Quanto maior o nmero de registo da tabela, mais relevante se torna o uso dos ndices em MySQL. Tipos de ndices que podemos encontrar no MySQL: PRIMARY KEY tem a mesma funcionalidade que um ndice UNIQUE, este tipo de ndice tem como funo identicar qualquer tuplo da tabela, por isso no deve ser usado em atributos que permitam o valor NULL , e dever ser usado sobre o menor nmero de atributos necessrios para identicar qualquer tuplo da tabela; UNIQUE Dene o valor de um atributo(coluna) como nico; INDEX refere-se a um tipo de ndice onde so permitidos valores no distintos, pode haver valores duplicados para o mesmo atributo que faz parte do ndice. Apenas so usados para melhorar o desempenho das queries; FULLTEXT este tipo de ndice usado em pesquisas de texto, e apenas podem ser usados em atributos do tipo CHAR, VARCHAR ou TEXT. Mtodos para criao de ndices: B-Trees R-Trees Hash O MySQL faz uso de ndices para o seguinte tipo de operaes: Pesquisa rpida de tuplos que esto de acordo com a clusula WHERE; Para eliminar tuplos a serem considerados, se for possvel escolher entre mltiplos ndices, o MySQL normalmente escolhe aquele que devolve um menor nmero de tuplos; 15

Para devolver tuplos de outras tables que so executadas nas junes; Para encontrar o valor mnimo e mximo para uma determinada coluna indexada; Para ordenar ou agrupar registos de uma determinada tabela, e se a ordenao ou agrupamento acontecer no prexo mais esquerda de uma chave que possa ser usada. Como por exemplo:

ORDER BY key_part1, key_part2

O ndice B-Tree poder ser usado em expresses de comparao de atributos (colunas) que usem os operadores =, >, >=, <, <=, ou BETWEEN, este tipo de ndice tambm poder ser usado em comparaes do tipo LIKE em que o argumento seja apenas uma string constante. Os ndices do tipo HASH so usados apenas em comparaes que faa uso dos operadores de igualdade tais como = ou <=>.

5.2

PostGreSQL

ndices no PostGreSQL [19]: Multi-coluna um ndice pode ser denido em mais do que uma coluna na mesma tabela; Unique dene o valor de uma coluna como nico, apenas os ndices B-Tree, podem ser declarados como UNIQUE; Expresso um ndice pode no se referir apenas a um atributo (coluna) da tabela, mas pode ser uma funo ou expresso que faz uso de uma ou mais colunas da tabela. O PostGreSQL suporta diversos tipos de ndice : B-tree Hash GiST GIN Btree , O PostGreSQL faz uso de um ndice deste tipo sempre que uma coluna indexada est envolvida numa comparao utilizando qualquer um dos seguintes operadores.

<, <=, =, >=, >

16

Consultas construdas com recurso ao uso de expresses tambm podero fazer recurso a pesquisa com ndices B-tree. Para alm disso num IS NULL ou IS NOT NULL em que a condio seja usada numa coluna de ndice pode ser feito uso de B-Tree. Hash, O PostGreSQL recorrendo ao uso de ndices do tipo HASH s poder lidar com comparaes de igualdade simples. O plano da query vai considerar o uso de um ndice deste tipo, caso a coluna indexada esteja envolvida numa comparao usando o operador =. GiST, este tipo de ndice no denido como tipo nico, mas sim como uma infra-estrutura de ndices dentro da qual muitas estratgias de indexao diferentes podero ser implementadas. Assim sendo os operadores particulares com os quais um ndice GiST pode ser usado, variam consoante a estratgia de indexao. Como exemplo a distribuio padro do PostGreSQL inclui classes de operadores GiST para vrios tipos de dados geomtricos bidimensionais que suportam consultas indexadas usando estes operadores:

<<, &<, &>, >>, <<, &<, &>, >>, @>, <@, ~=, &&

Exemplo: Os ndices GiST so capazes de optimizar pesquisas do tipo "nearestneighbor".

SELECT * FROM places ORDER BY location <-> point (101,456) LIMIT 10;

Que basicamente procura os 10 locais mais prximos de um dado ponto. possvel processar este tipo de queries, recorrendo a diferentes classes de operadores. GIN, so ndices invertidos que podem lidar com valores que contenham mais do que uma chave, matrizes por exemplo. Semelhana dos ndices GiST os GIN podem suportar diferentes estratgias de indexao denidas pelo utilizador e em particular operadores com os quais um ndice do tipo GIN pode ser usado depende da estratgia de indexao denida. Como exemplo, a distribuio padro do PostGreSQL, inclui classes de operadores GIN para matrizes unidimensionais, que suportam consultas indexadas usando estes operadores:

<@, @>, =, &&

17

Captulo 6

Expresses Complexas
A forma como as expresses so avaliadas e executadas extremamente importante para a performance de um sistema. Torna-se ainda mais importante quando falamos de expresses complexas que podem envolver vrias subqueries, junes, ordenaes, e muitas outras operaes. Existem trs mecanismos diferentes para fazer este tipo de avaliao: Materializao consiste em analisar as expresses (de baixo para cima) guardando o seu resultado em relaes temporrias guardadas na base de dados. Os resultados de cada operao intermdia so armazenados e utilizados em avaliaes de operaes nos nveis superiores; Pipelining consiste na passagem de tuplos para as operaes acima durante a execuo da operao corrente; Paralelizao consiste na execuo paralela de tarefas utilizando mltiplos processadores. O Oracle o nico SGBD dos aqui estudados que suporta este mecanismo.

6.1

MySQL

Aps alguma pesquisa vericmos que existe muito pouca informao sobre qualquer um dos mecanismos descritos anteriormente na documentao do MySQL. Vericmos tambm que ao contrrio do Oracle e do PostGreSQL, o MySQL no suporta materializao de vistas, suportando apenas a materializao de subqueries (ver seco 7.1.10). Conclumos assim que este SGBD no suporta paralelizao, suportando apenas pipelining e materializao, no sendo no entanto possvel escolher que mecanismo pretendemos usar para realizar a avaliao de expresses complexas.

6.2

PostGreSQL

O PostGreSQL, tal e qual como o Oracle e o MySQL, suporta pipelining e tambm materializao. Em relao paralelizao no foi encontrada qualquer referncia na documentao do PostGreSQL. Embora disponibilize diferentes mecanismos,

18

no permite que o utilizador tenha a liberdade de escolher qual o mecanismo a usar, cando essa escolha responsabilidade do planeador, dando este preferncia ao pipelining que, partida, produzir resultados mais rapidamente. As materializaes so usadas em vistas e em algumas subqueries, quando o planeador decide que ca mais em conta materializ-las do que repetir o trabalho em nveis superiores da rvore. Apesar de no ser possvel escolher qual o mecanismo a usar, possvel ligar ou desligar o uso de materializao utilizando o seguinte comando [20]:

enable_material(boolean);

O valor por defeito deste comando ON, no entanto mesmo quando est OFF o uso de materializao no est totalmente suprimido. Nesse caso o planeador est impedido de utilizar materializao, excepto se for necessria para efeitos de correco da query.

19

Captulo 7

Transformaes de Queries
A transformao de queries permite aos SGBDs simplicar o mais possvel uma query de forma a reduzir o nmero de operaes que so necessrias para obter o resultado nal. Isto contribui para uma reduo do tempo de processamento da query, sendo portanto tambm uma forma de optimizao, neste caso optimizao interna, ou seja, feita pelo prprio SGBD.

7.1

MySQL

O MySQL utiliza vrios tipos de optimizao interna [21], os quais discutiremos nas seces que se seguem.

7.1.1

Optimizao de Intervalos

Existem dois tipos de optimizao de expresses com intervalos [22], o primeiro para os casos em que o intervalo utiliza um ndice solteiro e o outro para quando o ndice multi-parte. Intervalos com ndice Solteiro Comeando pelo caso em que usado um ndice solteiro no intervalo, existem vrias formas de construir essa condio dentro da clusula WHERE. A denio de uma condio desse tipo pode ser feita das seguintes formas: Para ambos os ndices BTREE e HASH, a comparao de uma pea-chave com um valor constante uma condio de intervalo quando so usados os operadores =, <=>, IN(), IS NULL ou IS NOT NULL; Alm disso, para os ndices BTREE, a comparao de uma pea-chave com um valor constante uma condio de intervalo quando se utilizam os operadores >, <, >=, <=, BETWEEN, != ou <> , ou, em comparaes com LIKE se o argumento para LIKE uma string constante que no comea com um caractere especial; Para todos os tipos de ndices, condies mltiplas de intervalos combinadas com OR e AND formam uma condio de intervalo.

20

Na listagem acima quando referimos valores constantes, referimo-nos a qualquer um dos seguintes valores: Uma constante denida na query; Uma coluna de uma tabela const ou system usada na mesma juno; O resultado de uma subquery no correlacionada; Qualquer expresso composta inteiramente por sub-expresses dos tipos anteriores. Alguns exemplos de queries que utilizam condies deste tipo na clusula WHERE so as seguintes:

SELECT * FROM t1 WHERE key_col > 1 AND key_col < 10; SELECT * FROM t1 WHERE key_col = 1 OR key_col IN (15,18,20); SELECT * FROM t1 WHERE key_col LIKE ab% OR key_col BETWEEN bar AND foo;

importante notar que alguns valores no constantes podem ser convertidos para constantes durante a fase de propagao de constantes. O MySQL tenta extrair as condies de intervalo da clusula WHERE para cada um dos ndices possveis. Durante o processo de extraco, condies que no podem ser usadas para a construo da condio de intervalo so descartadas, as condies que produzem intervalos sobrepostos so combinadas, e as condies que produzem intervalos vazios so removidas. Consideremos a seguinte declarao, onde key1 uma coluna indexada e nonkey no indexada:

SELECT * (key1 < (key1 (key1 < (key1 <

FROM t1 WHERE abc AND LIKE abcde% OR key1 LIKE %b)) OR bar AND nonkey = 4) OR uux AND key1 > z);

O processo de extraco para a chave key1 realizado da seguinte forma:

21

1. Comeando na clusula WHERE original, so removidas as expresses (nonkey = 4) e (key1 LIKE %b) porque no podem ser utilizadas para vericar intervalos de proximidade. A forma correcta para as remover substitu-las por TRUE. Aps a remoo obtemos: 2. (key1 < abc AND (key1 LIKE abcde% OR TRUE)) OR

(key1 < bar AND TRUE) OR (key1 < uux AND key1 > z)
3. Resolvendo as condies que so sempre verdadeiras (key1 LIKE abcde% OR TRUE) ou falsas (key1 < uux AND key1 > z), e substituindo-as por constantes obtemos: 4. (key1 < abc AND TRUE) OR

(key1 < bar AND TRUE) OR (FALSE)


5. Removendo constantes de TRUE ou FALSE desnecessrias obtemos: 6. (key1 < abc) OR (key1 < bar) 7. Finalmente, ao combinarmos os dois intervalos sobrepostos obtemos a condio nal: 8. (key1 < bar) Em geral (e como foi demonstrado pelo exemplo anterior), a condio utilizada para a vericao de um intervalo menos restritiva que a clusula WHERE. O MySQL executa uma vericao adicional para ltrar linhas que satisfazem a condio do intervalo, mas no a clusula WHERE completa. Atualmente, o MySQL no suporta a fuso de vrios intervalos para o mtodo de acesso range para ndices espaciais. Para contornar esta limitao, pode-se usar um UNION com operaes SELECT idnticas, excepto que cada predicado espacial for colocado num SELECT diferente. Intervalos com ndices Multi-Parte Condies de intervalo em que so usados ndices multi-parte so uma extenso do caso anterior. A condio de intervalo num ndice multi-parte restringe linhas do ndice para permanecerem dentro de um ou vrios intervalos de tuplos chave. Intervalos de tuplos chave so denidos sobre um conjunto de tuplos chave, usando a ordenao do ndice. Por exemplo, considerando um ndice multi-parte denido como key1(key_part1, key_part2, key_part3), e o conjunto de tuplos chave ordenados por chave na tabela 7.1. A condio (key_part1 = 1) dene o seguinte intervalo:

(1,-inf,-inf) <= (key_part1,key_part2,key_part3) < (1,+inf,+inf)

22

Tabela 7.1: Exemplo de conjunto de tuplos chave num ndice. key_part1 NULL NULL NULL 1 1 1 2 key_part2 1 1 2 1 1 2 1 key_part3 abc xyz foo abc xyz abc aaa

Este intervalo cobre a quarta, quinta e sexta posies do conjunto na Tabela 7.1 e pode ser usado no mtodo de acesso a intervalos. Pelo contrrio, a condio key_part3 = abc no dene nenhum intervalo e no pode ser usada no mtodo de acesso a intervalos. De seguida, apresentamos uma lista de como as condies de intervalos funcionam para os ndices multi-parte: Para ndices HASH, cada intervalo que contem valores idnticos pode ser usado. Isto signica que o intervalo pode ser produzido apenas para condies da seguinte forma:

key_part1 cmp const1 AND key_part2 cmp const2 AND ... AND key_partN cmp constN;

Aqui, const1, const2, . . . e constN so constantes, cmp um dos seguintes operadores: =, , ou IS NULL, e as condies cobrem todas as partes do ndice. Isto , h N condies, uma para cada parte de um ndice com N partes. Para um ndice BTREE, um intervalo pode ser til para as condies combinadas com AND, onde cada condio compara uma pea chave com um valor constante usando =, <=>, IS NULL, >, <, >=, <=, !=, <>, BETWEEN, ou LIKE expresso (onde expresso no comea com um carcter especial). Um intervalo pode ser usado, desde que seja possvel determinar um nico tuplo chave que contm todas as linhas que combinam com a condio (ou dois intervalos se <> ou != for usado). O optimizador tenta usar peas-chave adicionais para determinar o intervalo desde que o operador de comparao seja =, <=>, ou IS NULL. Se o operador for >, <, >=, <=, !=, <>, BETWEEN, ou LIKE, o optimizador utiliza-o, mas no considera mais peas-chave. Para a expresso seguinte, o optimizador utiliza o = da primeira comparao. Ele tambm usa >= a partir da segunda comparao, mas no considera mais peas-chave e no usa a terceira comparao para a construo do intervalo:

23

key_part1 = foo AND key_part2 >= 10 AND key_part3 > 10

O intervalo solteiro :

(foo,10,-inf) < (key_part1,key_part2,key_part3) < (foo,+inf,+inf)

possvel que o intervalo criado contenha mais linhas do que a condio inicial. Por exemplo, o intervalo anterior inclui o valor (foo, 11, 0), que no satisfaz a condio original. Se as condies que abrangem conjuntos de linhas contidas dentro de intervalos so combinadas com OR, elas formam uma condio que abrange um conjunto de linhas contidas dentro da unio dos seus intervalos. Se as condies so combinados com AND, elas formam uma condio que abrange um conjunto de linhas contidas na interseco dos seus intervalos. Por exemplo, para esta condio num ndice de duas partes:

(key_part1 = 1 AND key_part2 < 2) OR (key_part1 > 5)

Os intervalos so:

(1,-inf) < (key_part1,key_part2) < (1,2) (5,-inf) < (key_part1,key_part2)

Neste exemplo, o intervalo na primeira linha usa uma pea-chave para o limite esquerdo e duas peas-chave para o limite direito. O intervalo na segunda linha utiliza apenas uma pea-chave. A coluna key_len no output do comado EXPLAIN, referido na seco 8.1.1, indica o comprimento mximo do prexo chave usado. Em alguns casos, key_len pode indicar que uma parte fundamental foi usada, mas isso pode no ser o que se esperaria. Supondo que key_part1 e key_part2 podem ser NULL. Ento, a coluna key_len apresentaria dois comprimentos das peas-chave para a seguinte condio:

24

key_part1 >= 1 AND key_part2 < 2

Mas, na verdade, a condio convertida para:

key_part1 >= 1 AND key_part2 IS NOT NULL

Os passos realizados para resolver condies de intervalo em ndices multi-parte so equivalentes aos descritos na seco anterior.

7.1.2

Optimizao por Fuso de ndices

O mtodo de fuso de ndices [23] usado para obter linhas com vrias intervalos de varrimento e para fundir os seus resultados num s. A fuso pode produzir unies, interseces ou unies-de-interseces de varrimentos subjacentes. Este mtodo de acesso funde a vericao de ndices de uma nica tabela. No output do comando EXPLAIN, apresentado em 8.1.1, o mtodo da fuso de ndices aparece como index_merge na coluna type. Neste caso, a coluna key contm uma lista de ndices usados, e key_len contm uma lista das maiores peaschave para esses ndices. Por exemplo:

SELECT * FROM tbl_name WHERE key1 = 10 OR key2 = 20; SELECT * FROM tbl_name WHERE (key1 = 10 OR key2 = 20) AND non_key=30; SELECT * FROM t1, t2 WHERE (t1.key1 IN (1,2) OR t1.key2 LIKE value%) AND t2.key1=t1.some_col; SELECT * FROM t1, t2 WHERE t1.key1=1 AND (t2.key1=t1.some_col OR t2.key2=t1.some_col2);

O mtodo de fuso de ndices tem vrios algoritmos de acesso, apresentados na coluna Extra da tabela de output do comando EXPLAIN (Seco 8.2.1). Esses algoritmos so: Using intersect(...); 25

Using union(...); Using sort_union(...). A escolha entre as diferentes variantes do mtodo fuso de ndices, e outros mtodos de acesso baseada em estimativas de custo das vrias opes disponveis.

7.1.3 Engine Condition Pushdown Optimization


O Engine Condition Pushdown Optimization (ECP) [24], melhora a ecincia de comparaes directas entre uma coluna no indexada e uma constante. Nesses casos, a condio "empurrada para baixo"para o mecanismo de armazenamento para avaliao. Esta optimizao pode ser usada somente pelo mecanismo de armazenamento NDBCLUSTER. Para o MySQL Cluster, esta optimizao pode eliminar a necessidade de enviar linhas no correspondentes atravs da rede entre os ns de dados do grupo e o MySQL Server que fez a consulta, e pode acelerar as consultas onde usada por um factor de 5 a 10 vezes acima dos casos onde a condio pushdown poderia ser usada mas no . Supondo que uma tabela MySQL Cluster denida da seguinte forma:

CREATE TABLE t1 ( a INT, b INT, KEY(a) ) ENGINE=NDBCLUSTER;

A condio de pushdown pode ser usada com consultas, como a mostrada abaixo, que inclui uma comparao entre uma coluna no indexada e uma constante:

SELECT a, b FROM t1 WHERE b = 10;

No entanto, uma condio de pushdown no pode ser usada nestes dois tipos de queries:

SELECT a,b FROM t1 WHERE a = 10; SELECT a,b FROM t1 WHERE b + 1 = 10;

A condio de pushdown no aplicvel primeira consulta porque existe um ndice em a. Na segunda consulta, no pode ser utilizada porque a comparao que envolve a coluna no indexada b indirecta. 26

Outras comparaes com suporte para a condio de pushdown incluem o seguinte: column [NOT] LIKE expresso Onde expresso dever ser uma string que contm o padro a ser correspondido. column IS [NOT] NULL column IN (lista_de_valores) Cada item na lista_de_valores deve ser uma constante. column BETWEEN constante1 AND constante2 constant1 e constante2 deveram ambas ser constantes. Em todos os casos na lista anterior, possvel que a condio seja convertida na forma de uma ou mais comparaes directas entre uma coluna e uma constante. A condio de pushdown est activada por defeito no MySQL. Para desactiv-la na inicializao do servidor, basta alterar o valor da varivel de sistema optimizer_switch. Esta condio tem ainda as seguintes limitaes: S suportada pelo mecanismo de armazenamento NDBCLUSTER; Colunas podem ser comparadas com apenas constantes, no entanto, isso inclui expresses que avaliam para valores constantes; Colunas usadas em comparaes no podem ser de qualquer um dos tipos BLOB ou TEXT ; Uma string a ser comparada com uma coluna deve usar o mesmo agrupamento da coluna; Junes no so suportadas directamente. Condies envolvendo vrias tabelas so puxadas separadamente, sempre que possvel. O comando EXPLAIN EXTENDED pode ser usado para determinar quais as condies que so realmente pushdown.

7.1.4 Index Condition Pushdown Optimization


Index Condition Pushdown (ICP) [25], uma otimizao para o caso onde o MySQL obtm linhas de uma tabela usando um ndice. Sem ICP , o mecanismo de armazenamento atravessa o ndice para localizar as linhas da tabela base e devolveas para o servidor MySQL que avalia a condio WHERE para as linhas. Com o ICP activo, e se as partes da condio WHERE puderem ser avaliadas usando somente os campos do ndice, o servidor MySQL empurra esta parte da condio para o mecanismo de armazenamento. O mecanismo de armazenamento, em seguida, avalia a condio do ndice empurrado, e somente se esta estiver satisfeita que a linha da tabela lida. O ICP pode reduzir o nmero de vezes que o mecanismo de armazenamento deve aceder tabela base e o nmero de vezes que o servidor MySQL deve aceder ao mecanismo de armazenamento. Este tipo de optimizao usado pelos mtodos de acesso range, ref, eq_ref, e ref_or_null quando h a necessidade de aceder a todas as linhas de uma tabela. Esta estratgia pode ser usada com o InnoDB e MyISAM. 27

Para entender melhor o funcionamento desta optimizao, vamos considerar primeiro como um ndice de varrimento avana quando o ICP no usado: 1. Obter a prxima linha, primeiro pela leitura do ndice, e depois usando o ndice para localizar e ler a linha completa da tabela. 2. Testar a parte da condio WHERE que se aplica a esta tabela. Aceitar ou rejeitar a linha com base no resultado do teste. Quando o ICP est activo, o varrimento feito da seguinte forma: 1. Obter o ndice da prxima linha (mas no a linha completa). 2. Testar a parte da condio WHERE que se aplica a esta tabela e que pode ser vericada usando apenas as colunas de ndice. Se a condio no for satisfeita, prossegue para o ndice da prxima linha. 3. Se a condio for satisfeita, usa o ndice para localizar e ler a linha completa da tabela. Testar a parte restante da condio WHERE que se aplica a esta tabela. Aceitar ou rejeitar a linha com base no resultado do teste. Quando o ICP utilizado, a coluna Extra do output do comando EXPLAIN tem o valor Using index condition. Este tipo de optimizao est activo por defeito no MySQL e pode ser activado ou desactivado alterando o valor da opo index_condition_pushdown da varivel de sistema optimizer_switch.

7.1.5

Optimizao do IS NULL

O MySQL pode realizar a mesma optimizao na expresso nome_coluna IS NULL [26] que ele pode usar para a expresso nome_coluna = valor_constante. Por exemplo, o MySQL pode usar ndices e intervalos para procurar por NULL com IS NULL. Exemplo:

SELECT * FROM tbl_name WHERE key_col IS NULL; SELECT * FROM tbl_name WHERE key_col <=> NULL; SELECT * FROM tbl_name WHERE key_col=const1 OR key_col=const2 OR key_col IS NULL;

Se uma clusula WHERE inclui uma condio do tipo nome_coluna IS NULL para uma coluna que declarada como NOT NULL, essa expresso imediatamente optimizada. Esta optimizao no ocorre em casos em que a coluna pode produzir um valor NULL. O MySQL pode tambm optimizar a combinao nome_coluna = expr OR nome_coluna IS NULL. O EXPLAIN mostra ref_or_null quando este tipo de optimizao usada. 28

7.1.6

Optimizao de LEFT JOIN e RIGHT JOIN

O optimizador de junes [27] calcula a ordem em que as tabelas devem ser unidas. A ordem de leitura de uma tabela forada pelo LEFT JOIN ou STRAIGHT_JOIN ajuda o optimizador de junes a fazer o seu trabalho muito mais rapidamente, porque h menos permutaes da tabela para vericar. De notar que isto signica que se for feita uma consulta do tipo seguinte, o MySQL faz um varrimento completo em b porque o LEFT JOIN obriga-o a ser lido antes de d:

SELECT * FROM a JOIN b LEFT JOIN c ON (c.key=a.key) LEFT JOIN d ON (d.key=a.key) WHERE b.key=d.key;

A correco neste caso seria inverter a ordem em que a e b so listados na clusula FROM:

SELECT * FROM b JOIN a LEFT JOIN c ON (c.key=a.key) LEFT JOIN d ON (d.key=a.key) WHERE b.key=d.key;

Se a condio no WHERE for sempre falsa para a linha gerada com valor NULL, o LEFT JOIN mudado para uma juno normal. Por exemplo, a clusula WHERE iria ser falsa na seguinte query se t2.column1 for NULL:

SELECT * FROM t1 LEFT JOIN t2 ON (column1) WHERE t2.column2=5;

Portanto, seguro converter a query anterior para um join normal:

SELECT * FROM t1, t2 WHERE t2.column2=5 AND t1.column1=t2.column1;

O mesmo que foi descrito nesta seco se aplica para o RIGHT JOIN.

29

7.1.7

Optimizao do ORDER BY

Em alguns casos, o MySQL pode usar um ndice para satisfazer a clusula ORDER BY sem fazer uma ordenao extra [28]. O ndice pode tambm ser usado mesmo se o ORDER BY no corresponder ao ndice exactamente, desde que todas as pores usadas do ndice e todas as colunas extra do ORDER BY sejam constantes na clusula WHERE. Todos os casos seguintes usam o ndice para resolver o ORDER BY.

SELECT * FROM t1 ORDER BY key_part1,key_part2,... ; SELECT * FROM t1 WHERE key_part1=constant ORDER BY key_part2; SELECT * FROM t1 ORDER BY key_part1 DESC, key_part2 DESC; SELECT * FROM t1 WHERE key_part1=1 ORDER BY key_part1 DESC, key_part2 DESC;

Em alguns casos, o MySQL no pode usar ndices para resolver o ORDER BY, no entanto usa ndices para encontrar linhas que correspondem clusula WHERE. Esses casos so alguns dos seguintes: O ORDER BY usado em chaves diferentes:

SELECT * FROM t1 ORDER BY key1, key2;


O ORDER BY usado em partes no consecutivas de uma chave:

SELECT * FROM t1 WHERE key2=constant ORDER BY key_part2;


Uso de ASC e DESC:

SELECT * FROM t1 ORDER BY key_part1 DESC, key_part2 ASC;


A chave usada para obter as linhas no a mesma que usada no ORDER BY :

SELECT * FROM t1 WHERE key2=constant ORDER BY key1;


O ORDER BY usado com uma expresso que no inclui a coluna da chave primria: 30

SELECT * FROM t1 ORDER BY ABS(key); SELECT * FROM t1 ORDER BY -key;


Quando se faz a juno de muitas tabelas, e as colunas no ORDER BY no so todas da primeira tabela no constante usada para obter as linhas. (Esta a primeira tabela no output do EXPLAIN que no tem o tipo de juno const; As expresses ORDER BY e GROUP BY so diferentes; indexado apenas um prexo da coluna usada no ORDER BY. Neste caso, o ndice no pode ser usado para resolver completamente a ordem de ordenao. Por exemplo, se tivermos uma coluna CHAR(20), que indexa apenas os 10 primeiros bytes, o ndice no distingue valores para alm do dcimo byte e ser necessrio um lesort. O tipo de ndice da tabela no guarda as linhas por ordem. Por exemplo, isto acontece quando usado um ndice HASH numa tabela MEMORY. A disponibilidade de um ndice para a ordenao pode ser afectada pelo uso do alias da coluna. Suponhamos que a coluna t1.a est indexada. Nesta declarao, o nome da coluna na lista de seleo a. Esta refere-se a t1.a, portanto, para a referncia a a no ORDER BY, o ndice pode ser usado:

SELECT a FROM t1 ORDER BY a;

Na prxima query, o nome da coluna na lista de seleco tambm a, no entanto este nome o alias de ABS(a). Portanto, para a referncia de a no ORDER BY o ndice no pode ser usado:

SELECT ABS(a) AS a FROM t1 ORDER BY a;

Por defeito, o MySQL ordena todas as queries com GROUP BY col1, col2, ... como se fossem ORDER BY col1, col2, .... Se for includa explicitamente uma clusula ORDER BY que contm a mesma lista de colunas, o MySQL optimiza o GROUP BY sem qualquer penalizao na rapidez, embora a ordenao tambm ocorra. Se a query inclui um GROUP BY mas se quer evitar que o resultado seja ordenado, pode impedir-se a ordenao usando ORDER BY NULL.

7.1.8

Optimizao do GROUP BY

A forma mais geral de satisfazer um GROUP BY [29] fazer um varrimento da tabela toda e criar uma nova tabela temporria onde todas as linhas de cada grupo so consecutivas, e depois usar essa tabela temporria para descobrir grupos e aplic-los s funes de agregao (se houver algumas). Em alguns casos, o MySQL

31

capaz de fazer muito melhor que isso, evitando a criao de tabelas temporrias usando ndices. Os pr-requisitos mais importantes para a utilizao de ndices com o GROUP BY so, primeiro, que todos os atributos das colunas usadas no GROUP BY referenciem o mesmo ndice, e segundo, que o ndice armazene as suas chaves em ordem (por exemplo, este um ndice BTREE e no um ndice HASH). Se o uso de tabelas temporrias pode ou no ser substitudo por acesso do ndice depende tambm de quais partes do ndice so usadas numa consulta, das condies especicadas por essas partes, e das funes de agregao seleccionadas. H duas maneiras de executar uma consulta GROUP BY com uso de ndices. No primeiro mtodo, a operao de agrupamento aplicada juntamente com todos os predicados de intervalo (se os houver). O segundo mtodo primeiro executa um varrimento dos valores no intervalo, e depois agrupa os tuplos resultantes. No MySQL, o GROUP BY usado para ordenao, portanto o servidor pode tambm aplicar optimizaes do ORDER BY em agrupamentos (ver Seco 7.1.7).

7.1.9

Optimizao do DISTINCT

Na maioria dos casos, a clusula DISTINCT [30] pode ser considerada como um caso especial do GROUP BY. Por exemplo, as duas queries a seguir so equivalentes:

SELECT DISTINCT c1, c2, c3 FROM t1 WHERE c1 > const; SELECT c1, c2, c3 FROM t1 WHERE c1 > const GROUP BY c1, c2, c3;

Devido a esta equivalncia, as optimizaes aplicveis a consultas com GROUP BY podem ser tambm aplicadas a consultas com uma clusula DISTINCT. Ao combinar LIMIT row_count com DISTINCT, o MySQL ir parar logo que encontrar row_count linhas nicas. Se numa consulta no forem utilizadas colunas de todas as tabelas, o MySQL ir parar o varrimento das tabelas no usadas logo que encontrar a primeira combinao. No caso seguinte, assumindo que t1 usado antes de t2, o MySQL pra de ler de t2 (para qualquer linha particular em t1) quando encontra a primeira linha em t2:

SELECT DISTINCT t1.a FROM t1, t2 where t1.a=t2.a;

32

7.1.10

Optimizao de Subqueries

Subqueries IN/=ANY Certas optimizaes so aplicveis a comparaes que usam o operador IN (ou ANY, que equivalente) [31], para testar os resultados de subqueries. Nesta seco discutimos esses tipos de optimizaes, em particular o desao de lidar com valores NULL nestas situaes. Consideremos a seguinte comparao com uma subquery:

outer_expr IN (SELECT inner_expr FROM ... WHERE subquery_where)

O MySQL avalia queries de fora para dentro. Isto , primeiro obtm o valor da expresso de fora outer_expr, e depois corre a subquery e obtm as linhas resultantes. Uma optimizao muito til informar a subquery que as nicas linhas de interesse so aquelas onde a expresso interna inner_expr igual expresso exterior outer_expr. Isto feito colocando uma igualdade apropriada na clusula WHERE. Portanto, a comparao anterior convertida para:

EXISTS (SELECT 1 FROM ... WHERE subquery_where AND outer_expr=inner_expr)

Depois da converso, o MySQL pode usar a nova igualdade para limitar o nmero de linhas que devem ser examinadas quando a subquery avaliada. No geral, a comparao de N valores com uma subquery que retorna linhas com N -valores pode tambm ser optimizada da forma descrita anteriormente. A converso anteriormente descrita tem algumas limitaes. Esta s e vlida se ignorarmos os valores NULL, ou seja, essa aproximao s vlida quando os valores de ambos os lados da expresso no so NULL, ou quando o resultado nal no NULL. Suponhamos portanto que outer_expr no NULL, mas a subquery no produz nenhum valor que satisfaa outer_expr = inner_expr. Ento o resultado de outer_expr IN (SELECT ...) ser: NULL, se o SELECT produzir uma linha onde inner_expr NULL; FALSE, se o SELECT produzir apenas valores que no so NULL ou no produzir nada. Nesta situao, a condio outer_expr = inner_expr deixa de ser vlida. necessrio procurar por tais linhas, mas se nenhuma for encontrada, tambm necessrio procurar por linhas onde inner_expr NULL. Sendo assim, a subquery convertida para:

33

EXISTS (SELECT 1 FROM ... WHERE subquery_where AND (outer_expr=inner_expr OR inner_expr IS NULL) )

A necessidade de avaliar a condio extra IS NULL a razo pela qual o MySQL tem o mtodo de acesso ref_or_null. A condio adicional OR ... IS NULL torna a execuo da query ligeiramente mais complicada, mas geralmente tolervel. O pior quando a expresso outer_expr pode ser NULL. De acordo com a interpretao do SQL do valor NULL como valor desconhecido, NULL IN (SELECT inner_expr ...) avaliado para: NULL, se o SELECT produzir quaisquer linhas; FALSE, se o SELECT produzir zero linhas. Portanto para realizar uma avaliao correcta, necessrio ser possvel vericar se o SELECT produziu ou no algumas linhas, para isso a expresso outer_expr = inner_expr no pode ser colocada na subquery. Essencialmente, devem haver formas de executar a subquery dependendo do valor de outer_expr. A forma adoptada pelo MySQL consiste basicamente em ter sempre em conta que o valor de outer_expr pode ser NULL. Assim se outer_expr for NULL, para avaliar a seguinte expresso, necessrio executar o SELECT original para determinar se este produz algumas linhas:

NULL IN (SELECT inner_expr FROM ... WHERE subquery_where)

Por outro lado quando outer_expr no NULL, absolutamente essencial que esta comparao:

outer_expr IN (SELECT inner_expr FROM ... WHERE subquery_where)

Seja convertida para esta:

EXISTS (SELECT 1 FROM ... WHERE subquery_where AND outer_expr=inner_expr )

34

Sem esta converso, as subqueries so mais lentas. Desta forma, necessrio que o MySQL seja capaz de determinar quando deve empurrar as condies para a subquery. A soluo encontrada usar um trigger que recebe essas condies, obtendo-se uma query da forma:

EXISTS (SELECT 1 FROM ... WHERE subquery_where AND trigcond(outer_expr=inner_expr))

De forma geral, se a comparao da subquery baseada em vrios pares de expresses externas e internas, a forma da comparao :

(oe_1, ..., oe_N) IN (SELECT ie_1, ..., ie_N FROM ... WHERE subquery_where)

E convertida para a seguinte expresso:

EXISTS (SELECT 1 FROM ... WHERE subquery_where AND trigcond(oe_1=ie_1) AND ... AND trigcond(oe_N=ie_N) )

Subqueries na clusula FROM O optimizador do MySQL resolve as subqueries na clusula FROM [31] da seguinte forma: A materializao de subqueries na clusula FROM adiada at os contedos desta serem necessrios durante a execuo da query, o que aumenta a performance; Durante a execuo da query, o optimizador dever adicionar um ndice para uma tabela derivada, de forma a acelerar a recolha de linhas.

7.2

PostGreSQL

No caso do PostGreSQL no encontramos tantos tipos de optimizao interna como no caso do MySQL, o que provavelmente signica que este suporta menos tipos de optimizao. Nesta seco ser falado da optimizao geral, feita pelo PostGreSQL e, de seguida, explicado o funcionamento de um algoritmo de optimizao utilizado pela tecnologia. 35

7.2.1

Optimizao Geral

O optimizer [32] comea por gerar planos para analisar cada tabela utilizada na query. Os planos possveis so determinados pelos ndices disponveis em cada tabela, existindo sempre a possibilidade de efectuar uma anlise sequencial. Por exemplo, assumindo que um ndice denido numa tabela e uma query contm a restrio table.attribute OPR constant. Caso o ndice combine com a table.attribute e OPR um dos operadores listado na classe de operadores desse mesmo ndice, um outro plano criado utilizando o ndice para analisar a tabela. Se existirem mais ndices que combinem com as restries da query mais planos sero criados. Planos de anlise de ndices so tambm gerados para ndices com uma ordenao que combina com a clusula ORDER BY da query, ou uma ordenao que poder ser til para um merge join, que ser explicado de seguida. Aps todos os planos de relaes nicas serem analisados, caso existam joins na query, o optimizer poder utilizar trs diferentes estratgias: nested loop join A tabela da direita analisada uma vez para cada linha encontrada na tabela da esquerda. Esta estratgia, apesar de simples de implementar poder perder em performance; merge join Cada tabela ordenada pelos atributos de juno antes do incio da juno. Ambas as tabelas so, depois, analisadas em paralelo e so combinadas as linhas que coincidem, formando-se as linhas de juno. Nesta estratgia cada linha apenas analisada uma vez, no entanto, tem o peso inicial de ordenao. A ordenao poder ser feita utilizando um algoritmo para ordenar, ou fazendo a anlise da tabela na ordem correcta utilizando um ndice na chave da juno. hash join A tabela da direita analisada e carregada para uma tabela de hash, utilizando os atributos da juno como chaves de hash. De seguida feita a anlise da tabela da esquerda e os valores apropriados de cada linha encontrada, so usados como chaves de hash para localizar a combinao de linhas, na tabela, correspondente. Quando a query envolve mais do que duas tabelas o resultado nal consiste numa rvore de paos de juno, cada um deles com dois inputs. O optimizer avalia as diferentes possibilidades de juno e encontra a mais barata.

7.2.2 Genetic Query Optimizer


Como foi explicado anteriormente, na seco 3.2, caso o nmero de joins seja demasiado grande, em vez de uma pesquisa exaustiva dos diferentes caminhos, o PostGreSQL utiliza um mtodo heurstico chamado de Genetic Query Optimizer (GEQO) [13]. Este mdulo tira partido de um algoritmo gentico. Um algoritmo gentico um mtodo heurstico que funciona com o uso de uma pesquisa aleatria. O conjunto das solues possveis para um problema de optimizao considerado como uma populao de indivduos e o grau de adaptao de cada indivduo ao seu ambiente especicado pela sua tness. As coordenadas de um indivduo no espao de pesquisa so representados pelos cromossomas e um gene uma subseco de um cromossoma que codica o valor de um nico

36

parmetro a ser optimizado. Pela simulao de operaes de evoluo (recombinao, mutao e seleco) novas geraes de pontos de pesquisa, que mostram uma maior mdia de tness, so encontrados. Para cada tabela individual o GEQO utiliza a anlise de planos tradicional e para os planos de juno utilizado o algoritmo gentico, como foi explicado anteriormente. O processo de optimizao como se fosse o problema do caixeiro viajante [33]. Planos possveis so codicados como integer strings. Cada string representa a ordem de juno de uma tabela da query com a prxima. Inicialmente, o GEQO gera, aleatoriamente, algumas sequncias possveis de junes e, para cada uma delas, invocado o planner tradicional para estimar o custo de executar a query com a sequencia de juno, sendo o custo estimado o mais barato de todas as possibilidades. As sequncias com um custo estimado inferior so consideradas com maior t. O algoritmo gentico descarta os candidatos com menor t e, novos candidatos so gerados pela combinao dos genes de candidatos com maior tness, isto , pela combinao de pores, aleatoriamente escolhidas, de sequncias (com um baixo custo) j conhecidas. Este processo repetido at que um determinado nmero de sequncias tenha sido considerado. De seguida, a que tiver maior tness durante a pesquisa, selecionada e gerada no plano nal. Este processo , inerentemente, no determinstico, devido s escolhas aleatrias feitas, tanto no inicio, como na seleco de subsequentes mutaes dos melhores candidatos. De forma a evitar mudanas surpreendentes na seleco de planos, cada vez que o GEQO corrido, o algoritmo reinicia o gerador de nmeros aleatrios com o parmetro de semente corrente. Sempre que os parmetros do GEQO e a semente sejam mantidos xos o mesmo plano ser gerado, para uma determinada query. A rvore do plano nal consiste numa sequencia de anlises de ndices das tabelas base, mais o resultado de uma das trs estratgias de juno e alguns passos auxiliares que sejam necessrios.

37

Captulo 8

Planos de Execuo de Queries


8.1 Uso do EXPLAIN

O comando EXPLAIN usado para obter informao sobre como o MySQL, PostGreSQL ou Oracle executam uma determinada query. Entre essa informao poderemos encontrar como feita a anlise da(s) tabela(s), como feita a juno destas e em que ordem, quais os custos associados aos mtodos de juno utilizados, entre outros. Assim com a ajuda deste comando possvel, por exemplo, determinar quando devemos adicionar ndices s tabelas de forma a executar mais rapidamente uma query. A sintaxe deste comando bastante diferente entre os trs SGBDs aqui discutidos. No caso do Oracle o comando EXPLAIN utilizado para gerar o plano de uma query e guarda-o numa tabela de sistema, sendo depois necessrio fazer um SELECT a esta tabela para obter a informao do plano, mas como poderemos ver nas prximas seces isso um pouco diferente no MySQL e PostGreSQL.

8.1.1

MySQL

No caso do MySQL a sintaxe do comando [34] a seguinte:

EXPLAIN [EXTENDED | PARTITIONS] { SELECT statement | DELETE statement | INSERT statement | REPLACE statement | UPDATE statement }

Como possvel vericar este comando pode ser utilizado para descrever a execuo de SELECT, DELETE, INSERT, REPLACE e UPDATE. O parmetro opcional EXTENDED, pode ser utilizado para obter informao adicional. E nalmente, o parmetro PARTITIONS, tambm opcional, til apenas para examinar queries que 38

envolvam tabelas particionadas. Os parmetros opcionais no podem ser usados ambos em simultneo. Este comando pode tambm ser utilizado com a seguinte sintaxe:

EXPLAIN nome_tabela

Neste caso o resultado ir ser informao acerca da tabela e respectivos campos, como por exemplo, chaves primrias e estrangeiras, campos obrigatrios e opcionais e os tipos de dados destes. Ao contrrio do que acontece no Oracle quando este comando executado no MySQL a tabela com os resultados imediatamente apresentada ao utilizador. O mesmo acontece no PostGreSQL, no entanto nesse caso apresentada uma rvore e no uma tabela. O contedo da tabela de output do EXPLAIN do MySQL apresentado na seco 8.2.1

8.1.2

PostGreSQL

Quanto ao PostGreSQL a sintaxe [35] um pouco diferente, como possvel ver abaixo:

EXPLAIN [ ( option [, ...] ) ] statement EXPLAIN [ ANALYZE ] [ VERBOSE ] statement


onde option pode ser uma das seguintes:

ANALYZE [ boolean ] VERBOSE [ boolean ] COSTS [ boolean ] BUFFERS [ boolean ] FORMAT { TEXT | XML | JSON | YAML }

Neste caso h um maior nmero de parmetros opcionais e podemos obter informao sobre o mesmo tipo de comandos que no MySQL e tambm sobre o CREATE TABLE AS, DECLARE, EXECUTE e VALUES, com excepo do REPLACE que no existe neste SGBD. A varivel boolean utilizada para especicar se o comando ser ou no utilizado, podendo assumir os valores TRUE, ON ou 1 para seleccionar a opo, ou FALSE, OFF ou 0 para desligar a opo. O parmetro opcional ANALYZE, quando usado causa a execuo da query e no apenas o seu planeamento, sendo assim possvel vericar se as estimativas do planeador esto ou no prximas da realidade. O VERBOSE equivalente ao EXTENDED do MySQL, pois tambm utilizado para obter informao adicional. O COSTS o nico que est seleccionado por defeito e responsvel por incluir informao sobre o custo de arranque, o custo total de cada n do plano, uma estimativa do nmero de linhas e respectivo comprimento. 39

O BUFFERS oferece informao sobre o uso de buffers e s deve ser utilizado com o parmetro ANALYZE. O FORMAT especica o formato do output, que pode ser TEXT, XML, JSON ou YAML. O valor por defeito deste comando o primeiro, embora os outros formatos contenham a mesma informao e sejam mais fceis de analisar por outros programas. Como j referimos anteriormente, o resultado do EXPLAIN do PostGreSQL apresentado na forma de rvore, imediatamente aps a execuo do comando. Para uma maior descrio sobre o output deste comando, consultar a seco 8.2.2.

8.2

Output do EXPLAIN

A forma como os resultados do comando EXPLAIN so apresentados diferente entre os vrios SGBDs a serem analisados.

8.2.1

MySQL

O MySQL, como dito em [36], retorna uma linha de informao por cada tabela utilizada num SELECT. Cada linha aparece na ordem pela qual este processa o contedo das tabelas, sendo as junes destas resolvidas utilizando o mtodo de juno nested-loop. Quando o parmetro EXTENDED utilizado, o EXPLAIN produz informao extra, como foi dito anteriormente, que pode ser visualizada utilizando o comando SHOW_WARNINGS aps a execuo do EXPLAIN. Esta informao apresenta como o optimizador qualica os nomes das tabelas e colunas no SELECT, qual o aspecto deste ltimo depois da aplicao de regras de rescrita e optimizao, e possivelmente outras notas sobre o processo de optimizao. Para alm disso, o uso do EXTENDED adiciona tabela de output a coluna ltered. Na Tabela 8.1 descrito o signicado de cada coluna de uma linha da tabela de output do EXPLAIN. Alguns dos valores de cada coluna so apresentados em maior detalhe depois da tabela. Tabela 8.1: Colunas da tabela de output do EXPLAIN. Coluna id select_type table type possible_keys key key_len ref rows ltered Extra Signicado O identicador do SELECT. O tipo do SELECT. A tabela correspondente linha de output. O tipo de juno utilizada. Os ndices possveis para escolha. O ndice escolhido. O comprimento do ndice escolhido. As colunas comparadas com o ndice. Estimativa de linhas a ser examinadas. Estimativa percentual dos registos da tabela que sero ltrados pela condio. Informao adicional.

40

A primeira coluna, id, contem o nmero sequencial do comando SELECT dentro da query. A coluna select_type pode assumir um dos valores apresentados na Tabela 8.2, apresentada abaixo. Tabela 8.2: Lista de valores para a coluna select_type do output do EXPLAIN. Valor SIMPLE PRIMARY UNION DEPENDENT UNION UNION RESULT SUBQUERY DEPENDENT SUBQUERY DERIVED UNCACHEABLE_SUBQUERY Signicado SELECT simples (no utiliza UNION nem subqueries). O SELECT principal, ou externo. O segundo ou ltimo SELECT numa UNION. O segundo ou ltimo SELECT numa UNION, dependente da query exterior. Resultado de uma UNION. Primeiro SELECT numa subquery. Primeiro SELECT numa subquery, dependente da queryexterior. Tabela derivada de um SELECT. Uma subquery para a qual o resultado no pode ser cached e que deve ser reavaliada por cada linha da query externa. O segundo ou ltimo SELECT numa UNION que pertence a uma query do tipo UNCACHEABLE_SUBQUERY (linha anterior).

UNCACHEABLE_UNION

A coluna type que indica o tipo de juno utilizada, pode assumir um dos seguintes valores: system a tabela contm apenas um registo, sendo este um caso especial do tipo de juno const; const a tabela tem pelo menos um registo que coincide, o que lido desde o inicio da query. As tabelas const so bastante rpidas uma vez que so lidas apenas uma vez; eq_ref um registo lido da tabela, para cada combinao de registos das tabelas anteriores; ref todos os registos que coincidam com o valor do ndice so lidos da tabela, para cada combinao de registos das tabelas tratadas anteriormente. O ref utilizado se a juno usar apenas o prexo mais esquerda da chave ou se a chave no primria ou de ndice UNIQUE. Pode ser usado para colunas indexadas que sejam comparadas a partir dos operadores de comparao =, <=>; fulltext esta juno processada a partir de um ndice FULLTEXT ; ref_or_null idntico ao ref, se bem que ainda feita uma procura extra pelo MySQL, procura de registos que contenham valores NULL. Este tipo de optimizao de juno utilizado maioritariamente na avaliao de subqueries; 41

index_merge indica que foi utilizada uma optimizao Index Merge. Neste caso, a coluna key da tabela resultante do comando EXPLAIN, contm a lista de ndices usados, enquanto que a key_len contm a lista das maiores partes das chaves dos ndices utilizados; unique_subquery substitui o ref por algumas subqueries IN, isto , a partir de uma funo de pesquisa por ndice, reformula a subquery de forma a obter uma maior ecincia; index_subquery este tipo de juno semelhante ao unique_subquery. Substituindo as subqueries IN, mas funciona para os ndices no-nicos de subqueries; range apenas os registos que esto num dado intervalo so devolvidos, estes registos so seleccionados a partir da utilizao de ndices. Para estes tipos de juno a coluna ref tem o valor NULL. O range pode ser usado quando uma chave comparada com uma constante atravs da utilizao de operadores de comparao; index este tipo de juno o mesmo que o ALL, exceptuando o facto de que apenas a rvore de ndices vericada. Normalmente, este tipo mais rpido que o ALL, uma vez que o cheiro dos ndices maioritariamente mais pequeno que o cheiro de dados; ALL feita uma vericao completa sobre uma tabela para cada combinao de registos das tabelas j analisadas. possvel evitar este ALL atravs da criao de ndices que permitem a recuperao do registo da tabela baseada em valores constantes ou valores de colunas de tabelas anteriores. Quanto coluna possible_keys, esta pode assumir o valor NULL, representando a inexistncia de ndices relevantes para a seleco. Neste caso, possvel tentar melhorar o desempenho da query, examinando a clusula WHERE, e vericando se existe alguma coluna referenciada que beneciasse com a criao de um ndice. A coluna key pode referenciar um ndice que no est presente na coluna possible_keys. Isso pode acontecer se nenhum dos ndices em possible_keys for apropriado e se todas as colunas seleccionadas pela query so colunas de outro ndice qualquer. Se o valor de key for NULL, o MySQL no encontrou nenhum ndice que tornasse a query mais eciente. O MySQL pode ser forado a usar ou ignorar um ndice listado em possible_keys utilizando um dos seguintes comandos na query, FORCE INDEX, USE INDEX, IGNORE INDEX. No InnoDB, um ndice secundrio pode ser seleccionado mesmo que a query j tenha seleccionado a chave primria, uma vez que o InnoDB guarda o valor da chave primria com cada ndice secundrio. Em relao s tabelas MyISAM, pode utilizar-se o comando ANALYZE TABLE para ajudar o optimizador a escolher os melhores ndices. A coluna ltered opcional, como j foi referido anteriormente deve ser usado o parmetro EXTENDED para aparecer. Esta indica uma estimativa percentual dos registos da tabela que sero ltrados pela condio, isto , rows contm o nmero r ows f il t er ed representa o nmero de estimado de registos que so examinados e 100 registos que sofrero a juno das tabelas anteriores. Finalmente, a coluna Extra contm alguma informao adicional. Segue-se uma lista com os valores que esta coluna pode tomar. Se se pretender melhorar a

42

velocidade de uma query, aconselhvel analisar os valores Using lesort e Using temporary. const row not found a tabela encontra-se vazia, para uma query do tipo:

SELECT ... FROM nome_tabela;

Distinct o MySQL procura por valores distintos e assim que encontra um registo que coincida, pra a procura por mais registos; Full scan on NULL key esta situao ocorre na optimizao de uma subquery, uma vez que o plano de optimizao no pde utilizar a pesquisa por ndice; Impossible Having a clusula HAVING sempre falsa e no selecciona qualquer registo; Impossible Where a clusula WHERE sempre falsa e no selecciona qualquer registo; Impossible Where notice after reading const tables o MySQL leu todas as tabelas constantes e informa que a clusula WHERE sempre falsa; No matching min/max row nenhum registo satisfaz a condio de uma query do tipo:

SELECT MIN(...) FROM ... WHERE condio.

no matching row in const table para queries com junes, existe uma tabela sem registos ou ento sem registos que satisfaam a condio do ndice nico; No tables used a query no tem a clusula FROM, ou ento tem uma clusula FROM DUAL em que nenhuma tabela foi especicada; Not exists o MySQL consegue fazer uma optimizao do LEFT JOIN na query e no necessita de examinar mais registos nesta tabela para as anteriores combinaes depois de encontrar um registo que respeite o critrio de LEFT JOIN ; Range checked for each record (index map N) o MySQL no encontrou nenhum ndice que fosse bom para utilizar. Ainda assim, vericou que alguns podem ser utilizados depois de se conhecerem os registos das tabelas anteriormente analisadas; Scanned N databases este valor indica quantas directorias foram processadas durante a execuo da query;

43

Select tables optimized away a query contm apenas funes de agregao (Min(), Max()) que foram resolvidas atravs de um ndice. O plano de optimizao determinou que apenas um registo deveria ser devolvido; Skip_open_table, Open_frm_only, Open_trigger_only, Open_full_table qualquer destes valores indica que foi aplicada uma optimizao na abertura do cheiro sobre as queries que envolvem as tabelas INFORMATION_SCHEMA; Skip_open_table os cheiros das tabelas no necessitam ser abertos. A informao j se encontra disponvel a partir da pesquisa nas directorias da base de dados; Open_frm_only apenas os cheiros .frm da tabela necessitam de ser abertos; Open_trigger_only apenas os cheiros .TRG da tabela necessitam de ser abertos; Open_full_table os cheiros .frm, .MYD e .MYI da tabela necessitam de ser abertos; unique row not found para uma query do tipo,

SELECT ... FROM nome_tabela,

nenhum registo satisfaz a condio de ndice nico ou de chave-primria da tabela; Using lesort o MySQL deve fazer mais um passo para encontrar a forma de recuperar os registos ordenados; Using index a informao da tabela obtida utilizando apenas informaes que estejam na rvore de ndices, sem ter que fazer nenhuma pesquisa adicional para ler o registo actual. Tal pode acontecer quando a consulta s utiliza colunas que fazem parte de um nico ndice. No caso do storage engine InnoDB, as tabelas que tm um clustered index denido pelo utilizador, esse ndice pode ser utilizado mesmo quando est ausente o valor Using index na coluna Extra. Este o caso em que a coluna type tem index e a key contm Primary; Using index for group-by Idntico ao anterior, indicando que o MySQL descobriu um ndice que pde ser usado para obter todas as colunas de uma query com GROUP BY ou DISTINCT sem qualquer acesso extra ao disco para a actual tabela; Using join buffer as tabelas provenientes de junes anteriores so lidas em pores para dentro do join buffer, e ento os seus registos so utilizados no buffer para efectuar a juno com a actual tabela; Using sort_union(...), Using union(...), Using intersect(...) indica como os ndices so unidos obtendo-se o tipo de juno index_merge;

44

Using temporary - para resolver a consulta o MySQL necessita criar uma tabela temporria para guardar o resultado. Esta situao normalmente sucede quando a query contm as clusulas GROUP BY e ORDER BY referindo-se a colunas diferentes; Using where - indica o uso da clusula WHERE que o utilizador usou para limitar a consulta. No caso da coluna Extra no conter este valor e o tipo de join contiver ALL ou index, algo de errado se passa com a query; Using where with pushed condition - este valor apenas se aplica a tabelas NDBCLUSTER1 . Signicando que o MySQL Cluster est a utilizar a optimizao Condition Pushdown para melhorar a ecincia de uma comparao directa entre uma constante e uma coluna no indexada.

8.2.2

PostGreSQL

No PostGreSQL, contrariamente ao MySQL, o output [37] do comando EXPLAIN uma rvore, onde cada n corresponde a um plano. Os ns no nvel mais baixo da rvore contm informao sobre como as tabelas so percorridas. Estes ns podem ser de diferentes tipos consoante os mtodos de acesso utilizados: sequencial scan, index scan e bitmap index scan. Se a query necessitar de operaes de juno, agregao, ordenao, ou outras operaes que afectem de algum modo os dados na(s) tabela(s), ento iram haver ns adicionais acima dos referidos anteriormente para executar essas operaes. Uma vez mais, h tambm mais do que uma forma de realizar este tipo de operaes, portanto podem aparecer aqui diferentes tipos de ns. No nal, cada n da rvore apresentado numa linha, que contm o tipo bsico deste e o custo estimado para a execuo desse n. A primeira linha do output (n no nvel mais alto) apresenta uma estimativa do custo total de execuo do plano, sendo este o nmero que se planeia minimizar. Abaixo apresentamos um exemplo trivial do aspecto do output:

EXPLAIN SELECT * FROM tenk1; QUERY PLAN --------------------------------------------------------Seq Scan on tenk1 (cost=0.00..458.00 rows=10000 width=244)

Como possvel observar neste exemplo, o output tem uma nica linha que comea por dizer o tipo de scan utilizado na tabela tenk1, que foi neste caso o sequential scan. E frente apresenta alguns valores que tm o seguinte signicado (da esquerda para a direita): cost Este campo apresenta dois valores separados por ... O primeiro uma estimativa do custo de arranque e o segundo uma estimativa do custo
1 NDBCLUSTER mais um dos storage engines do MySQL, com caractersticas como: adicionar ndices e alterar tabelas online, adicionar ns e reorganizar tabelas online, fazer backup e upgrades online, mecanismo de triggers assncronos sobre alteraes de dados.

45

total da operao. Este ltimo s aparece se for possvel executar a operao at ao m. Ambos os custos so geralmente medidos em unidades de disk page fetches; rows Nmero estimado do total de linhas que seriam obtidas ao executar este plano. Este valor s apresentado caso seja possvel executar a operao at ao m; width Estimativa do tamanho mdio (em bytes) das linhas retornadas por este plano.

46

Captulo 9

Estimativas
9.1 MySQL

9.1.1 Query Performance


Relativamente ao MySQL, na maioria dos casos, a estimativa da performance [38] de uma query feita pela contagem do nmero de disk seeks efectuados. Para tabelas de pequena dimenso possvel encontrar uma linha num disk seek, devido ao ndice estar, provavelmente, em cache. No entanto, para tabelas de maior dimenso, feita uma estimativa utilizando ndices de B-tree, da seguinte forma: log( r ow _count )
index _ block_leng th log( 3

2 ) index _leng th+dat a_ point er _leng th

+1

Sendo o resultado o nmero de seeks necessrios para encontrar uma linha. Em MySQL, um bloco de ndices corresponde a 1.024 bytes e o apontador para os dados 4 bytes. Sendo, ento, a ttulo de exemplo, para uma tabela com 500.000 linhas com um comprimento de chave de trs bytes temos: log(500.000) log( 1024 3
2 ) 3+4

+ 1 = 4seeks.

Este ndice iria necessitar de cerca de 500.000 7 3/2 = 5, 2MB de capacidade de armazenamento (assumindo um buffer com uma taxa de preenchimento de 2/3). Estando a maior parte do ndice em memria, s seria necessrio uma ou duas chamadas para a leitura da data, para encontrar a linha. Em relao escrita necessrio quatro pedidos seek para encontrar o local onde colocar o novo valor de ndice e, geralmente, dois seeks para actualizar o ndice e escrever a linha. Apesar desta estimativa, isto no quer dizer que a performance da aplicao seja, ao longo do tempo, log N . Desde que tudo se mantenha em cache, tanto pelo 47

OS como pelo MySQL, a performance s diminui, um pouco, quando as tabelas se tornam relativamente grandes. Quando os dados se tornam demasiado grandes para serem cached que a aplicao comea a car muito mais lenta devido ao nmero elevado de disk seeks. Para evitar que isto acontea aconselhado o aumento do tamanho da cache ao longo que se d o aumento dos dados. Para as tabelas MyISAM, por exemplo, o tamanho da cache controlado pela varivel de sistema key_buffer_size. No sistema MySQL existe ainda a possibilidade de optimizar queries baseando esta operao em duas variveis de sistema : optimize_prune_level por omisso esta varivel tem o valor 1 e permite que sejam descartados alguns planos de execuo baseando-se para isso no nmero de linhas acedidas em cada tabela. Esta congurao escolhe na maioria das vezes o melhor plano para execuo da query, permitindo assim reduzir drasticamente o tempo de compilao da query. optimizer_search_depth esta varivel permite que o optimizador de queries possa olhar para um plano incompleto, e complet-lo de forma a tornar a query mais eciente. Um valor menor desta varivel permite um tempo de resposta reduzido no processamento da query, i.e. pensando num exemplo de uma query com cerca de 12, 13 ou mais tabelas, a mesma precisar de horas ou dias para ser processada, caso o valor do optimizer_search_depth esteja prxima do nmero de tabelas presentes na query. No caso de ser utilizado um valor menor digamos que 3,4 o tempo de processamento da query reduz-se drasticamente. Em caso de no haver um valor razovel para esta varivel deve-se por omisso usar o valor 0.

9.2
9.2.1

PostGreSQL
Analyze

O comando ANALYZE colecciona estatsticas acerca do contedo das tabelas, e guarda esse resultado numa classe de sistema pg_statistic. Posteriormente o plano da query, usa estas estatsticas para criar plano ptimo que permite uma eciente execuo da query. Se no for passado nenhum parmetro ao comando ANALYZE, todas as tabelas existentes na Base de Dados so examinadas, com passagem de parmetros possvel especicar quais as tabelas e colunas que queremos analisar. Sintaxe:

ANALYZE [ VERBOSE ] [ table [ ( column [, ...] ) ] ]

Os parmetros existentes no comando ANALYZE so os seguintes: VERBOSE Activa o visualizao de mensagens devolvidas pela execuo do comando; table Dene o nome da tabela a ser analisada; 48

column Especica o nome da coluna a ser analisada, por omisso analisa todas as colunas da tabela. No OUTPUT do comando podemos vericar as estatsticas geradas consoante a tabela que est a ser analisada. Na congurao por omisso, existe um processo do sistema denominado autovacuum que se encarrega de automaticamente analisar as tabelas quando ocorre insero de dados na mesma ou quando sofrem alteraes. Se esta opo de autovacuum, no estiver activa, convm correr o comando ANALYZE periodicamente pois a base de dados est sujeita a inmeras alteraes. As estatsticas permanentemente actualizadas, permitem escolher o melhor plano para execuo da query. A operao ANALYZE apenas precisa de um read lock na tabela ou tabelas a analisar, permitindo assim que sejam executadas outras operaes sobre a tabela. No caso em que as tabelas so demasiado grandes, o comando ANALYZE apenas considera para gerar estatsticas uma pequena amostra da tabela e no toda a tabela, isto permite que mesmo em tabelas de grande dimenso o comando ANALYZE seja executado num curto espao de tempo. As estatsticas recolhidas pelo comando ANALYZE consistem numa amostra sobre a quantidade de valores comuns existentes num determinado atributo da tabela, as estatsticas incluem ainda um histograma que contm a distribuio dos dados para cada coluna. A extenso da anlise pode ser controlada ajustando a varivel default_statistics_target , ou ento coluna a coluna atravs do comando ALTER TABLE SET STATISTICS, podendo assim denir o nmero de estatsticas a serem recolhidas. Por omisso o valor de default_statistics_target 100. Quanto maior este valor, mais tempo o comando ANALYZE levar a executar, sendo que por outra lado um maior nmero de estatsticas permite melhorar a ecincia dos planos de execuo.

9.2.2

Estimativas de Linhas

Os exemplos mostrados, em seguida, foram retirados de [39] e, como explicado, os outputs so retirados da verso 8.3, pelo que, o comportamento em verses mais recentes (ou antigas), poder variar. Para alm disso, como o ANALYZE utiliza uma recolha aleatria de amostras enquanto produz as estatsticas, os resultados podem, tambm, variar, depois de um novo ANALYZE. Dada a seguinte query:

EXPLAIN SELECT * FROM tenk1 QUERY PLAN --------------------------------------------------------Seq Scan on tenk1 (cost=0.00..458.00 rows=10000 width=244)

O nmero de pginas e de linhas procurado na tabela pg_class. Esta tabela guarda, nas colunas reltuples e relpages, o nmero total de entradas em cada tabela

49

e ndice, assim como, o nmero de blocos de disco ocupados por cada tabela e ndice.

SELECT relpages, reltuples FROM pg_class WHERE relname = tenk1; relpages | reltuples ----------+----------358 | 10000

Estes nmeros so referentes ao ltimo VACUUM ou ANALYZE. Depois, o planner vai buscar o nmero de pginas actual tabela. Se esse nmero for diferente que o relpages, o reltuples escalado de acordo com a diferena, de forma a que o nmero de linhas seja estimado. Neste caso os valores so iguais, portanto o nmero de linhas estimado o mesmo que o reltuples. Ser agora apresentado um exemplo com uma condio de intervalo na clusula WHERE:

EXPLAIN SELECT * FROM tenk1 WHERE unique1 < 1000; QUERY PLAN -------------------------------------------------------------------------------Bitmap Heap Scan on tenk1 (cost=24.06..394.64 rows=1007 width=244) Recheck Cond: (unique1 < 1000) -> Bitmap Index Scan on tenk1_unique1 (cost=0.00..23.80 rows=1007 width=0) Index Cond: (unique1 < 1000)

O planner examina a condio da clusula WHERE e procura a funo de seletividade para o operador < na tabela pg_operator. Esta funo encontra-se na coluna oprrest e a entrada, neste caso, scalarltsel. A funo retorna um histograma para unique1 da tabela pg_statistics. Para queries manuais mais conveniente a procura na vista pg_stats. De seguida, a fraco do histograma ocupada por < 1000 trabalhada. O histograma divide a distncia em buckets de frequncia iguais, de forma a que apenas seja necessrio localizar o bucket a que pertence o valor e contar todos os outros anteriores e parte dele. O valor 1000 pertence ao segundo bucket (993-1997). Assumindo uma distribuio linear dos valores dentro de cada bucket, possvel calcular a seletividade da seguinte forma:

sel ec t i vi t y =

1+(1000 bucket [2].min) bucket [2].max bucket [2].min

num_ buckets

1+(1000993) 1997993

10

= 0, 100697

Isto , um bucket total mais a fraco linear do segundo a dividir pelo nmero de buckets. 50

O nmero de linhas estimadas poder agora ser calculado como o produto da seletividade e da cardinalidade de tenk1:

r ows = r el _car d inal i t y selec t ivi t y = 10000 0, 100697 1007

Vamos agora apresentar um exemplo de igualdade na clusula WHERE:

EXPLAIN SELECT * FROM tenk1 WHERE stringu1 = CRAAAA; QUERY PLAN ---------------------------------------------------------Seq Scan on tenk1 (cost=0.00..483.00 rows=30 width=244) Filter: (stringu1 = CRAAAA::name)

Desta vs a funo de seletividade a eqsel. Nesta caso, como se trata de uma igualdade o histograma no til. Em vez disso, uma lista dos valores mais comuns (Most Common Values - MCVs) utilizada para determinar a seletividade. Seleccionando os MCVs atravs de uma query obtemos:

SELECT null_frac, n_distinct, most_common_vals, most_common_freqs FROM pg_stats WHERE tablename=tenk1 AND attname=stringu1; null_frac n_distinct most_common_vals | 0 | 676 | {EJAAAA,BBAAAA,CRAAAA,FCAAAA,FEAAAA, GSAAAA,JOAAAA,MCAAAA,NAAAAA,WGAAAA} most_common_freqs | {0.00333333,0.003,0.003,0.003,0.003,0.003, 0.003,0.003,0.003,0.003}

Uma vez que, a CRAAAA aparece na lista de MCVs, basta corresponder a entrada na lista com as MCFs (Most Common Frequencies)

sel ec t ivi t y = mc f [3] = 0, 003

Sendo ento a estimativa para o nmero de linhas o produto da seletividade com a cardinalidade de tenk1:

r ows = 10000 0, 003 = 30

51

Considerando agora um exemplo em que a constante no se encontra na lista MCV:

EXPLAIN SELECT * FROM tenk1 WHERE stringu1 = xxx; QUERY PLAN ---------------------------------------------------------Seq Scan on tenk1 (cost=0.00..483.00 rows=15 width=244) Filter: (stringu1 = xxx::name)

Desta vez ser necessrio uma abordagem diferente. A ideia ser utilizar o facto de que o valor no se encontra na lista, juntamente com o conhecimento das frequncias de todos os MCVs: 1 mv f

sel ec t i vi t y =
=

num_dist inc t num_mcv


676 10

1 (0, 00333333 + 0, 003 + 0, 003 + 0, 003 + 0, 003 + 0, 003 + +0, 003 + 0, 003 + 0, 003 + 0, 003)

= 0, 0014559

Ou seja, so adicionadas todas as frequncias dos MCVs e subtradas de 1. O valor obtido , depois, dividido pelo nmero de valores distintos. Esta abordagem assume que a fraco da coluna que no se encontra em nenhum dos MCVs est, uniformemente, distribuda por todos os outros valores distintos. O nmero de linhas estimado calculado normalmente: r ows = 10000 0, 0014559 = 15(apr ox imadament e)

No exemplo anterior, no qual era utilizado a condio unique1 < 1000 para a clusula WHERE, foi mostrada uma simplicao do que a scalarltsel realmente faz. O exemplo estava correcto, uma vez que, como o atributo unique1 uma coluna nica, no contm nenhuns MCVs. No caso da coluna no ser nica, ser utilizado tanto um histograma como uma lista de MCV e, o histograma, no inclui a poro da populao da coluna representada pelos MCVs. Nesta situao a scalarltsel aplica directamente a condio (< 1000) a cada valor da lista de MCV e adiciona as frequncias dos MCVs para cada um em que a condio se verica. Desta forma possvel obter uma estimativa exacta da seletividade dentro da poro da tabela que MCVs. Seguidamente o histograma utilizado da mesma forma que anteriormente, para estimar a seletividade na poro da tabela que no MCVs. Os dois nmeros so depois combinados para estimar a seletividade geral. Vamos agora considerar um caso com mais do que uma condio na clusula WHERE: 52

EXPLAIN SELECT * FROM tenk1 WHERE unique1 < 1000 AND stringu1 = xxx; QUERY PLAN -------------------------------------------------------------------------------Bitmap Heap Scan on tenk1 (cost=23.80..396.91 rows=1 width=244) Recheck Cond: (unique1 < 1000) Filter: (stringu1 = xxx::name) -> Bitmap Index Scan on tenk1_unique1 (cost=0.00..23.80 rows=1007 width=0) Index Cond: (unique1 < 1000)

O planner assume que as duas condies so independentes, podendo a seletividade de cada clusula ser multiplicada:

sel ec t i vi t y = sel ec t i vi t y (unique1 < 1000)selec t ivi t y (st r ingu1 = x x x ) = 0, 100697 0, 0014559 = 0, 0001466 r ows = 10000 0, 0001466 1

Por m, ser examinada uma query que envolve uma juno:

EXPLAIN SELECT * FROM tenk1 t1, tenk2 t2 WHERE t1.unique1 < 50 AND t1.unique2 = t2.unique2; QUERY PLAN -------------------------------------------------------------------------------------Nested Loop (cost=4.64..456.23 rows=50 width=488) -> Bitmap Heap Scan on tenk1 t1 (cost=4.64..142.17 rows=50 width=244) Recheck Cond: (unique1 < 50) -> Bitmap Index Scan on tenk1_unique1 (cost=0.00..4.63 rows=50 width=0) Index Cond: (unique1 < 50) -> Index Scan using tenk2_unique2 on tenk2 t2 (cost=0.00..6.27 rows=1 width=244) Index Cond: (unique2 = t1.unique2)

Antes do nested-loop join a restrio em tenk1, unique1 < 50 avaliada. Isto feito analogamente ao exerccio com a condio intervalo, mostrado anteriormente. Desta vez o valor 50 encontra-se no primeiro bucket do histograma do unique1:

sel ec t i vi t y =

0+(50 bucket [1].min) bucket [1].max bucket [1].min

num b uckets

0+(500) 9930

10

= 0, 005035 r ows

= 10000 0, 005035 50

A restrio para a juno t2.unique2 = t1.unique2. Apesar do operador ser uma igualdade, devido a tratar-se de uma juno, a funo de seletividade obtida da coluna oprjoin da tabela pg_operator e da coluna eqjoinsel. Esta ltima contm informao estatstica para o tenk2 e o tenk1: 53

SELECT tablename, null_frac,n_distinct, most_common_vals FROM pg_stats WHERE tablename IN (tenk1, tenk2) AND attname=unique2; tablename | null_frac | n_distinct | most_common_vals -----------+-----------+------------+-----------------tenk1 | 0 | -1 | tenk2 | 0 | -1 |

Como todos os valores so nicos, no existe nenhuma informao MCV para o unique2. ento utilizado um algoritmo que conta apenas com o nmero de valores distintos para ambas a relaes, juntamente com as fraces nulas:

selec t ivi t y = = (1nul l _ f r ac 1)(1nul l _ f r ac 2)min( = 1 num_dist inc t 1 num_dist inc t 2 , 1 )

(1 0) (1 0) max (10000, 10000) = 0, 0001

Isto , subtrai-se a fraco nula de cada uma das relaes e divide-se pelo mximo dos nmeros de valores distintos. O nmero de linhas que cada juno poder emitir calculado como a cardinalidade do produto cartesiano de dois inputs, multiplicados pela seletividade:

r ows = (out er _car d inali t y inner _car dinali t y ) selec t ivi t y = (50 10000) 0, 0001 = 50

Caso existissem listas de MCV para as duas colunas a eqjoinsel teria usado uma comparao directa das listas MCV para determinar a seletividade da juno dentro das partes das populaes da coluna, representadas pelos MCVs. Para o resto das populaes a estimativa calculada de igual forma ao mostrado neste exemplo.

54

Captulo 10

Concluso
A realizao deste trabalho deu-nos a oportunidade de aprender sobre diferentes tecnologias de base de dados e ajudou-nos a perceber melhor como funcionam internamente e que diferentes funcionalidades oferecem aos utilizadores. Temos agora um melhor conhecimento para tomar decises, como qual a tecnologia mais adequada a certas situaes, assim como que conguraes podero ser necessrias fazer para melhor garantir o funcionamento de um sistema. Relativamente s tecnologias estudadas (MySQL, PostGreSQL e Oracle), -nos possvel concluir que so bastante diferentes internamente em diferentes pontos como, optimizao, parsing, estimativas, etc. Apesar de, aparentemente, disponibilizarem funcionalidades idnticas, estas funcionam de forma muito diferente internamente, como por exemplo, o comando EXPLAIN tem o mesmo objectivo para os trs, mas o seu output totalmente diferente em cada um deles. de salientar os tipos de ndice implementados em cada um dos sistemas de gesto de base de dados. Desse ponto de vista o PostGreSQL tira partido do uso dos ndices GiST e GIN que implementam diferentes algoritmos dos utilizados no ndice Btree, utilizado nos dois SGBDs estudados. O uso dos tipos de ndice GiST e GIN tira partido dos algoritmos que implementam de forma a poderem usar diferentes classes de operadores na construo de queries, estes operadores permitem fazer diferentes tipos de pequisa e simultaneamente optimizar as pesquisas que tradicionalmente so feitas, recorrendo ao uso de indces Btree. Por ltimo, vem a principal vantagem do MySQL e do PostGreSQL que o facto de ser open source. Qualquer pessoa pode adoptar esta ferramenta para desenvolver as suas aplicaes, livre de pagamento, e ainda pode costumiz-la sua maneira, o que no acontece nos sistemas Oracle visto que so pagos e tm cdigo fechado.

55

Bibliograa
[1] Oracle, Oracle home page. http://www.oracle.com/, November 2011. [2] MySQL, Mysql home page. http://www.mysql.com/, November 2011. [3] PostGreSQL, Postgresql home page. http://www.postgresql.org/, November 2011. [4] Wikipedia, Sql. http://en.wikipedia.org/wiki/SQL, November 2011. [5] Wikipedia, Mysql. http://en.wikipedia.org/wiki/MySQL, November 2011. [6] Wikipedia, Sql. http://en.wikipedia.org/wiki/SQL, November 2011. [7] Wikipedia, Postgresql.

http://en.wikipedia.org/wiki/

PostgreSQL, November 2011.


[8] Wikipedia, Sql/psm. http://en.wikipedia.org/wiki/SQL/PSM, November 2011. [9] O. Wiki, Oracle parsing.

http://orafaq.com/wiki/Parsing#

Parsing, November 2011.


[10] C. A. Bell, Expert MySQL. Springer-Verlag New York, Inc., 233 Spring Street, 6th Floor, New York, NY 10013: Apress, 2007. [11] PostGreSQL, The path of a query. http://www.postgresql.org/docs/ 9.1/static/query-path.html, November 2011. [12] PostGreSQL, Parser stage. http://www.postgresql.org/docs/9.1/ static/parser-stage.html, November 2011. [13] PostGreSQL, Genetic query optimizer. http://www.postgresql.org/ docs/9.1/static/geqo.html, November 2011. [14] MySQL, Mysql internals algorithms. http://forge.mysql.com/wiki/ MySQL_Internals_Algorithms, November 2011. [15] MySQL, Nested loop joins. http://dev.mysql.com/doc/refman/5. 6/en/nested-loop-joins.html, November 2011.

56

[16] N. Conway, 2011.

neilconway.org/talks/optimizer/optimizer.pdf,

Inside the postgresql query optimizer. http://www. November

[17] PostGreSQL, Index scanning. http://www.postgresql.org/docs/9. 1/static/index-scanning.html, November 2011. [18] MySQL, Mysql indexes. http://dev.mysql.com/doc/refman/5.6/ en/mysql-indexes.html, November 2011. [19] PostGreSQL, Indexes. http://www.postgresql.org/docs/9.1/ interactive/indexes.html, November 2011.

[20] PostGreSQL, Postgresql query planning. http://www.postgresql.org/ docs/9.1/static/runtime-config-query.html, November 2011. [21] MySQL, Internal details of mysql optimizations. http://dev.mysql. com/doc/refman/5.6/en/optimization-internals.html, November 2011. [22] MySQL, Range optimization. http://dev.mysql.com/doc/refman/5. 6/en/range-optimization.html, November 2011. [23] MySQL, Index merge optimization. http://dev.mysql.com/doc/ refman/5.6/en/index-merge-optimization.html, November 2011. [24] MySQL, Engine condition pushdown optimization. http://dev.mysql.

com/doc/refman/5.6/en/condition-pushdown-optimization. html, November 2011.


[25] MySQL, tion. Index condition pushdown optimiza-

http://dev.mysql.com/doc/refman/5.6/en/ index-condition-pushdown-optimization.html, November 2011.

[26] MySQL, Is null optimization. http://dev.mysql.com/doc/refman/5. 6/en/is-null-optimization.html, November 2011. [27] MySQL, Left join and right join optimization. http://dev.mysql. com/doc/refman/5.6/en/left-join-optimization.html, November 2011. [28] MySQL, Order by optimization. http://dev.mysql.com/doc/refman/ 5.6/en/order-by-optimization.html, November 2011. [29] MySQL, Group by optimization. http://dev.mysql.com/doc/ refman/5.6/en/group-by-optimization.html, November 2011.

[30] MySQL, Distinct optimization. http://dev.mysql.com/doc/refman/ 5.6/en/distinct-optimization.html, November 2011. [31] MySQL, Subquery optimization. http://dev.mysql.com/doc/ refman/5.6/en/subquery-optimization.html, November 2011.

[32] PostGreSQL, Planner/optimizer. http://www.postgresql.org/docs/ 9.1/static/planner-optimizer.html, November 2011.

57

[33] Wikipedia, Problema do caixeiro viajante. http://pt.wikipedia.org/ wiki/Problema_do_caixeiro_viajante, November 2011. [34] MySQL, Mysql explain syntax. http://dev.mysql.com/doc/refman/ 5.6/en/explain.html, November 2011. [35] PostGreSQL, Explain. http://www.postgresql.org/docs/9.1/ static/sql-explain.html, November 2011.

[36] MySQL, Explain output format. http://dev.mysql.com/doc/refman/ 5.6/en/explain-output.html, November 2011. [37] PostGreSQL, Using explain. http://www.postgresql.org/docs/9.1/ static/using-explain.html, November 2011. [38] MySQL, Estimating performance. http://dev.mysql.com/doc/ refman/5.6/en/estimating-performance.html, November 2011.

[39] PostGreSQL, Row estimation examples. http://www.postgresql.org/ docs/9.1/interactive/row-estimation-examples.html, November 2011.

58

Вам также может понравиться