domingo, 23 de novembro de 2014

Oracle: Índices (1) – Introdução

Introdução

image

De forma análoga ao SQL Server, também no Oracle, a utilização de Índices é essencial para obter alto desempenho numa base de dados (BD).

Num artigo anterior, fizemos uma introdução à utilização de índices no SQL Server. Vamos agora fazer trabalho análogo para os índices do Oracle. Não vamos repetir a explicação detalhada de alguns conceitos base, que já foi efectuada nesse artigo. Em cada tópico, vão ser incluídos links para os tópicos equivalentes no artigo do SQL Server, onde os detalhes podem ser consultados.

Vamos então começar a analisar como podemos usar os índices no Oracle, para obter uma base de dados que tenha uma boa performance, integridade de dados e, ao mesmo tempo, mantenha a sobrecarga associada aos índices, num mínimo.

Conteúdo

O que é um Índice?

Um índice corresponde a uma estrutura em disco, associada a uma  tabela ou view, que agiliza a pesquisa de linhas nessa tabela ou view.

A estrutura do índice é separada da tabela e não afecta a forma como os dados são guardados fisicamente. Afecta sim a forma como são lidos a partir da tabela.

Ver exemplos e detalhe aqui.

Estrutura de um Índice

À semelhança do SQL Server, os índices no Oracle são implementados através de uma estrutura de Árvore-B.

Ver detalhe aqui.

Apesar da estrutura ser idêntica, existe uma diferença essencial, entre o Oracle e o SQL Server, nos dados que são armazenados na estrutura da árvore-B e, consequentemente, na forma como são usados os índices.

Bloco
Um bloco é a menor unidade de disco que o Oracle consegue ler ou escrever. Todos os dados do Oracle - tabelas, índices, clusters - são armazenados em blocos. O tamanho do bloco é configurável para cada BD, normalmente 4Kb, 8Kb, 16Kb ou 32Kb. O tamanho de uma linha de uma tabela é, geralmente, mais pequeno que o tamanho do bloco, por isso o mesmo bloco pode acomodar várias linhas.

A estrutura de árvore-B dos índices do Oracle, guarda o endereço de blocos de BD e não o endereço de linhas de tabela. Então, o Oracle não lê "apenas uma linha", vai ler todo o bloco e ignorar as linhas que não precisa. Minimizar este desperdício é um dos fundamentos da Oracle Performance Tuning.

Tipos de Índices

No Oracle, existem dois tipos principais de índices: B-Tree (nonclustered) e Bitmap.

Existem mais tipos de índices, como cluster, bitmap join, function-based, reverse key e text, mas acabam por ser variantes daqueles dois.

Convém aqui enfatizar que os índices cluster do Oracle não têm nada de semelhante com os índices clustered do SQL Server. No Oracle aquilo que se assemelha às tabelas clustered do SQL Server são as Index-Organized Tables, que também são guardadas numa estrutura árvore-B (em vez de heap), ordenada pela Chave Primária.

Mais informação sobre índices clustered do SQL Server aqui.

Limites dos Índices

No Oracle, também existem algumas limitações internas aos índices.

Tamanho da chave
O tamanho de uma chave de índice está limitado a um máximo de 32 colunas, para índices B-Tree e 30 colunas para índices Bitmap.

Número de índices
Não existe limite para o número de índices numa tabela.

Qualquer destes limites é muito elevado e há poucos casos em que um sistema bem projectado se aproxime sequer deles. Existem duas razões fundamentais para isso não acontecer:

  • À medida que aumenta o número de índices também aumenta o tamanho total ocupado pela tabela (com todos os seus índices). Claro que os discos rígidos são baratos e abundam as soluções de armazenamento, mas o aumento do tamanho duma BD tem outros efeitos: as operações de manutenção (backups, restauros, verificações de consistência e reconstrução de índices) vão levar mais tempo, à medida que o tamanho da BD aumenta;
  • Os índices têm que ser actualizados em sincronismo com as alterações dos dados. Quantos mais índices existirem numa tabela, mais os locais e maior o número de operações necessárias para actualizar. Se existirem 10 índices numa tabela, a inserção duma nova linha tem que ser feita em 11 locais (na tabela e em cada um desses índices).
    Nas BDs que são principalmente de leitura (de suporte à decisão, ou datawarehouses) isto pode ser aceitável. Mas nas BDs em que são frequentes as operações de alteração de dados - inserir, alterar, eliminar (sistemas OLTP), a sobrecarga imposta pela existência de muitos índices pode não ser aceitável.

Como o Oracle usa os Índices

O Oracle pode executar as seguintes operações relacionadas com índices:

INDEX UNIQUE SCAN
Este tipo de pesquisa, usa a estrutura árvore-B para localizar um valor específico. O Oracle usa esta operação se houver um predicado (filtro pesquisável) que garanta que o resultado da pesquisa não tenha mais que uma linha.

INDEX RANGE SCAN
À semelhança da anterior, este tipo de pesquisa, usa a estrutura árvore-B, mas agora para encontrar um conjunto de valores e não apenas um valor específico.

A operação de pesquisa é executada a partir da página de raiz. A partir das linhas desta página, o mecanismo de consultas vai localizar a página do seguinte nível inferior do índice, que contém a primeira linha que está a ser pesquisada. O mecanismo vai, então, ler essa página. Se a página estiver no nível de folha do índice, a pesquisa termina aí. Se não é o nível de folha, então o mecanismo de consulta identifica novamente a página do nível inferior seguinte, que contém o valor especificado. Este processo continua até que o nível de folha seja atingido.

Quando o mecanismo de consultas localiza a página de folha que contém o valor de chave especificado, ou o início do intervalo especificado de valores-chave, vai lendo ao longo das páginas de folha até que todas as linhas correspondentes ao predicado sejam devolvidas. A figura seguinte mostra um exemplo de como uma pesquisa seria feita, num índice, para devolver as linhas com o valor 4 na chave:

INDEX FULL SCAN
Este tipo de pesquisa corresponde a uma leitura completa de todas as páginas de folha do índice. Dependendo de várias estatísticas do sistema, a BD pode executar esta operação se necessitar de todas as linhas, pela ordem do índice – p.ex., por causa de uma cláusula ORDER BY.

Quando a varredura do índice é feita pelo mecanismo de consultas, é sempre uma leitura completa de todas as páginas de folha do índice, independentemente de todas as linhas serem retornadas ou não. Nunca é uma leitura parcial.

Uma varredura não envolve apenas a leitura dos níveis de folha do índice, as páginas de nível superior também são lidas durante a operação.

INDEX FAST FULL SCAN
Este tipo de pesquisa corresponde a uma leitura completa de todas as páginas de folha do índice, conforme guardadas no disco. Esta operação é geralmente realizada em vez de uma varredura (scan) completa da tabela, se todas as colunas necessárias estão disponíveis no índice.

