Arquivo da categoria: Banco de Dados

Ampliando a comunicação – Mais um canal para falar de SQL Server e Banco de Dados

Bom Dia Pessoal,

Após a correria com as certificações e a semana do SQL Server, estou aqui para mais um rápido Post.

Primeiramente eu quero agradecer a todos que participaram da Semana do SQL Server assistindo aos eventos, postando dúvidas, divulgando o evento e contribuindo de uma forma geral. Infelizmente não pude apresentar por um problema com o aúdio do microfone. Mesmo chegando praticamente uma hora antes da sessão começar, não consegui configurar o microfone e acabou que não pude fazer o Webcast. Eu aproveito para agradecer também a Andressa que foi muito prestativa e me deu todo o suporte nesse evento e ao Felipe pela oportunidade.

Ainda assim, não poderia deixar de disponibilizar o conteúdo de alguma forma. Andei pensando numa forma de não somente disponibilizar esse vídeo especificamente, mas outros vídeos de SQL Server em geral que eu gravei e que por ventura venha a gravar. Aproveitei para abrir uma conta no Youtube e começarei a divulgar os vídeos das apresentações que faço (Webcasts, SQL Server DF, Virtual Pass, etc). Aos interessados, segue o link para assistir alguns dos vídeos que já disponibilizei (17 até agora):

Canal de gmasql
http://www.youtube.com/user/gmasql

Como fiz a gravação posteriormente, não fiquei limitado ao tempo de uma hora e acabei fazendo quase duas horas de gravação do Webcast “Evitando Erros Comuns na Elaboração de Código T-SQL”. Por uma questão de regras no Youtube, tive que quebrar o Webcast em várias partes:

Quem quiser o vídeo inteiro, segue o link para efetuar o download:

https://skydrive.live.com/redir.aspx?cid=f4f5c630410b9865&resid=F4F5C630410B9865!119

Dividi em dois arquivos, pois, excedeu o tamanho de 100MB

20110805_Evitando_Erros_Comuns_na_Elaboracao_de_Codigo_TSQL.part1
20110805_Evitando_Erros_Comuns_na_Elaboracao_de_Codigo_TSQL.part2

[ ]s,

Gustavo

Dois anos de blog, vários artigos, muitas visitas e valiosos feedbacks

Boa Noite Pessoal,

Hoje fazem exatamente dois anos que iniciei os trabalhos com um blog oficial. Em 13/07/2008, eu estava fazendo minha primeira postagem "A figura do administrador de banco de dados (DBA)" que era uma melhoria da minha primeiro postagem no Plugmasters. A idéia de publicar artigos surgiu de forma a complementar minha participação nos fóruns e a atuação como instrutor oficial MCT. Quando comecei a atuação no fórum era muito comum uma dúvida se repetir com muita frequência (não canso de ver os logs que cresceram demais, as conexões que dão pau, etc). Em diversas situações, eu acabava repetindo a explicação mudando algumas palavras e aperfeiçoando-a, mas nunca ficava boa, pois, dá uma certa preguiça digitar novamente a "mesma" coisa. A mesma coisa que acontecia nos fóruns acontecia nas aulas. Em um curso como o 2780 ou o 6231, era muito comum nos capítulos de Disaster Recovery eu passar boa parte da aula desenhando a estrutura do log de transações, seus LSNs e porque não devemos truncar o log.

Essa idéia de ineficiência começou a me incomodar. Afinal será que era realmente necessário "repetir" para cada vez que uma dúvida ou uma aula aparecessem ? Eu nunca tinha tido um blog, página ou algo do tipo e comecei a perceber que seria realmente um bom cartão de visitas falar algo do tipo "Procure no meu blog que há uma explicação detalhada sobre esse assunto". Sim, sem dúvida uma frase dessas valeria pontos extras em uma entrevista de emprego, em uma atividade de consultoria e certamente na avaliação dos alunos após terminar um curso.

Tendo essa idéia em mente, comecei então a publicar alguns artigos no Plugmasters. O objetivo dos artigos era complementar os MOCs para que minhas aulas ficassem mais didáticas. Não tenho nada contra os cursos oficiais, mas o fato de não haver "regionalização", acaba tornando-os complicados em algumas vezes e para evitar esses momentos, comecei com artigo simples como Planos de Manutenção, Geração de Scripts, DAC, etc. Posteriormente evoluí um pouco para outros assuntos como modelagem e XML.

A idéia de ter um artigo meu publicado na internet e de fácil referência era boa. "Está com dúvida em XML ? Tenho uns artigos bons sobre esse assunto. Quer saber sobre hierarquias ? Tem um monte de alternativas minhas publicadas…". Alguns comentários como "Parabéns pelo Artigo, uma verdadeira aula. hehe", "Um dos melhores artigos que já encontrei na internet", "Ajudou-me bastante ter o entendimento do assunto", "Muito bom aprendi muita coisa", são realmente muito gratificantes. Embora nem tudo fossem flores sempre ("Poderia ser mas expecífico, não contém informações completas… As informações contidas não são o suficiente"), de uma forma geral, o Plugmasters me ajudou bastante a melhorar os artigos técnicos e ajudar no fórum e complementar minhas aulas como MCT. Só havia um pequeno problema… Eu não podia falar que o site era meu. Limitava-me a dizer "o meu artigo", mas nunca "o meu site", "a minha página", "o meu blog".

A idéia de algo "meu" começou a me interessar. Do que adiantaria fazer ótimos artigos para um site que não tem identificação direta com o SQL Server ? Alguns achariam, alguns comentariam, mas nunca seria "referência". Também comecei a sentir falta de poder personalizar as coisas ao meu modo além do que cada artigo postado necessitava de uma aprovação prévia. O título de MVP também era uma ambição e poder dizer "tenho um blog dedicado a SQL Server" certamente contaria pontos para obtê-lo. Entrei no fórum em dezembro de 2007, mas no meio de 2008 além do enorme fluxo de dúvidas dos fóruns, minha caixa de e-mails estava lotada de dúvidas de SQL Server. Quando tudo isso juntou, aí sim senti falta de ter algo próprio e por fim decidi fazer montar meu próprio blog.

Criar um blog é algo muito fácil. Há várias ofertas e com apenas alguns cliques o blog está criado. A grande dificuldade é atualizá-lo, manter artigos de qualidade e fazer com as pessos visitem e indiquem o blog. Não basta ter conhecimento. É preciso ter disposição, didática, tempo, etc (é bem mais difícil que criar com certeza). Logo nos primeiros meses houve muitos acessos por conta das assinaturas dos feeds rss (havia dia com mais 100 visitas diárias e isso era muito bom). Entretanto como fazer para que a taxa continuasse crescente ? O que um blog deve ter para ser interessante ? Se eu observar os vários blogs de SQL Server hoje é complicado competir, pois, há muitos colunistas de qualidade e eu precisava bolar uma estratégia para mantê-lo "interessante".

A primeira coisa que pensei era em procurar algo que os demais blogs não tivessem ou não oferecessem na quantidade que o usuário gostaria. Claro que isso é algo muito difícil (senão impossível), mas alguns pontos poderiam ser explorados. Se eu observar os blogs de alguns papas do SQL Server como o Paul Randal, Kalen Delaney, Pinal Dave, Kimberly Trip, é realmente muito difícil competir. Não preciso ir tão longe. Basta olhar os artigos de tuning do Fabiano Neves Amorim, os artigos de Internals do Luti (ex MS) ou o portal MCDBA Brasil do Nilton Pinheiro para citar apenas alguns dos excelentes nomes no cenário nacional. Bem, como tantos nomes fortes resolvi adotar algumas premissas (quase sempre seguidas) que grandes nomes já usam:

  • Praticidade: Todos os artigos tem que ter um "quê" prático, ou seja, devem ser diretamente aplicáveis ao dia. Gosto de alguns devaneios, mas escrever algo em que não possa ter pelo menos um único script não é uma coisa que me agrada. Por isso não me interesso muito em publicar artigos relacionados a SQLOS, as "várias" áreas de memória do SQL Server ou ainda qual a diferença entre um lock e um latch. Não que não sejam importantes ou desinteressantes (muito pelo contrário), mas deixo essa tarefa para os livros mais aprofundados.
  • Riqueza de detalhes: É muito simples responder que o uso do CLR pode proporcionar o acesso a arquivos, que o backup de filegroup pode ser realizado (e restaurado) ou que as DMVs podem ajudar a resolver problemas de bloqueios no SQL Server. Sim, com certeza isso é verdade, mas será que apenas "falando" é possível que alguém que não conheça esses recursos consiga sair do outro lado ? Na maioria das vezes a resposta é não. Quando escrevo algum procedimento, posso demorar nas explicações e na quantidade de scripts, mas tenho como objetivo que qualquer pessoa que leia um artigo consiga fazer por si própria sem dúvidas ou ambiguidades.
  • Originalidade: Não tenho por hábito efetuar cópias de outros materiais como o help do SQL Server, livros, códigos ou artigos de outras pessoas. Não sei tudo de SQL Server (muito longe disso), mas ao invés de simplesmente copiar, prefiro exercitar minha criatividade. Mesmo nas raras vezes que copio alguma coisa de alguém, não deixo de citar e agradecer a fonte, pois, no caso das cópias os créditos não são meus. Particularmente não sou adepto de cópias. Qualquer bom DBA sabe que a "redundância" na maioria das vezes é indesejável.
  • Frequência: Existem blogs que publicam artigos uma vez por mês com artigos excelentes. Existem blogs que publicam artigos diários, mas sem muito critério. Não acho que publicar um artigo uma vez por mês torne um blog muito popular, mas postar diariamente normalmente diminui a qualidade dos artigos. Optei por uma frequência meio termo e tento publicar algo semanalmente (variando desde uma dica rápida até longos tutoriais).
  • Não trivialidade: Há muitos assuntos úteis relacionados a SQL Server, mas que certamente muitos irão falar a respeito. Todos sabem que o SQL Server 2008 R2 está repleto de novidades, que a nuvem é uma das grandes apostas da Microsoft, que o TechED 2010 está se aproximando. Certamente são notícias interessantes, mas que não dão nenhum caráter de exclusividade já que provavelmente os próprios Feeds da Microsoft trarão essas informações. Como busco algo um pouco "diferente", optei por não publicar posts desse tipo. Uma vez, enquanto estava no MVP Summit de 2009, ouvi de um funcionário da Microsoft (brasileiro) que o que ele mais gostava no meu blog era que ele não era nada trivial, ou seja, eu costumava escrever sobre coisas que quase ninguém escrevia. Isso sem dúvida me deixou bem feliz e gosto de manter essa característica. Não há nada no meu blog que seja desconhecido. Há vários artigos que outros inclusive conseguiriam escrever melhor, mas poucos teriam interesse em discorrer.
  • Feedback: Muitas vezes lemos algo de que gostamos, mas raras às vezes registramos nossa opinião. Pode parecer simples, mas muitas vezes eu mesmo já li textos ótimos e não tive a "coragem" de postar um único comentário sequer. Reconhecendo esse hábito, não deixo de responder os comentários que aparecem no blog. Claro que muitas vezes não dá tempo de responder no dia, mas tento sempre que possível responder aqueles que deixaram algum elogio ou crítica (ninguém é obrigado a concordar com tudo).

Após dois anos, faço um balanço geral muito positivo dessa iniciativa. Há muitos elogios que gostaria de publicar e muitas pessoas que gostaria de agradecer, mas vou resumir em uma mensagem que recebi já algum tempo:

Gustavo,
Estou passando apenas para dizer que o seu blog é otimo!!! Também quero agradecer as ajudas no forum de SQL.
Cara, sou seu fã!!!
Abraços!!

Infelizmente o Live retirou as estatísticas e não tenho mais como acompanhar os artigos mais lidos ou a quantidade de visitas diárias, mas tenho um último PRINT antes das estatísticas serem retiradas:

Se eu for considerar que o blog começou em 13/07/2010 e as estatísticas são de 28/05/2010 passaram-se 684 dias. Com um total de visitas de 85576 dá uma média de 125 visitas por dia o que equivale a pouco mais de 5 visitas por hora. Quando bati o que chamei de recorde número 1 em 02/09/2009 eu possuía 33807 visitas. A diferença de visitas até hoje foi de 51969 visitas e dá uma média de 165 visitas diárias (quase 7 por hora). Percebo que as estratégias estão dando certo e que o caminho está correto pelo aumento do número de visitas. É uma pena que o Live tenha retirado as estatísticas (isso é um grande motivo para pensar em mudar de endereço), mas continuarei tentando fazer o melhor possível.

Agradeço desde já todos os feedbacks, colaborações, comentários, opiniões, etc dados por todos. Sem dúvida foram bastante valiosos.

[ ]s,

Gustavo

A quantidade de linhas fala por si só ?

Bom Dia Pessoal,

Há alguns dias atrás passei uma tarde em minha cadeira monitorando o ambiente e logo ali ao lado estavam reunidos alguns amigos DBAs, analistas de negócio e a área usuária trabalhando na migração de uma aplicação para um ambiente mais parrudo que o atualmente utilizado. Além das pessoas envolvidas, estava na outra ponta da linha do telefone o fornecedor do software. Durante toda essa iteração escutei várias vezes frases do tipo "tem mais de sete milhões de linhas", "a quantidade de linhas é muito grande", etc.

É impressionante como existem muitas argumentações de carga baseadas puramente na quantidade de linhas. Quantas vezes uma software house não usa a quantidade de linhas como robustez da sua solução ("Meu Software processa mais de um milhão de linhas por dia") ? Quantas vezes um fornecedor não recomenda um servidor mais parrudo para processar muitos registros ("Veja bem, recomendo o servidor XPTO com 103 processadores e 105 GB de RAM, pois, serão mais de 1.000 linhas por segundo") ? Ou ainda decisões precipitadas como "A tabela tem dois milhões de registros. É melhor a gente particioná-la para obter desempenho".

Será mesmo que o número de linhas é uma boa métrica para carga, volume e dimensionamento ? Será que podemos dizer que a solução A é melhor que a solução B apenas porque A trabalha com mais linhas que B ? O número de linhas é um indicador importante com certeza, mas não pode ser utilizado isoladamente da forma como muitos utilizam, pois, pode levar a interpretações equivocadas.

Uma metáfora em relação ao mundo cotidiano

Em uma situação hipotética, um casal possui um casa em um grande terreno e está interessado em adquirir uma piscina. Algumas tendências como aquecimento global, trabalho home office e os três filhos pequenos que pedem para ir ao clube todos os dias fizeram com que essa decisão fosse "acelerada" e eles precisam decidir rapidamente.

Uma dos maiores problemas para quem tem piscina em casa refere-se à manutenção. A limpeza da piscina, por exemplo, pode demandar esvaziá-la e posteriormente enchê-la renovando a água "suja" para uma mais "limpa". Como água é um bem que está se tornando cada vez mais escasso e a conta de água é progressiva (quanto mais água se consome, mais se paga e essa relação não é proporcional, pois, a taxa é crescente com o volume) é imprescindível escolher a piscina que ofereça o lazer necessário, mas com a maior economia de água possível.

O casal vai à casa de piscinas mais especializada da cidade e o vendedor dá as seguintes opções:

  • A piscina de 1,5m de profundidade custa R$ 8.000,00
  • A piscina de 2,0m de profundidade custa R$ 12.000,00
  • A piscina de 2,5m de profundidade custa R$ 16.000,00

Normalmente uma piscina com 1,5m de profundidade está muito adequada para lazer e prática da natação. Considerando que as crianças são pequenas, ter uma piscina com 2,0m ou 2,5m de profundidade é até desaconselhável. Vale a pena lembrar que o principal parâmetro para decisão da compra é a quantidade de água (tem que ser a menor possível).

O raciocínio é bem simples. À medida que a piscina se torna mais funda, mais água será necessária para enchê-la. Então a piscina mais econômica será aquela que tem a menor profundidade. Logo a piscina de 1,5m deve ser a escolhida. Pensando assim, o casal optou pela piscina de 1,5m. Como todo cliente inteligente, antes de fechar a compra, o casal pediu para visualizar as piscinas. O esqueleto das mesmas é parecido com a figura abaixo:

De acordo com o raciocínio anterior, a piscina de menor profundidade deveria ser a que mais economizaria, pois a piscina mais raza é a que gasta menos água. Esse raciocínio parece correto, mas é logicamente inconsistente. Primeiro porque a quantidade de água é calculada em função do volume e não da profundidade. Embora a profundidade faça parte do cálculo do volume (Comprimento * Altura * Largura), ela sozinha não determinará o maior volume, pois, existem outros componentes envolvidos no cálculo.

Quando elaborei a figura coloquei todas com o mesmo comprimento variando apenas a largura e a profundidade. A piscina de profundidade 1,5m possui 6x de largura, a de 2,0m possui 3x de largura e de 2,5m possui 2x de largura. Como todas tem o mesmo comprimento vejamos o cálculo do volume para as piscinas

  Comprimento Largura Altura Volume
Piscina 1 c 6x 1,5m 9cx
Piscina 2 c 3x 2,0m 6cx
Piscina 3 c 2x 2,5m 5cx

As medidas de volume mostram que a piscina de 1,5m que possui a menor profundidade ocupa 50% a mais no volume de água em relação à piscina de profundidade de 2,0m e quase o dobro em relação à piscina de 2,5m de profundidade. A regra da profundidade mostrou-se completamente falsa já que possui um raciocínio inconsistente e levaria uma decisão equivocada. Isso porque a medida a ser analisada é o volume de água e não a profundidade (altura) da piscina em questão. A profundidade até poderia definir a piscina que possui o maior volume de água mas isso só seria verdade se as proporções entre comprimento e altura fossem as mesmas para as três piscinas o que não necessariamente é verdade (nesse caso não foi).

Aplicação em banco de dados

E o que o exemplo das piscinas tem a ver com banco de dados ? Se formos pensar nos bancos de dados relacionais e suas tabelas, não teremos propriamente uma figura em três dimensões como uma piscina, mas para cada tabela haverá um plano bidimensional representado por linhas e colunas. O tamanho de uma tabela irá variar diretamente em função dessas duas dimensões, ou seja, quanto maior forem o número de linhas e o número de colunas maior será o tamanho da tabela.

É importante notar que o tamanho das tabelas normalmente é uma medida de grandeza muito melhor que a quantidade de linhas. Embora a quantidade de linhas seja um componente importante para calcular o tamanho da tabela, o tamanho das colunas é igualmente importante e comumente desprezado (quase ninguém pergunta quantas colunas existem na tabela, mas é muito comum perguntar o quantidade de linhas). Embora normalmente a tabela que tem a maior quantidade de linhas seja mais volumosa que a tabela que tem menos quantidade de linhas, isso não é uma verdade absoluta. O exemplo a seguir (SQL Server 2008), mostra uma situação em que isso não acontece:

— Cria uma tabela de Controle Orçamentário
CREATE TABLE ResumoConsolidado (
    Ano SMALLINT, CentroCusto CHAR(5),
    JanPlanejado MONEY, JanExecutado MONEY, JanRealizado MONEY,
    FevPlanejado MONEY, FevExecutado MONEY, FevRealizado MONEY,
    MarPlanejado MONEY, MarExecutado MONEY, MarRealizado MONEY,
    AbrPlanejado MONEY, AbrExecutado MONEY, AbrRealizado MONEY,
    MaiPlanejado MONEY, MaiExecutado MONEY, MaiRealizado MONEY,
    JunPlanejado MONEY, JunExecutado MONEY, JunRealizado MONEY,
    JulPlanejado MONEY, JulExecutado MONEY, JulRealizado MONEY,
    AgoPlanejado MONEY, AgoExecutado MONEY, AgoRealizado MONEY,
    SetPlanejado MONEY, SetExecutado MONEY, SetRealizado MONEY,
    OutPlanejado MONEY, OutExecutado MONEY, OutRealizado MONEY,
    NovPlanejado MONEY, NovExecutado MONEY, NovRealizado MONEY,
    DezPlanejado MONEY, DezExecutado MONEY, DezRealizado MONEY)