TABLE ACCESS BY INDEX ROWID (Lookup)
Os lookups ocorrem quando o Oracle usa um índice para localizar as linhas pedidas por uma consulta, mas esse índice não contém todas as colunas necessárias para satisfazer a consulta. Para obter as colunas restantes, o Oracle usa o endereço da linha (ROWID), para ler directamente da tabela.

TABLE ACESS FULL ou FULL TABLE SCAN
Lê a tabela inteira - todas as linhas e colunas – conforme armazenada no disco. Apesar da leitura de multi-blocos melhorar consideravelmente a velocidade duma varredura completa de tabela, esta ainda é uma das operações mais pesadas, em termos de BD. Além de altas taxas de I/O, uma varredura completa da tabela tem que inspecionar todas as linhas da tabela, pelo que também pode consumir uma quantidade considerável de tempo de CPU.

Considerações para a criação de Índices

Por mais benéfica que a utilização de índices possa ser, estes devem ser projectados com cuidado. Como resultado, a criação de índices deve levar em conta algumas considerações:

  • Os índices existem, principalmente, para aumentar a performance.
  • Tenha em consideração a relação custo/benefício dos índices.
  • Considere técnicas não-standard e alternativas de indexação, como Índices Bitmap (mas não para OLTP) ou Índices Funcionais.
  • Use ferramentas de análise e tuning, em especial o Execution Plan.
  • Optimize as pesquisas para a utilização de índices. P.ex., um índice não é uma grande ajuda em condições do tipo NOT: <>, NOT IN, NOT LIKE, …

Referências

- "How do indexes work internally in Oracle?", na AskTheOracel.net

- "Understanding Indexes", na Oracle FAQ's

- "Oracle Execution Plan Operations", de Markus Winand para a Use the Index, Luke

- "Managing Indexes", no Oracle Help Center

- "Overview of Indexes", no Oracle Help Center

- "Logical Database Limits", no Oracle Help Center

sexta-feira, 21 de novembro de 2014

Software: Gestão Semântica de Versões (Semantic Versioning)

Introdução

Quem anda no mundo do desenvolvimento de software, sabe que uma das maiores dores de cabeça é a Gestão de Dependências.

Quanto mais um sistema cresce, mais componentes são adicionados, maior é a complexidade e dificuldade de se gerirem as dependências entre os módulos e maior é a probabilidade de se atingirem bloqueios ou inconsistências.

É aqui que entra a Gestão de Versões!

A adopção de um sistema de atribuição de números de versão aos componentes de software, que seja claro e lógico, dá um preciosa ajuda a mitigar os problemas colocados pela gestão de dependências.

Neste artigo, vamos analisar um sistema de gestão de versões, amplamente utilizado, a Gestão Semântica de Versões (Semantic Versioning).

Este sistema é da autoria de Tom Preston-Werner e a sua especificação detalhada pode ser encontrada aqui.

Conteúdo

O que é a Gestão Semântica de Versões (SemVer)?

A Gestão Semântica de Versões, no original Semantic Versioning (referida abreviadamente como SemVer), é um sistema de controlo de versões que tem vindo a ganhar adeptos ao longo dos últimos anos. Com novos plugins, extensões e bibliotecas a ser construídas quase diariamente e com uma forma universal de atribuição de versões a projectos de desenvolvimento de software, é uma ferramenta muito útil para nos ajudar a gerir e manter o registo das evoluções de um sistema.

A especificação SemVer define que o número da versão de um componente de software é composto por 3 partes: Major.Minor.Patch

Cada um destes números é incrementado da seguinte forma:

  • MAJOR (Principal): quando são feitas alterações incompatíveis com a API existente;
  • MINOR (Secundário): quando são adicionadas funcionalidades de forma compatível com versões anteriores;
  • PATCH (Emenda): quando são corrigidos bugs de forma compatível com versões anteriores.

Existem rótulos adicionais para metadados de pré-lançamento (pre-release) e compilação (build), que são disponibilizados como extensões do formato Major.Minor.Patch.

Como funciona a Gestão Semântica de Versões?

Num sistema com muitas dependências, o lançamento de novas versões pode tornar-se um pesadelo muito rapidamente. Isto é conhecido como o “inferno de dependências”. Se as especificações de dependência forem muito apertadas, corre-se o risco de atingir um bloqueio de versão (incapacidade de actualizar um componente, sem ter que actualizar todos os componentes dependentes). Por outro lado, se as dependências forem especificadas de forma muito vaga, então, inevitavelmente, vai-se atingir alguma promiscuidade de versões (é assumida a compatibilidade com mais versões futuras do que seria razoável). Atingiu o inferno de dependências quando um bloqueio de versão e/ou uma promiscuidade de versão o impedem de avançar com o projecto de forma fácil e segura.

A proposta da SemVer é composta por um conjunto simples de regras e requisitos, que determinam a forma como os números de versão são atribuídos e incrementados. Estas regras são baseadas em algumas práticas comuns já existentes. Para que o sistema funcione, é necessário declarar uma API pública, clara e precisa. Esta pode consistir em documentação ou ser forçada pelo próprio código da aplicação. Após a declaração, as alterações à API são comunicadas através de incrementos específicos a cada uma das partes constituintes do número de versão (major, minor ou patch).

O funcionamento da SemVer assenta em saber determinar o momento certo para incrementar o componente correcto, i.e., determinar qual ou quais os números da versão devem ser alterados para cada lançamento do software.

Porquê a Gestão Semântica de Versões?

Porquê usar um sistema de gestão de versões? Porque faz sentido!

Há algo que devemos ter a noção: o controlo de versões sem directrizes, basicamente, não tem significado. Incrementar para a versão 3.2? OK. Mas porquê? Porque não 4? Porque não 3.1.1? Porque não 3.11? Porque não 3.1.nova-versao?

Seguir orientações rigorosas ajuda a dar significado aos números de versão.

Por exemplo, se tivermos a versão 1.3.37, sabemos que este é o primeiro grande lançamento, mas já houve três versões secundárias, com novos recursos. No entanto, também notamos que se trata da emenda 37 a esta versão secundária, o que significa que havia um número razoável de bugs (maiores ou menores) envolvidos.

A SemVer também nos ajuda na gestão de dependências. Vamos imaginar que estamos a construir uma biblioteca chamada Veículos e que nesta biblioteca temos uma dependência sobre o componente Motor. No primeiro lançamento da biblioteca para produção, o componente Motor tem a versão 2.3.8. Isso significa que podemos especificar o Motor como uma dependência da biblioteca Veículos, com versão maior ou igual a 2.3.0, mas menor que 3.0.0. A versão principal significa uma alteração sem compatibilidade com a API actual, pelo que se passarmos o Motor para a versão 3.0.0, nada nos garante que temos compatibilidade com o resto da biblioteca.

Especificação SemVer 2.0.0

A especificações actualizadas para a SemVer pode ser encontradas no endereço: http://semver.org/

À data da criação deste artigo, estamos na versão 2.0.0, com a seguinte especificação:

  1. O software que usa a SemVer TEM QUE declarar uma API pública. Esta API pode ser declarada no próprio código, ou existir explicitamente em documentação. No entanto, quando feita, deve ser precisa e abrangente.
  2. Um número de versão normal deve assumir a forma X.Y.Z, onde X, Y, e Z são inteiros não negativos e não podem conter zeros à esquerda. X é a versão principal (Major), Y é a versão secundária (Minor) e Z é a versão da emenda (Patch). Cada elemento deve aumentar numericamente. Por exemplo: 1.9.0 –> 1.10.0 -> 1.11.0.
  3. Sempre que um pacote seja lançado, o seu conteúdo NÃO PODE ser modificado. Qualquer modificação deve ser lançada como uma nova versão.
  4. A versão principal (Major) a zero (0,y,z) serve para o desenvolvimento inicial. Qualquer coisa pode mudar a qualquer altura. A API pública não deve ser considerada estável.
  5. A versão 1.0.0 define a API pública. A forma como o número de versão é incrementado a partir deste lançamento inicial, depende dessa API pública e de como ela é alterada.
  6. A versão de emenda (Patch) Z (x.y.z | x>0) SÓ PODE ser incrementada se for introduzida uma correcção de um bug compatível com a API pública. A correcção de um bug define-se como uma alteração interna que corrige um comportamento incorrecto.
  7. A versão secundária (Minor) Y (x.y.z | x>0) SÓ PODE ser incrementada se for introduzida uma nova funcionalidade compatível com a API pública. A versão secundária TEM QUE ser incrementada sempre que uma funcionalidade da API pública for marcada como obsoleta. A versão secundária PODE ser incrementada pela introdução de novas funcionalidades ou melhorias substanciais, no código privado. PODE ainda incluir alterações ao nível da emenda (Patch). A versão de emenda (Patch) TEM QUE ser reposta a zero quando a versão secundária (Minor) é incrementada (1.3.55 –> 1.4.0).
  8. A versão principal (Major) X (x.y.z | x>0) TEM QUE ser incrementada se for introduzida uma alteração incompatível com a API pública. PODE incluir alterações ao nível secundário (Minor) e emendas (Patch). Tanto a versão secundária (Minor), como a versão de emenda (Patch) TÊM QUE ser repostas a zero quando a versão principal (Major) é incrementada (1.3.55 –> 2.0.0).
  9. Uma versão de pré-lançamento (pre-release) PODE ser identificada acrescentando um hífen e uma série de identificadores, separados por pontos, imediatamente após a versão de emenda (Patch). Os identificadores terão as seguintes características:
    • SÓ PODEM incluir caracteres alfanuméricos ASCII e hífen [0-9A-Za-z];
    • Um identificador NÃO PODE estar vazio;
    • Um identificador numérico NÃO PODE conter zeros à esquerda.
    As versões de pré-lançamento têm uma precedência mais baixa que a versão normal associada. Uma versão de pré-lançamento indica que a versão é instável e pode não satisfazer todos os requisitos de compatibilidade pretendidos, conforme indicado na sua versão normal associada. Exemplos: 1.0.0-alpha, 1.0.0-alpha.1, 1.0.0-beta, 1.0.0-RC, 1.0.0-0.3.7, 1.0.0-x.7.z.92.
  10. Podem ser identificados metadados de compilação (build) acrescentando um sinal de mais e uma série de identificadores, separados por pontos, imediatamente após a versão de emenda (Patch) ou pré-lançamento. Os identificadores terão as seguintes características:
    • SÓ PODEM incluir caracteres alfanuméricos ASCII e hífen [0-9A-Za-z];
    • Um identificador NÃO PODE estar vazio.
    Os metadados de compilação (build) DEVEM ser ignorados na determinação da precedência de versões. Assim  duas versões que diferem apenas nos metadados de compilação têm a mesma precedência. Exemplos: 1.0.0-alpha+001, 1.0.0+20130313144700, 1.0.0-beta+exp.sha.5114f85.
  11. A Precedência refere-se ao modo como as versões são comparados umas com as outras, quando ordenadas. A precedência TEM QUE ser calculada através da separação da versão em principal (Major), secundária (Minor), emenda (Patch) e de pré-lançamento, nessa ordem (metadados de compilação (build) não figuram na precedência).
    A precedência é determinada pela primeira diferença quando se compara cada um destes identificadores, da esquerda para a direita, como se segue: as versões principal, secundária e emenda são sempre comparados numericamente. Exemplo: 1.0.0 < 2.0.0 < 2.1.0 < 2.1.1. Quando as versões principal, secundária e emenda são iguais, a versão de pré-lançamento tem precedência menor do que a versão normal. Exemplo: 1.0.0-alpha < 1.0.0.
    A precedência de duas versões de pré-lançamento com as versões principal, secundária e emenda iguais, TEM QUE ser determinada comparando cada identificador separado por pontos, da esquerda para a direita, até que seja encontrada uma diferença, da seguinte forma: identificadores que consistem apenas em dígitos, são comparados numericamente e identificadores com letras ou hífens são comparados lexicalmente por ordem do código ASCII. Os identificadores numéricos têm sempre menor precedência que os identificadores alfanuméricos.
    Um conjunto maior de identificadores de pré-lançamento tem uma precedência maior do que um conjunto menor, se todos os identificadores anteriores forem iguais. Exemplo: 1.0.0-alfa < 1.0.0-alpha.1 < 1.0.0-alpha.beta < 1.0.0-beta < 1.0.0-beta.2 < 1.0.0-beta.11 < 1.0.0-rc.1 < 1.0.0.

FAQ

Como devo lidar com revisões na fase de desenvolvimento inicial (0.y.z)?

A coisa mais simples a fazer é começar a versão de desenvolvimento inicial em 0.1.0 e incrementar a versão secundária a cada lançamento subsequente.

Como sei quando lançar a versão 1.0.0?

Se o software já está a ser usado em produção, então já deve estar na versão 1.0.0. Se possui uma API estável, da qual os utilizadores passaram a depender, então deve ser a 1.0.0. Se já se está a preocupar bastante com compatibilidade com versões anteriores, então já deve ser a 1.0.0.

Isto não desencoraja o desenvolvimento ágil (Agile) e iteração rápida?

A versão principal (Major) a zero tem o foco exatamente no desenvolvimento rápido. Se estiver a mudar a API todos os dias, provavelmente está na versão 0.y.z ou num branch separado de desenvolvimento, a trabalhar numa próxima versão principal.