— Cria uma tabela de Lancamentos Contábeis
CREATE TABLE Lancamentos (
    IDLancamento INT IDENTITY(1,1),
    DataLancamento DATE,
    ValorLancamento MONEY,
    CentroCusto CHAR(5))

— Insere 1 milhão de resumos consolidados
INSERT INTO ResumoConsolidado VALUES (2009,‘MARKT’,
    150000000,120000000,100000000,
    150000000,120000000,100000000,
    150000000,120000000,100000000,
    150000000,120000000,100000000,
    150000000,120000000,100000000,
    150000000,120000000,100000000,
    150000000,120000000,100000000,
    150000000,120000000,100000000,
    150000000,120000000,100000000,
    150000000,120000000,100000000,
    150000000,120000000,100000000,
    150000000,120000000,100000000)
GO 1000000

— Insere 10 milhões de lançamentos
INSERT INTO Lancamentos VALUES (‘20091220’,1256.12,‘MARKT’)
GO 10000000

Após a execução do script temos uma tabela ResumoConsolidado com 1 milhão de registros e uma tabela de Lançamentos com 10 milhões de registros. Se formos seguir a "falsa" lógica, certamente a tabela de lançamentos é muito mais volumosa, pois, tem 10 milhões de registros contra apenas 1 milhão da tabela de lançamentos. Vejamos então o que o SQL Server nos revela sobre a volumetria dessas tabelas através do script abaixo:

EXEC sp_spaceused @objname = ‘ResumoConsolidado’, @updateusage = ‘true’
EXEC sp_spaceused @objname = ‘Lancamentos’, @updateusage = ‘true’

Após aproximadamente 50 minutos, o resultado das stored procedures é mostrado na tabela abaixo:

name rows reserved data index_size unused
ResumoConsolidado 1000000 320072 KB 320000 KB 8 KB 64 KB
Lancamentos 10000000 300808 KB 300752 KB 8 KB 48 KB

A primeira conclusão é que número de linhas não significa necessariamente muito espaço. A tabela Lancamentos possui 10 milhões de linhas e ocupa apenas 300MB. Com a quantidade de memória dos servidores atuais beirando as dezenas de GB, uma tabela de 300MB caberia em memória sem maiores dificuldades se fosse necessário (isso considerando a completa ausência de índices para facilitar o acesso). A segunda conclusão (e mais importante) é que ao contrário do que se pensava, a tabela com a maior quantidade de linhas não necessariamente é a mais volumosa. A tabela ResumoConsolidado possui 1 milhão de linhas e ocupa 320MB enquanto que a tabela Lancamentos possui dez vezes mais a quantidade de linhas e ainda ocupa menos espaço ficando em 300MB. Assim como a profundidade da piscina, a quantidade de linhas se analisada isoladamente pode levar à raciocínios e decisões equivocadas. A explicação é bem simples. Embora a tabela ResumoConsolidado tenha a menor quantidade de linhas, o tamanho de cada linha é significativamente maior. Para 320MB e 1 milhão de linhas teremos cerca de 320bytes por linha. No caso da Lancamentos, o tamanho da linha fica em torno de 30bytes (300MB / 10.000.000 de linhas). Se fóssemos representar as tabelas em forma bidimensional (linhas x colunas) teríamos as seguintes "áreas".

Se formos considerar que um retângulo possui a altura de 1 milhão de linhas e a largura de 30bytes, para a tabela ResumoConsolidado seria necessário um pouco mais que dez retângulos colocados horizontalmente. Como cada retângulo possui 30bytes com dez retângulos conseguimos preencher 300 bytes, mas 2/3 de um retângulo consegue-se os 20 bytes restantes e assim se obtêm os 320 bytes por linha. Multiplicando esses 320 bytes pela altura de 1 milhão de linhas chega-se a área ed 320MB retornada pela sp_spaceused. No caso da tabela Lancamentos, é necessário empilhar dez retângulos. Cada retângulo possui a largura de 30 bytes que é correspondente à largura do registro. Como a altura de cada retângulo é de 1 milhão de registros, é preciso dez retângulos para chegar na marca de 1 milhão de registros.

Com a utilização dos retângulos é fácil fazer as devidas comparações. A tabela ResumoConsolidado utiliza dez retângulos e mais um pedaço de um retângulo (2 / 3) enquanto que a tabela Lancamentos utiliza apenas 10 retângulos. A diferença entre elas é justamente a área vermelha que corresponde a 20MB. Como pode ser percebido, a tabela ResumoConsolidado ocupará mais espaço em relação à tabela Lancamentos ainda que a tabela ResumoConsolidado tenha menos linhas (apenas um retângulo de altura).

A relevância da quantidade de linhas

Se o tamanho de uma tabela depende da quantidade de linhas e da quantidade de colunas, uma vez que o tamanho da linha permaneça mais ou menos homogêneo é possível fazer julgamentos a partir da quantidade de linhas. Se uma tabela A possui uma linha de tamanho de 100 bytes com 25 milhões de linhas e uma tabela B possui uma linha de tamanho 150 btyes, mas apenas 1 milhão de linhas seguramente a primeira tabela é muito mais volumosa. Entretanto, dada as infinitas realidades de negócio e seus modelos de dados jamais poderemos obter um tamanho padrão para o tamanho de linhas e por consequência dificilmente a quantidade de linhas será um bom indicador de volumetria. Salvo casos absurdos como bilhões ou trilhões de linhas (que fatalmente produzem tabelas muito grandes) será sempre necessário "desconfiar" quando surgir o argumento "a tabela possui milhões de linhas".

Como podemos observar, o tamanho da tabela é uma métrica muito mais adequada que a quantidade de linhas. Ainda assim, o tamanho da tabela não é por si só uma medida que diga muita coisa sozinha. Uma base de 10TB pode até impressionar pelo tamanho, mas não significa necessariamente algo crítico ou que mereça uma atenção fora do normal. Se formos considerar os dados "vivos", ou seja, aqueles que são realmente acessados se restrijam a 100GB por exemplo, certamente a importância de 10TB ficará muito reduzida. 10TB significam muito espaço, longas janelas de backup, mas administrar 100GB não tem o mesmo peso que administrar 10TB efetivos.

O que é de fato importante visualizar é que criticidade e grandeza de uma base de dados dependem de vários fatores. Quantidade de acessos simultâneos à base de dados, tamanho das transações, quantidade de tabelas, total de aplicações diferentes que acessam a base são por exemplo fatores que podem dizer muito mais sobre uma determinada base de dados do que meramente "minha base tem mais de 10 milhões de linhas".

Quase todo processo de troubleshooting, consultoria, documentação e afins possivelmente perguntará "qual é a quantidade de linhas" ou algo parecido. É bem fácil e intuitivo. Isso não está errado. Está apenas incompleto. A quantidade de linhas é importante, mas sozinha nunca será relevante. É preciso sempre usar esse dado dentro de um contexto para evitar distorções.

[ ]s,

Gustavo

A Impedância, o Mapeamento Objeto Relacional e Implementações – Parte III

Bom Dia Pessoal,

Por conta das correrias de fim de ano, não consegui entrar em 2010 sem "zerar" minha dívida de artigos de 2009. Não é bom deixar dívidas de um ano para o outro, mas como acabei não dando conta, estou prosseguindo com essa terceira parte a representação de mecanismos de herança para bancos de dados relacionais. Nas partes I e II, restringi-me apenas às representações lógicas padrão (uma tabela para toda a herança, uma tabela para cada classe e uma tabela para cada classe concreta). Tais representações são diretamente mapeáveis para um modelo físico. Abordei também como uma situação de negócio pode comprometer ou justificar a escolha de uma ou outra abordagem, bem como um comparativo dos pontos fortes e fracos de cada representação. Nessa última parte, mostrarei algumas implementações físicas não triviais para lidar com a herança.

Por ser especialista em SQL Server, focarei as implementações voltadas para esse SGBD (em especial o 2008). Como as opções para esse SGBD são relativamente variadas, nesse artigo falarei especificamente sobre uma implementação que utiliza o conceito de Sparse Columns.

Utilizarei exatamente os mesmos exemplos do último artigo, ou seja, após as alterações negociais. Abaixo o diagrama de classes:

A notação de Peter Chen simplificada é apresentada abaixo:

O recurso Sparse Columns

Aos fãs do mapeamento da herança em uma única tabela, a funcionalidade Sparse Columns é sem dúvida um ótimo recurso. O grande dilema da implementação em uma única classe é que se as classes forem muito diferentes, ou seja, possuírem muitas características privadas, a tabela ficará com uma quantidade de elementos nulos muito grande provocando muito desperdício de espaço e dificuldades nas regras de validação de inserção e atualização de registros. O uso do recurso de Sparse Columns se propõe a resolver o problema de espaço, de validação das regras de inseração e atualização além de facilitar algumas consultas. Esse recurso tem as seguintes características:

  • Valores nulos não requerem espaço quando forem armazenados
  • Valores não nulos requerem espaço adicional para armazenamento
  • Valores fixos requerem 4 bytes extras
  • Valores variáveis requerem dois bytes adicionais

Para utilizar esse recurso, será criada uma única tabela com o mapeamento de toda a herança.

— Criação da Tabela
CREATE TABLE Colaborador (
    Matricula INT NOT NULL,
    Nome VARCHAR(50) NOT NULL,
    Gerencia VARCHAR(80) NOT NULL,
    Cargo VARCHAR(50) NOT NULL,
    Tipo INT NOT NULL,
    NumeroPis CHAR(11) SPARSE NULL,
    EmpresaContratante VARCHAR(80) SPARSE NULL,
    DataContratacao DATE SPARSE NULL,
    Curso VARCHAR(80) SPARSE NULL,
    Faculdade VARCHAR(80) SPARSE NULL,
    PrevisaoTermino DATE SPARSE NULL,
    TemaMonografia VARCHAR(80) SPARSE NULL,
    LinkAcesso VARCHAR(100) SPARSE NULL,
    Projeto VARCHAR(80) SPARSE NULL,
    Especialidade VARCHAR(80) SPARSE NULL,
    Detalhes XML COLUMN_SET FOR ALL_SPARSE_COLUMNS)