Se mesmo a menor mudança incompatível com a API pública requer aumento da versão principal (Major), não vou acabar na versão 42.0.0 muito rapidamente?

Esta é uma questão de desenvolvimento responsável e conhecimento antecipado. Mudanças incompatíveis não devem ser introduzidas de forma ligeira em software que tem muito código dependente. O custo necessário à atualização pode ser significativo. Ter que aumentar a versão principal para introduzir mudanças incompatíveis, significa que pensará no impacto dessas mudanças e que avaliará a relação custo/benefício envolvida.

Documentar toda a API pública dá muito trabalho!

É sua responsabilidade como programador profissional documentar corretamente o software que vai ser usado por outros. Gerir a complexidade do software é uma parte extremamente importante de manter um projeto eficiente e isso é difícil de fazer se ninguém sabe como usar o seu software, ou que métodos são seguros de chamar. A longo prazo, a SemVer e a insistência numa API pública bem definida, podem manter tudo e todos a funcionar suavemente.

O que eu faço se, acidentalmente, lançar uma mudança incompatível com versões anteriores como uma versão secundária (Minor)?

Assim que perceber que não cumpriu a especificação da SemVer, repare o problema e lance uma nova versão secundária, que corrige o problema e restaura a compatibilidade. Mesmo nesta circunstância, é inaceitável modificar versões já lançadas. Se for apropriado, documente a versão incumpridora e informe os seus utilizadores do problema, de forma a que eles fiquem cientes da versão em questão.

O que devo fazer se atualizar as minhas próprias dependências sem modificar a API pública?

Isso seria considerado compatível, uma vez que não afeta a API pública. Software que depende explicitamente das mesmas dependências que o seu pacote, deve ter a sua própria especificação de dependência e o autor notificará quaisquer conflitos. Para determinar se a mudança é ao nível de emenda (Patch) ou ao nível secundário, dependente se atualizou as dependências a fim de corrigir um bug ou introduzir uma nova funcionalidade.

E se alterei inadvertidamente a API pública de forma incompatível com a mudança no número de versão (ex.: o código introduz, incorretamente, uma grande mudança incompatível, no lançamento de um patch)

Use o bom senso. Se tiver uma audiência enorme, que será drasticamente afectada pela mudança de comportamento de voltar ao que a API pública pretendia, então pode ser melhor realizar um lançamento de uma versão principal (Major), mesmo que a correção pudesse ser considerada estritamente uma versão de emenda (Patch). Lembre-se, SemVer trata de transmitir significado à forma como os números de versão mudam. Se estas mudanças são importantes para os seus utilizadores, utilize o número da versão para informá-los.

Como devo lidar com descontinuação de funcionalidades?

Descontinuar funcionalidades (deprecating) é um processo comum no desenvolvimento de software e muitas vezes é necessário para poder haver progresso. Quando descontinua partes da sua API pública, deve fazer duas coisas: (1) atualizar a sua documentação, para que os utilizadores saibam das mudanças, (2) lançar uma versão secundária (Minor) que anuncie a descontinuação. Antes de remover completamente a funcionalidade numa versão principal (Major), deve haver, pelo menos, uma versão secundária (Minor) que possui a descontinuação anunciada, permitindo com que os utilizadores façam uma transição tranquila para a nova API.

A SemVer tem um limite de tamanho para o número de versão?

Não, mas use o bom senso. Uma string de versão com 255 caracteres, por exemplo, é provavelmente um exagero. Porém, sistemas específicos podem definir seus próprios limites para o tamanho da string.

Licença

A Especificação da SemVer é da autoria de Tom Preston-Werner, criador do Gravatar e co-fundador do GitHub.

A SemVer é disponibilizada sob a licença Creative Commons - CC BY 3.0.

Caso queira deixar feedback, por favor abra um issue no GitHub.

Referências

Semantic Versioning 2.0.0

"Semantic Versioning: Why You Should Be Using it", de Hugo Giraudel para o SitePoint.

sexta-feira, 14 de novembro de 2014

Windows: Qual a diferença entre edição “OEM” e “Retalho”

Já tentou comprar uma licença do Windows na Amazon ou outra loja online? E em lojas nacionais, como a FNAC ou a WORTEN?

Parece simples, mas nem sempre é. A realidade é que vai encontrar licenças System Builder (OEM), mais baratas e licenças Full Version (Retalho), mais caras.

Então a pergunta que se coloca é: Qual a diferença entre estas versões?

Antes de mais, devemos esclarecer que, no que toca a funcionalidades, ambas as edições são idênticas, i.e., instalando uma versão OEM ou uma versão de Retalho, o seu Windows funciona da mesma forma.

Vamos ver um pouco mais em detalhe as diferenças.

As licenças destinam-se a alvos diferentes

Os dois tipos de licença diferem conceptualmente. A licença OEM é destinada aos fabricantes e integradores de hardware, que constroem computadores para depois vender a terceiros, enquanto a licença de Retalho se destina ao público em geral (pelo menos em teoria – a realidade é que a maioria dos utilizadores não compra o Windows numa caixa).

Licenças Versão Completa/Retalho (Full Version/Retail)
Estas são as licenças standard para o consumidor do Windows. Elas foram projectadas para os normais utilizadores de computadores, que pretendem comprar uma licença para actualizar a sua máquina para uma nova versão do Windows. Este tipo de licença permite ao utilizador instalar o Windows em qualquer computador e mesmo mudar para outro, mas a mesma licença só pode estar instalada num único PC em cada momento.

Se alguma vez entrou numa loja de informática e viu uma caixa com o logo do Windows, numa prateleira, então estava a olhar para uma edição de Retalho do Windows.

Licenças Integrador Sistemas/OEM (System Builder/OEM)
Estas licenças são usadas pelos fabricantes de computadores (OEM – Original Equipment Manufacturers). São usadas não só pelos grandes fabricantes como IBM, Asus ou Dell, como pelos pequenos integradores e lojas locais de informática, onde podemos comprar computadores com configurações à medida. Este tipo de licença fica vinculada ao PC onde é instalada a primeira vez, para sempre. Não pode ser usada noutro PC.

Posso usar uma licença OEM?

A Microsoft tem alternado a sua política no tocante a permitir ou não que os normais entusiastas da computação usem licenças OEM, quando constroem as suas próprias máquinas.

No Windows XP, Windows Vista, e Windows 8, era permitido.
No
Windows 7 e agora no Windows 8.1, não é permitido.

Mas não vai saber isto a não ser que leia as letras miúdas das licenças.

Antes do Windows 7, a compra de uma licença OEM para o seu próprio PC era perfeitamente legítima. Com o Windows 7, a Microsoft alterou as populares licenças OEM do Windows. As pessoas normais deixaram de estar autorizadas a usá-las para construir seus próprios PCs, mas a Microsoft continuou a vender massivamente as licenças OEM a essas mesmas pessoas. Por exemplo, este ainda é o S.O. mais vendido na Amazon e a Microsoft sabe porquê: porque as pessoas normais compram a versão OEM (mais barata).

 

A Microsoft viu que a desregulação do licenciamento OEM do Windows 7 estava de loucos, por isso resolveu corrigir a situação no Windows 8 - foi acrescentada uma permissão de “Licença de Uso Pessoal”, à licença OEM do Windows 8. Isso significa que pode comprar uma licença Windows 8 OEM e usá-la num computador que esteja a montar em casa, para seu uso pessoal.

No fim de contas, as pessoas estavam a usar licenças OEM nas suas máquinas pessoais e a Microsoft acabou simplesmente por normalizar a situação que ela própria tinha criado com a alteração ao licenciamento do Windows 7.

Entretanto, chegou o Windows 8.1, que é considerado pela Microsoft como um S.O. completamente novo. E tem novas regras de licenciamento também. A permissão de uso pessoal foi retirada da licença OEM, voltando à situação do Windows 7, sendo apenas permitida para integradores que montem máquinas para revenda.

Esta questão está claramente resumida no guia de licenciamento para uso pessoal, para parceiros OEM, da Microsoft (pode ser consultado aqui):

No entanto, já passou mais de um ano e continuamos a encontrar as cópias OEM do Windows 8.1 no topo de vendas da Amazon ou da Newegg. As pessoas continuam a comprar estas licenças, que representam uma poupança significativa, relativamente às versões de Retalho. Claramente, são compradas para uso pessoal e não por integradores ou fabricantes de computadores.

A informação sobre o licenciamento nestes sites não dizem claramente “ESTA LICENÇA NÃO É AUTORIZADA PARA USO NO SEU PRÓPRIO PC”, que é o deveria dizer se a Microsoft pensasse em levar a sério os termos do seu contrato de licença OEM. Quando pesquisa o Windows 8.1 no site da Amazon, é exibida uma mensagem que diz mais ou menos isto: “Se for um integrador de sistemas, a Amazon oferece-lhe produtos Windows OEM. Caso contrário compre os nossos títulos Windows 8.1”. Esta mensagem é demasiado vaga – qualquer pessoa que esteja a montar o seu próprio PC, pode pensar que é um integrador de sistemas. Mas não é - pelo menos de acordo com os termos da licença do Windows 8.1. Todavia, com o Windows 8, já era um integrador de sistemas. No Windows 7 também não era, mas nos anteriores era. Confuso o suficiente? Bem, as pessoas podem estar confundidas, mas as licenças OEM continuam a vender bem. Winking smile

Limitações das licenças OEM

Apesar de mais baratas, as licenças OEM têm algumas limitações (legítimas):

  • Licença só pode ser usada num único PC
    Após instalar a sua cópia OEM do Windows, a licença fica vinculada ao computador, para sempre. Especificamente, fica vinculada ao modelo de motherboard. A licença OEM fica associada a um único sistema, enquanto com uma licença de Retalho pode usá-la noutro computador, no futuro.
  • Sem suporte directo da Microsoft
    Não dão direito a suporte directo e gratuito por parte da Microsoft. A licença OEM estipula que o construtor do sistema é o responsável por fornecer o suporte – quando compra um computador com versão OEM do Windows, é suposto a empresa ou pessoa que que lho vendeu providenciar o suporte. Se montar o seu próprio computador com uma licença OEM do Windows, então é responsável por fornecer o seu próprio suporte. Claro que as licenças Windows OEM permitem obter e instalar as actualizações do Windows Update.
  • Escolher 32 bits ou 64 bits na compra
    Quando compra uma versão OEM do Windows, tem que escolher a media de instalação de 32 bits ou de 64 bits, enquanto na versão de Retalho, a mesma media permite instalar a edição de 32 bits ou a de 64 bits. Como a licença OEM é para usar num único PC, espera-se que a escolha da versão 32 bits ou 64 bits seja feita no momento da compra (claro que hoje em dia, deve querer apenas a edição de 64 bits, de qualquer forma).
  • Não pode ser usada para atualizar o sistema
    A cópia OEM do Windows não pode ser usada para actualizar uma versão mais antiga do Windows – p.ex., a atualização do Windows XP para o Windows 7, ou do Windows 7 para o Windows 8.1. A licença está projectada para instalação em PCs novos, que ainda não tenham qualquer sistema operativo.

Que licença devo comprar?

Supondo que não tem problemas em ultrapassar os constrangimentos do licenciamento, uma versão OEM do Windows faz muito sentido se você for um geek, a construir o seu próprio PC. Se estiver disposto a vincular essa cópia do Windows ao seu hardware e não precisar ligar para o suporte da Microsoft, pode economizar algum dinheiro.

Quanto dinheiro vai poupar, depende da edição do Windows que quiser comprar e da loja onde comprar, mas, numa loja como a Amazon, consegue economizar entre os 15% e os 40%.

A Microsoft já não comercializa versões de Retalho do Windows 7, embora continue a vender versões OEM. Isto leva a situações de termos as poucas licenças de Retalho, ainda disponíveis, a custar 4 ou 5 vezes o valor da versão OEM.

Referências

“What’s the Difference Between the “System Builder” and “Full Version” Editions of Windows?”, de Chris Hoffman para a How-To-Geek.

"Microsoft is Misleading Consumers With Windows 8.1 System Builder Licensing", de Chris Hoffman para a How-To-Geek.

domingo, 9 de novembro de 2014

Estas são as Apps de Mensagens menos Seguras

 

Um novo relatório diz que o Skype, o Chat do Facebook e até mesmo o Google Talk/Hangouts não são assim tão seguros.

Os chamados sistemas de "mensagens seguras", incluindo aplicações populares como o Skype e o Facebook Chat, na verdade não cumprem a sua suposta segurança, de acordo com um relatório divulgado na passada terça-feira por um grupo de direitos digitais.

O “Secure Messaging Scorecard” da Fundação Electronic Frontier (EFF) avaliou a segurança de mais de 30 aplicações de email, media social, chamadas de voz e vídeo, em sete categorias, incluindo se o provedor consegue ler as suas mensagens e se as suas comunicações anteriores estão seguras se as chaves de acesso forem roubadas.

Algumas das plataformas de chat mais populares, incluindo o Facebook Chat, Snapchat, WhatsApp, BBM, AIM e até mesmo o GTalk/Hangouts, não possuem a criptografia necessária para proteger as comunicações dos fabricantes das aplicações, embora, segundo o relatório da EFF, as mensagens sejam encriptadas durante o transporte.