Todas as colunas que são potencialmente nulas foram atribuídas como SPARSE. Ao final foi declarada uma coluna do tipo XML com uma definição "COLUMN_SET FOR ALL_SPARSE_COLUMNS". Comentarei sobre essa coluna posteriormente. O próximo passo é criar as regras de validação através de CHECK CONSTRAINTs. A regra a seguir especifica que dependendo do tipo, apenas as colunas corretas podem ser preenchidas.

ALTER TABLE Colaborador
ADD CONSTRAINT CKTipoColaborador CHECK (

    — Tipo 1 -> Efetivo
    (Tipo = 1 AND (
        NumeroPis IS NOT NULL AND
        EmpresaContratante IS NULL AND
        DataContratacao IS NULL AND
        Curso IS NULL AND
        Faculdade IS NULL AND
        PrevisaoTermino IS NULL AND
        TemaMonografia IS NULL AND
        LinkAcesso IS NULL AND
        Projeto IS NULL AND
        Especialidade IS NULL)) OR

    — Tipo 2 -> Terceirizado
    (Tipo = 2 AND (
        NumeroPis IS NULL AND
        EmpresaContratante IS NOT NULL AND
        DataContratacao IS NOT NULL AND
        Curso IS NULL AND
        Faculdade IS NULL AND
        PrevisaoTermino IS NULL AND
        TemaMonografia IS NULL AND
        LinkAcesso IS NULL AND
        Projeto IS NULL AND
        Especialidade IS NULL)) OR

    — Tipo 3 -> Estagiário
    (Tipo = 3 AND (
        NumeroPis IS NULL AND
        EmpresaContratante IS NULL AND
        DataContratacao IS NULL AND
        Curso IS NOT NULL AND
        Faculdade IS NOT NULL AND
        PrevisaoTermino IS NOT NULL AND
        TemaMonografia IS NULL AND
        LinkAcesso IS NULL AND
        Projeto IS NULL AND
        Especialidade IS NULL)) OR

    — Tipo 4 -> Estagiário Projeto Final
    (Tipo = 4 AND (
        NumeroPis IS NULL AND
        EmpresaContratante IS NULL AND
        DataContratacao IS NULL AND
        Curso IS NOT NULL AND
        Faculdade IS NOT NULL AND
        PrevisaoTermino IS NOT NULL AND
        TemaMonografia IS NOT NULL AND
        LinkAcesso IS NOT NULL AND
        Projeto IS NULL AND
        Especialidade IS NULL)) OR

    — Tipo 5 -> Consultor Externo
    (Tipo = 5 AND (
        NumeroPis IS NULL AND
        EmpresaContratante IS NULL AND
        DataContratacao IS NULL AND
        Curso IS NULL AND
        Faculdade IS NULL AND
        PrevisaoTermino IS NULL AND
        TemaMonografia IS NULL AND
        LinkAcesso IS NULL AND
        Projeto IS NOT NULL AND
        Especialidade IS NOT NULL)))

A próxima etapa é inserir alguns colaboradores para posteriormente visualizarmos o que o recurso de sparse columns pode oferecer.

— Insere um efetivo
INSERT INTO Colaborador (Matricula, Nome, Gerencia, Cargo, Tipo, NumeroPis)
VALUES (1,‘Cristiane’,‘RH’,‘Analista Jr.’,1,‘1235324’)

— Insere um terceirizado
INSERT INTO Colaborador (Matricula, Nome, Gerencia, Cargo, Tipo, EmpresaContratante, DataContratacao)
VALUES (2,‘Fausto’,‘Marketing’,‘Estoquista’,2,‘B2P Associados’,‘20080219’)

— Insere um estagiário
INSERT INTO Colaborador (Matricula, Nome, Gerencia, Cargo, Tipo, Curso, Faculdade, PrevisaoTermino)
VALUES (3,‘Carol’,‘Finanças’,‘Estagiário’,3,‘Contabilidade’,‘UFRS’,‘20110101’)