As aplicações de mensagens populares, mais seguras, são o iMessage e o FaceTime da Apple, que são encriptadas de forma a que nem forasteiros, nem a própria Apple possam aceder às suas mensagens. Ainda assim, ambas carecem de funções de segurança para verificar as identidades dos seus contactos e o seu código não está aberto para revisão independente.

Dos 38 sistemas avaliados no relatório, apenas 6 conseguiram cumprir todas as sete categorias:

  1. A sua comunicação é encriptada durante o trânsito?
  2. A sua comunicação é encriptada com uma chave a que o provedor do serviço não tem acesso?
  3. Pode verificar de forma independente a identidade de seu interlocutor?
  4. As suas últimas comunicações estão seguras se as chaves forem roubadas?
  5. O código está aberto para revisão independente?
  6. O projecto e design da criptografia está bem documento?
  7. Houve uma auditoria de segurança independente?

As seis que passaram os testes, são todas aplicações menos conhecidas e propositadamente construídas com a segurança em mente.

Além do Mxit, uma aplicação de mensagens popular na África do Sul, a outra aplicação que falhou todos os sete indicadores de segurança é a QQ, a aplicação de mensagens mais popular na China, com quase mil milhões de utilizadores.

 

Tradução livre do artigo "These Are the Least Secure Messaging Apps", de Jack Linshi para a Time.

sábado, 8 de novembro de 2014

SQL Server: Índices (1) – Introdução

Introdução

Um dos caminhos mais importantes para obter alto desempenho numa base de dados (BD) do SQL Server são os Índices. Os índices são os objectos de BD que permitem acelerar o processo de consulta das linhas de uma tabela, de uma maneira semelhante à forma como o índice de um livro ajuda a encontrar, rapidamente, informações dentro desse livro.

Uma boa compreensão dos índices é essencial para os administradores de BD (DBA), mas também para os programadores, essencialmente pela seguinte razão: quando um pedido de dados chega ao SQL Server, este só tem duas opções possíveis para aceder às linhas solicitadas:

  • Percorrer todas as linhas da(s) tabela(s) que contém os dados, examinando cada uma para ver se corresponde aos critérios de selecção;
  • Ou usar um índice, se existir, para localizar rapidamente os dados solicitados.

A primeira opção está sempre disponível no SQL Server. A segunda opção só estará disponível se forem dadas instruções ao SQL Server, para criar um índice.

Como os índices têm um custo associado (ocupam espaço e devem ser mantidos sincronizados com as tabelas), não são obrigatórios no SQL Server. É possível ter uma BD sem nenhum índice. Provavelmente irá ter uma péssima performance e problemas de integridade de dados, mas o SQL Server permite criar uma BD com estas características.

Mas não é isto que nós queremos! O que queremos é uma base de dados que tenham uma boa performance, integridade de dados e, ao mesmo tempo, mantenha a sobrecarga associada aos índices, num mínimo. Neste artigo, vamos começar a tratar deste objectivo.

Conteúdo

O que é um Índice?

Índices mal concebidos e falta de índices são as fontes primárias de bloqueios nas aplicações de BD. Projectar índices eficientes é fundamental para alcançar um bom desempenho.

Os índices permitem ao SQL Server encontrar e/ou modificar dados num espaço de tempo menor, utilizando um mínimo de recursos para atingir um máximo de performance. Os índices, quando bem construídos, também permitem ao SQL Server atingir um nível de concorrência máxima, permitindo que as consultas efectuadas por um utilizador tenham pouco impacto nas consultas executadas por outros. Finalmente, os índices providenciam uma forma eficiente de fazer cumprir a integridade dos dados, garantindo a unicidade de valores chave, quando um índice único é criado.

Mas, afinal, o que é um índice?

Um índice corresponde a uma estrutura em disco, associada a uma  tabela ou view, que agiliza a pesquisa de linhas nessa tabela ou view.

Um índice contém chaves, construídas a partir de uma ou mais colunas da tabela ou view, que permitem ao SQL Server encontrar a linha ou linhas associadas aos valores das chaves, de forma rápida e eficiente. Por exemplo, numa tabela com informação pessoal, podemos criar um índice para a coluna do Número Contribuinte (NIF). Se efectuarmos uma pesquisa baseada num NIF, o SQL Server primeiro vai pesquisar o valor da chave no índice e, em seguida, vai usar o índice para localizar directamente a respectiva linha de dados, na tabela. Sem o índice, teria que se percorrer todas as linhas da tabela até se encontrar o NIF pretendido, o que costuma ter um impacto significativo na degradação do desempenho.

Podem-se criar índices para a maioria das colunas de uma tabela ou view. As excepções são, principalmente as colunas configuradas com tipos de dados de grandes objectos (BLOB e CLOB), como image, text e varchar(max). Também se podem criar índices em colunas do tipo XML, mas esses índices são um pouco diferentes e estão fora do âmbito deste artigo.

Estrutura de um Índice

Um índice é composto por um conjunto de páginas (nós) que são organizadas numa estrutura de Árvore-B. Esta estrutura é de natureza hierárquica, com o nó da raiz na parte superior da hierarquia e os nós de folha na parte inferior.

Quando é feita uma consulta sobre uma coluna indexada, o SQL Server começa no nó de raiz e navega, para baixo, através dos nós intermédios, sendo cada camada mais granular do que a anterior. O mecanismo de consulta continua para baixo, através dos nós de índice, até atingir o nível da folha. Por exemplo, se pesquisarmos o valor 123, numa coluna indexada, o mecanismo de consulta começa no nível da raiz e determina qual a página de referência no primeiro nível intermédio. Neste exemplo, a primeira página aponta para os valores 1-100 e a segunda página, para os valores 101-200, de modo que o mecanismo de consulta irá para a segunda página. O mecanismo continua e determina que deve ir para a terceira página no nível intermédio seguinte. Finalmente, o mecanismo de consulta navega até ao nó de folha que corresponde ao valor 123 (percurso a vermelho na imagem). O nó de folha contém toda a linha de dados ou apenas um ponteiro para essa linha, dependendo se o índice é clustered ou nonclustered.

Índices Clustered e Nonclustered

No SQL Server, existem dois tipos principais de índices: o Clustered e Nonclustered.

Clustered Index
Um índice Clustered armazena as linhas de dados de uma tabela ou view já ordenadas, com base na chave do índice. Com um índice clustered,  os dados são armazenados na própria estrutura do índice. Como fisicamente as linhas da tabela só podem ter uma ordem, apenas pode existir um índice clustered por tabela.

A única ocasião em que as linhas duma tabela são armazenadas de forma ordenada é quando a tabela tem um índice clustered. Neste caso temos uma tabela clustered (clustered table). Quando a tabela não é clustered, as linhas de dados são armazenadas numa estrutura desordenada chamada heap.