— Insere um estagiário de projeto final
INSERT INTO Colaborador (Matricula, Nome, Gerencia, Cargo, Tipo,Curso, Faculdade, PrevisaoTermino, TemaMonografia, LinkAcesso)
VALUES (4,‘Flávia’,‘RH’,‘Estagiário’,4,‘Serviço Social’,‘UFP’,‘20100601’,‘Teorias Sociais no Mundo Corporativo – Um caso prático’,http://ufp.br/monografias/ss/06xttss/)

— Insere um consultor externo
INSERT INTO Colaborador (Matricula, Nome, Gerencia, Cargo, Tipo, Projeto, Especialidade)
VALUES (5,‘Elton’,‘Administrativo’,‘Consultor de Processos’,5,‘Mapeamento de Processos Organizacionais’,‘Estruturação de Processos’)

Agora que os registros estão devidamente realizados, vejamos o que uma simples consulta sobre a tabela de colaboradores pode retornar (apenas os três primeiros registros):

SELECT TOP 3 * FROM Colaborador

O resultado é exibido na tabela abaixo:

Matrícula Nome Gerência Cargo Tipo Detalhes
01 Cristiane RH Analista Jr. 1 <NumeroPis>1235324</NumeroPis>
02 Fausto Marketing Estoquista 2 <EmpresaContratante>B2P Associados</EmpresaContratante>
<DataContratacao>2008-02-19</DataContratacao>
03 Carol Finanças Estagiário 3 <Curso>Contabilidade</Curso>
<Faculdade>UFRS</Faculdade>
<PrevisaoTermino>20110101</PrevisaoTermino>

Alguns detalhes interessantes chamam a atenção nessa consulta:

  • Todas as colunas marcadas como SPARSE foram omitidas ainda que o SELECT * FROM tenha sido utilizado
  • A coluna "Detalhes" declarada como COLUMN_SET FOR ALL_SPARSE_COLUMNS retornou automaticamente todos os elementos preenchidos em um tipo de dados XML

Quando uma coluna é marcada como SPARSE "não haverá" consumo de espaço para valores nulos. O uso da propriedade SPARSE em conjunto com a propriedade COLUMN_SET FOR ALL_SPARSE_COLUMNS pode prover outros benefícios interessantes na elaboração de consultas já que haverá suporte a XML disponível. A consulta abaixo, por exemplo, retorna todos os efetivos e o número do PIS via XQuery:

SELECT
    Matricula, Nome, Gerencia, Cargo, Tipo,
    Detalhes.value(‘/NumeroPis[1]’,‘CHAR(11)’) As NumeroPis
FROM Colaborador
WHERE Tipo = 1

O fato da coluna NumeroPis ter sido omitida em uma instrução SELECT * FROM não significa que ela não possa ser mais acessada. É possível utilizá-la normalmente bastando referenciá-la. A mesma consulta pode ser reescrita de uma forma mais fácil.

SELECT Matricula, Nome, Gerencia, Cargo, Tipo, NumeroPis
FROM Colaborador
WHERE Tipo = 1

Embora a coluna "Detalhes" se assemelhe muito a uma coluna calculada, ao contrário destas, ela permite atualizações desde que em conformidade com as estruturas da tabela. Os comandos a seguir atualizam os dados da empresa contratante e da data de contratação do terceirizado Fausto.

— Faz a atualização
DECLARE @Alteracoes XML
SET @Alteracoes =
<EmpresaContratante>B2P Tecnologia</EmpresaContratante>
<DataContratacao>2009-02-19</DataContratacao>’

UPDATE Colaborador SET Detalhes = @Alteracoes
WHERE Matricula = 2

— Confere os dados
SELECT Matricula, EmpresaContratante, DataContratacao, Detalhes
FROM Colaborador
WHERE Matricula = 2

O resultado é exibido logo abaixo:

Matrícula EmpresaContratante DataContratacao Detalhes
02 B2P Tecnologia 19/02/2009 <EmpresaContratante>B2P Tecnologia</EmpresaContratante>
<DataContratacao>2009-02-19</DataContratacao>

Entretanto, para que essa atualização seja realmente efetiva, é necessário informar todas as características privadas da classe. Os comandos a seguir fazem apenas a atualização da data de contratação sem informar a empresa contratante.

— Faz a atualização
DECLARE @Alteracoes XML
SET @Alteracoes = ‘<DataContratacao>2009-06-19</DataContratacao>’

UPDATE Colaborador SET Detalhes = @Alteracoes
WHERE Matricula = 2

Uma mensagem de erro é gerada:

Msg 547, Level 16, State 0, Line 5
The UPDATE statement conflicted with the CHECK constraint "CKTipoColaborador". The conflict occurred in database "tempdb", table "dbo.Colaborador".
The statement has been terminated.

Como a coluna EmpresaContratante não foi informada, a atualização tentará deixar o seu valor como nulo. Felizmente a check constraint previniu que isso ocorresse relatando por tanto um erro de integridade já que não é possível um terceirizado (tipo 2) ter a empresa contratante não informada.

Quando utilizar o recurso Sparse Columns ?

O recurso Sparse Columns faz uma troca entre alguns bytes extras, overhead de CPU em troca de economia de espaço na presença de valores nulos. Seguindo essa premissa, o uso desse recurso deve considerar como primeiro princípio a forte presença de valores nulos em várias colunas. Se houver poucos valores nulos em poucas colunas, o uso desse recurso poderá incorrer em mais espaço e menos desempenho. Se houver muitos valores nulos em muitas colunas a utilização de sparse columns se torna bastante interessante, já que poderá incorrer em economias de espaço significativas.

No quesito modelagem, quanto mais numerosas forem as subclasses e quanto maior a quantidade de características privadas de cada uma dessas subclasses, mais recomendável será o uso de sparse columns, pois em um cenário desses, a quantidade de colunas nulas em várias colunas será certa. No exemplo em questão, um efetivo terá apenas o número do PIS informado, deixando nulas todas as demais colunas que representam características privadas como EmpresaContratante, DataContratacao, Curso, Faculdade, PrevisaoTermino, etc.

Um ponto que pode passar bem desapercebido é a presença de colunas do tipo VARCHAR. Essas colunas são otimizadas em relação ao armazenamento, pois, gastam dois bytes extras para controle, mas consomem apenas a área utilizada em oposição a tipos CHAR que embora não possuam os bytes de controle sempre gastam o tamanho proposto (mesmo que não tenha sido utilizado). A presença de muitas colunas VARCHAR não se beneficia tanto do recurso de Sparse Columns como as colunas de tamanho fixo (demonstrarei isso a seguir).

Outro ponto a ser analisado são as facilidades providas pela utilização da coluna Detalhes. Dependendo de como a aplicação está estruturada, ter a forte utilização de XML para mapear essas classes e efetuar a persistência pode ser compensador mesmo que o armazenamento não justifique sua implementação.

Comparação

Para que os conceitos sejam melhor fixadas nada melhor que um benchmark entre o uso da funcionalidade e uma solução padrão. O script a seguir distribui as frequências dos funcionários da FKW em 40% de efetivos, 30% de terceirizados, 20% de estagiários, 5% de estagiários de projeto final e 5% de consultores externos. Serão populados mil colaboradores em uma tabela que utiliza o recurso de sparse columns e uma que não utiliza. Embora os dados estejam repetidos, a idéia principal para comparação é volume e dados duplicados não inferem nessa comparação.

— Script de distribuição de frequência
— 40% efetivos
— 30% terceirizados
— 20% estagiários
— 05% estagiários de projeto final
— 05% consultores externos
— 100% -> 1000 registros

— Exclui todos os registros de colaboradores
DELETE FROM Colaborador

— Insere os efetivos
DECLARE @iterador INT = 1
WHILE @iterador <= 400
BEGIN
    INSERT INTO
Colaborador (Matricula, Nome, Gerencia, Cargo, Tipo, NumeroPis)
    VALUES (@iterador,‘Cristiane’,‘RH’,‘Analista Jr.’,1,‘1235324’)
    SET @iterador += 1
END

— Insere os terceirizados
WHILE @iterador <= 700
BEGIN
    INSERT INTO
Colaborador (Matricula, Nome, Gerencia, Cargo, Tipo, EmpresaContratante, DataContratacao)
    VALUES (@iterador,‘Fausto’,‘Marketing’,‘Estoquista’,2,‘B2P Associados’,‘20080219’)
    SET @iterador += 1
END

— Insere os estagiários
WHILE @iterador <= 900
BEGIN
    INSERT INTO
Colaborador (Matricula, Nome, Gerencia, Cargo, Tipo, Curso, Faculdade, PrevisaoTermino)
    VALUES (@iterador,‘Carol’,‘Finanças’,‘Estagiário’,3,‘Contabilidade’,‘UFRS’,‘20110101’)
    SET @iterador += 1
END

— Insere os estagiários de projeto final
WHILE @iterador <= 950
BEGIN
    INSERT INTO
Colaborador (Matricula, Nome, Gerencia, Cargo, Tipo,Curso, Faculdade, PrevisaoTermino, TemaMonografia, LinkAcesso)
    VALUES (@iterador,‘Flávia’,‘RH’,‘Estagiário’,4,‘Serviço Social’,‘UFP’,‘20100601’,‘Teorias Sociais no Mundo Corporativo – Um caso prático’,http://ufp.br/monografias/ss/06xttss/)
    SET @iterador += 1
END

— Insere os consultores externos
WHILE @iterador <= 1000
BEGIN
    INSERT INTO
Colaborador (Matricula, Nome, Gerencia, Cargo, Tipo, Projeto, Especialidade)
    VALUES (@iterador,‘Elton’,‘Administrativo’,‘Consultor de Processos’,5,‘Mapeamento de Processos Organizacionais’,‘Estruturação de Processos’)
    SET @iterador += 1
END

— Monta uma tabela sem o recurso de sparse columns
CREATE TABLE ColaboradorNormal (
    Matricula INT NOT NULL,
    Nome VARCHAR(50) NOT NULL,
    Gerencia VARCHAR(80) NOT NULL,
    Cargo VARCHAR(50) NOT NULL,
    Tipo INT NOT NULL,
    NumeroPis CHAR(11) NULL,
    EmpresaContratante VARCHAR(80) NULL,
    DataContratacao DATE NULL,
    Curso VARCHAR(80) NULL,
    Faculdade VARCHAR(80) NULL,
    PrevisaoTermino DATE NULL,
    TemaMonografia VARCHAR(80) NULL,
    LinkAcesso VARCHAR(100) NULL,
    Projeto VARCHAR(80) NULL,
    Especialidade VARCHAR(80) NULL)

— Insere todos os registros da primeira tabela na segunda
INSERT INTO ColaboradorNormal (
    Matricula,Nome,Gerencia,Cargo,Tipo,NumeroPis,EmpresaContratante,DataContratacao,
    Curso,Faculdade,PrevisaoTermino,TemaMonografia,LinkAcesso,Projeto,Especialidade)
SELECT
    Matricula,Nome,Gerencia,Cargo,Tipo,NumeroPis,EmpresaContratante,DataContratacao,
    Curso,Faculdade,PrevisaoTermino,TemaMonografia,LinkAcesso,Projeto,Especialidade
FROM Colaborador

— Compara os tamanhos
EXEC sp_spaceused Colaborador, ‘true’
EXEC sp_spaceused ColaboradorNormal, ‘true’

O resultado mostra que as implementações são praticamente idênticas. Na verdade o uso do recurso Sparse Columns consumiu um pouco mais de espaço embora a implementação tradicional tenha desperdiçado um pouco mais conforme o quadro abaixo:

name rows reserved data index_size unused
Colaborador 1000 136 KB 96 KB 8 KB 32 KB
ColaboradorNormal 1000 136 KB 88 KB 8 KB 40 KB

Embora seja um pouco "frustante" visualizar o recurso de sparse columns não tenha incorrida na economia desejada não é difícil entender o resultado. As colunas fixas que são marcadas como sparse são apenas o Número do Pis, a data de contratação e a previsão de término. As demais colunas VARCHAR já não irão utilizar todo o espaço necessário e o uso de colunas marcadas como sparse irá incorrer nos bytes adicionais de controle o que no final das contas deixará ambas as implementações equivalentes no quesito armazenamento. A decisão ficará entre evitar o overhead de controle das colunas SPARSE ou abrir mão das possibilidades do XML na coluna "Detalhe".

A alteração da frequência pode produzir alguns resultados mais próximos dos desejados. Dessa vez, a taxa de colaboradores sofrerá algumas alterações. Haverá 10% de efetivos, 10% de terceirizados, 15% de estagiários, 10% de estagiários de projeto final e 55% de consultores externos.

— Script de distribuição de frequência
— 10% efetivos
— 10% terceirizados
— 15% estagiários
— 10% estagiários de projeto final
— 55% consultores externos
— 100% -> 1000 registros

— Exclui todos os registros de colaboradores
DELETE FROM Colaborador
DELETE FROM ColaboradorNormal

— Insere os efetivos
DECLARE @iterador INT = 1
WHILE @iterador <= 100
BEGIN
    INSERT INTO
Colaborador (Matricula, Nome, Gerencia, Cargo, Tipo, NumeroPis)
    VALUES (@iterador,‘Cristiane’,‘RH’,‘Analista Jr.’,1,‘1235324’)
    SET @iterador += 1
END

— Insere os terceirizados
WHILE @iterador <= 200
BEGIN
    INSERT INTO
Colaborador (Matricula, Nome, Gerencia, Cargo, Tipo, EmpresaContratante, DataContratacao)
    VALUES (@iterador,‘Fausto’,‘Marketing’,‘Estoquista’,2,‘B2P Associados’,‘20080219’)
    SET @iterador += 1
END

— Insere os estagiários
WHILE @iterador <= 350
BEGIN
    INSERT INTO
Colaborador (Matricula, Nome, Gerencia, Cargo, Tipo, Curso, Faculdade, PrevisaoTermino)
    VALUES (@iterador,‘Carol’,‘Finanças’,‘Estagiário’,3,‘Contabilidade’,‘UFRS’,‘20110101’)
    SET @iterador += 1
END

— Insere os estagiários de projeto final
WHILE @iterador <= 400
BEGIN
    INSERT INTO
Colaborador (Matricula, Nome, Gerencia, Cargo, Tipo,Curso, Faculdade, PrevisaoTermino, TemaMonografia, LinkAcesso)
    VALUES (@iterador,‘Flávia’,‘RH’,‘Estagiário’,4,‘Serviço Social’,‘UFP’,‘20100601’,‘Teorias Sociais no Mundo Corporativo – Um caso prático’,http://ufp.br/monografias/ss/06xttss/
)
    SET @iterador += 1
END

— Insere os consultores externos
WHILE @iterador <= 1000
BEGIN
    INSERT INTO
Colaborador (Matricula, Nome, Gerencia, Cargo, Tipo, Projeto, Especialidade)
    VALUES (@iterador,‘Elton’,‘Administrativo’,‘Consultor de Processos’,5,‘Mapeamento de Processos Organizacionais’,‘Estruturação de Processos’)
    SET @iterador += 1
END

— Insere todos os registros da primeira tabela na segunda
INSERT INTO ColaboradorNormal (
    Matricula,Nome,Gerencia,Cargo,Tipo,NumeroPis,EmpresaContratante,DataContratacao,
    Curso,Faculdade,PrevisaoTermino,TemaMonografia,LinkAcesso,Projeto,Especialidade)
SELECT
    Matricula,Nome,Gerencia,Cargo,Tipo,NumeroPis,EmpresaContratante,DataContratacao,
    Curso,Faculdade,PrevisaoTermino,TemaMonografia,LinkAcesso,Projeto,Especialidade
FROM Colaborador

— Compara os tamanhos
EXEC sp_spaceused Colaborador, ‘true’
EXEC sp_spaceused ColaboradorNormal, ‘true’

A forte presença de consultores externos mudou significativamente a distribuição de espaço em relação às implementações:

name rows reserved data index_size unused
Colaborador 1000 200 KB 192 KB 8 KB 0 KB
ColaboradorNormal 1000 264 KB 200 KB 8 KB 56 KB

Como o consultor externo não possui os atributos de tamanho fixo como número do pis, data de contratação e previsão de término, a implementação com o uso de sparse columns se beneficia, pois, esses campos não irão ocupar espaço se não forem preenchidos o que fatalmente aconteceria na implementação tradicional.

Esse comparativo mostra que do ponto de vista de armazenamento, a distribuição dos dados exerce papel fundalmental na escolha de uma ou de outra opção.

Limitações

A adoção do recurso de Sparse Columns pode trazer várias vantagens das quais notoriamente se destaca a economia de espaço desde que obedecidos alguns pressupostos. Entretanto, essa implementação acarreta algumas limitações que devem ser conhecidas antes de se optar por esse recurso:

  • Nem todo tipo de dados é suportado (geográfico, geométrico, varbinary(max) são alguns exemplos)
  • Colunas que sejam marcadas como sparse não podem compor índices clustered e índices unique
  • Tabelas que possuam sparse columns não podem ser comprimidadas
  • A replicação do tipo MERGE não suporta Sparse Columns
  • O uso de COLUMN SET deve ser feito imediatamente sob pena da tabela ter de ser refeita
  • A coluna COLUMN SET não pode ser indexada

Há várias outras limitações a serem analisadas. O Books OnLine possua uma lista mais detalhada a partir dos links abaixo:

Using Sparse Columns
http://technet.microsoft.com/en-us/library/cc280604.aspx

Using Column Sets
http://technet.microsoft.com/en-us/library/cc280521.aspx

[ ]s,

Gustavo

A Impedância, o Mapeamento Objeto Relacional e Implementações – Parte II

Boa Noite Pessoal,

No artigo anterior demonstrei algumas alternativas de implementação para mapear situações de herança criadas em uma representação orientada a objeto para um banco de dados relacional. As três alternativas clássicas foram abordadas (uma tabela por herança, uma tabela por classe e uma tabela por classe concreta), os prós e contras iniciais foram detalhados em relação a espaço, simplicidade, desempenho, etc, mas propositalmente não abordei um critério de avaliação: a resiliência a alterações de negócio. Quando se projeta um modelo de dados é imprescindível visualizar futuras alterações no mundo real que certamente irão influenciar a implementação do modelo. Não é possível prever com exatidão que alterações virão, mas é importante preparar-se para que quando elas vierem, a solução como um tudo tenha o menor impacto possível em relação ao modelo de dados. Hoje demonstrarei como uma evolução de regras de negócio podem afetar as implementações anteriores. Todo o artigo utilizará os mesmos exemplos anteriores, ou seja, refletirá a representação da força de trabalho da fictícia empresa FKW Soluções.

Representações Lógicas / Conceituais

A FKW Soluções conta com diversos perfis em sua força de trabalho. Há profissionais efetivos, estagiários, terceirizados e consultores externos para suportar às demandas por recursos humanos dessa organização. O diagrama de classes projetado é apresentado na figura abaixo:

O modelo conceitual simplificado na representação de Peter Chen é apresentado abaixo:

Mudanças na Organização FKW Soluções

A FKW defende que investir nos estagiários é uma boa política de gestão de recursos humanos. Os estagiários normalmente passam por um rígido processo seletivo antes de ingressarem na empresa e embora tenham um salário acima do mercado, os custos de contratação e manutenção desses profissionais é inferior aos dos demais uma vez que a FKW fica desobrigada de diversos passivos trabalhistas. A longo prazo, o programa de estágio é visto como um processo seletivo maior no qual os estagiários que realmente se destacam acabam preenchendo as vagas no quadro sejam como efetivos ou terceirizados. A preparação desses estagiários normalmente ocorre nos seus semestres finais quando os mesmos fazem um projeto (TCC) aplicável à empresa. Normalmente esses estagiários que são supervisionados representam 5% a 10% do total de estagiários.

A FKW entende que a departamentalização é necessária para gerir as principais atividades de seus colaboradores, mas percebe também que mais importante que os limites de uma gerência ou de outra é a atuação por papéis, ou seja, um colaborador da área de contabilidade pode estar envolvido em outras atividades que não necessariamente às impostas pela sua gerência como a avaliação da expansão ou não das atividades da FKW em outros estados. Isso é muito comum principalmente nas atividades de projetos que ultrapassem os limites de um único departamento. Nessas situações, um conhecimento multidisciplinar é necessário e possivelmente haverá formação de equipes de colaboradores para realização de um projeto. As equipes não são restritas à realização de projetos internos à FKW. É possível que equipes sejam formadas para a execução de projetos sociais.

As mudanças na realidade a ser modelada demandam alterações no diagrama de classes, no modelo conceitual bem como impactam as três implementações até então trabalhadas. O novo diagrama de classes é exposto na figura abaixo:

A notação de Peter Chen simplificada é apresentada abaixo:

A especialização de estagiário em estagiário de projeto final acompanha a letra P para informar que essa especialização é parcial, ou seja, não necessariamente todo estagiário será um estagiário de projeto final. Como essa é a única especialização possível não é necessário especificar se ela é sobreposta ou disjunta como foi o caso da especialização de colaborador em efetivo, estagiário, tercerizado ou consultor externo.

A nova realidade pode provocar impactos significativos nas implementações anteriormente abordadas. A seguir são apresentadas as três alternativas de mapeamento detalhadas no artigo anterior, porém adaptadas para as novas regras.

O mapeamento em uma única tabela

Seguindo a mesma realidade antes das mudanças, o uso de uma única tabela irá mapear todos os atributos das classes e suas especializações no caso das classes envolvidas na herança. A classe "Equipe" corresponde uma classe a parte e será mapeada para uma outra tabela. Como uma equipe é feita de vários colaboradores e um colaborador pode ser incluso em várias equipes haverá uma associação entre essas entidades.

Essa alternativa ressalta a principal vantagem e as desvantagens dessa implementação. A simplicidade continua presente e a representação através de uma única tabela faz com que a codificação das consultas continue simples. Mesmo a presença de uma nova entidade chamada "equipe", os impactos nesse relacionamento foram mínimos. As desvantagens tornam-se mais aparentes, cada novo tipo de colaborador que surgir, força a presença de novas colunas na tabela. Considerando que apenas 5% a 10% do total desses estagiários terão as novas colunas preenchidas e que os estagiários não representam a totalidade dos colaboradores, muito provavelmente menos de 5% dos registros terão essas colunas preenchidas, acentuando os problemas das colunas nulas (espaço e controle) bem como as etapas de validação das operações de INSERT e UPDATE (novos atributos demandaram novas regras). Validar que um colaborador efetivo, um terceirizado e um consultor externo não tenham as duas novas colunas preenchidas representa mais codificação e manutenção nesse tipo de implementação.

O mapeamento de uma tabela por classe concreta

A associação entre colaboradores e equipes é uma das maiores desvantagens nessa alternativa. A figura do colaborador é abstrata e essa implementação não representa classes abstratas. Nesse caso, ao invés de simplesmente optar por um relacionamento mais "trivial" entre colaboradores e equipes será necessário representar esse relacionamentos entre todas as classes concretas, ou seja, todas as tabelas.

Para representar os efetivos que fazem parte de equipes é necessário implementar uma tabela que faça essa associação. O mesmo foi necessário para cada classe concreta envolvida, ou seja, estagiários, estagiários de projeto final, terceirizados e consultores externos. Se fosse utilizada uma única tabela (Participantes), a integridade ficaria difícil de manter, pois, uma tabela genérica de participantes se relacionaria com qual das classes concretas ?

A gestão do espaço e a codificação de inserts, updates e deletes ainda são diferenciais, mas outras dificuldades se potencializam. A obtenção de todos os colaboradores e suas equipes envolverá um acesso em praticamente três tabelas por classe concreta (a classe em si, a associativa e a tabela de equipes). A existência de 5 classes concretas (efetivos, estagiários, estagiários de projeto final, terceirizados e consultores externos) envolverá 15 acessos para a obtenção da lista de colaboradores que participam de equipes.

A migração de estagiários comuns para estagiários de projeto final também compõe um desafio. Será necessário importar os dados entre tabelas e refazer todas as ocorrências de associações envolvidas. Um estagiário comum que esteja em um equipe do projeto X, ao se tornar um estagiário de projeto final terá que ter seus dados cadastrados na tabela de estagiários de projeto final juntamente com os dados na tabela de estagiários de projeto final participantes de alguma equipe. Além desse cadastro, seus dados terão de ser excluídos das tabelas de estagiários e estagiários participantes. A migração de estagiários para outro tipo de colaboradores pode não ser tão comum, mas é de se esperar que um estagiário venha a se tornar um estagiário de projeto final.

O mapeamento de uma tabela por classe envolvida

Essa alternativa mapeia cada classe para uma tabela independente da classe ser concreta e abstrata. A presença de uma classe "equipe" e uma associação entre colaborador e equipe derivará duas novas tabelas. Como o colaborador do tipo estagiário de projeto final também é um estagiário, essa especialização também deve ser contemplada.

Essa alternativa mostra-se uma pouco mais resistente às novas definições. A implementação da classe abastrata colaborador permite um relacionamento direto com a classe equipe através da tabela participantes. A presença da classe "Estagiários Projeto Final" também representa uma implementação direta através de uma especialização da tabela de estagiários em um relacionamento 1 x 1.

Obter a relação de todos os colaboradores participantes de equipes é uma tarefa performática nessa alternativa. A gestão de espaço é efetiva e a complexidade de codificação de instruções de inserts, updates e deletes é moderada. O ponto crítico dessa alternativa refere-se à profundidade da herança envolvida. O cadastro de um estagiário de projeto final envolverá o acesso à três tabelas (colaboradores, estagiários e estagiários projeto final) representando passos adicionais. A recuperação tende a ser mais lenta, pois, dois joins serão necessários enquanto às abordagens anteriores dispensam essa junções.

Conclusão

Assim como a primeira parte desse artigo já ressalta que não há nenhuma abordagem "melhor" que as demais, a adição de novas definições no negócio mostra que todas as alternativas continuam cercadas de vantagens e desvantagens. Não é possível escolher uma alternativa mais "correta" já que cada uma delas buscará alguns poucos objetivos em particular. A tabela abaixo mostra um comparativo e recomendações entre as estratégias:

Objetivo Uma única tabela Uma tabela por classe concreta Uma tabela por classe
Operações DML (Insert, Update & Delete) Ruim Bom Moderado
Espaço Ruim Bom Bom
Relacionamentos das classes com uma outra classe comum Bom Ruim Bom
Desempenho nas consultas às classes Bom Moderado Ruim
Desempenho nas consultas às classes e uma classe comum Bom Ruim Bom

Como é possível observar, não há uma implementação que seja perfeita para todas as situações e isso permite afirmar que nunca uma alternativa pode ser considerada sempre certa ou sempre errada. Há situações que ainda não foram avaliadas e que podem mudar o julgamento sobre uma alternativa em relação às demais. Como seria por exemplo que essas alternativas se comportariam se o estagiário de projeto final tivesse de ser avaliado por um profissional efetivo ? E se ao invés de ser avaliado por apenas um efetivo, ele pudesse ser avaliado por vários efetivos e vários terceirizados sendo que a quantidade de avaliadores é variável ? Essa representa somente mais cenário que pode prover diversas vantagens e desvantagens a cada uma dessas alternativas.

O segredo em escolher a alternativa certa não é simplesmente fechar os olhos e escolher sempre a alternativa A ou a B. O caminho para a escolha certa está justamente em analisar os pontos fortes e fracos de cada uma bem como a possibilidade de ocorrência desses pontos. Já vi alguns modelos de dados que separam a relação de clientes em duas tabelas, uma para pessoas físicas e outra para pessoas jurídicas. Não há simplesmente nada de errado em fazer essa separação se ambas as tabelas não se relacionaram a nada em comum (digamos que os processos de venda, cobrança, etc para pessoas físicas e jurídicas obedeçam à características completamente diferentes). Juntar várias tabelas em um só, como é o caso de motos, carros e caminhonetes também não é um erro se elas compartilharem várias características em comum e aparecer uma ou outra coluna com o valor nulo. Manter uma tabela com algumas poucas colunas e especializá-la em várias outras tabelas também não é uma implementação ruim se houver muitas características diferentes. Seria o caso da universidade que possui seus alunos e seus funcionários sendo que ambos possuem pouquíssimas características em comum (um login, um e-mail) e N outras características diferentes (direito a assistir aula, obrigatoriedade do pagamento de mensalidades, resultado de um processo seletivo, contra-cheque, ficha admissional, etc.

O importante é adequar a escolha que tenha mais pontos positivos e menos negativos à realidade a ser modelada. Vale lembrar que ela pode não ser estática e é bom sempre estar de olho nas evoluções futuras para não ser surpreendido.

Nessa parte do artigo detalhei apenas as mesmas implementações lógicas que as do artigo anterior acompanhadas de uma evolução negocial. Os modelos lógicos apresentados podem ser diretamente transpostos para modelos físicos já que qualquer SGBD relacional suporta as alternativas abordadas. No próximo artigo detalharei um pouco mais os modelos físicos do ponto de vista das implementações proprietárias para lidar com situações de herança.

[ ]s,

Gustavo

A Impedância, o Mapeamento Objeto Relacional e Implementações – Parte I

Boa Noite Pessoal,

Após uma correria danada para fazer as provas 70-453 e 70-454 e fazer minha apresentação no SQL Server Day estou aos poucos retomando minhas atividades. Ainda quero voltar a postar nos fóruns de SQL Server do MSDN e Technet, mas uma coisa por vez, pois, esse fim de ano está muito corrido e ainda tem algumas pendências de SQL Server para resolver. Hoje falarei um pouco sobre modelagem de dados, especificamente sobre implementações relacionadas às aplicações que estão imersas no paradigma da orientação a objeto e os dados que estão armazenamentos em bancos de dados cujo o Engine continua sendo relacional.

A orientação a objeto provê diversos benefícios em relação a sua predecessora (a análise estruturada) tais como encapsulamento, polimorfismo, herança, etc. Essas características proporcionam soluções muito mais fáceis de manter e resilientes a alterações de negócio. A representação através da orientação a objeto traduz os objetos do mundo real da forma como eles realmente são em oposição a representação de funcionalidades como era na análise estruturada. Se por um lado as aplicações são beneficiadas por uma abordagem orientada a objeto, a persistência dos dados nos bancos relacionais demanda uma atenção muito maior, pois, a tradução entre esses dois mundos não é direta. Essa realidade divergente é conhecida como "Incompatibilidade de Impedância" (ou simplesmente Impedância), embora o termo "Mapeamento Objeto Relacional" seja o mais utilizado.

Os bancos de dados relacionais possuem algumas alternativas clássicas para lidar com a Impedância e prover o mapeamento objeto relacional. Alguns fabricantes oferecem recursos proprietários diferenciando-se uns dos outros, mas nessa primeira parte do artigo apresentarei apenas soluções mais triviais e independentes do SGBD em questão. Para exemplificar as alternativas existentes, apresentarei uma situação fictícia (embora se enquadre perfeitamente em muitas organizações) abordando um diagrama de classes simplificado e suas implementações em bancos de dados relacionais. O que prentendo destacar refere-se especificamente a situações que envolvam herança. Antes de propriamente apresentá-las, já adianto que na disciplina de modelagem de dados, raras as alternativas que podem ser tidas como "sempre corretas" uma vez que a elaboração de um modelo sempre terá uma dose de subjetividade do administrador de dados, vantagens e desvantagens bem como regras de negócio que diferem bastante em cada organização. A realidade a ser apresentada não é diferente.

Uma situação de negócio

A empresa FKW Soluções é uma empresa em ascensão e contínuo crescimento. Em virtude de seu mercado de atuação ser altamente dinâmico e volátil, a FKW conta com vários tipos de colaboradores em sua força de trabalho. Inicialmente havia na empresa apenas profissionais da casa (chamados de efetivos), mas com o tempo estagiários, terceirizados, consultores externos somaram-se ao capital humano da FKW. Um sistema de gestão de pessoas foi desenvolvido para auxiliar a administração desses profissionais. A lista de características desses tipos de colaboradores é listada na tabela abaixo:

Colaborador Características
Efetivo Matrícula, Nome, Gerência, Cargo, Número do PIS
Estagiário Matrícula, Nome, Gerência, Cargo, Curso, Faculdade, Previsão de Término
Terceirizado Matrícula, Nome, Gerência, Cargo, Empresa Contratante, Data da Contração
Consultor Externo Matrícula, Nome, Gerência, Cargo, Projeto, Especialidade

As descrições dos termos utilizados são relatadas a seguir:

  • Matrícula: A matrícula do colaborador na FKW 
  • Nome: O nome do colaborador
  • Gerência: A área da empresa onde o colaborador está alocado
  • Cargo: O cargo atualmente exercido pelo colaborador
  • Número do PIS: O número do profissional efetivo no Programa de Integração Social
  • Curso: O curso universitário que o estagiário atualmente está matriculado
  • Faculdade: A faculdade a qual o estagiário está matriculado
  • Previsão de Término: A previsão de término de curso do estagiário
  • Empresa Contratante: A empresa a qual o colaborador terceirizado se encontra
  • Data da Contratação: A data na qual o colaborador terceirizado foi contratado na empresa contratante
  • Projeto: O projeto no qual o consultor externo foi alocado
  • Especialidade: A área de especialidade do consultor

Uma descrição genérica de cada tipo de colaborador pode ser realizada logo abaixo:

  • Efetivos: são colaboradores que trabalham na empresa através de contrato de trabalho (CLT).
  • Estagiários: são colaboradores universitários que trabalham período parcial ou integral na empresa.
  • Terceirizados: são colaboradores que estão trabalhando na empresa através de um contrato de alocação de mão de obra por uma outra empresa (Outsourcing).
  • Consultor Externo: são colaboradores que estão na empresa por um período determinado e normalmente em um projeto específico.

Algumas descrições auxiliares são expostas para evitar confusões:

  • A características "cargo" para estagiários não será simplesmente estagiário. Um estagiário que faça o curso economia, pode por exemplo ter o cargo de estagiário em investimentos no mercado financeiro ou estagiário em orçamento empresarial
  • A data de contratação para terceirizados foi incluída para evitar que empresas terceiras que ganhem um contrato simplesmente incluam um profissional sem histórico nessa empresa

Em uma situação real diversas outras características seriam listadas, mas para manter a simplicidade e a didática desse exemplo, o artigo irá limitar-se às expostas até aqui. Do ponto de vista de modelagem de dados e objetos, outras entidades naturalmente apareceriam como "Cargo", "Gerência", "Faculdade", "Empresa Contratante", etc. Vou desconsiderá-las nesse exemplo.

Diagramas e Representações

Do ponto de vista de aplicação, a implementação OO é bem direta. Como os colaboradores compartilham características em comum, pode-se definir uma classe abstrata com essas características. Diz-se que a classe é abstrata porque todo colaborador tem que se necessariamente um efetivo, um estagiário, um terceirizado ou um colaborador externo já que todos os tipos de colaboradores na força de trabalho foram detalhados e não há a possibilidade de um colaborador que não se enquadre em nenhum desses tipos. Após a definição da classe abstrata (que nesse caso é uma superclasse), são derivadas as classes mais específicas (subclasses) na ordem 1:1 em relação aos tipos de colaborador. Considerando somente os atributos da classe, o diagrama para essa situação é representado pela figura abaixo:

Para aqueles que prefiram um modelo conceitual na notação do Peter Chen, a representação desconsiderando os atributos é exibida na figura abaixo:

A notação de Peter Chen mostra que no diagrama um colaborador especializa-se em efetivo, estagiário, tercerizado ou consultor externo. As letras T e D são extensões ao modelo e significam que a especialização é total, ou seja, todo colaborador tem que ser um dos quatro tipos e que a especialização é disjunta, ou seja, o colaborador só pode ser um e unicamente um dos quatro tipos especificados. Os atributos foram desconsiderados por razões óbvias já que essa notação acaba "poluindo" a visualização quando considerados os atributos.

Alternativas de mapeamento

Considerando que o repositório de persistência será um banco de dados relacional e que mapeia-se aqui em um nível lógico, ou seja, desconsiderando-se as implementações específicas e particularidades de um ou de outro SGBD, as alternativas para modelar os colaboradores resumem-se em apenas três.

  • Mapeamento de uma tabela por hierarquia ou herança
  • Mapeamento de uma tabela por classe concreta
  • Mapeamento de uma tabela por classe especificada

O mapeamento em uma uma única tabela

Nessa alternativa todos os atributos de todas as classes são diretamente mapeados para uma única tabela que normalmente recebe o nome da superclasse.

Em uma única tabela ficam concentrados todos os atributos de profissionais efetivos, estagiários, terceirizados e consultores externos.

A principal vantagem dessa implementação é a simplicidade. Quando um colaborador vier a mudar de cargo (um estagiário que venha a ser contratado), basta atualizar os novos atributos e se a regra de negócio exibir, remover os valores dos atributos do cargo anterior. Como os dados estão todos em uma única tabela, as tarefas de junção com outras tabelas é bem simples. A inserção, atualização e exclusão de dados também será focada em uma única tabela. Relatórios que façam menção a colaboradores (como uma lista de colaboradores por gerência) também são bem fáceis de serem elaborados embora haja a necessidade de tratamento de colunas nulas.

As principais desvantagens dessas implementação são as regras de validação nas operações de cadastro, a "explosão" de atributos e o espaço utilizado.

O atributo Faculdade, por exemplo, refere-se somente aos estagiários. De acordo com a implementação estabelecida, consultores externos não possuem esse atributo. Se não houver nenhum mecanismo de validação, a tabela permite que um consultor externo possua uma faculdade e isso pode levar a problemas de consistência. Se houver um registro com os atributos número do Pis, projeto e especialidade, não será possível estipular se o colaborador é um profissional efetivo ou um consultor externo. A presença de uma coluna "Tipo de Colaborador" pode contornar esse problema, mas ainda assim a inconsistência se mantém. Todo cadastro de novos colaboradores deverá ter regras específicas para evitar que atributos de subclasses diferentes sejam preenchidos. Se novos atributos como semestre ou número de créditos forem adicionados para os estagiários, todas as regras de inserção e atualização terão de ser revistas de forma a impedir que um efetivo tenha esses atributos preenchidos.

A presença de todos os atributos de todas as classes pode implicar em limitações de implementação. Alguns SGBDs tem limites na quantidade de colunas possíveis e ainda que esses limites dificilmente venham a ser transpostos, não é muito performático uma tabela com muitas colunas, pois, implica em

Como a especialização é disjunta, ou seja, um colaborador só pode ser de um único tipo, todos os demais atributos deverão ser nulos. Quando um estagiário é cadastrado, os atributos Número do PIS, Empresa Contratante, Data da Contratação, Projeto e Especialidade ficarão nulos. Situações similares ocorrem quando um terceirizado ou um efetivo são cadastrados. A presença de tantas colunas nulas incorre em overhead adicional e desperdiço de espaço principalmente para tipos de tamanho fixo.

O mapeamento de uma tabela por classe concreta

Essa alternativa cria uma tabela para cada subclasse envolvida. Cada uma das tabelas criadas recebe o nome da subclasse correspondente e os atributos da subclasse são diretamente mapeados para as colunas da respectiva tabela. Os atributos da superclasse são repetidos em cada uma dessas tabelas.

Os dados genéricos de colaboradores como matrícula, nome, gerência e cargo são repetidos para cada tabela e os dados específicos de cada subclasse estão em sua tabela respectiva. Como existem quatro tipos de colaborador é necessário quatro tabelas para realizar essa representação.

A administração de espaço é uma das principais vantagens dessa implementação. Embora a "duplicidade" das colunas entre as tabela dê uma idéia de desperdício de espaço, vale lembrar que o que está duplicado são as colunas e não os dados. A consulta de lista de empregados por gerência irá exigir a união de todas as tabelas, mas dispensa o tratamento de colunas nulas.

A codificação das instruções de inserção, alteração e exclusão também são bem simples, pois, todos os dados necessários estarão em uma única tabela facilitando a implementação e a manutenção.

O controle da integridade representa um dos principais desafios nesse tipo de implementação. Como as tabelas são distintas, como assegurar que uma mesma matrícula não irá representar um estagiário e um efetivo ? E no caso de um colaborador vir a efetuar um treinamento ? Se aparecer uma entidade "treinamento" qual das "matrículas" deveria se relacionar ? A da tabela efetivos, a da tabela estagiário ? Esse pode representar um certo entrave, uma vez que há certa dificuldade na representação da classe abstrata

O mapeamento de uma tabela por classe envolvida

Essa alternativa emprega a criação de uma tabela por classe envolvida independente da sua capacidade de ser instanciada, ou seja, classes abstratas e concretas serão mapeadas.

A vantagem mais evidente dessa implementação é a coerência com a orientação a objeto. Ela é a que melhor traduz o ambiente OO para o ambiente relacional. Como os atributos estão mapeados por classe o controle de redundância é garantido sem a necessidade de se armazenar atributos nulos o que é refletido em desempenho e economia de espaço.

A presença de tabelas adicionais incorre em desvantagens natas. O cadastro de cada colaborador envolverá operações em duas tabelas (a de colaboradores e a do tipo requerido) o que torna as operações de inserção, alteração e exclusão um pouco mais onerosas do ponto de vista de desempenho e manutenção. A divisão dos dados por várias tabelas provoca a necessidade de juntá-las através de JOINs o que também significa menos desempenho em relação ao uso de uma única tabela.

Conclusão

As três alternativas apresentadas podem efetuar o mapeamento objeto relacional (MOR) de uma herança. Existem prós e contras além de várias variações proprietárias de implementação. As alternativas foram expostas e analisadas sobre várias aspectos, mas de forma nenhuma o assunto se esgota aqui. Nos próximos artigos irei expor a realidade apresentada a evoluções de negócio que podem fazer com que uma ou outra escolha adequada mostre-se inadequada. Futuramente demonstrarei algumas implementações proprietárias que contornam várias das limitações levantadas.

Cabe ressaltar que nenhuma das três alternativas é adequada para todas as situações e que de forma nenhuma uma alternativa pode ser considerada sempre "correta" em relação às demais e que da mesma forma nenhuma delas pode ser tida necessariamente como "errada". A representação a ser transposta para o modelo pode ser melhor favorecida por uma determinada alternativa, mas de forma nenhuma é possível estipular uma melhor alternativa que se enquadre em todos os casos.

[ ]s,

Gustavo

Recorde № 1 – 427 Visitas ao blog em um único dia

Boa Noite Pessoal,

Como de costume, sempre tento visualizar diariamente o número de acessos ao blog. É uma forma saber se o blog está caminhando em uma direção boa ou ruim. O número de visitas é um ótimo (e talvez um dos poucos) indicadores que possuo para saber se o blog está agradando ou não quem o visita. Normalmente o número de acessos fica entre 100 e 150 acessos durante a segunda e sexta e no fim de semana esse número cai para 10 a 30 acessos nos sábados e domingos.

Todo mês eu supero o número de visitas anteriores e lembro-me de que quando cheguei a 100 visitas em um único dia já foi um reconhecimento importante, pois, embora esse número seja insignificante perto do número de acessos de sites mais populares, ter 100 visitas em um blog de SQL Server do spaces é gratificante. Hoje para a minha surpresa, após fazer o acesso de rotina, tive a surpresa de visualizar 427 acessos em um único dia e totalizar 659 na semana (e ainda estamos na terça-feira). É realmente um crescimento bem surpreendente perto das médias que normalmente eu apuro. Não sei exatamente a que se deve esse aumento, pois, o Live não fornece tantas informações assim.

Fiz uma pequena apuração sobre os artigos mais lidos e constatei que os artigos referente a criação da tabela de números (partes I e II), os cáculos com data e hora (partes I, II, III e IV), os cálculos financeiros, consultas SQL e o mercado de ações (partes I, II e III) e os artigos de importação de XML (partes I, II, III e IV) estão entre os fortemente consultados no blog. Algumas categorias como “Mitos do SQL Server” e “Piores Práticas” também tem tido acessos um pouco acima do normal. Vi também que o Google, o fórum de SQL Server do MSDN e do TechNet e as comunidades SQL Server Brasil e SQL Brasil têm contribuído muito para as visitas. Algumas matérias como “Mitos do SQL Server – Será que COUNT(1) ou COUNT(‘X’) são mais performáticos que COUNT(*) ?” e “Como evitar contratar profissionais DBAs "Fake" e despreparados” renderam muitos comentários.

Eu iniciei o blog em 13 de julho de 2008 e de lá pra cá são 75 postagens (tá dando pra manter a média semanal (rs)). A cada artigo tento trazer a melhor explicação e qualidades possíveis para o assunto abordado. Muitas vezes não é possível esgotar o mesmo, mas a idéia é fazer de cada artigo uma excelente referência sobre um tema em particular. Ultimamente projetos, aulas, trabalho, estudos, família, etc tem tirado um pouco minha atenção dos fóruns, do blog e da ajuda às comunidades de SQL Server, mas realmente é bastante gratificante ter esse feedback. Espero em breve estar postando um recorde №2 (ajudem aê (rs)).

A todos os que visitam, comentam, indicam e contribuem com o blog eu gostaria de dar os meus sinceros agradecimentos.
Continuarei tentando fazer o melhor trabalho possível.

[ ]s,

Gustavo