Nonclustered Index

Um índice noncluster é criado em separado da tabela. Fisicamente, as linhas dos dados são armazenadas na estrutura da tabela  (que pode ser clustered ou heap) e as linhas do índice são armazenadas numa estrutura de árvore-B separada.

Cada linha do índice contém o valor da chave e um localizador de linha. Este localizador aponta para a linha de dados da tabela, correspondente ao valor da chave do índice nonclusterd. Isto significa que o mecanismo de consulta necessita executar um passo adicional, de modo a obter realmente os dados.

As linhas do índice são armazenados na ordem dos valores da chave, mas as linhas de dados podem não ter qualquer ordem em particular, a menos que seja uma tabela clustered. Mesmo assim, é normal que a ordem dos dados na tabela não seja a mesma da ordem das chaves do índice nonclustered.

A estrutura do localizador de linha depende se ele aponta para uma tabela em cluster ou em heap. Se referenciar uma tabela clustered, o localizador de linha aponta para o valor da chave do índice clustered. Se referenciar uma tabela em heap, o localizador aponta directamente para a linha de dados.

Ao contrário dos índices clustered, podemos criar mais do que um índice nonclustered para a mesma tabela ou view. Para além de podermos criar vários índices noncluster, também podemos adicionar colunas ao índice (included columns). Isto significa que podemos armazenar, ao nível da folha, não só os valores das colunas indexadas, mas também os valores destas colunas incluídas. Isto permite realizar consultas completamente cobertas por índices e, por vezes, ultrapassar alguns dos limites impostos para as chaves dos índices.

Tipos de Índices

Para além de serem clustered e nonclustered, os índices podem ter características e configurações adicionais:

Índice Composto
Um índice cuja chave é composta, i.e., que contém mais que uma coluna. Ambos os índices clustered e nonclustered podem ser índices compostos. Existem limitações ao número e tamanho total das colunas que compõem a chave.

Índice Único (Unique)
Um índice que garante a singularidade de cada valor da chave indexada.

Se a chave do índice for simples (apenas uma coluna), então garante-se que o valor dessa coluna não se repete em nenhuma das linhas da tabela. Se a chave for composta, os valores de cada coluna individual podem-se repetir, mas cada combinação de valores das colunas da chave já não. Por exemplo, numa tabela que regista dados sobre um jogo de futebol, temos uma chave composta por duas colunas, uma com o tempo de jogo em minutos (0-90) e outra com o número de golos marcados (0-?). Podemos ter a seguinte sequência de dados da chave: (0,0) (5,0) (10,0) (11,1) (11,2), mas não podemos ter (0,0) (5,0) (10,0) (11,1) (11,2) (11,2).

Índice de Cobertura
Um tipo de índice que inclui todas as colunas que são necessárias para processar uma consulta particular. Por exemplo, a consulta pode devolver as colunas nome e apelido de uma tabela, com base no valor na coluna ContactId. Pode-se criar um índice de cobertura, que inclui todas as três colunas.

Limites dos Índices

Existem algumas limitações internas aos índices.

Tamanho da chave
O tamanho de uma chave de índice está limitado a um máximo de 900 bytes e 16 colunas. Este é definitivamente um limite e não um objetivo, pois quanto maior for a chave, mais páginas tem e mais profunda fica a árvore do índice. À medida que o número de páginas e a profundidade da árvore aumentam, menos eficiente se torna a utilização do índice. Índices maiores também usam mais espaço de armazenamento e podem resultar num uso menos eficiente de cache de dados do SQL Server.

Número de índices
Até ao SQL Server 2005 havia um limite de 250 índices por tabela, um cluster e 249 noncluster. A partir do SQL Server 2008, com a adição de índices filtrados, essa limitação foi aumentada para 1000, um cluster e 999 índices noncluster.

Qualquer destes limites é muito elevado e há poucos casos em que um sistema bem projectado se aproxime sequer deles. Existem duas razões para isso não acontecer:

  • À medida que aumenta o número de índices também aumenta o tamanho total ocupado pela tabela (com todos os seus índices). Claro que os discos rígidos são baratos e abundam as soluções de armazenamento, mas o aumento do tamanho duma BD tem outros efeitos: as operações de manutenção (backups, restauros, verificações de consistência e reconstrução de índices) vão levar mais tempo, à medida que o tamanho da BD aumenta;
  • Os índices têm que ser actualizados em sincronismo com as alterações dos dados. Quantos mais índices existirem numa tabela, mais os locais e maior o número de operações necessárias para actualizar. Se existirem 10 índices noncluster numa tabela, a inserção duma nova linha tem que ser feita em 11 locais (na tabela e em cada um desses índices).
    Nas BDs que são principalmente de leitura (de suporte à decisão, ou datawarehouses) isto pode ser aceitável. Mas nas BDs em que são frequentes as operações de alteração de dados - inserir, alterar, eliminar (sistemas OLTP), a sobrecarga imposta pela existência de muitos índices pode não ser aceitável.

Como o SQL Server usa os Índices

Vamos imaginar que queremos efectuar uma consulta sobre uma tabela, com um dado critério (p.ex. todas as linhas em que uma dada coluna tenha o valor ‘X’). Se a tabela não tiver um índice baseado na coluna selecionada, a única maneira de encontrar todas as ocorrências correspondentes ao critério dado, é ler a tabela inteira. Agora, se a tabela tiver um índice, o SQL Server acelera a localização de valores dentro desse índice de duas maneiras:

  1. O índice é ordenado segundo as colunas da chave. Isto significa que uma vez encontrados todos os valores correspondentes ao critério, o resto da tabela pode ser ignorado. Isto é o mesmo que acontece numa lista telefónica: uma vez encontradas todas as entradas com um apelido em particular, o resto da lista pode ser ignorada, pois mais nenhuma correspondência é possível;
  2. A estrutura da árvore do índice permite uma abordagem do tipo dividir-e-conquistar, para a localização de linhas, onde grandes partes da tabela são rapidamente excluídas da pesquisa. Isto está ilustrado na figura da Estrutura de um Índice, anterior.

Quando temos um índice numa tabela, existem 4 operações básica que o SQL Server pode executar sobre esse índice:

Scans (Varreduras)
Uma varredura de índice (index scan) é uma leitura completa de todas as páginas de folha do índice. Quando a varredura é feita num índice clustered, na realidade é uma varredura de toda a tabela (table scan).

Quando a varredura do índice é feita pelo mecanismo de consultas, é sempre uma leitura completa de todas as páginas de folha do índice, independentemente de todas as linhas serem retornadas ou não. Nunca é uma leitura parcial.

Uma varredura não envolve apenas a leitura dos níveis de folha do índice, as páginas de nível superior também são lidas durante a operação.

Seeks (Pesquisas)
Uma pesquisa de índice (index seek) é uma operação em que o SQL Server usa a estrutura árvore-B para localizar um valor específico, ou o início de um conjunto de valores. Para uma pesquisa de índice ser possível, deve haver um predicado (filtro pesquisável) especificado na consulta e um índice correspondente (ou parcialmente correspondente) a esse predicado. Nos próximos artigos desta série iremos examinar esta questão em maior detalhe.

A operação de pesquisa é executada a partir da página de raiz. A partir das linhas desta página, o mecanismo de consultas vai localizar a página do seguinte nível inferior do índice, que contém a primeira linha que está a ser pesquisada. O mecanismo vai, então, ler essa página. Se a página estiver no nível de folha do índice, a pesquisa termina aí. Se não é o nível de folha, então o mecanismo de consulta identifica novamente a página do nível inferior seguinte, que contém o valor especificado. Este processo continua até que o nível de folha seja atingido.

Quando o mecanismo de consultas localiza a página de folha que contém o valor de chave especificado, ou o início do intervalo especificado de valores-chave, vai lendo ao longo das páginas de folha até que todas as linhas correspondentes ao predicado sejam devolvidas. A figura seguinte mostra um exemplo de como uma pesquisa seria feita, num índice, para devolver as linhas com o valor 4 na chave:

Se o índice contém todas as colunas que necessita para a consulta, nas suas páginas de folha, então temos um índice de cobertura para essa consulta. Se o índice não contém todas as colunas requeridas, então o SQL Server vai fazer uma localização (lookup) na tabela base para obter as outras colunas, a fim de processar a consulta.

Lookups (Localizações)
Os lookups ocorrem quando o SQL Server usa um índice para localizar as linhas pedidas por uma consulta, mas esse índice não contém todas as colunas necessárias para satisfazer a consulta, ou seja, o índice não faz a cobertura dessa consulta. Para obter as colunas restantes, o SQL Server faz um lookup, quer numa tabela clustered, quer numa heap.

Um lookup numa tabela clustered é sempre uma pesquisa (seek) de uma única linha do índice clustered. Então, se for necessário fazer lookup a 500 linhas, isso significa 500 pesquisas individuais ao índice clustered.

Updates (Atualizações)
Sempre que uma linha for alterada, essas alterações devem ser feitas não só na tabela base (clustered ou heap), mas também em qualquer índice que contenha as colunas que foram afetadas pela alteração. Isso aplica-se às operações de INSERT, UPDATE e DELETE.

Considerações para a criação de Índices

Por mais benéfica que a utilização de índices possa ser, estes devem ser projectados com cuidado (já vimos anteriormente alguns dos problemas relacionados com a criação excessiva de índices). Como resultado, a criação de índices deve levar em conta algumas considerações:

  • O tamanho da chave dum índice clustered deve ser pequeno, porque ela vai fazer parte de todos os índices nonclustered.
    O ideal é tentar implementar o índice clustered em colunas exclusivas (unique) e que não permitam valores nulos. É por isso que a Chave Primária é muitas vezes usada para o índice clustered da tabela, embora considerações sobre consultas também devam ser levadas em conta ao determinar quais colunas a usar no índice;
  • Os índices noncluster compostos são geralmente mais úteis que os índices simples, a não ser que todas as consultas sobre a tabela sejam filtradas com uma coluna de cada vez;
  • Para índices compostos, deve levar em consideração a ordem das colunas na definição do índice. As colunas que são usadas em expressões de comparação na cláusula WHERE (como WHERE Nome = 'Luis') devem ser as primeiras da lista. As colunas subsequentes devem ser ordenadas com base na singularidade dos seus valores, com a mais exclusiva incluída primeiro;
  • Os índices não devem ser maiores do que o necessário. Demasiadas colunas no índice, desperdiça espaço de armazenamento e aumenta a quantidade de locais em que os dados têm que ser alterados quando ocorre um INSERT, UPDATE ou DELETE;
  • Se um índice é único, deve-se especificar que ele é único. O optimizador pode usar essa informação para gerar planos de execução mais eficientes.
    A singularidade de valores duma coluna afecta o desempenho do índice. De um modo geral, quantos mais valores duplicados tiver uma coluna, pior o índice executa. Por outro lado, quanto mais exclusivo for cada valor, melhor é o desempenho. Sempre que possível, implementar índices únicos;
  • Nas tabelas que são modificadas frequentemente, use o mínimo de colunas possível no índice, e não crie muitos índices, uma vez que vai retardar as operações de actualização de dados;
  • Se uma tabela contém uma grande quantidade de dados, mas existem poucas modificações, deve usar tantos índices quanto o necessário, para melhorar o desempenho das consultas. No entanto, deve usar criteriosamente os índices nas tabelas pequenas, porque o mecanismo de consulta pode demorar mais tempo a navegar pelo índice do que executar uma varredura (scan) da tabela.

Outras considerações para a criação de índices é a forma como a BD vai ser consultada. Conforme mencionado acima, deve levar em conta a frequência das modificações de dados. Além disso, deve considerar o seguinte:

  • Tente inserir ou modificar tantas linhas quanto possível numa única instrução, em vez de usar múltiplas consultas;
  • Crie índices nonclustered para as colunas usadas com frequência nos predicados das suas instruções e nas condições de JOIN;
  • Considere criar índices para colunas usados em consultas de correspondência exata.

Nos próximos artigos desta série vamos analisar em mais detalhe algumas destas considerações e recomendações.

Resumo

Neste artigo, tentámos dar uma visão geral sobre os conceitos e funcionamento dos índices no SQL Server e fornecer algumas das orientações que devem ser consideradas na criação e implementação dos índices. Isto é apenas uma pequena introdução ao tema, não pretendendo ser, de forma alguma, um trabalho completo e exaustivo sobre indexação em SQL Server.

O desenho e a implementação de índices são componentes importantes de qualquer projecto de BD no SQL Server. Nós próximos artigos desta série vamos desenvolver alguns dos conceitos introduzidos e ver exemplos concretos da utilização e manipulação dos índices.

Entretanto, recomenda-se a consulta dos SQL Server Books Online, para mais informações sobre os conceitos aqui descritos e considerações adicionais.

Referências

- "Introduction to Indexes", de Gail Shaw para a SQL Server Central

- "Stairway to SQL Server Indexes: Level 1, Introduction to Indexes", de David Durant para a SQL Server Central

- "SQL Server Index Basics", de Robert Sheldon para a Simple Talk

- "Indexes", na Microsoft Developer Network (MSDN)

- "SQL Server Index Design Guide", na Microsoft TechNet

- "Books Online for SQL Server", na Microsoft TechNet