Sei sulla pagina 1di 68

Sumário

04,07 e 11 :. SQL Azure


Introdução a SQL Azure Database, plataforma
Edição 13 Número 13 Ano 04 2010 de bando de dados relacionais baseada em
Nuvem.
EDITORES Por: Diego Nogare
Alexandre Tarifa
Diego Nogare
Emerson Facunte
Sergio Gonçalves 15:. Aplicações com “N” camadas
REVISÃO em ASP.Net - Parte II
Felipe Pocchini
Segunda parte do artigo, aplicando conceitos
Fernanda Sallai
de camadas em ASP.Net
MONTAGEM / FORMATAÇÃO Por: Felipe Pocchini
Milton Carvalhaes

EDITORAÇÃO E DIAGRAMAÇÃO 20:. FileStream


Adriano Almeida
Fernanda Sallai Conheça esta nova feature do Microsoft SQL
Server 2008
COLABORADORES
Caio Azevedo Por: Eduardo Bergantini Pint
Diego Nogare
Eduardo Bergantini Pint
Felipe Pocchini
Fabiano Neves Amorim 23:. Utilizando a proprieadade Identity
José Heberton Vilela de Melo Insert e DBCC CHECKIDENT
Laerte Junior
Conheça as propriedades para tratar
entidades no banco de dados
Por: José Heberton Vilela de Melo

Fale com Editor 28 :. O Paradigma FILLFACTOR


É muito importante para a equipe Veja um exemplo detalhado na pratica
saber a sua opinião sobre a utilizando conceitos deste paradigma.
revista, caso tenha alguma critica, Por: Laerte Junior
sugestão, ou elogio entre em
contato.

Caso tenha interesse em publicar


um artigo na revista envie o título
43:. SQL Reporting Service 2005
e um resumo do tema em formato Parte III
Word.
Continuação do artigo explorando Microsoft
site@codificandomagazine.net SQL Reporting Service 2005

Por: Caio Azevedo

Produzido por:
53:. Introdução ao Query Processor
Saiba mais sobre o responsável por calcular a
maneira mais eficiente de acesso aos dados
No SQL Server
www.codificando.net Por: Fabiano Neves Amorim

03:. Editorial 67:. .Close ( )


Edição 13 Número 13 Ano 04 2010

Editorial
Mais um ano de muitas conquistas se acabou, e um novo ano cheio de novidades começa agora!
Em 2009 a equipe da revista foi sensacional, o nosso time está cada vez mais forte e profissionalizado.
Cada um dos integrantes é peça fundamental no nosso trabalho na revista, e seu trabalho é muito
importante para que possamos entregar esse conteúdo para vocês!

Neste ano de 2010, muitas ferramentas do nosso mundo serão lançadas em RTM nos possibilitando ter
mais agilidade nas atividades e ganho de tempo em nosso dia-a-dia. Tenho certeza que muitos de nós
conquistarão patamares que estão sendo galgados a tempos, realizando sonhos e desafios que ficaram
pendentes de 2009.

Neste ano, teremos o lançamento oficial do Visual Studio 2010, do Windows Azure, do Office 2010,
SharePoint 2010 e algumas outras ferramentas... Viram só quantas novidades teremos agora?! E como nós
do Codificando .Net sempre fazemos, montaremos eventos presenciais e on-line para poder mostrar à
vocês estas novas ferramentas e novidades da nossa área.

Quero deixar um agradecimento especial à todos que nos acompanham, lendo esse material, e aos nossos
colaboradores que dispendem de tempo valioso pra ajudar a divulgar tecnologia, escrevendo! Não poderia
esquecer, de forma alguma, do time de profissionais que fazem esse trabalho acontecer, o time de editores
da revista.

Um grande abraço e muitas conquistas em 2010!


Família Codificando .Net"

Valeu gente.

Diego Nogare
site@codificandomagazine.net
e-magazine

SQL Azure Database


(Introdução) – SQL Server
2008
Por: Diego Nogare

O SAD (SQL Azure Database) é uma áreas de estudo dentro da plataforma


plataforma de banco de dados relacionais, Azure é o SAD (SQL Azure Database,
baseado “na nuvem”. Este conceito de lembram), que como o nome já sugere, é
nuvem pode ser uma novidade para um banco de dados relacional
alguns, mas há algum tempo já vem sendo hospedado na nuvem.
noticiado por muitas outras tecnologias, na
Microsoft é principalmente citado quando Utilizar um serviço na nuvem, não
se fala em plataforma Azure. Computação obriga você a eliminar seu parque
na nuvem é um conceito no qual os computacional local, pelo contrário,
aplicativos e/ou serviços ficam hospedados alguns serviços serão mais
na web, não mais em um servidor local e compensadores se utilizar o que já tem
proprietário, e pode ser acessado hoje em seu DataCenter. Na minha
normalmente pelos usuários da aplicação. concepção, vamos utilizar o SAD
É um serviço de alta disponibilidade que quando uma aplicação precisar utilizar
muitas grandes empresas de tecnologias banco de dados e o cliente não tem o
estão investindo hoje em dia. Alguns servidor de banco de dados local e nem
benefícios que favorecem a expansão deste quer comprar este servidor, neste caso a
tipo de tecnologia “na nuvem” vão de saída ideal seria utilizar o serviço na Codificando.net e-magazine
escalabilidade, alta-disponibilidade até nuvem. Mas quando uma empresa já
segurança com os recursos de proteção de tem o banco local, e tem infra-estrutura
dados através de infra-estrutura. Todos suficiente para rodar a aplicação
estes investimentos/gastos são de localmente, não é necessário contratar os
responsabilidades do provedor de serviço serviços da Microsoft.
que está disponibilizando a tecnologia na
nuvem, diminuindo o gasto com hardware Só pra constar, estes DataCenters da
por parte da empresa que utilizará o Microsoft são bem grandes, por volta de
serviço. uns 50Km² cada um, e com vários
servidores “blade” virtualizados. Isso
A Microsoft está apostando alto neste significa que provavelmente você terá
conceito de computação na nuvem, e a um servidor lógico rodando Windows
plataforma Azure é uma prova viva disso Server 2008 e SQL Server 2008, mas a
(ou virtual, como queiram! rs). Uma das máquina física será uma só (pra um

www.codificando.net Dez / Jan- 2010 | 4


SQL Azure Database (Introdução) – SQL Server 2008 e-magazine

monte de servidores lógicos). qualquer, que seja fácil para lembrar-se


Depois desta historinha introdutória durante o desenvolvimento. Neste caso,
sobre o Azure, vamos nos “conectar a foi utilizado SSDS-Sql-Magazine-Brasil.
nuvem”! Logo mais embaixo tem uma caixa (3)
que precisa ser marcada para avançar na
Primeiro passo a ser realizado para se criação da solução. Após preencher estes
trabalhar com o Azure é se cadastrar no dois itens, clique em Create Soluction
portal, após este cadastro (que é gratuito (4). Veja na figura 2 onde localizar estes
durante seu período de CTP) será processos.
possível acessar e estudar todos os
serviços Azure. Para fazer este cadastro
será necessário ter em mãos seu LiveID,
que é o mesmo e-mail e senha utilizados
para acessar o HOTMAIL ou seu
MESSENGER. Para realizar o cadastro
acesse o link http://
portal.ex.azure.microsoft.com/
default.aspx e vá até o item do
Microsoft Connect (1) nesta página,
então siga os passos para se cadastrar
gratuitamente. Após o cadastro, volte a
página inicial e acesse o item Sign Up Figura 2: Preenchendo os campos necessários da
solução.
(2), acompanhe na Figura 1 onde estão
estes itens.
Após esta etapa do processo, uma
atualização automática da página
acontecerá e rolando a tela para baixo
mostrará sua senha(2) para utilização do
serviço. Dois detalhes importantes: Codificando.net e-magazine
Primeiro é que o serviço não ficará
disponível imediatamente, é necessário
acessar um link (1) para validar a criação
após o cadastro e então utilizar os
serviços da plataforma Azure. Segundo
detalhe é que as soluções são únicas,
Figura 1: Localizando o Microsoft Connect no site. logo não será possível criar outra
solução com o mesmo nome utilizado
neste exemplo. Veja na Figura 3 onde
Acessando o Sign Up será possível localizar a senha gerada.
visualizar os recursos da plataforma
Azure disponíveis (1). Então localize a
caixa de texto que pergunta o nome da
sua solução (2). Dê um nome sugestivo

www.codificando.net Dez / Jan- 2010 | 5


SQL Azure Database (Introdução) – SQL Server 2008 e-magazine

Figura 3: Senha informada pelo sistema.

Ao acessar o link de confirmação, uma


mensagem de sucesso é informada e sua
Figura 5: Passos para alteração de Senha.
solução é apresentada do lado direito da
tela (1). Ao clicar sobre sua solução, é Depois do cadastro, e algum tempo pra
possível gerenciar alguns itens, inclusive a validar seus dados, será enviado um e-mail
alteração da senha. Para alterar a senha, é para seu endereço cadastrado, validando
necessário acessar o item Solution sua conta. O e-mail que é enviado é assinado
Credentials (1) [Figura 4] e em seguida pela conta ssdstlk@microsoft.com
expandir o menu de Solution Password (libere ele em seu cadastro de spam), com o
(1), na sequência informe a nova senha e título SQL Azure Invitation. Veja a figura 6,
confirme (2) [Figura 5], por fim clique em a caixa de entrada com o e-mail recebido.
Save (3) e se o resultado for satisfatório a Neste e-mail, vem os passos a serem
mensagem de que a senha foi atualizada seguidos para se iniciar o trabalho com o
com sucesso (4) deve aparecer. Azure, passando um código de validação e
Acompanhe a Figura 4 e 5 para encontrar também alguns links para ajudar no seu
estes itens no site desenvolvimento.

Codificando.net e-magazine
Figura 6: E-Mail de confirmação do Azure

Nesta primeira parte da sequência de artigos


sobre SAD, foi explicado um pouco sobre o
serviço na nuvem e como se cadastrar para
utilizar o serviço. O próximo artigo será
Figura 4: Gerenciamento das soluções.
sobre como criar a primeira aplicação com o
SAD hospedando nosso banco na nuvem.

Diego Nogare
Graduado em Ciência da Computação, Pós-Graduado em Engenharia de Computação com ênfase em Desenvolvimento
Web com .NET. Colaborador do Portal Linha de Código e da revista SQL Magazine, Líder do grupo de usuários
Codificando .NET, Líder dos Microsoft Student Partners [MSP] de São Paulo e Microsoft Most Valuable Professional
[MVP] em SQL Server, possui certificações MCP e MCTS em SQL Server 2005, é palestrante em eventos da Microsoft,
Codificando .NET e INETA BR, mantém o site: www.diegonogare.net.

www.codificando.net Dez / Jan- 2010 | 6


e-magazine

Conectando ao SAD (SQL


Azure Database) – SQL Server
2008
Por: Diego Nogare

No primeiro artigo sobre SAD (http:// onde será inserido o código. Após a
www.linhadecodigo.com.br/Artigo.aspx? inserção do código válido no site e
id=2493), foi explicado superficialmente o clicando em “Submit” é necessário
que é o SQL Azure Database e como criar aceitar os termos de uso clicando em “I
nossa conta na nuvem. Depois de receber o Accept”. Após este passo, vamos definir
e-mail de confirmação, que pode demorar as credenciais de acesso à nossa base do
alguns dias para chegar, vamos nos SQL Azure Database, veja a Figura 2. A
conectar ao SAD e começar de fato a partir deste momento, o SAD se
trabalhar na nuvem. comportará parecido como uma
instancia do SQL, podendo realizar
Os pré-requisitos para trabalhar nestes quase todas as atividades que se faz em
exemplos são poucos. Basicamente é uma instância local.
necessário aquele e-mail de confirmação
com seu código de validação do Azure,
uma conta ativa na LIVE, e também ter
alguma versão do SSMS 2008 (SQL Server
Management Studio 2008). Neste caso,
utilizaremos a versão Express que pode ser Codificando.net e-magazine
baixada gratuitamente aqui: http://
www.microsoft.com/downloads/
details.aspx?
displaylang=en&FamilyID=08e52ac2-1d62-
45f6-9a4a-4b76a8564a2b

Lendo o e-mail de confirmação, temos as


instruções, que inicia pedindo para nos Figura 1: Local pra inserção do Invitation Code.

conectarmos ao site https://sql.azure.com,


utilizar nossa conta da LIVE para a
primeira credencial e em seguida colocar
o Invitation Code que foi fornecido através
do e-mail. Veja a Figura 1, o site da Azure

www.codificando.net Dez / Jan- 2010 | 7


Conectando ao SAD (SQL Azure Database) – SQL Server e-magazine

de bases de dados. Também é possível


ver a string de conexão para acessar o
SAD através de algum cliente do SQL e
trabalhar remotamente. Veja a Figura 4,
o que tem quando se clica no link
“Manage”.

Figura 2: Credenciais para conexão ao SAD.

É interessante manter a localização como


“USA_Northwest” pois estamos
trabalhando com uma versão CTP, outra
localização pode ser que dê algum
resultado diferente.
Figura 4: Bases de dados na instância criada.

Após inserir os dados das credenciais, e


clicar em “Create Server”, uma instância Quando clicamos no botão “Connection
do SQL será criada nos servidores deles, String”, um pop-up é aberto e as strings
e poderemos acessar a qualquer de acesso ao SAD são mostradas. É só
momento. Veja a Figura 3, a instância copiar a string do tipo de fonte que será
criada. acessada a nossa instância na nuvem, e
então trabalhar na nossa aplicação
cliente preferida. Veja a Figura 5, as
strings de conexões para a aplicação que
criamos neste exemplo. Codificando.net e-magazine

Figura 3: A instância do SQL na nuvem

Para gerenciar nossas bases na instância,


podemos acessar o link “Manage” que Figura 5: String de Conexão da instância.
está à direita da tela e realizar a criação

www.codificando.net Dez / Jan- 2010 | 8


Conectando ao SAD (SQL Azure Database) – SQL Server e-magazine

Agora que já temos a instância criada, e você criou e no campo “Password”


a string de conexão. Vamos utilizar o forneça a senha criada. Após isso, clique
SSMS 2008 Express pra acessar a nossa em “Connect” e o SSMS se conectará à
base na nuvem e trabalhar com o SQL sua instância na nuvem. Caso dê algum
Server “hosteado” pela Microsoft em erro de conexão, será necessário habilitar
seus DataCenters. o a conexão por TCP/IP no Configuration
Manager.

Após abrir o SSMS, por padrão, já é


exibida a tela de login. Pelo SAD ainda
ser uma versão CTP, ainda não é
possível realizar a conexão por esta tela
inicial, mas na versão RTM do SAD será
bem provável que vamos conseguir
conectar sem maiores problemas. Por
não efetuar o login nesta tela, vamos
clicar em “Cancel” (1) e em seguida em
“New Query” (2). Acompanhe na Figura
6, a ordem a ser clicada e onde estão os
botões.

Figura 7: Autenticação real ao SAD.

Outro ponto de atenção, por se tratar de


uma versão CTP do SAD, um erro
sempre é apresentado ao se conectar
com o SSMS. É só clicar em OK e
prosseguir com o estudo, como se nada Codificando.net e-magazine
Figura 6: Forma de conexão ao Azure.
tivesse acontecido. O erro está
apresentado na Figura 8.

Após clicar em “New Query” (item 2 da


Figura 6), uma outra tela de login (que é
exibida na Figura 7) é mostrada, se sua
tela aparecer diferente desta apresentada Figura 8: Erro “aceitável” ao se conectar no SAD
no artigo, clique em “Options >>” no através do SSMS.

final da sua tela de login que ficará igual


Agora que já está conectado ao servidor
à essa. Nos itens marcados de vermelho,
SQL hospedado na nuvem, pode-se
insira os dados da string de conexão
fazer um teste simples consultando a
fornecidos, se precisar, consulte a Figura
versão do servidor SQL instalado.
5. No campo “Server Name” insira o
Fazendo uma busca no Azure
endereço do seu servidor na nuvem, no
(SELECT @@VERSION) é possível ter
campo “Login” coloque o usuário que

www.codificando.net Dez / Jan- 2010 | 9


Conectando ao SAD (SQL Azure Database) – SQL Server e-magazine

esse retorno. Veja a Figura 9.

Figura 9: Consulta ao servidor da nuvem

No próximo artigo sobre SAD, vamos


criar um banco de dados através do
SSMS e consultar no gerenciador web do
Azure.

Diego Nogare
Graduado em Ciência da Computação, Pós-Graduado em
Engenharia de Computação com ênfase em
Desenvolvimento Web com .NET. Colaborador do Portal
Linha de Código e da revista SQL Magazine, Líder do
grupo de usuários Codificando .NET, Líder dos Microsoft
Student Partners [MSP] de São Paulo e Microsoft Most
Valuable Professional [MVP] em SQL Server, possui
certificações MCP e MCTS em SQL Server 2005, é
palestrante em eventos da Microsoft, Codificando .NET e
INETA BR, mantém o site: www.diegonogare.net.

Codificando.net e-magazine

www.codificando.net Dez / Jan- 2010 | 10


e-magazine

Criando primeiro DB com SAD


(SQL Azure Database) – SQL
Server 2008
Por: Diego Nogare

Depois de nos cadastrarmos nos serviços


da Azure (http://
www.linhadecodigo.com.br/Artigo.aspx?
id=2493) e fazer nossas conexões no SAD
(http://www.linhadecodigo.com.br/
Artigo.aspx?id=2518), chegou a hora de
criarmos o primeiro banco de dados e ver
a interação entre a nuvem e uma Figura 1: Verificando os databases que temos na
nuvem
aplicação cliente.

Quando nos conectamos através do SSMS Já que estou conectado na base de dados
(SQL Server Management Studio) ao Master (que é a única base de dados que
SAD, precisamos nos atentar à alguns tenho no momento), vou criar um novo
detalhes por se tratar de uma versão CTP. Database pra exemplificar o restante do
Por exemplo, a forma de se conectar e em artigo. Vou utilizar uma sintaxe básica
qual banco de dados será. Por padrão, (create database dbLinhaDeCodigo
quando nos conectamos ao SAD através ) pra criar o banco (1) e vou conferir no
do SSMS, fazemos a conexão à base serviço on-line do Azure (2), para Codificando.net e-magazine
Master, para exemplificar alguns assegurar que realmente está lá. Confira
detalhes, vou abrir uma instância do a Figura 2, estes itens.
SSMS 2008 Express e me conectar ao
banco de dados default do meu SAD, e
após a conexão vou verificar todos os
Databases criados lá no meu servidor na
nuvem. Esta consulta pode ser
acompanhada na Figura 1.

Figura 2: Criação do banco de dados e verificação no

www.codificando.net Dez / Jan- 2010 | 11


Criando primeiro DB com SAD (SQL Azure Database) – SQL e-magazine

Agora que já criamos uma nova base de


dados no Azure, vamos ver os segredos
para nos conectar à ela. Como já dito
algumas vezes, estamos em uma versão
CTP do Azure então pra realizar tarefas
corriqueiras que fazemos de uma forma
quando trabalhamos com um SQL
Server qualquer, no Azure é um pouco
diferente! Por exemplo, pra conectar a
algum database, é necessário informar
na tela de login e não utilizando a
sintaxe “USE XXXXX” ou alterando o
combobox na IDE do SSMS, e é esta
conexão que faremos agora.

Vamos para a tela de login de uma


“New Query” (1), informamos o “Server Figura 4: Escolha do database nas opções de
conexão.
Name”, “Login” e “Password”(2) e
precisamos clicar em “Options >>”(3).
Veja a Figura 3, estas opções. Após se conectar à esta “New Query” do
SAD, na base que criamos, vamos criar
uma tabela e popular alguns registros lá
dentro. Veja o código da criação da
tabela na Listagem 1, e inserção dos
dados na Listagem 2.

CREATE TABLE tblArtigo


(codigo INT IDENTITY NOT NULL
,titulo NVARCHAR(50) NOT NULL
,autor NVARCHAR(30) NOT NULL Codificando.net e-magazine
,resumo NVARCHAR(100))

CREATE CLUSTERED INDEX idxTitulo


ON tblArtigo(titulo)

Figura 3: Opções de conexão do SSMS


Vejam que é necessário criar um index
clustered pra poder inserir dados na
Após clicar em “Options >>” está nosso
tabela, caso não tenham criado, uma
segredinho, será necessário informar
mensagem de erro será disparada e não
qual é o banco de dados que a instância
persistirá os dados.
se conectará, informe o
nome dbLinhaDeCodigo no campo INSERT INTO tblArtigo
“Connect to Database”(1) e em seguida (titulo, autor, resumo)
clique em “Connect”(2). Veja estes itens VALUES ('SAD - Criando Banco'
,'Diego Nogare'
na Figura 4.

www.codificando.net Dez / Jan- 2010 | 12


Criando primeiro DB com SAD (SQL Azure Database) – SQL e-magazine

,'Neste artigo será


criado o primeiro banco em
SAD...')

INSERT INTO tblArtigo


(titulo, autor, resumo)
VALUES ('LINQ com VS2010'
,'Andrey Sanches'
,'Por ser amante de
Orientação à Objetos, o LINQ me Figura 6: Verificação das bases de dados existentes.
fez...')

Visto que agora já temos um database,


INSERT INTO tblArtigo
(titulo, autor, resumo)
uma tabela e alguns dados na nuvem,
VALUES ('Novidades do VB 2010' vamos remover este database criado.
,'Alexandre Tarifa' Através do gerenciador on-line do Azure,
,'Analisando o Roadmap para mostrar que realmente existe uma
do Visual Basic, podemos...')
integração entre a nuvem e sua aplicação
Após fazer algumas inserções, vou cliente. Após a remoção da base, vamos
disparar um Select simples na tabela novamente fazer uma busca, pra ver o que
(SELECT *FROM tblArtigo ), pra retorna.
constatar se os dados foram realmente
inseridos e persistidos na nuvem. Pra Acessando o gerenciador do Azure,
visualizar os dados inseridos, veja a selecionamos o radiobutton em frente ao
Figura 5. nome da base de dados que desejamos
remover e clicamos em “Drop Database”.
Um pop-up de confirmação será
apresentado, aguardando sua autorização
para remover o referido banco de dados.
Após a confirmação, não existirá mais a
Figura 5: Realizando um Select na nuvem base que foi apagada. Veja o pop-up de Codificando.net e-magazine
confirmação na Figura 7.
Voltando ao início do texto, a primeira
verificação que foi feita neste artigo foi
consultar as bases que tínhamos no
servidor. Vamos realizar a mesma
validação de antes, mas agora sendo em
algum momento após a criação da nova
database. Veja o resultado na Figura 6.

Figura 7: Pop-up de confirmação de exclusão de base


de dados.

www.codificando.net Dez / Jan- 2010 | 13


Criando primeiro DB com SAD (SQL Azure Database) – SQL e-magazine

Se fizer novamente a primeira


verificação que foi realizada, será
constatado exatamente o mesmo retorno,
visto que não temos mais a base que foi
criada, somente a MASTER.

Após realizar todos os exemplos deste


artigo, pudemos ver como se conectar ao
SAD e criar um database, uma tabela e
alguns dados na nuvem. Após isso,
vimos como droparum banco de dados
da nuvem e provar essa interação entre
as partes.

Diego Nogare
Graduado em Ciência da Computação, Pós-Graduado
em Engenharia de Computação com ênfase em
Desenvolvimento Web com .NET. Colaborador do
Portal Linha de Código e da revista SQL Magazine, Líder
do grupo de usuários Codificando .NET, Líder dos
Microsoft Student Partners [MSP] de São Paulo e
Microsoft Most Valuable Professional [MVP] em SQL
Server, possui certificações MCP e MCTS em SQL Server
2005, é palestrante em eventos da Microsoft,
Codificando .NET e INETA BR, mantém o site:
www.diegonogare.net.

Codificando.net e-magazine

www.codificando.net Dez / Jan- 2010 | 14


e-magazine

Aplicações em N Camadas com


ASP.NET - PARTE II

Por: Felipe Pocchini

Aplicações em n camadas são neste artigo. Uma de suas grandes


desenvolvidas de forma distribuída, onde vantagens é que através dela, podemos
cada camada tem sua responsabilidade mudar a qualquer momento nosso
dentro do contexto. Para um modelo de sistema de banco de dados, sem
aplicação Web são comumente usadas 3 prejudicar a lógica do negocio.
camadas: Presentation(Apresentação),
Business(Lógica do negócio) e Data Para adicionar a camada ao projeto,
(Responsável pelas transações com o banco vamos clicar com o botão direito na
da dados). Para esta segunda parte do solução e adicionar um novo projeto.
artigo, iremos criar a camada Data, que
será responsável por todas as transações
com o banco de dados.

Codificando.net e-magazine

Figura 2: Adicionando um novo projeto a solução


(Add > New Project).

Esse novo projeto vai ser do tipo Class


Library, pois aqui serão criadas somente
as classes responsáveis pela
Figura 1: Exemplo de aplicação em N Camadas.
comunicação com o banco de dados.

Iremos adicionar a camada Data


juntamente com a primeira parte criada

www.codificando.net Dez/ Jan - 2010 | 15


Aplicações em N Camadas com ASP.NET - PARTE II e-magazine

A classe Clientes vai conter apenas um


atributo e os métodos responsáveis pelas
transações SQL, já que nossa entidade foi
definida na camada Entity.
Como aprendemos na primeira parte
deste artigo, vamos criar um atributo que
irá receber a string de conexão com o
banco de dados:

Figura 3: Projeto do tipo Class Library. connectionString

Este é um atributo de uso exclusivo da


Com o projeto adicionado a solução,
classe Clientes, não sendo preciso criar
podemos agora trabalhar na camada
uma propriedade para acessá-lo, pois o
Data da qual receberá uma entidade
mesmo já está encapsulado.
através da camada business, executando
Mais uma vez vamos contar com recursos
as transações com o banco de dados.
do Visual Studio para facilitar nossa vida
para a criação dos métodos:

Figura 4: Projeto criado.


Figura 6: Adicionando métodos na classe Clientes
(Add > Method).
Vamos utilizar a opção View Class

Codificando.net e-magazine
Diagram, para criar a classe Clientes da
Crie mais esses métodos seguindo os
maneira que aprendemos na primeira
passos acima:
parte deste artigo:

Alterar, Excluir, Obter, Listar.


O resultado final será esse:

Figura 5: Visualizando o diagrama de classes da


camada de Data (View Class Diagram). Figura 7: Classe Clientes com todos os
métodos e atributos definidos.

www.codificando.net Dez/ Jan - 2010 | 16


Aplicações em N Camadas com ASP.NET - PARTE II e-magazine

Para visualizar o código da classe Agora vamos adicionar na classe Clientes


Clientes, basta dar um duplo clique na os namespaces, System.Data e
classe. System.Data.SqlClient do Framework para
trabalharmos com as classes do
ADO.NET.

Figura 10: namespace System.Data e


System.Data.SqlClient adicionados a classe

Vamos atribuir a string de conexão ao


atributo “connectionString”.

Figura 11: atributo connectionString recebendo


Figura 8: Visualização do código da classe Clientes

Como podemos ver na Figura 8, os Vamos implementar agora os métodos da


métodos da classe Clientes foram classe Clientes, acompanhe abaixo:
criados, porém não estão
implementados. Neste caso, como o foco Inserir
é estudar aplicações em n camadas,
vamos agora implementar cada método
sem a preocupação de estudar
ADO.NET, onde no final do artigo você

Codificando.net e-magazine
encontra referências para aprofundar os
conhecimentos sobre o mesmo.

Para a camada Data reconhecer uma


entidade da camada Entity, é necessário
adicionar a referencia da camada Entity
na camada Data.

Figura 12: implementação do método Inserir.

Figura 9: Adicionando referencia da camada Entity


na camada Data (Add Reference > Projects > OK).

www.codificando.net Dez/ Jan - 2010 | 17


Aplicações em N Camadas com ASP.NET - PARTE II e-magazine

Alterar Obter

Figura 13: implementação do método Alterar.

Figura 15: implementação do método Obter.


Excluir

Listar

Codificando.net e-magazine

Figura 14: implementação do método Excluir.

Figura 16: implementação do método Listar.

Concluímos que ao final de mais uma


etapa, teremos a classe Clientes definida
juntamente com a camada finalizada. Na

www.codificando.net Dez/ Jan - 2010 | 18


Aplicações em N Camadas com ASP.NET - PARTE II e-magazine

terceira parte desse artigo vamos criar a


camada de negócio (Business) que ficará
responsável pela comunicação e
validação dos dados, entre a
apresentação (Presentation) e a camada
de dados (Data).

Participe desse artigo deixando seu


comentário.
Aprofunde seus conhecimentos sobre
esse tema na comunidade ASP.NET
Aprofunde seus conhecimentos sobre
esse tema na comunidade ADO.NET

Para saber mais:


Visão geral de aplicativo de dados n
camadas
ADO.NET

Até a próxima, grande abraço a todos.


Felipe Pocchini

Felipe Pocchini

Graduado em Ciência da Computação pela

Codificando.net e-magazine
Universidade José do Rosário Vellano (UNIFENAS), em
Alfenas – MG, trabalha com desenvolvimento de
aplicações Web e Windows Forms utilizando a
tecnologia .Net. Moderador da comunidade
Desenvolvendo para Web, colaborador da comunidade
Codificando.Net e editor da revista eletrônica
Codificando .Net e-Magazine.

www.codificando.net Dez/ Jan - 2010 | 19


e-magazine

FileStream, a nova feature do SQL


Server 2008

Por: Eduardo Bergantini Pint

Entendendo o FileStream FILEGROUP FgTesteSave


(NAME = N'Teste_Data2', FILENAME
=
O SQL Server sempre proveu a N'D:\Teste\data_save\Teste.ndf',
SIZE = 8MB, MAXSIZE = UNLIMITED,
capacidade de armazenar dados binários, FILEGROWTH = 16MB),
assim você podia pegar qualquer tipo de FILEGROUP FgTesteDocuments
CONTAINS FILESTREAM DEFAULT
arquivo e armazená-lo em uma coluna do (NAME = N'Teste_Documents',
tipo VARBINARY ( MAX ), FILENAME = N'D:\Teste\document')
LOG ON
no entanto um BLOB (Binary Large (NAME = N'Teste_Log', FILENAME =
Object) tem um padrão de usabilidade N'D:\Teste\log\Teste.ldf', SIZE =
diferente de dados relacionais, que são 8MB, MAXSIZE = 2048GB, FILEGROWTH
= 16MB)
concatenados por meio de I/O e GO
armazenados como dados estendidos,
não é possível fazer um streaming de um
BLOB.

Por causa dessa limitação, a solução


paliativa dos desenvolvedores era
disponibilizar o arquivo em um diretório
e apenas indicar o caminho no banco de
dados, que ainda sim é uma solução

Codificando.net e-magazine
viável mesmo dispondo do FileStream.

Criando e utilizando o FileStream

Por padrão o FILESTREAM vem Figura 01: Diretório de criação do FileStream


antes de ser gerado
habilitado na instância do SQL Server
2008, quando você vai criar o seu banco
de dados deve apontar para ele onde Na criação de um FileStream repare bem
ficará a armazenado o diretório do seu que você deve apontar um diretório e
FileStream. não um arquivo, dentro desse diretório
serão criados os arquivos para
CREATE DATABASE [Teste] ON FileStream.
PRIMARY
(NAME = N'Teste_Data', FILENAME =
N'D:\Teste\data\Teste.mdf', SIZE
= 8MB, MAXSIZE = UNLIMITED,
FILEGROWTH = 16MB),

www.codificando.net Dez / Jan - 2010 | 20


FileStream, a nova feature do SQL Server 2008 e-magazine

que será responsável pelo armazenamento


desses arquivos.
CREATE TABLE [dbo].[TestarMedia] (
[testeID] UNIQUEIDENTIFIER NOT NULL
ROWGUIDCOL PRIMARY KEY,
[dataCriacao] DATETIME NOT NULL DEFAULT
(GETDATE()),
[criadoPor] NVARCHAR(255) NOT NULL,
[fileName] NVARCHAR(255) NOT NULL,
[tipoTeste] NVARCHAR(255) NOT NULL,
[localizacao] GEOMETRY NULL,
[arquivo] VARBINARY(MAX) FILESTREAM);
GO

Figura 02: Diretório do FileStream criado pelo


SQL Server 2008

Mas e nos casos em que o banco de dados


ainda não tem FileStream?

Nesse caso você utilizaria o seguinte


código, para dizer ao seu banco de dados
criar a estrutura de FileStream:
ALTER DATABASE [Teste]
ADD FILEGROUP FgTesteDocuments
CONTAINS FILESTREAM Figura 03: Criando uma tabela para utilizar o
GO novo recurso
ALTER DATABASE [Teste]
ADD FILE
(
NAME= 'fs_filestream', Colunas utilizando o FileStream requerem a
FILENAME = propriedade ROWGUILDCOL, ela serve
N'D:\Teste\document'
Codificando.net e-magazine
)
para o sistema de armazenamento manter
TO FILEGROUP FgTesteDocuments traçado a instância do banco no filesystem.
GO
Alterando o banco de dados para aceitar
FileStream Um dos pontos positivos de utilizar o
FileStream para armazenar seus arquivos é
A primeira vez que você for para o que, por estar dentro do SQL Server você
diretório document, você encontrará não terá problema com perda de dados ou
alguns arquivos NTFS com GUID's como corrupção de dados, a menos que tenha
nome, e alguns arquivos principais com ocorrido na hora de ser inserido, podendo
arquivos de log. Todo esse funcionamento assim recuperar seus dados em caso de
serve para criar o namespace do catastrofes realizando um simples restore
FileStream. no banco.

Em seguida vamos criar a nossa tabela FONTE: livro Microsoft SQL Server 2008 -

www.codificando.net Dez / Jan - 2010 | 21


FileStream, a nova feature do SQL Server 2008 e-magazine

Implementation and Maintenance

Eduardo Bergantini Pint

Desenvolvedor .Net à 2 anos pela empresa


MinhaVida (www.minhavida.com.br). Com ênfase
em aplicativos web de alta performance membro e
colaborador da comunidade codificando.net.

Codificando.net e-magazine

www.codificando.net Dez / Jan - 2010 | 22


e-magazine

Utilizando a propriedade
Identity_Insert e DBCC
Por: José Heberton Vilela de Melo

Nesse artigo, farei uma breve de identidade existentes, antes de inserir


demonstração sobre a propriedade valores explicitamente.
Identity_Insert, utilizada para permitir a Poderá surgir o seguinte
inserção de valores explícitos na coluna questionamento: Inserir valores
de identidade de uma tabela. manualmente em uma coluna que é auto
incremento? Sim. Isso mesmo. Será
Demonstrarei também a utilização do possível realizar, utilizando a
DBCC CHECKIDENT que serve para propriedade SET IDENTITY_INSERT
verificar o valor de identidade atual para definida para ON.
a tabela especificada e, se necessário,
altera o valor de identidade. Onde Digamos que criamos uma entidade com
também é possível usar o DBCC uma coluna que será auto incremento.
CHECKIDENT para definir Inserimos 4 registros nela e teremos a
manualmente um novo valor de seguinte população na entidade,
identidade atual de uma coluna conforme figura 1.
identidade. IdCliente NoCliente DaCadastro
1 Nome1 2009-09-23
É comum, encontramos em entidades de 2 Nome2 2009-09-23

Codificando.net e-magazine
um banco de dados, colunas que são 3 Nome3 2009-09-23
auto incremento. Estas, são definidas 4 Nome4 2009-09-23

pela propriedade IDENTITY com os seus Figura 1. Entidade com a coluna auto
respectivos valores seqüenciados. incremento.

Geralmente, quando executamos


eventos de exclusão de registros nas Agora, se excluirmos os dois últimos
entidades, acaba se gerando intervalos registros e inserirmos dois novos
indesejáveis. Se esta for uma registros, teríamos a seguinte população
preocupação, não utilize a propriedade na entidade conforme figura 2.
IDENTITY. IdCliente NoCliente DaCadastro

1 Nome1 2009-09-23
Entretanto, para que nenhum intervalo
2 Nome2 2009-09-23
seja criado ou para preencher um 5 Nome5 2009-09-23
intervalo existente causado por uma
6 Nome6 2009-09-23
exclusão, poderemos avaliar os valores
Figura 2. Entidade com valores identidades fora
de seqüência.

www.codificando.net Dez / Jan - 2010 | 23


Utilizando a propriedade Identity_Insert e DBCC CHECKIDENT e-magazine

Agora, observe que a nossa entidade registros e inserir mais dois novos
possui um intervalo entre o segundo e o registros.
terceiro registro. Isso é totalmente
-- REMOVENDO 2 REGISTROS DA
desagradável para quem gosta de manter ENTIDADE #TbIdentity
seus registros organizados na sua base de
DELETE FROM #TbIdentity WHERE
dados. Para corrigirmos esse tipo de IdCliente > 2
problema, demonstrarei dois exemplos -- INSERINDO DOIS NOVOS REGISTROS
que ajudarão a reorganizar os registros da INSERT INTO #TbIdentity
coluna IdCliente. (NoCliente, DaCadastro)
VALUES ('Nome5',GETDATE
())
-- CRIANDO UMA ENTIDADE TEMPORARIA ,('Nome6',GETDATE())
CREATE TABLE #TbIdentity
( Nesse ponto, teremos a seguinte situação
IdCliente INT IDENTITY(1,1) na entidade temporária, conforme figura
PRIMARY KEY
,NoCliente VARCHAR(35) NOT NULL 4.
,DaCadastro DATE
DEFAULT(GETDATE()) IdCliente NoCliente DaCadastro
) 1 Nome1 2009-09-23
GO 2 Nome2 2009-09-23
5 Nome5 2009-09-23
6 Nome6 2009-09-23

-- POPULANDO A ENTIDADE Figura 4. Entidade temporária com valores


identidade fora de seqüência.
#TbIdentity COM 4 REGISTROS

INSERT INTO #TbIdentity Vamos agora, inserir valores para que


(NoCliente, DaCadastro)
VALUES ('Nome1',GETDATE possamos preencher o intervalo entre o
()) segundo e o terceiro registro. Mas, para
,('Nome2',GETDATE())
, isso, teremos que definir a propriedade
('Nome3',GETDATE()) SET IDENTITY_INSERT para ON. Essa
,
propriedade, permite que seja inserido
Codificando.net e-magazine
('Nome4',GETDATE())
-- RECUPERANDO AS INFORMAÇÕES DA explicitamente valores em uma coluna
ENTIDADE #TbIdentity definida com a propriedade IDENTITY,
SELECT * FROM #TbIdentity ou seja, auto incremento.

Nesse momento, teremos a seguinte Vale lembrar que somente uma tabela em
situação na entidade temporária, conforme uma sessão poderá ter a propriedade
figura 3. IDENTITY_INSERT definida como ON.
IdCliente NoCliente DaCadastro Isso quer dizer que, se uma entidade
1 Nome1 2009-09-23 estiver com a propriedade definida como
2 Nome2 2009-09-23 ON e uma instrução SET
3 Nome3 2009-09-23
4 Nome4 2009-09-23
IDENTITY_INSERT ON for emitida para
outra entidade, o SQL Server retornará
Figura 3. Entidade temporária com coluna auto
incremento. uma mensagem de erro informando que
SET IDENTITY_INSERT já está definido
Agora, vamos excluir os dois últimos como ON.

www.codificando.net Dez / Jan - 2010 | 24


Utilizando a propriedade Identity_Insert e DBCC CHECKIDENT e-magazine

-- DEFININDO A PROPRIEDADE
IDENTITY_INSERT PARA ON -- INSERINDO NOVOS REGISTROS AINDA
COM A PROPRIEDADE DEFINIDA PARA ON
SET IDENTITY_INSERT #TbIdentity ON
O valor default desta propriedade INSERT INTO #TbIdentity
é OFF, e é preciso específicar o (IdCliente ,NoCliente, DaCadastro)
nome da tabela na qual irá receber VALUES (10,'Nome10',GETDATE())
o valor da propriedade.

-- INSERINDO NOVOS REGISTROS Com isso, teremos a seguinte situação


demonstrada na figura 6.
INSERT INTO #TbIdentity
(IdCliente ,NoCliente, DaCadastro) IdCliente NoCliente DaCadastro
VALUES 1 Nome1 2009-09-23
(3,'Nome5',GETDATE())
2 Nome2 2009-09-23
,(4,'Nome6',GETDATE
()) 3 Nome3 2009-09-23
4 Nome4 2009-09-23
Observe que, depois de definida a 5 Nome5 2009-09-23
6 Nome6 2009-09-23
propriedade para ON, será preciso 10 Nome10 2009-09-23
explicitar o nome da coluna e os valores no
Figura 6. Entidade temporária com valor
comando INSERT, como mostra o exemplo identidade inserido manualmente.
T-SQL anterior.
Agora, vamos definir a propriedade
Agora, poderemos observar que o
IDENTITY_INSERT para OFF.
intervalo que tínhamos na entidade #
TbIdentity entre o segundo e o terceiro -- DEFININDO A PROPRIEDADE
registro, foi preenchido corretamente, IDENTITY_INSERT PARA OFF
conforme mostra a figura 5. SET IDENTITY_INSERT #TbIdentity
OFF

IdCliente NoCliente DaCadastro -- INSERINDO UM NOVO REGISTRO


1 Nome1 2009-09-23
2 Nome2 2009-09-23 INSERT INTO #TbIdentity
3 Nome3 2009-09-23 (NoCliente, DaCadastro)
VALUES ('Nome11',GETDATE())
4 Nome4 2009-09-23
5
6
Nome5
Nome6
2009-09-23
2009-09-23
Depois de executado esse comando T- Codificando.net e-magazine
SQL, teremos a seguinte situação,
Figura 5. Entidade temporária com valores
identidade seqüenciados corretamente. demonstrada na figura 7, comprovando a
teoria explicada anteriormente.
Uma observação importante é que se for
explícito um valor maior que o valor de IdCliente NoCliente DaCadastro
1 Nome1 2009-09-23
identidade atual na entidade, o SQL Server
2 Nome2 2009-09-23
usará esse novo valor como o valor de 3 Nome3 2009-09-23
identitade atual, ou seja, se for explícito o 4 Nome4 2009-09-23
valor 10 no comando INSERT e, se você 5 Nome5 2009-09-23
6 Nome6 2009-09-23
modificar o valor da propriedade 10 Nome10 2009-09-23
IDENTITY_INSERT de ON para OFF e 11 Nome11 2009-09-23
inserir um novo valor, o valor da coluna Figura 7. Entidade temporária com valor
identidade receberá o valor 11, conforme identidade inserido automaticamente.

demonstrado no código abaixo.

www.codificando.net Dez / Jan - 2010 | 25


Utilizando a propriedade Identity_Insert e DBCC CHECKIDENT e-magazine

Outra forma de reorganizarmos a identidade da coluna da entidade com a


identidade de uma entidade específica, é propriedade CHECKIDENT.
utilizando a propriedade CHECKIDENT
do comando DBCC, podendo ser definido -- VERIFICANDO A IDENTITIDADE DA
COLUNA IDENTITADE
um novo valor manualmente para uma
coluna identidade de uma entidade. DBCC CHECKIDENT('#TbIdentity',
NORESEED)
Digamos que, tenhamos uma entidade
com uma coluna definida com o valor Checking identity information:
identidade. Inserimos 4 registros nela e current identity value '4',
current column value '4'.
teremos a seguinte população na entidade, DBCC execution completed. If DBCC
conforme demonstrado na figura 8. printed error messages, contact
your system administrator.

IdCliente NoCliente DaCadastro Ao executar o T-SQL acima, o SQL Server


1 Nome1 2009-09-23
2 Nome2 2009-09-23
retornará uma mensagem nos mostrando
3 Nome3 2009-09-23 o valor atual da identidade como quatro e
4 Nome4 2009-09-23 o valor corrente também como quatro.
Figura 8. Entidade temporária com a coluna auto Observe que, quem é responsável por
incremento.
mostrar o valor da identidade sem ser
modificado é o argumento NORESEED,
Agora, se excluirmos os dois últimos que é especificado juntamente com a
registros e inserirmos dois novos registros, propriedade CHECKIDENT.
teríamos a seguinte população na
entidade, conforme demonstra a figura 9. Para reorganizarmos esses valores sem
correr o risco de ser criado, intervalos
IdCliente NoCliente DaCadastro
1 Nome1 2009-09-23 entre os registros na entidade, deveremos
2 Nome2 2009-09-23 especificar o argumento RESEED,
5 Nome5 2009-09-23 acompanhado de um valor que será
6 Nome6 2009-09-23
Codificando.net e-magazine
substituído pelo valor da identidade atual.
Figura 9. Entidade temporária com valores
identidades fora de seqüência.
Veremos, no exemplo a seguir:

-- DEFININDO O VALOR DA IDENTITADE


DA COLUNA IDENTITADE
Agora observe que nossa entidade possui
um intervalo do segundo registro para o DBCC CHECKIDENT('#TbIdentity',
RESEED, 2)
terceiro, isso é totalmente desagradável
Checking identity information: current identity
para quem gosta de manter seus registros value '4', current column value '2'.
DBCC execution completed. If DBCC printed error
organizados na sua base de dados messages, contact your system administrator.
conforme falado anteriormente, e uma Observe agora, que o valor
identidade corrente passa a ser
outra forma de corrigir esse tipo de justamente o que foi informado na
problema alem da propriedade IDENTITY expressão T-SQL.
seria a utilização da propriedade
Agora, vamos inserir mais dois novos
CHECKIDENT.
registros e observar o resultado do
mesmo.
O primeiro passo é verificar o valor

www.codificando.net Dez / Jan - 2010 | 26


Utilizando a propriedade Identity_Insert e DBCC CHECKIDENT e-magazine

-- INSERINDO DOIS NOVOS REGISTROS

INSERT INTO #TbIdentity(NoCliente,


DaCadastro)
VALUES ('Nome3',GETDATE())
,('Nome4',GETDATE())

Agora, teremos o seguinte resultado após a


inserção dos valores na entidade
#TbIdentity, conforme demonstrado na
figura 10.

IdCliente NoCliente DaCadastro


1 Nome1 2009-09-23
2 Nome2 2009-09-23
3 Nome3 2009-09-23
4 Nome4 2009-09-23
Figura 10. Entidade temporária com novos
valores identidade.

Espero ter sido bem sucinto quanto ao uso


da propriedade SET IDENTITY_INSERT e
DBCC CHECKIDENT.

A todos um bom estudo e até a próxima.

José Heberton Vilela de Melo


MSN: heberton_melo@hotmail.com

MCP | MCTS em SQL Server 2008 | Projetista de Dados

Líder da Turma do 2° Ano de Banco de Dados da FAL


Vice-Líder da DBA-RN Students Tech Club Microsof
Grupo: www.dbarnacademic.ning.com
Codificando.net e-magazine

www.codificando.net Dez / Jan - 2010 | 27


e-magazine

O Paradigma FILLFACTOR

Por: Laerte Junior

Um grupo de cientistas colocou cinco Moral da História


macacos numa jaula. No centro dela
colocaram uma escada e, sobre ela, um Se fosse possível perguntar a algum
cacho de bananas. Quando um macaco deles por que batiam em quem tentasse
subia a escada para apanhar as bananas, os subir a escada, com certeza a resposta
cientistas lançavam um jato de água fria seria:
nos que estavam no chão. "Não sei, as coisas sempre foram assim
Depois de certo tempo, quando um por aqui"
macaco ia subir a escada, os outros o
enchiam de pancada. Passado mais algum O Paradigma FillFactor
tempo, mais nenhum macaco subia a
Tive a oportunidade de participar em
escada, apesar da tentação das bananas.
um projeto em que a empresa tinha um
Então, os cientistas substituíram um dos
DBA Junior. Em determinada análise
cinco macacos.
que estávamos fazendo, uma análise e
A primeira coisa que ele fez foi subir a
reorganização dos índices com base na
escada e foi rapidamente retirado pelos
carga de cada um, surgiu o diálogo:
outros, que lhe bateram. Depois de
algumas surras, o novo integrante do
- Essa tabela eu conheço é muito Insert .
Pode colocar um Fillfactor baixo!
Codificando.net e-magazine
grupo não subia mais a escada.
- Por que?, perguntei eu.
Um segundo foi substituído, e o mesmo
- Eu não sei, aprendi assim e todo
ocorreu, tendo o primeiro substituto
mundo fala isso...
participado, com entusiasmo, na surra ao
novato. Um terceiro foi trocado, e repetiu-
O paradigma FillFactor I " A
se o fato. Um quarto e, finalmente, o
existência do page split"
último dos veteranos foi substituído.
Os cientistas ficaram, então, com um Continuando a minha pergunta,
grupo de cinco macacos que, mesmo questionei-o sobre Page Split e a
nunca tendo tomado um banho frio, resposta foi:
continuavam a bater naquele que tentasse "Ah, isso eu sei, é fácil. É quando o SQL
chegar às bananas. SERVER fica parecendo pipoca pulando
de um lado para outro para achar os
dados."

www.codificando.net Dez/ Jan - 2010 | 28


O Paradigma FILLFACTOR e-magazine

De uma certa maneira ele não estava A verdade com 100% de FillFactor
errado e eu, particularmente, adorei o Simplificando:
"pulando feito pipoca". Mas, sinceramente, John, Robert, Phil, Luca, Lucy, Chloe,
essa era uma resposta que eu preferia não Hannah and Julia decidiram ir à praia.
ter ouvido. Imagine se fosse alguém do John era o organizador e resolveu
Storage Team... colocar homens em um carro e mulheres
em outro. Um dia antes da viagem, Luca
O que é Page Split? resolveu não ir e Richard foi convidado.
O layout ficou parecido com a figura 1 :
Nós sabemos que o SQL SERVER trabalha
com páginas de 8kb e cada página possui
um fator de preenchimento, chamado
fillfactor. Por default este fator é 0, ou seja,
página totalmente preenchida e sem
espaço livre para novos registros.
Quando um registro é inserido ou
atualizado, este registro tem que ser
armazenado no espaço da página. Se a
página não possui espaço livre, o SQL
Server precisa reorganizar todas as
páginas para armazenar o novo registro.
Mas estas novas páginas não são
contínuas.
Figura 1 – Layout sem espaço no carro.

O FillFactor é aplicado em um índice


No último minuto, Luca decidiu ir, mas
quando este é criado ou reorganizado e
não havia espaço no carro e, como a
informa o quanto cada página do nível
ordem era carro dos homens primeiro e
Codificando.net e-magazine
folha será preenchida. Page Split é um
mulheres depois, ele teve que ir com o
processo interno que o Engine usa para
seu.
acomodar os dados novos (ou quando
mudamos o tamanho da informação em
Se John quisesse falar com Luca, ele
um campo varchar, por exemplo). Este
tinha que pular o carro das garotas e, o
processo consome uma carga considerável
pior, se ele quisesse falar com Lucy , ele
de I/O, tendo em vista que o Engine tem
tinha que pedir pro Luca, pois ele era o
que ler a IAM (Index allocation Map),
único a ter o número do celular dela.
alocar novas páginas, mover os dados na
Se isto é custoso para John, imagine pro
ordem correta do índice etc. O FillFactor é
Engine do SQL Server....
mais efetivo no índice cluster, mas pode
ser aplicado nos índices não cluster.
Na verdade, aqui temos um Page
O Paradigma FillFactor II "A Split "praiano."
verdade está lá dentro"
Vamos ver o que acontece:

www.codificando.net Dez/ Jan - 2010 | 29


O Paradigma FILLFACTOR e-magazine

Este script nos gera um page split e o


resultado da figura 3 :

Figura 2 – Layout com a mala do Luca.

if object_id('Testfillfactor')
is not null
drop table Testfillfactor
go

create table Testfillfactor


( id int not null,
name char(2000)
)
create unique clustered index
PK_TestFill on Testfillfactor
(id) Figura 3 – Representação do dbcc ind.

WITH( PAD_INDEX = OFF,


FILLFACTOR = 100, Como a gente pode ver :
STATISTICS_NORECOMPUTE
= OFF,
♦ Duas Páginas de Dados (Data Pages)
IGNORE_DUP_KEY = OFF,
ALLOW_ROW_LOCKS = ON, - Coluna PageType = 1 que são as
ALLOW_PAGE_LOCKS = ON páginas 7412 e 7414
)
ON [PRIMARY] ♦ Uma Página de Índice (Index Page) -
go Coluna Pagetype = 2 que é a página
Codificando.net e-magazine
set nocount on 7426
declare @loop int
set @loop = 1 ♦ Uma IAM Page - Coluna PageType =
while @loop < 11 10 que é a página 7413
begin ♦ Nosso foco são as páginas de dados
insert into TestFillfactor
values (@loop,'Name ' + (Data Pages)
convert(char(10),@loop))
set @loop = @loop + 2 01. Página 7412
end
go
♦ Próxima Página de dados
dbcc ind(dba, Testfillfactor, (NextPageID) = 7414
1, 0)
go ♦ Página de Dados Anterior
alter index PK_TestFill on (PrevPageID) = 0
Testfillfactor Rebuild

www.codificando.net Dez/ Jan - 2010 | 30


O Paradigma FILLFACTOR e-magazine

02. Página 7414

♦ Próxima Página de dados


(NextPageID) = 0
Página de Dados Anterior (PrevPageID) =
7412
♦ Como eu criei a tabela com um valor
fixo (char 2000), deverá caber na
página 7412 quatro linhas, que
devem ser o ID 1, 3, 5 e 7.

Para verificar usamos conforme figura 4:


Figura 5 – Script para visualizar informação da
dbcc page( 0, 1, 7412, 3) Figura 4

Correto. Na página 7412 nós temos os


IDs 1, 3, 5 e 7

Na página 7414 nós temos somente uma


Figura 4 – Representação do dbcc page. linha que é o ID 9, sobrando espaço não
pelo FillFactor, e sim porque não
Como a coluna m_slotCnt me informa o tivemos dados suficientes para preenchê
número de linhas que esta página tem (4) e -la.
a coluna m_freeCnt o número de bytes
livres na página, minha conta está correta. Usando o script (figura 5), podemos
Podemos executar este script para confirmar (figura 6):
visualizar esta afirmação (figura 5):

create table #dbccpageresults


( ParentObject varchar(max),
[Object] varchar Codificando.net e-magazine
(max),
[Field] varchar
(max),
[Value] varchar(max)
)
insert into #dbccpageresults
exec ('dbcc page( 0, 1, 7412,
3 ) with tableresults')

select * from #dbccpageresults


Figura 6 – Script visualizar informação da
where [field] = 'id' página 7414.
go
drop table #dbccpageresults
E representando (figura 7):

www.codificando.net Dez/ Jan - 2010 | 31


O Paradigma FILLFACTOR e-magazine

Como podemos ver, uma nova página de


dados (Data Page) foi inserida e nós temos
o Page Split.

Isso me lembra o Haley Joel Osment no


filme Sexto Sentido: "Eu Vejo Page
Spliiiiiiiiitsssss!!!!"

Perceba que pelas colunas NextPageID e


Figura 7 – Representação das páginas , próxima PrevPageID, o Engine tem que ir da
e anterior.
página 7412 para a 7427 e depois para a
7414 para completar o ciclo da
Agora vamos inserir mais 4 linhas pares informações.
(no script inserimos linhas ímpares).
Lembre-se de que o índice cluster é sobre o Representando (figura 9):
ID (figura 8).

Insert into Testfillfactor


values (2,'Name 2')
go
Insert into Testfillfactor
values (4,'Name 4')
go
Insert into Testfillfactor
values (6,'Name 6')
go
Insert into Testfillfactor
values (8,'Name 8')
go
Figura 9 – Representação Page Split.
dbcc ind(dba, Testfillfactor,
1, 0)
Codificando.net e-magazine
go
Luca há muito tempo e sei que ele vai
mudar de idéia. Vou deixar um espaço em
cada carro, caso ele queira levar mais
alguém também".

E isto aconteceu, no último minuto Luca


chegou. E trouxe sua amiga, Jana. Como
John deixou um espaço livre em cada
carro, não houve problema em acomodar
todo mundo, e todos curtiram o final de
semana!

Figura 8 – Representação do Page Split. Uma coisa já vemos de cara: o número de

www.codificando.net Dez/ Jan - 2010 | 32


O Paradigma FILLFACTOR e-magazine

carros aumentou com o mesmo número de set nocount on


declare @loop int
pessoas que iam (antes do Luca e Jana). set @loop = 1
while @loop < 11
Vamos usar o (script 1) para vermos o que begin
insert into
acontece , mas alterando o FillFactor para TestFillfactor values
30%. (@loop,'Name ' + convert(char
(10),@loop))
set @loop = @loop + 2
end
go
dbcc ind(dba, Testfillfactor,
1, 0)
go
alter index PK_TestFill on
Testfillfactor Rebuild

E o que a figura 11 nos diz, sem pensar


muito?

Figura 10 - Representação da Viagem com


espaço nos carros.

if object_id
('Testfillfactor') is not
null
drop table Testfillfactor
go
create table Testfillfactor
( id int not null,
Figura 11 – Representação Fillfactor 30%.

Codificando.net e-magazine
name char(2000)

)
create unique clustered index Uma página de dados foi criada, mas
PK_TestFill on Testfillfactor com o mesmo número de linhas com o
(id)
FillFactor de 100%
WITH( PAD_INDEX = OFF,
FILLFACTOR = 30, Como podemos ver:
STATISTICS_NORECOMPUTE = OFF,
IGNORE_DUP_KEY = OFF, Três Páginas de Dados (Data Pages)
ALLOW_ROW_LOCKS = ON, Coluna PageType = 1, que são as páginas
ALLOW_PAGE_LOCKS = ON
) 7430,7406 e 7408;
ON [PRIMARY]
go Uma Página de Índice (Index Page)

www.codificando.net Dez/ Jan - 2010 | 33


O Paradigma FILLFACTOR e-magazine

Coluna Pagetype = 2, que é a página 7407;


Uma IAM Page - Coluna PageType = 10,
que é a página 7431.

Nosso foco são as páginas de dados (Data


Pages)

01. Página 7430

♦ Próxima Página de dados


(NextPageID) = 7406 Figura 12 – Representação Página FillFactor
♦ Página de Dados Anterior 30% .

(PrevPageID) = 0
Como a coluna m_slotCnt me informa o
02. Página 7406 número de linhas que esta página tem (2)
e a coluna m_freeCnt o número de bytes
♦ Próxima Página de dados livres na página, minha conta novamente
(NextPageID) = 7408 está correta. E outra, a página 7406, terá
♦ Página de Dados Anterior os IDs 5 e 7, e a página 7408 o ID 9.
(PrevPageID) = 7430
Podemos executar este script para
03. Página 7408 visualizar esta afirmação:

♦ Próxima Página de dados dbcc traceon( 3604 )


go
(NextPageID) = 0 create table #dbccpageresults (
♦ Página de Dados Anterior ParentObject varchar(max),
(PrevPageID) = 7406 [Object]
varchar(max),

Codificando.net e-magazine
[Field]
Com eu criei a coluna fixa (char 2000) varchar(max),
[Value]
devemos ter na página 7430 duas linhas , varchar(max)
que seriam o ID 3 e 5. Lembre-se que o )
insert into #dbccpageresults exec
índice cluster sobre o ID. ('dbcc page( 0, 1, 7430, 3 ) with
tableresults')
Verifcando (figura 12): go
select 'PAGE 7430',* from
dbcc page( 0, 1, 7430, 3) #dbccpageresults where [field] =
'id'
go
truncate table #dbccpageresults
go

www.codificando.net Dez/ Jan - 2010 | 34


O Paradigma FILLFACTOR e-magazine

insert into #dbccpageresults


exec ('dbcc page( 0, 1, 7406,
3 ) with tableresults')
go
select 'PAGE 7406',* from
#dbccpageresults where [field]
= 'id'
go
truncate table
#dbccpageresults
go
insert into #dbccpageresults
exec ('dbcc page( 0, 1, 7408, Figura 14 – Representação das Páginas.
3 ) with tableresults')
go Novamente vamos inserir mais 4 linhas
select 'PAGE 7408', * from pares :
#dbccpageresults where [field]
= 'id' Insert into Testfillfactor values
go (2,'Name 2')
drop table #dbccpageresults go
Insert into Testfillfactor values
(4,'Name 4')
go
Insert into Testfillfactor values
(6,'Name 6')
go
Insert into Testfillfactor values
(8,'Name 8')

E vamos rodar o script novamente :

dbcc traceon( 3604 )


go
create table #dbccpageresults (
ParentObject varchar(max),
[Object] varchar(max),
[Field] varchar(max),
[Value] varchar(max)
) Codificando.net e-magazine
insert into #dbccpageresults exec
('dbcc page( 0, 1, 7430, 3 ) with
tableresults')

go
select 'PAGE 7430',* from
#dbccpageresults where [field] =
'id'
go
truncate table #dbccpageresults
go
Figura 13 – Script para visualizar informações
insert into #dbccpageresults exec
das páginas.
('dbcc page( 0, 1, 7406, 3 ) with
tableresults')
go
Ou: select 'PAGE 7406',* from
#dbccpageresults where [field] =
'id'

www.codificando.net Dez/ Jan - 2010 | 35


O Paradigma FILLFACTOR e-magazine

go O resultado é o mesmo! Vamos mais a


truncate table #dbccpageresults
go fundo:
insert into #dbccpageresults exec
('dbcc page( 0, 1, 7408, 3 ) with dbcc page( 0, 1, 7430, 1 )
tableresults')
go go
select 'PAGE 7408', * from dbcc page( 0, 1, 7406, 1 )
#dbccpageresults where [field] = 'id' go
go dbcc page( 0, 1, 7408, 1 )
drop table #dbccpageresults

O resultado sera (figura 16) :

Figura 16 – Script visualizar informação sem page Figura 18 – Visualização das Páginas.
splits.

As páginas estão contínuas, e o engine não


E representando (figura 19):
precisa pular de uma página a outra para
achar os dados. Não temos Page Split!!Será?
dbcc ind(dba, Testfillfactor, 1, 0) Codificando.net e-magazine

Figura 19 – Sem Page Splits.

"Eu não vejo Page Spliiiiiiitttsssss".

Figura 17 - Representação das Páginas.

www.codificando.net Dez/ Jan - 2010 | 36


O Paradigma FILLFACTOR e-magazine

Qual é a mágica? name5 varchar(1000),

name6 varchar(1000),
Não tem mágica. É matemática pura.
name7 varchar(1000),
Temos espaço em cada página para
acomodar os dados novos! name8 varchar(1000),
)
create unique clustered index
O Paradigma FillFactor III - Índice PK_TestFill on Testfillfactor(id)
Cluster+Identity = 100% FillFactor sem WITH( PAD_INDEX = OFF,
Page Splits? FILLFACTOR = 100,
STATISTICS_NORECOMPUTE =
OFF,
É comum encontrarmos em fóruns a IGNORE_DUP_KEY = OFF,
ALLOW_ROW_LOCKS = ON,
seguinte pergunta (ou parecida com ela): ALLOW_PAGE_LOCKS = ON
"tenho um CIX (clustered index) no )
campo identity. Posso deixar com ON [PRIMARY]
go
FillFactor de 100%?". E a resposta
tradicional: "Sim. Já que os dados são set nocount on
declare @loop int
inseridos no final da página, não haverá set @loop = 1
page splits". while @loop < 50
begin
insert into TestFillfactor
A resposta correta na verdade é (name1,name2,name3,name4,name5
DEPENDE. ,name6,name7,name8)
values ('Name 1 ' +
convert(char(10),@loop),'Name
Depende dos tipos de colunas que terão 2 ' + convert(char
sua tabela e, principalmente, se elas terão (10),@loop),'Name 3 ' +
convert(char(10),@loop),
atualizações no tamanho do seu conteúdo 'Name 4 ' + convert(char
(varchar, nvarchar, varbinary). (10),@loop),'Name 5 ' +
convert(char(10),@loop),'Name
6 ' + convert(char
Codificando.net e-magazine
Page Split ocorre no update também. (10),@loop),'Name 7 ' +
Vamos lá? convert(char(10),@loop),
'Name 8 ' + convert(char
(10),@loop))
if object_id('Testfillfactor') is set @loop = @loop + 1
not null end
drop table Testfillfactor go
go
Criamos uma tabela com tipos de dados
create table Testfillfactor
( id int identity(1,1) not variante. Reparem que os campos nome
null, são varchar. Populamos com 50 linhas
name1 varchar(1000), contínuas (identity , com CIX no campo
ID). Teoricamente não haveria Pages
name2 varchar(1000),
Splits.
name3 varchar(1000),

name4 varchar(1000),
Será?

www.codificando.net Dez/ Jan - 2010 | 37


O Paradigma FILLFACTOR e-magazine

alter index PK_TestFill on


Testfillfactor Rebuild
go
dbcc ind(dba, Testfillfactor,
1, 0)
go

Figura 21 – Representação de page splits no


update .

Uma CIVILIZAÇÂO DE PAGE


SPLITS!

Fig 20 – Sem page Splits na Inserção. Certeza, Laerte? Apesar de o campo


NextPageId já me mostrar isso, mas vamos
ver:

Correto. Não vemos "Page


Peguei a Página 7548. O próximo deveria ser
SPLIIIIIIIIITTSSS". MAS, vamos alterar o a Página 7549.
conteúdo dos campos nome?
create table #dbccpageresults
update Testfillfactor set ( ParentObject varchar
name1 = REPLICATE('X',1000), (max),

name2 = REPLICATE('X',1000), [Object] varchar(max),

name3 = REPLICATE('X',1000), [Field] varchar(max),

name4 = REPLICATE('X',1000), [Value] varchar(max) Codificando.net e-magazine


)
name5 = REPLICATE('X',1000), insert into #dbccpageresults
exec ('dbcc page( 0, 1, 7548,
name6 = REPLICATE('X',1000), 3 ) with tableresults')

name7 = REPLICATE('X',1000), select * from #dbccpageresults


where [field] = 'id'
name8 = REPLICATE('X',1000) go
go truncate table
dbcc ind(dba, Testfillfactor, #dbccpageresults
1, 0) go
insert into #dbccpageresults
exec ('dbcc page( 0, 1, 7549,
3 ) with tableresults')
Vendo como ficou: go

www.codificando.net Dez/ Jan - 2010 | 38


O Paradigma FILLFACTOR e-magazine

select * from select * from #dbccpageresults


#dbccpageresults where where [field] = 'id'
[field] = 'id' go
go drop table #dbccpageresults
drop table #dbccpageresults

Figura 23 – Visualização das Páginas.

Figura 22 – Visualização das Páginas. Agora sim! Ou seja da página 7548 pulou
para a página 8174 para continuar a
Errado! ordem do CIX (clustered index)!

Segundo o NextPageID, a Próxima Ou seja, a afirmação que só basta colocar


Página é a 8174, que está lá embaixo e o CIX no identity e pode deixar o
nem aparece na imagem por não caber! FillFactor com 100% que não terá Page
Pegando as páginas 7548 e 8174: Splits é LENDA. Além do que, fazendo
isso, se sua tabela tiver uma carga alta de
create table #dbccpageresults inserts, você poderá criar um hotspot
( ParentObject varchar
(max), (muita inserção ao mesmo tempo).

[Object] varchar(max), Se sua tabela tem campos de tamanho Codificando.net e-magazine


[Field] varchar(max), variável (varchar, nvarchar, varbinary) e
estes são altamente atualizados (seja com
[Value] varchar(max))
insert into #dbccpageresults valores maiores ou menores)
exec ('dbcc page( 0, 1, 7548, provavelmente você terá Page Split.
3 ) with tableresults')

select * from Se sua tabela tem campos de tamanho


#dbccpageresults where variável (varchar, nvarchar, varbinary) e
[field] = 'id' estes NÃO são atualizados ou não tem, a
go
truncate table colocação do CIX no identity e FillFactor
#dbccpageresults de 100% parece ser mais viável.
go
insert into #dbccpageresults
exec ('dbcc page( 0, 1, 8174, O Paradigma FillFactor IV - Muito
3 ) with tableresults') cuidado!
go

www.codificando.net Dez/ Jan - 2010 | 39


O Paradigma FILLFACTOR e-magazine

Espera, deixa eu ver se entendi. NESTE insert into TestFillfactor


values (@loop,'Name ' + convert
CASO: (char(10),@loop))
set @loop = @loop + 1
end
Com FillFactor de 100% o Engine acomoda go
4 linhas na página. Eu tenho um menor set statistics io on
go
número de páginas e Page Split. select ID from TestFillfactor
where id = 9999
Com FillFactor de 30% o Engine acomoda go
set statistics io off
2 linhas na página. Eu tenho um número
maior de páginas, mas não tenho Page Table 'Testfillfactor'. Scan
count 1, logical reads 55,
Split. physical reads 0, read-ahead
reads 0, lob logical reads 0, lob
physical reads 0, lob read-ahead
Mas um número maior de páginas não reads 0.
quer dizer mais Logical Reads?
CORRETO! Agora, com 100% de FillFactor:
if object_id('Testfillfactor') is
Vamos ver se é verdade? not null
drop table Testfillfactor
go
Primeiro, com 30% de FillFactor:
create table Testfillfactor
if object_id('Testfillfactor') is ( id int not null,
not null
drop table Testfillfactor name char(2000)
go )
create unique clustered index
create table Testfillfactor PK_TestFill on Testfillfactor(id)
( id int not null,
WITH( PAD_INDEX = OFF,
name char(2000) FILLFACTOR = 100,
) STATISTICS_NORECOMPUTE =
create unique clustered index OFF,
PK_TestFill on Testfillfactor(id) IGNORE_DUP_KEY = OFF,

WITH( PAD_INDEX = OFF,


ALLOW_ROW_LOCKS = ON,
ALLOW_PAGE_LOCKS = ON Codificando.net e-magazine
FILLFACTOR = 30, )
STATISTICS_NORECOMPUTE = ON [PRIMARY]
OFF, go
IGNORE_DUP_KEY = OFF, alter index PK_TestFill on
ALLOW_ROW_LOCKS = ON, Testfillfactor Rebuild
ALLOW_PAGE_LOCKS = ON go
)
ON [PRIMARY] set nocount on
Go declare @loop int
go set @loop = 1
alter index PK_TestFill on while @loop < 10000
Testfillfactor Rebuild begin
go insert into TestFillfactor
set nocount on values (@loop,'Name ' + convert
declare @loop int (char(10),@loop))
set @loop = 1 set @loop = @loop + 1
while @loop < 10000 end
begin go

www.codificando.net Dez/ Jan - 2010 | 40


O Paradigma FILLFACTOR e-magazine

set statistics io on Identifique as consultas das tabelas


go
select ID from TestFillfactor envolvidas (DMVs e Profiler são uma
where id = 9999 boa ajuda)
go
set statistics io off
Converse com o pessoal de Negócios
Table 'Testfillfactor'. Scan count
1, logical reads 30, physical (analista de negócios) e entenda o
reads 0, read-ahead reads 0, lob "produto final" do uso destas consultas.
logical reads 0, lob physical
reads 0, lob read-ahead reads 0. Por exemplo, um relatório de vendas
online por filial
É verdade!
Crie suas próprias métricas de controle e
Baixo FillFactor --> Alto Page Reads organização. Um baseline não serve
Alto FillFactor --> Baixo Page Reads somente para dados macros do servidor
Se o seu problema é um caso particular,
Se formos pela lógica: crie um baseline para este processo.
Como você poderá saber se melhorou ou
Muito Insert, update = Baixo FillFactor ficou pior com seus ajustes se você não
Muito Select = Alto FillFactor sabe como era o comportamento dele
antes, durante e depois?
Mas sabemos que ná prática não existe
regra. Cada ambiente é diferente do outro Entenda o Produto (SQL Server)
e possui características próprias, seja pela Nada melhor que você entender um
regra de negócio envolvida, seja por pouco como funciona internamente o
limitação de infra (falta de janela de que está acontecendo. Isto lhe dará uma
reindexação) ou alta disponibilidade. visão clara e objetiva para definir sua
Algumas vezes é interessante deixar um solução.
alto Fillfactor para uma tabela de muito

Codificando.net e-magazine
insert e update, mas também esta tabela Exemplo de ótimas leituras:
tem muito select, pois alimenta um
relatório muito importante pra sua Inside Microsoft SQL Server 2005: T-SQL
organização e é chamada muitas vezes ao Querying
dia... Neste caso, reindexar ONLINE (ou
reorganizar) mais vezes este índice pode Inside Microsoft SQL Server 2005: The
ser mais vantajoso. Storage Engine

Eu tenho certeza disso? Claro que não. Inside Microsoft SQL Server 2005: Query
Tuning and Optimization
Mas eu faço algumas coisas que me
E os mesmos livros no SQL SERVER 2008
ajudam na análise e definição da solução: Não tenha medo de dizer "eu não sei, mas
Analise a carga de seus índices vou ver e aprender". Isso é muito melhor do
separadamente (cada um deles tem uma que dizer "eu não sei... sempre foi assim...
caraterística diferente) aprendi assim". Na verdade você esta

www.codificando.net Dez/ Jan - 2010 | 41


O Paradigma FILLFACTOR e-magazine

dizendo "eu não sei, não quero saber e não


tenho a mínima vontade de aprender" e isso
não soa bem.

Quando tiver todo controle da situação: teste.


Teste muito. Canse de testar antes de dizer "o
jeito de fazer é assim". As pessoas esperam
isso de você.

A decisão correta é "faça assim. Eu sei o que


estou falando!".

Conclusão

Vimos que o FillFactor pode ser o herói ou


vilão da história.

Teste, implemente com cuidado.

Trate cada objeto e entidade do seu banco de


dados como única e sendo assim o
comportamento é diferente uma das outras.

E não olhe para Paradigmas. Especialmente em


TI.

Até a próxima!

Laerte Junior

Certificado MCDBA com mais de 8 anos de atuação com

Codificando.net e-magazine
SQL SERVER, fascinado por códigos e scripts, escreve
artigos para MCDBABrasil, Imasters e Simple-Talk aonde
possue um blog também.

Coloca suas experiências com SQL SERVER e Powershell


no www.laertejuniordba.spaces.live.com

Developer do projeto CODEPLEX SQLPSX - SQL Server


Powershell Extensions
http://sqlpsx.codeplex.com/

Laerte Junior
$hell Your Experience

www.laertejuniordba.spaces.live.com
www.simple-talk.com/community/blogs/laerte/
www.twitter.com/laertejuniordba

SQL Server Powershell Extensions Developer

www.codificando.net Dez/ Jan - 2010 | 42


e-magazine

Explorando microsot sql reporting


services 2005

Por: Caio Azevedo

Olá pessoal, nessa edição vários exemplos Produto”.


dos relatórios Local Mode, lembrando que
todos os códigos aqui implementados Criando o Relatório
estão disponíveis no site da nossa
comunidade, http:// Esse relatório exibe as colunas com o
comunidade.codificando.net/, bom nome, categoria, total em estoque e valor
divertimento. unitário de cada produto.

Parte 3 – local mode - demos Primeiro Passo: Construção do


DataSet
Exemplos de relatórios
Adicionar um objeto dataSet com o nome
A seguir criaremos alguns relatórios para Tabular (vide sessão “Repositório de
exemplificar o que já vimos até então, bem dados Local - DataSet”) à aplicação na
como alguns recursos que veremos com os pasta DataSources, e adicionar a ele um
relatórios que criaremos. Nossos exemplos datatable com a estrutura da figura 1.
são baseados no modelo de dados
apresentado na parte dois do nosso artigo
que relaciona pedidos, itens de pedido,
produtos e vendedores.

Relatório tabular
Codificando.net e-magazine
Figura 1 – Datatable Produtos Estoque.
Nesse exemplo criaremos um relatório
que nos permite visualizar a relação de Esse datatable será preenchido com os
produtos, suas respectivas categorias, total dados provenientes do resultado da
em estoque e valor unitário. O usuário seguinte stored procedure:
desse relatório pode selecionar uma ou getProdutosinCategorias, que recebe
mais categorias de produtos que deseja como parametro uma string com as
visualizar. O relatório faz uso de identificações das categorias separadas
formatação condicional para destacar as por vírgula.
quantidades em estoque se esse for
inferior a 250, também faremos uso dos Segundo Passo: Criação e
recursos de formatação de moeda e modelagem do Relatório
ordenação da coluna: “Nome do Incluiremos um novo relatório em nosso

www.codificando.net Dez / Jan - 2010 | 43


Explorando microsot sql reporting services 2005 e-magazine

projeto chamado TBProdutosporCategoria,


na pasta Reports (vide artigos anteriores).
Usando um objeto Table da toolbox dos
relatórios, criaremos a estrutura do
relatório formatado conforme a figura 2 .

Figura 3 – ordenação colunas.

Figura 2 – relatório tabular. Criando o Cliente

Para configuração do cliente, adicionamos e


Terceiro Passo: Formatar o relatório
configuramos um controle ReportViewer.
Em seguida adicionamos o código cliente
Destacaremos os itens da coluna de
para carga do dataTable e configuração do
estoque com valor inferior a 250, para tal
reportViewer criado. A seguir
selecionamos a janela de propriedades da
apresentamos um trecho do código para
caixa de texto e no atributo Color
carga da datatable e configuração do
selecionamos Expressions, então criamos
reportViewer com destaque para passagem
uma instrução da seguinte forma:
dos parâmetros na stored procedure
=IIf(Fields! utilizada para carga do datatable,
QT_ESTOQUE.Value<250,"Red","Blue") idscategoria.

Em seguida, adicionamos as SqlParameter[] parms = {


new SqlParameter Codificando.net e-magazine
funcionalidades de ordenação nas ("@idCategorias",
colunas, para tal, basta configurar a caixa SqlDbType.VarChar,20)
de texto “Nome Produto”, na tab Interative };
parms[0].Value = getIdCategorias
Sort, como na figura 3. (); //método auxiliar que recupera
as categorias da interface do
usuário.
cmdReport.CommandType =
CommandType.StoredProcedure;
cmdReport.Connection = conReport;
foreach (SqlParameter parm in
parms)
cmdReport.Parameters.Add
(parm);
cmdReport.CommandText =
"getProdutosinCategorias";
drReport = cmdReport.ExecuteReader
();

www.codificando.net Dez / Jan - 2010 | 44


Explorando microsot sql reporting services 2005 e-magazine

dsReport.Tables[0].Load(drReport); pedido, e sua respectiva quantidade


drReport.Close();
conReport.Close(); vendida.
rptViewTable.LocalReport.ReportPat
h = "Reports//
TBProdutosporCategoria.rdlc"; Primeiro Passo: Construção do
ReportDataSource rds = new
ReportDataSource();
DataSet
rds.Name =
"Tabular_ProdutosEstoque"; Adicionar um objeto dataSet com o nome
rds.Value = dsReport.Tables[0];
rptViewTable.LocalReport.DataSourc MasterDetail (vide sessão “Repositório de
es.Clear(); dados Local - DataSet”) à aplicação na
rptViewTable.LocalReport.DataSourc
es.Add(rds); pasta DataSources, e adicionar a ele um
this.rptViewTable.RefreshReport(); datatable com a estrutura da figura 5.
Finalmente eis nosso relatório em ação:

Figura 5 – datatable Itens do Pedido.

Esse datatable será preenchido com os


dados provenientes do resultado da
seguinte instrução SQL:
SELECT [ITE].ID_PEDIDO,
[PRO].DS_PRODUTO, [ITE].QT_PRODUTO
Figura 4 – relatório em ação. FROM TB_ITENS_PEDIDO [ITE] INNER
JOIN TB_PRODUTO [PRO] ON
[ITE].ID_PRODUTO = [PRO].ID_PRODUTO
Relatório master-detail
Segundo Passo: Criação e modelagem
do Relatório
Codificando.net e-magazine
Nesse exemplo criaremos um relatório
que nos permite visualizar pedidos e seus
respectivos itens. Para criação do master- Incluiremos um novo relatório em nosso
detail, faremos uso da funcionalidade de projeto chamado MDItensPedido na pasta
subreports com parâmetros para Reports. Usando um objeto Table da
relacionar o relatório principal (lista de toolbox dos relatórios, criaremos a estrutura
pedidos) e seus respectivos itens. do relatório formatado conforme a figura
abaixo.
Criando o relatório Detail

Começaremos com a construção do


relatório que será o “detail” da nossa
implementação. Esse relatório exibe duas
colunas com a descrição do produto do
Figura 6 – relatório detail.

www.codificando.net Dez / Jan - 2010 | 45


Explorando microsot sql reporting services 2005 e-magazine

Terceiro Passo: Criar o parâmetro para Adicionar um datatable ao nosso Dataset


associar ao “Master” com a estrutura da figura 8.

Aqui criaremos o parâmetro, (vide sessão


“Parametrização”), que será o link com o
relatório “Master”, esse parâmetro
chamaremos de idPedido do tipo Integer e
“Hidden”.
Figura 8 – DataTable do Pedido.

Quarto Passo: Criar um filtro


Esse datatable será preenchido com os
Através das propriedades da tabela criada dados provenientes do resultado da
no segundo passo, criaremos um filtro dos seguinte instrução SQL:
dados do relatório, onde a identificação do
pedido será aquela correspondente ao SELECT [ped].ID_PEDIDO,
[VEN].NO_VENDEDOR, CONVERT
parâmetro criado no terceiro passo. A (SMALLDATETIME, [PED].DT_PEDIDO,
figura 7 ilustra a operação. 103) as DT_PEDIDO, SUM
([ITE].QT_PRODUTO*[PRO].VL_PRECO)
as [Valor do Pedido] FROM
TB_PEDIDO [PED] INNER JOIN
TB_ITENS_PEDIDO [ITE] ON
[PED].ID_PEDIDO = [ITE].ID_PEDIDO
INNER JOIN TB_PRODUTO [PRO] ON
[ITE].ID_PRODUTO = [PRO].ID_PRODUTO
INNER JOIN TB_VENDEDOR [VEN] ON
[PED].ID_VENDEDOR =
[VEN].ID_VENDEDOR GROUP BY
[ped].ID_pedido,[VEN].NO_VENDEDOR,
[PED].DT_PEDIDO

Segundo Passo: Criação e modelagem


do Relatório
Figura 7 – configurando filtro.
Incluiremos um novo relatório em nosso Codificando.net e-magazine
Criando o relatório Master projeto chamado MDPedido, na pasta
Reports. Usando um objeto Table da
Na criação do relatório “master”, exibimos toolbox dos relatórios criaremos a estrutura
a identificação do pedido, o nome do do relatório formatado conforme a figura 9:
vendedor, a data do pedido e o valor em
reais da venda do pedido. O grande
diferencial desse relatório é a inclusão do
item Subreport como se fosse uma coluna
de uma table e configurar o subreport para
associar o campo de identificação do
pedido ao seu parâmetro.

Primeiro Passo: Construção do Figura 9 – relatório master.

Datatable no DataSet

www.codificando.net Dez / Jan - 2010 | 46


Explorando microsot sql reporting services 2005 e-magazine

Terceiro Passo: Configurar o [VEN].NO_VENDEDOR, CONVERT


(SMALLDATETIME, [PED].DT_PEDIDO,
subreport 103) as DT_PEDIDO, SUM
([ITE].QT_PRODUTO*[PRO].VL_PRECO)
as [Valor do Pedido] FROM
Aqui configuraremos o item subreport de TB_PEDIDO [PED] INNER JOIN
modo a estabelecer o vínculo entre o TB_ITENS_PEDIDO [ITE] ON
[PED].ID_PEDIDO = [ITE].ID_PEDIDO
relatório master e o detail através do INNER JOIN TB_PRODUTO [PRO] ON
parâmetro, idPedido, criado no relatório [ITE].ID_PRODUTO = [PRO].ID_PRODUTO
INNER JOIN TB_VENDEDOR [VEN] ON
Detail, essa configuração é feita nas [PED].ID_VENDEDOR =
propriedades do subreport , tab [VEN].ID_VENDEDOR GROUP BY
[ped].ID_pedido,[VEN].NO_VENDEDOR,
Parameters, como ilustra a figura 10: [PED].DT_PEDIDO ; SELECT
[ITE].ID_PEDIDO, [PRO].DS_PRODUTO,
[ITE].QT_PRODUTO FROM
TB_ITENS_PEDIDO [ITE] INNER JOIN
TB_PRODUTO [PRO] ON
[ITE].ID_PRODUTO =
[PRO].ID_PRODUTO";
drReport = cmdReport.ExecuteReader
();
dsReport.Load
(drReport,LoadOption.OverwriteChang
es,dsReport.Tables
[0],dsReport.Tables[1]);
Figura 10 – parâmetros do subReport.
drReport.Close();
conReport.Close();
rptViewMasterDetail.LocalReport.Rep
ortPath = "..//..//Reports//
MDPedido.rdlc";
Criando o Cliente ReportDataSource rds = new
ReportDataSource();
rds.Name = "MasterDetail_Pedido";
Para configuração do cliente, adicionamos rds.Value = dsReport.Tables[0];
e configuramos um controle rptViewMasterDetail.LocalReport.Dat
aSources.Clear();
ReportViewer. Em seguida adicionamos o rptViewMasterDetail.LocalReport.Dat
código cliente para carga dos dataTables e aSources.Add(rds);

Codificando.net e-magazine
rptViewMasterDetail.RefreshReport
configuração do reportViewer criado. A ();
seguir apresentamos um trecho do código
Os dados do relatório “detail” são
para carga das duas datatables e carregados com a tabela ItensPedido
configuração do reportViewer. A primeira do dataSet, e são configurados no
evento de processamento do
instrução (em vermelho) carrega a tabela subReport que é acessível através
Pedido e a segunda a ItensPedido. Vemos do delegate
SubreportProcessingEventHandler que
também que só configuramos o é assinado no construtor da classe
datasource do relatório “master”, e o da aplicação com a seguinte
relatório “detail” ? A seguir: instrução:
rptViewMasterDetail.LocalReport.Sub
reportProcessing += new
cmdReport.CommandType = SubreportProcessingEventHandler
CommandType.Text; (SubReportDetailProcessing);
cmdReport.Connection = conReport; Em seguida implementamos o método
cmdReport.CommandText = "SELECT SubReportDetailProcessing com as
[ped].ID_PEDIDO, seguintes instruções:

www.codificando.net Dez / Jan - 2010 | 47


Explorando microsot sql reporting services 2005 e-magazine

private void dados Local - DataSet”) à aplicação na


SubReportDetailProcessing(object
sender, pasta DataSources, e adicionar à ele um
SubreportProcessingEventArgs e) datatable com a estrutura da figura 12.
{
e.DataSources.Add(new
ReportDataSource
("MasterDetail_ItensPedido",
dsReport.Tables[1]));
}
Finalmente eis nosso relatório em ação: Figura 12 – DataTable Vendas.

Esse datatable será preenchido com os


dados provenientes do resultado da
seguinte instrução SQL:
SELECT [VEN].NO_VENDEDOR, SUM
([ITE].QT_PRODUTO*[PRO].VL_PRECO)
as [Valor do Pedido] FROM TB_PEDIDO
[PED] INNER JOIN TB_ITENS_PEDIDO
[ITE] ON [PED].ID_PEDIDO =
Figura 11 – relatório master-detail. [ITE].ID_PEDIDO INNER JOIN
TB_PRODUTO [PRO] ON
[ITE].ID_PRODUTO = [PRO].ID_PRODUTO
INNER JOIN TB_VENDEDOR [VEN] ON
Relatório gráfico [PED].ID_VENDEDOR =
[VEN].ID_VENDEDOR WHERE CONVERT
Nesse exemplo criaremos um relatório que (SMALLDATETIME, [PED].DT_PEDIDO,
103) BETWEEN '99/99/9999' AND
nos permite visualizar graficamente as '99/99/9999' GROUP BY
vendas, em reais, dos nossos vendedores [VEN].NO_VENDEDOR
por período. Nesse relatório faremos uso
da funcionalidade Chart da toolbox dos Segundo Passo: Criação e
modelagem do Relatório
relatórios, o período das vendas a serem
consultadas será passado como parâmetro
Incluiremos um novo relatório em nosso
para instrução SQL que fará a busca no
projeto chamado GrVendas, na pasta
banco de dados, o que é uma alternativa
mais prudente que o uso de filtros no
Reports. Usando um objeto Chart da Codificando.net e-magazine
toolbox dos relatórios, criaremos a estrutura
relatório já que não necessitamos recuperar
do relatório formatado conforme a figura
todos os registros das vendas.
13:

Criando o relatório

Esse relatório correlaciona duas


informações para gerar nosso gráfico,
Nome do vendedor e o total de sua venda.

Primeiro Passo: Construção do DataSet.


Adicionar um objeto dataSet com o nome
Grafico (vide sessão “Repositório de
Figura 13 – formatando relatório chart.

www.codificando.net Dez / Jan - 2010 | 48


Explorando microsot sql reporting services 2005 e-magazine

Terceiro Passo: Configurar o 103) BETWEEN CONVERT


(SMALLDATETIME,'" +
relatório txtDtInicio.Text + "',103) AND
CONVERT(SMALLDATETIME,'" +
Aqui configuraremos o item Chart de txtDtFim.Text + "',103) GROUP BY
[VEN].NO_VENDEDOR";
modo a torná-lo parecido ao exibido na
imagem 13. drReport = cmdReport.ExecuteReader
();
dsReport.Tables[0].Load(drReport);
Quarto Passo: Criar os drReport.Close();
parâmetros do período conReport.Close();

rptViewGrafico.LocalReport.ReportPa
Nosso relatório também exibe o período th = "..//..//Reports//
GrVendas.rdlc";
da consulta que é exibido na sessão ReportParameter[] parPeriodo =
header do relatório. Para recuperar essas { new ReportParameter
("dtInicio",txtDtInicio.Text), new
informações fornecidas pelo cliente ReportParameter
recorremos aos parâmetros, dtInicio e ("dtFim",txtDtFim.Text)};
rptViewGrafico.LocalReport.SetParam
dtFim, esta configuração é feita nas eters(parPeriodo);
propriedade do relatório , tab Parameters. ReportDataSource rds = new
ReportDataSource();
Criando o Cliente rds.Name = "Grafico_Vendas";
rds.Value = dsReport.Tables[0];
rptViewGrafico.LocalReport.DataSour
Para configuração do cliente, adicionamos ces.Clear();
rptViewGrafico.LocalReport.DataSour
e configuramos um controle ces.Add(rds);
ReportViewer. Em seguida adicionamos o
rptViewGrafico.RefreshReport();
código cliente para carga do dataTable e
configuração do reportViewer criado. A Finalmente eis nosso relatório em ação:
seguir apresentamos um trecho do código
para carga da datatable e configuração do
reportViewer com destaque para

Codificando.net e-magazine
passagem dos parâmetros dtInicio e
dtFim.
cmdReport.CommandType =
CommandType.Text;
cmdReport.Connection = conReport;
cmdReport.CommandText = "SELECT
[VEN].NO_VENDEDOR, SUM
([ITE].QT_PRODUTO*[PRO].VL_PRECO)
as [Valor do Pedido] FROM
TB_PEDIDO [PED] INNER JOIN
TB_ITENS_PEDIDO [ITE] ON Figura 14 – relatório chart em ação
[PED].ID_PEDIDO = [ITE].ID_PEDIDO
INNER JOIN TB_PRODUTO [PRO] ON
[ITE].ID_PRODUTO = Relatório document map
[PRO].ID_PRODUTO INNER JOIN
TB_VENDEDOR [VEN] ON
[PED].ID_VENDEDOR = Nesse exemplo criaremos um relatório que
[VEN].ID_VENDEDOR WHERE CONVERT nos permite visualizar pedidos, seus
(SMALLDATETIME, [PED].DT_PEDIDO,

www.codificando.net Dez / Jan - 2010 | 49


Explorando microsot sql reporting services 2005 e-magazine

respectivos itens e o valor total do pedido [VEN].ID_VENDEDOR INNER JOIN


TB_ITENS_PEDIDO [ITE] ON
dentro de um período informado pelo [PED].ID_PEDIDO= ITE.ID_PEDIDO
usuário. Utilizaremos um recurso INNER JOIN TB_PRODUTO [PRO] ON
ITE.ID_PRODUTO = PRO.ID_PRODUTO
chamado DocumentMap, onde listamos os
vendedores e seus respectivos pedidos Segundo Passo: Criação e
com recurso de um link para os detalhes modelagem do Relatório
do vendedor ou do pedido.
Incluiremos um novo relatório em nosso
Criando o relatório projeto chamado DMapPedido, na pasta
Reports. Usando um objeto Table da
Esse relatório lista os vendedores, seus toolbox dos relatórios criaremos a estrutura
pedidos e detalhes do pedido, com do relatório formatado conforme a figura
recurso de navegação via Document Map. 16:

Primeiro Passo: Construção do


DataSet

Adicionar um objeto dataSet com o nome


DocumentMap (vide sessão “Repositório
de dados Local - DataSet”) à aplicação na
pasta DataSources, e adicionar à ele um
datatable com a estrutura da figura 15.
Figura 16 – formatando relatório Document Map.

Terceiro Passo: Configurar o


relatório

Aqui configuraremos o item Table de modo

Codificando.net e-magazine
a torná-lo parecido ao exibido na imagem
acima. Para tal faremos uso de uma das
Figura 15 –datatable Peddo. propriedades mais poderosas das tabelas
que é a tab Groups. Essa propriedade nos
permite, como o nome diz, agrupar os
Esse datatable será preenchido com os
registros por um ou mais campos, similar à
dados provenientes do resultado da
cláusula GROUP BY do T-SQL. Na figura 16
seguinte instrução SQL:
percebe-se que fizemos dois agrupamentos,
SELECT [PED].ID_PEDIDO,
1 e 2, respectivamente pelos campos
[PED].ID_VENDEDOR, NO_VENDEDOR e ID_PEDIDO.
[VEN].NO_VENDEDOR,
[PED].DT_PEDIDO ,[pro].DS_PRODUTO, Começamos nossa configuração criando um
[ite].QT_PRODUTO, [pro].VL_PRECO
FROM TB_PEDIDO [PED] INNER JOIN relatório com os atributos acima,
TB_VENDEDOR [VEN] ON configurando-o como um relatório tabular,
[PED].ID_VENDEDOR =

www.codificando.net Dez / Jan - 2010 | 50


Explorando microsot sql reporting services 2005 e-magazine

em seguida nas propriedades da tabela na área de rodapé do agrupamento de


criamos os agrupamentos nomeados pedidos, com uma expressão que soma os
table1_grpVendedor e table1_grpPedido, valores individuais de cada produto
necessariamente nessa ordem, conforme a multiplicado pela quantidade vendida,
imagem 17. codificado da seguinte forma:
=Sum(Fields!
QT_PRODUTO.Value*Fields!
VL_PRECO.Value)

Finalmente, formatamos as caixas de texto


com data e moeda, bem como as cores de
fundo das linhas.

Quarto Passo: Criar os parâmetros


do período

Nosso relatório também exibe o período da


consulta que é exibido na sessão header do
Figura 17 – criando grupos do relatório Document
Map. relatório. Para recuperar essas informações
fornecidas pelo cliente recorremos aos
Em seguida, na mesma caixa de edição do parâmetros, dtInicio e dtFim, essa
grupo, configuramos o recurso de configuração é feita nas propriedades do
Document Map, que corresponde a um relatório - tab Parameters.
dos recursos de navegação dos relatórios
do Reporting Services. Essa configuração é Criando o Cliente
feita simplesmente especificando o
Document Map Label de cada grupo. Para Para configuração do cliente, adicionamos e
o primeiro grupo, utilizamos o campo configuramos um controle ReportViewer.

Codificando.net e-magazine
correspondente ao nome do vendedor, no Em seguida adicionamos o código cliente
segundo sofisticamos com a criação de para carga do DataTable e configuração do
uma expressão que concatena uma string reportViewer criado. A seguir
com o campo de identificação do pedido. apresentamos um trecho do código para
Finalmente movemos os campos nome do carga da datatable e configuração do
vendedor e identificação do pedido para reportViewer com destaque para passagem
as linhas de cabeçalho dos seus dos parâmetros dtInicio e dtFim.
respectivos grupos.
cmdReport.CommandType =
CommandType.Text;
Outro elemento interessante em nosso cmdReport.Connection = conReport;
relatório, e muito comum em relatórios cmdReport.CommandText = "SELECT
[PED].ID_PEDIDO, [PED].ID_VENDEDOR,
com agrupamento, são totalizadores. No [VEN].NO_VENDEDOR, [PED].DT_PEDIDO,
nosso relatório, sumarizamos o total do [pro].DS_PRODUTO, [ite].QT_PRODUTO,
[pro].VL_PRECO FROM TB_PEDIDO [PED]
pedido em uma caixa de texto posicionada INNER JOIN TB_VENDEDOR [VEN] ON

www.codificando.net Dez / Jan - 2010 | 51


Explorando microsot sql reporting services 2005 e-magazine

[PED].ID_VENDEDOR = Os relatórios Local-mode são uma excelente


[VEN].ID_VENDEDOR INNER JOIN
TB_ITENS_PEDIDO[ITE] ON alternativa para pequenas e médias
[PED].ID_PEDIDO = [ITE].ID_PEDIDO aplicações onde os relatórios podem
INNER JOIN TB_PRODUTO [PRO] ”;
cmdReport.CommandText += " ON compartilhar recursos dos sistemas e não
[ITE].ID_PRODUTO = dispomos de uma infra-estrutura mais
[PRO].ID_PRODUTO WHERE CONVERT
(SMALLDATETIME, elaborada. Abaixo relacionamos alguns dos
[ped].DT_PEDIDO,103) BETWEEN itens que apontamos como limitações desse
CONVERT(SMALLDATETIME,'" +
txtDMdtInicio.Text + "',103) AND modelo de relatórios.
CONVERT(SMALLDATETIME,'" +
txtDMdtFim.Text + "',103)";
drReport = cmdReport.ExecuteReader ♦ Só exporta para os formatos Excel e
(); PDF
♦ Não suporta interface customizada
dsReport.Tables[0].Load(drReport);
drReport.Close(); ♦ Não disponibiliza interface aos
conReport.Close(); usuários para os parâmetros
rptViewGrafico.LocalReport.ReportP ♦ Document map não suportado em
ath = "..//..//Reports// FireFox
DMapPedido.rdlc";
ReportParameter[] parPeriodo = ♦ Compartilha os recursos da aplicação
{ new ReportParameter cliente
("dtInicio",txtDMdtInicio.Text),
new
ReportParameter É isso ai pessoal, no próximo capítulo uma
("dtFim",txtDMdtFim.Text)}; verdadeira revolução, os relatórios remote
rptViewGrafico.LocalReport.SetPara
meters(parPeriodo); mode, simplesmente imperdível, até lá.
ReportDataSource rds = new
ReportDataSource();
rds.Name = "DocumentMap_Pedido"; Caio Azevedo
rds.Value = dsReport.Tables[0];
rptViewGrafico.LocalReport.DataSou
rces.Clear(); Graduado em Ciência da Computação, Engenharia Civil e
rptViewGrafico.LocalReport.DataSou louco por ciências exatas em especial física e matemática.
rces.Add(rds); Coordenador da Célula Microsoft da Magna Sistema e

Codificando.net e-magazine
Arquiteto Microsoft, palestrante, tecno-colunista e
rptViewGrafico.RefreshReport(); instrutor da treinando .net. MCP, MCAD, MCSD, MCTS e
MCPD. E fanático pela série Star Wars – “may the force be
Finalmente eis nosso relatório em ação: with you.”

Figura 18 – relatório Document Map em ação

Limitações

www.codificando.net Dez / Jan - 2010 | 52


e-magazine

Introdução ao Query Processor

Por: Fabiano Neves Amorim

Início Ambiente

Escolher o melhor caminho para chegar Para melhor entendimento dos exemplos
a determinado lugar pode ser deste artigo criaremos uma tabela, com
considerado para muitos uma arte, isso alguns dados e uma visão, que servirão
porque sempre existem vários caminhos como base para os testes que serão
que levam ao mesmo destino. Executar apresentados. A Listagem 1 contém o
uma tarefa da forma mais eficiente script para criação destes objetos.
possível requer que o caminho O Script cria a tabela Funcionarios com
percorrido seja o melhor dentre as algumas informações (ID, Nome, Salário,
centenas de variáveis que podem Telefone e Cidade) e, em seguida, são
influenciar na escolha do melhor inseridos alguns registros. Logo após,
percurso. uma view (vw_Funcionarios) é criada. A
grosso modo, podemos dizer que Views
No SQL Server o responsável por são tabelas virtuais definidas por uma
calcular a maneira mais eficiente de consulta T-SQL. A nossa view, criada na
acesso aos dados é chamado de Query Listagem 1, retorna o nome e o salário de
Processor, ele é dividido em duas partes, todos os funcionários que ganham mais
o Query Optimizer e o Query Execution de R$ 900,00.
Engine. Veremos neste artigo como o Codificando.net e-magazine
Query Optimizer funciona e quais os CREATE TABLE Funcionarios(ID
Int IDENTITY(1,1) PRIMARY KEY,
passos necessários para execução de um Nome
comando T-SQL. VarChar(30),
Salario
Numeric(18,2),
Entender como funciona e como
Telefone VarChar(15),
interpretar o trabalho do Query Cidade
Optimizer é uma das melhores maneiras VarChar(80));
de aprimorar seus conhecimentos em INSERT INTO Funcionarios(Nome,
SQL Server. Esse conhecimento será de Salario, Telefone, Cidade)
VALUES('José', 850.30, '11-
grande valor quando você precisar fazer 55960015', 'São Paulo');
algum trabalho de tunning em banco de
INSERT INTO Funcionarios(Nome,
dados. Salario, Telefone, Cidade)
VALUES('Antonio', 950, '11-
81115544', 'São Paulo');

www.codificando.net Dez / Jan - 2010 | 53


Introdução ao Query Processor e-magazine

INSERT INTO Funcionarios(Nome, série de passos para compilar e executar


Salario, Telefone, Cidade)
VALUES('João', 1200, '11- um comando T-SQL. Vamos analisar
44123321', 'São Paulo'); melhor este comportamento.
CREATE VIEW vw_Funcionarios Supondo que um SELECT simples, por
AS exemplo, SELECT * FROM Funcionarios,
Listagem 1. Script para criação dos objetos de seja enviado ao servidor, a primeira tarefa
teste.
que o Query Processor fará com o
SELECT Nome, Salario FROM comando é verificar se o mesmo está no
Funcionarios Cache Plan (mais informações sobre o
WHERE Salario > 900
Cache Plan no final do artigo). Caso ele
Query Optimizer não esteja em cache, o Query Processor
enviará o comando para os processos de
Quando um comando T-SQL é executado Parse e Bind.
no SQL Server o Query Processor entra em O Parse/Bind executa um processo
ação para gerar um plano de execução. conhecido como Algebrizer. Durante este
Este plano dirá qual é a melhor maneira de processo o SQL tenta encontrar possíveis
acessar os dados gastando menos recursos erros de escrita na sintaxe e lógica do
e com o desempenho mais eficiente comando. Por exemplo, o comando “select
possível. id from tab1 group by nome” gera uma
Podemos observar na Figura 1 a ação do exceção, pois a coluna id não pertence ao
Query Optimizer (em vermelho) e uma group by e não está utilizando uma
função de agregação (SUM, COUNT, ...).
O Algebrizer também expande as
definições do comando, isso significa que
ele troca “select *” por “select col1, col2,
col3...”, ou “select col1 from View” pelo
nome das tabelas envolvidas na view.

Codificando.net e-magazine
Sempre que uma view é referenciada em
uma consulta, o SQL Server acessa as
tabelas que contém os dados. Na Figura 2,

Figura 1. Fluxograma de passos necessários para


gerar um plano de execução. Figura 2. Ilustração de uma View acessando uma
tabela.

www.codificando.net Dez / Jan - 2010 | 54


Introdução ao Query Processor e-magazine

por exemplo, podemos visualizar que o mais rapidamente. Ao optar por este
SQL acessa a tabela Funcionarios para ler recurso, o SQL utiliza mais de um
os valores das colunas Nome e Salario. processador para executar uma consulta.
Outro passo será resolver os nomes e tipos Dessa forma, o gasto com recursos se
de objetos envolvidos na consulta. Pode torna maior, já que mais processadores
acontecer de haver um sinônimo para uma serão utilizados, porém, o tempo de
determinada tabela que está em outro retorno tende a ser menor comparado a
servidor. Quando isso acontece, o SQL execução em apenas um processador.
precisa identificar que este sinônimo faz Durante a fase de análise o Query
referência a um objeto que está em outro Optimizer realiza algumas tarefas, entre
banco de dados, e este banco pode estar elas: identificar todos os possíveis
até mesmo ligado a outro servidor argumentos de pesquisa que podem estar
utilizando um Linked Server. especificados na cláusula WHERE e
Após estas análises o Parse/Bind retorna verificar se existem Joins entre tabelas que
um binário chamado Query Processor devem ser otimizados. Baseado nestas
Tree, que é uma representação lógica dos informações, ele analisa quais as opções
passos necessários para a execução do de acesso aos dados, quais índices deve
comando SQL. O Query Processor Tree é utilizar, em qual ordem os Joins devem ser
enviado para o próximo passo da execução realizados e qual o melhor algoritmo de
da consulta, que é a análise do Query Join para cada operação.
Optimizer. Na análise do Query Optimizer também
É importante destacar que nem sempre um existe um processo chamado
comando é enviado para a análise do “Simplification”, que é executado logo no
Query Optimizer. Por exemplo, alguns inicio da otimização. Uma das tarefas do
comandos DDL, tais como o CREATE “Simplification” é conhecida como
Table, que são de definição das estruturas “Predicate PushDown”, onde ele tenta
dos dados, não têm necessidade de uma reescrever sua consulta jogando os

Codificando.net e-magazine
análise do Query Optimizer, pois só há argumentos de pesquisa para a cláusula
uma forma de o SQL executar esta where (veja a Listagem 2).
operação.
Quando o Query Optimizer recebe o SELECT * FROM Funcionarios
INNER JOIN Funcionarios AS
Query Processor Tree, ele dará inicio a Listagem 2. Consulta com argumentos de
uma série de análises a fim de encontrar pesquisa especificados no join
qual é a maneira mais eficiente de acessar Funcionarios2
os dados desejados. ON Funcionarios.ID =
Funcionarios2.ID
O Query Optimizer trabalha baseado no AND Funcionarios.Nome =
custo de cada operador de acesso a dados, 'Antonio'
WHERE Funcionarios.ID > 1
ou seja, ele tenta encontrar a maneira que
Com base na consulta da Listagem 2,
gastará menos recursos para retornar os
quando o comando for executado, durante
dados. Também é levada em consideração
a fase de Simplification, o SQL irá
a velocidade de execução da consulta, por
reescrever a segunda consulta deslocando
exemplo, ele pode decidir por utilizar
o argumento de pesquisa
paralelismo a fim de retornar os dados

www.codificando.net Dez / Jan - 2010 | 55


Introdução ao Query Processor e-magazine

(Funcionarios.Nome = ‘Antonio’) para a default, e pode ser alterado definindo a


cláusula where, como pode ser visto na primary key como nonclustered no
Listagem 3. comando de criação da tabela. O SQL

SELECT * FROM Funcionarios


INNER JOIN Funcionarios AS
Listagem 3. Consulta com argumentos de
pesquisa especificados no where.

Funcionarios2
ON Funcionarios.ID =
Funcionarios2.ID
WHERE Funcionarios.ID > 1
AND Funcionarios.Nome =
'Antonio' Figura 4. Execution Plan gerado pelo Query
Optimizer

Na Figura 3 temos uma simples


utilizou este índice clustered para ler os
dados da tabela Funcionarios.
Veremos mais informações sobre
operadores na seção Operadores.

Visualizando o Plano de
execução
Existem três maneiras de visualizar um
Figura 3. Query Optimizer. plano de execução: o modo gráfico, modo
texto e XML. Vamos analisar os dois
representação gráfica de como o Query modos mais utilizados para análise:
Optimizer funciona. Como pode ser visto, gráfico e texto.
o resultado da análise será o Query Plan, Para visualizar o plano de execução em
ou plano de execução. modo gráfico, basta digitar um código T- Codificando.net e-magazine
Na Figura 4 podemos visualizar a SQL no SQL Server Management Studio e
representação gráfica de um plano de pressionar ctrl+l. Neste modo diversas
execução simples. informações complementares são exibidas.
Com base na estrutura da tabela Estas informações são chamadas de hints.
Funcionarios, podemos verificar na Figura Os hints contêm informações importantes
4 que para o comando SELECT * FROM sobre o objeto que está sendo acessado ou
Funcionarios, o Query Optimizer gerou sobre a operação que será executada, por
um plano de execução que acessa a tabela exemplo, dados sobre a utilização de
Funcionarios utilizando o operador memória, CPU e custo de execução de
Clustered Index Scan. cada operador dentro de todo o plano de
Durante a criação de uma tabela o SQL execução. Também são apresentados
Server automaticamente cria um índice dados informando se o resultado do
clustered para as colunas definidas como operador está ordenado ou não, número
primary key. Este é o comportamento estimado de linhas que serão retornadas e

www.codificando.net Dez / Jan - 2010 | 56


Introdução ao Query Processor e-magazine

etc. valor é utilizado internamente pelo Query


Para exibir os hints de um determinado Optimizer para identificar qual será o
operador, basta posicionar o cursor do melhor operador a ser utilizado.
mouse sobre o operador desejado. O modo gráfico de visualização é a
Na Figura 5, por exemplo, podemos maneira mais simples de analisar planos
analisar diversas informações em relação de execução. Seguem alguns pontos que
aos custos gerados pelo operador são importantes de serem destacados:
Clustered Index Scan. Entre elas: ♦ Possui uma interface que facilita a
visualização dos hints e a
♦ Actual Number of Rows: Número de compreensão do plano de execução;
linhas retornadas pelo operador; ♦ Fácil de encontrar possíveis pontos
♦ Estimated I/O Cost: Valor relativo ao de contenção, isto é, operadores que
custo de I/O necessário para executar possuem alto valor de custo. Cada
o operador. É desejado que este valor operador possui um valor de 0 a
seja o menor possível; 100%, onde é apresentada a
♦ Estimated CPU Cost: Valor relativo porcentagem de custo de execução
ao custo de CPU necessário para de cada um em relação a todo o
executar o operador. É desejado que plano de execução. Ao analisar o
este valor seja o menor possível; plano, podemos facilmente
♦ Estimated Operator Cost: Este é o identificar quais são estes
operadores;
♦ Pode ser salvo em formato XML e
aberto no SQL Server Management
Studio (somente SQL Server 2005 e
posterior).

Outra maneira de visualizar os planos de

Codificando.net e-magazine
execução é utilizando o modo texto. Para
habilitar a exibição do plano de execução
neste modo é necessário ativar uma das
Figura 5. Hint com dados do plano de execução. opções de ShowPlan, são elas:

custo do operador dentro de todo o ♦ SET SHOWPLAN_TEXT ON:


plano de execução. Um percentual de Retorna o plano de execução de cada
custo é exibido entre parênteses. comando do batch. Os comandos
não são executados, portanto o plano
Uma lista completa com a descrição de de execução é o estimado, e não o
cada valor exibido pode ser encontrada no atual;
Help do SQL Server. ♦ SET SHOWPLAN_ALL ON:
Como podemos perceber, o valor exibido Semelhante ao SHOWPLAN_TEXT,
nas informações de Cost é um número sem a diferença entre eles é que o
um real sentido, pois não é o custo em SHOWPLAN_ALL retorna mais
milissegundos, nem o número de IO. Este informações sobre o plano;

www.codificando.net Dez / Jan - 2010 | 57


Introdução ao Query Processor e-magazine

♦ SET STATISTICS PROFILE ON: Entretanto, muitas vezes ele é a melhor


Retorna o plano de execução maneira de se analisar o que o SQL está
completo, semelhante ao fazendo. Sobre este modo, os pontos que
SHOWPLAN_ALL, com a diferença merecem destaque são:
de que o PROFILE executa os ♦ Mais fácil para analisar grandes
comandos do batch, gerando o plano planos de execução, pois o plano fica
atual; bem organizado em uma árvore
SET SHOWPLAN_XML ON: Retorna o hierárquica. A área de visualização
plano de execução em um XML formatado. dos planos em modo gráfico exige
Não executa os comandos do batch. que tenhamos que ficar arrastando as
♦ SET STATISTICS XML ON: barras de rolagem de um lado para o
Semelhante ao SHOWPLAN XML, outro, tornando a análise um pouco
com a diferença de que o mais difícil;
STATISTICS XML executa o batch. ♦ Todas as informações já são exibidas,
não precisa dos hints;
Listagem 4. Exemplo de consulta e plano de ♦ Fácil para exportar para Excel ou
execução em modo texto.
enviar por e-mail.
Como exemplo, execute o comando SET
SHOWPLAN_TEXT ON e depois execute a Listagem 5. Exemplo de consulta e plano de
consulta SELECT * FROM Funcionarios. O execução em modo texto.

resultado será a exibição do plano de


execução em modo texto, como pode ser UPDATE Funcionarios SET Nome = 50
WHERE ID = '10'
visto Listagem 4.
UPDATE [Funcionarios] set [Nome] =
SELECT * FROM Funcionarios @1 WHERE [ID]=@2
|--Clustered Index Scan(OBJECT: |--Clustered Index Update
( [dbo].[Funcionarios]. (OBJECT:( [dbo].[Funcionarios].
[ PK_Funciona__3214EC277D430130])) [PK…]), SET:( [dbo].
[Funcionarios].[Nome] =

Codificando.net e-magazine
[Expr1003]), DEFINE:([Expr1003]
Este plano é exatamente o mesmo que =CONVERT_IMPLICIT(varchar(30),
visualizamos na representação gráfica da [@1],0)), WHERE:( [dbo].
[Funcionarios].[ID]
Figura 4. Ele representa uma simples =CONVERT_IMPLICIT(int,[@2],0)))
leitura dos dados da tabela Funcionarios,
utilizando operador Clustered Index Scan,
que acessa o índice Operadores
PK__Funciona__3214EC277D430130.
Os ícones que são exibidos nos planos de
Na Listagem 5 podemos visualizar um execução (Figura 6) são conhecidos por
plano de execução em modo texto para um operadores. Eles são os responsáveis por
update na tabela Funcionarios. Observe executar as operações necessárias para
que o texto apresentado contém muitas rodar um comando T-SQL.
funções de processos internos do SQL Existem diversos operadores e ao longo
Server, o que acaba fazendo com que o dos artigos sobre o Query Optimizer
plano fique complexo de entender. veremos mais alguns deles. Dessa forma,

www.codificando.net Dez / Jan - 2010 | 58


Introdução ao Query Processor e-magazine

vamos entender um pouco mais sobre não existe dependência, um operador


como eles se comportam, quando e porque SORT pode ser utilizado para ordenar um
são necessários. resultado ou pode ser utilizado para
Operadores executam e calculam tarefas ordenar uma coluna, a fim de saber qual é
geradas pelo plano de execução, por o maior valor (MAX) da tabela. Isso faz
exemplo, um operador de Nested Loop com que o Query Optimizer tenha mais
executa um Join. Operadores de Index opções de escolha sobre qual operador
Seek fazem leitura de um range de valores utilizar.
em um índice, por exemplo, uma consulta Uma característica importante a ser
que deseja retornar os dados de uma tabela destacada é que existem duas categorias
onde o valor da coluna Código esteja entre de operadores: os operadores
5 e 10, em uma tabela que contém registros “nonblocking” e os operadores “blocking”
de 0 a 100, o SQL pode usar o operador de ou “stop-and-go”:
Index Seek para ler apenas as páginas de ♦ Os operadores nonblocking são
dados do índice que contém as linhas com aqueles que lêem as linhas do input e
os valores de 5 a 10. Operações de produzem o output ao mesmo
agregação como MAX, MIN, SUM, tempo. No método conhecido por
COUNT e AGV são calculadas pelo GetRow(), conforme a leitura das
operador de Stream Aggregate. O Stream linhas vai acontecendo, o operador
Aggregate agrupa todas as linhas de uma executa sua tarefa e retorna o output
tabela por uma ou mais colunas, para o próximo operador fazer seu
calculando o valor do comando de trabalho. O operador de Nested
agregação utilizado na consulta. Por Loop é um bom exemplo desse
exemplo, uma consulta que deseja retornar comportamento. Assim que a
quantos pedidos os clientes fizeram em primeira linha é recebida (GetRow())
2008 agrupado pelo nome do cliente; neste o SQL faz o Join com a tabela do
caso, o SQL irá utilizar o Stream Aggregate outer, e caso o relacionamento seja

Codificando.net e-magazine
para agrupar todos os clientes em uma verdadeiro a linha é retornada no
linha e calcular o SUM da quantidade de output. Este processo se repete até o
pedidos. fim da leitura da tabela do Join;
Como já mencionado, para produzir o ♦ Já os operadores “blocking”
melhor plano de execução o Query necessitam primeiro ler todas as
Optimizer analisa qual é o melhor tipo de linhas (normalmente no método
operador para executar determinada Open()) do input para depois retorná
tarefa, tentando encontrar qual deles -las para o output. Um exemplo
executará o processo mais rápido e/ou clássico de operadores blocking é o
utilizando a menor quantidade de Sort, que necessita primeiro ler todas
recursos. as linhas do input para fazer a
Todo operador executa os métodos Open ordenação e, por fim, retornar as
(), GetRow() e Close(). Devido a esta linhas ordenadas.
característica, os operadores são
independentes, e, por isso, o SQL consegue Existem alguns cenários onde cada tipo de
gerenciá-los com maior facilidade. Como operador é melhor aproveitado, por

www.codificando.net Dez / Jan - 2010 | 59


Introdução ao Query Processor e-magazine

exemplo, operadores nonblocking são geração de um plano de execução é bem


preferíveis quando utilizamos as cláusulas complexo e requer um tempo extra na
TOP, Hint FAST N ou mesmo um Exists. execução da consulta. Quanto maior e
Como exemplo vamos utilizar o comando mais complexa for sua consulta, mais
Exists. Este comando é utilizado para tempo o Query Processor leva para
validar se um valor existe dentro de um analisar todas as variantes, e por fim gerar
contexto. Normalmente ele é utilizado um plano de execução para o comando T-
junto com subqueries para validar se um SQL. Toda essa operação de gerar o plano
valor existe em uma tabela. de execução causa delay e normalmente
Durante a execução do Exists, se ao menos faz alto uso de CPU. Por isso, o SQL
uma linha for retornada para o output, isso Server usa um mecanismo para evitar que
já caracteriza uma condição verdadeira. toda vez que uma consulta for enviada
para o banco, o Query Processor tenha
que gerar um novo plano de execução. É
justamente este o papel do Cache Plan:
evitar que uma consulta que já tenha
Figura 6. Alguns operadores do plano de execução.
passado pelo Query Optimizer seja
Ou seja, se houve algum retorno, isso enviada novamente para otimização.
significa que o valor existe, e neste caso o Conforme podemos observar no
Query Execution (responsável por executar fluxograma (Figura 1), o primeiro
os planos gerados pelo Query Optimizer) processo que o Query Processor faz é
encerra o processo de leitura (GetRow). procurar no cache se já existe um plano de
Apenas uma linha é o suficiente para saber execução para a consulta enviada ao
se o valor procurado existe ou não. Se servidor. Isso significa que quando um
tivermos que esperar todas as linhas serem plano de execução é gerado para uma
lidas para depois retornar o output, como determinada consulta, o SQL grava este
os operadores blocking fazem, esta plano em uma área de memória a fim de

Codificando.net e-magazine
vantagem de encerrar o processo assim reutilizar o mesmo plano de execução
que encontrar alguma linha não seria para consultas semelhantes.
aproveitada. A área de memória utilizada para
Existem pouco mais de 100 operadores, armazenamento dos planos de execução é
entre eles: Scan, Compute Scalar, exatamente a quantidade de memória
Aggregate, Sort, Spools e Key Lookup, disponível para uso do servidor SQL
apresentados na Figura 6. Server. No SQL Server 7.0 havia uma área
Para finalizar esta seção é importante citar específica para o armazenamento dos
que não existe o melhor operador para planos, chamada “procedure cache”.
fazer um Join ou uma Agregação. Cada Porém, a partir da versão 2000 isso foi
operador é melhor para uma determinada alterado para que o SQL pudesse utilizar
situação. toda a memória disponível ao SQL Server.
Na verdade, no SQL Server 7.0 só eram
Cache armazenados planos de execução de
procedures (por isso se chamava
Como podemos observar, o processo de “procedure cache”), consultas ad-hoc não

www.codificando.net Dez / Jan - 2010 | 60


Introdução ao Query Processor e-magazine

tinham o plano armazenado em cache. que envolve a consulta ser alterado, ou


um novo índice ser criado ou até mesmo
Reutilizando planos de consulta apagado. Nestas situações o SQL não
conseguirá reutilizar o plano de execução,
Em muitas ocasiões, reutilizar o plano de
o que resulta em uma nova análise do
execução pode ser uma grande vantagem,
Query Processor.
já que economizamos todo o tempo que
Existem diversas maneiras de saber se um
seria gasto pelo Query Processor para
plano de execução foi reutilizado ou não.
analisar um novo plano. Entretanto,
Para isso abra uma consulta no SQL
reutilizar um plano de execução que está
Server Management Studio e execute o
armazenado em cache pode ser um
código da Listagem 6.
problema, pois nem sempre a mesma
Na primeira linha é executado um
consulta retorna a mesma quantidade de
comando (DBCC FREEPROCCACHE)
dados. Por isso, o SQL Server é bem
para limpar a área de cache atual,
cauteloso quando estamos falando de
apagando todos os planos de consulta que
reutilização de planos de execução, já que
estão armazenados em memória. Feito
pode haver situações onde um mesmo
isso, são executadas três simples consultas
plano não seja o ideal para consultas
para retornar os dados de um
parecidas. Por exemplo, vamos imaginar
determinado funcionário especificado na
que uma consulta que retorna apenas 10
cláusula where. Por fim, selecionamos os
linhas seja enviada pela primeira vez para
registros da sys.dm_exec_cached_plans,
o SQL Server, e o Query Processor gerou
que é uma view do sistema que retorna os
um plano de execução que utiliza um
planos de execução que estão em cache.
índice nonclustered mais um bookmark
Esta view retorna uma coluna chamada
para ler uma pequena quantidade de
plan_handle que é do tipo binário. Para
registros. Nestas condições o Query
converter este valor binário para um texto,
Engine executa este plano e depois o
o SQL disponibiliza uma function do
armazena em cache.
Codificando.net e-magazine
sistema chamada sys.dm_exec_sql_text.
Agora imagine que uma nova consulta,
igual à primeira, seja enviada para o SQL Listagem 6. Exemplo de consulta e acesso ao
cache plan.
Server, mas desta vez a condição de busca
informada no where requeira que milhares
Ela lê uma entrada em binário e retornar
de linhas sejam retornadas. Se o SQL optar
uma coluna chamada text, que contém o
por reutilizar o plano de execução isso não
vai ser bom, pois é bem provável que seja Use Cac Ob Comando_SQL
melhor fazer um Scan em toda a tabela do Cou heO jty
nts bjTy pe
que utilizar o índice mais o bookmark. O
pe
cenário descrito é bastante comum de 1 Compil Ad SELECT * FROM
acontecer. ed Plan hoc Funcionarios WHERE
Nome = 'Antonio'
Outro fator importante de ser observado é Compil Ad SELECT * FROM
2
que algumas operações podem deixar um ed Plan hoc Funcionarios WHERE
plano que está em cache desatualizado. Nome = 'José'

Por exemplo, pode acontecer do schema


Tabela 1. Valores que estão em cache retornados
pela DMV sys.dm_exec_cached_plans.

www.codificando.net Dez / Jan - 2010 | 61


Introdução ao Query Processor e-magazine

plano em modo texto. Plan Sub no cache, não com o plano


completo, mas somente com um Plan
DBCC FREEPROCCACHE; Sub. Isso vai permitir que o SQL
GO
SELECT * FROM Funcionarios WHERE reconheça que um plano já foi
Nome = 'José' gerado para esta consulta. A partir
GO
SELECT * FROM Funcionarios WHERE da segunda execução deste
Nome = 'Antonio' comando, o SQL substitui este plano
GO
SELECT * FROM Funcionarios WHERE pelo plano completo;
Nome = 'José' ♦ Parse Tree: Representa o parse de
GO
SELECT usecounts, cacheobjtype, uma view, function, etc.;
objtype, "text" AS Comando_SQL ♦ Extended Proc: Grava o plano para
FROM sys.dm_exec_cached_plans
CROSS APPLY sys.dm_exec_sql_text extended procedures, por exemplo, a
(plan_handle) xp_cmdShell;
WHERE cacheobjtype = 'Compiled
♦ CLR Compiled Func: Funções
Plan'
AND "text" NOT LIKE '% criadas utilizando CLR;
dm_exec%'; ♦ CLR Compiled Proc: Procedures
O resultado do comando acima deve ser criadas utilizando CLR.
parecido com os registros da Tabela 1.
A DMV (Dynamic Management Views) A coluna Objtype retorna qual o tipo do
sys.dm_exec_cached_plans retorna todos objeto que está armazenado, por exemplo,
os planos de execução que estão pode ser um comando Adhoc, proc, view,
armazenados no cache do SQL Server. trigger, entre outros.
Você pode utilizar esta view para saber se Observe na Tabela 1 que a coluna
um determinado plano foi reutilizado ou UseCounts contém o valor 2 para a
não, a quantidade de memória que um consulta SELECT * FROM Funcionarios
plano está utilizando e também para WHERE Nome = 'José', mostrando que o
verificar quantas vezes um plano foi SQL Server utilizou duas vezes o mesmo

Codificando.net e-magazine
reutilizado. plano de execução.
A coluna UseCounts retorna a quantidade Uma observação importante em relação ao
de vezes em que o plano de execução foi cache plan é que para consultas adhoc,
reutilizado. A coluna CacheObjType que não estejam parametrizadas (ou seja,
retorna o tipo do objeto em cache. Ela pode iguais a que utilizamos acima), para que o
apresentar os seguintes valores: Query Processor consiga fazer proveito do
plano que está em cache as consultas
♦ Compiled Plan: Representa um plano precisam ser escritas exatamente iguais.
de execução completo; Inclusive os valores no where terão que
♦ Compiled Plan Sub: Existe uma ser os mesmos. Repare que no exemplo da
propriedade do banco chamada Listagem 6 o SQL só reutilizou o plano de
“optimize for ad hoc workloads”. execução em cache porque a terceira
Quando habilitada, assim que uma consulta enviada para o servidor é
consulta AdHoc é enviada pela idêntica à primeira consulta, inclusive o
primeira vez ao SQL, ele grava um WHERE Nome = ‘José’.
Isso significa que cada caractere será

www.codificando.net Dez / Jan - 2010 | 62


Introdução ao Query Processor e-magazine

analisado e comparado com o comando O SQL Server é bem cauteloso em relação


em cache. Uma simples quebra de linha ou a quando parametrizar uma consulta. Este
uma letra maiúscula ou até mesmo um processo somente será adotado para
código de comentário já será o suficiente consultas que são consideradas seguras.
para inviabilizar o uso do plano em cache, Uma consulta é segura quando o plano
acarretando na criação de um novo plano selecionado não muda caso os parâmetros
de execução. (filtros) mudem. Vejamos um exemplo de
consulta considerada segura:
Parametrização ♦ Para uma consulta que busca por um
valor em uma tabela, passando um
Sempre que possível o SQL Server tenta filtro para uma coluna que contém
alterar sua consulta para torná-la apta à um índice único, o SQL sabe que
reutilização dos planos de execução. Este apenas um valor será retornado.
comportamento chama-se parametrização. Independente do valor do parâmetro
Consultas parametrizadas têm mais recebido, pois a presença do índice
chances de terem seu plano de execução único obriga que exista apenas um
reutilizado. registro com o mesmo valor em toda
No SQL Server 2005 existem dois tipos de a tabela.
parametrização, o Simple Parameterization
(conhecido como auto-parameterization, Vejamos um exemplo de consulta
no SQL Server 2000) e Forced considerada não segura:
Parameterization. Ao utilizar a ♦ Fazer um seek, ou seja, ler um range
parametrização Simple, o SQL é mais de informação a partir de um índice
cauteloso em relação às quais consultas pode ser uma ótima escolha. Por
parametrizar, já a opção forced tenta outro lado, utilizar este mesmo plano
parametrizar a maior quantidade de para uma consulta que retorna várias
consultas possível. linhas pode não ser a melhor opção.
Quando um banco de dados é criado o
padrão de parametrização é o Simple. Para Vamos analisar um exemplo de Codificando.net e-magazine
alterar esta opção acesse as propriedades parametrização e reutilização do plano de
do banco de dados e selecione a opção execução. Para isso execute o código da
Forced na propriedade Parameterization. Listagem 7. Neste código, executamos
Quando a opção Forced está selecionada o duas simples consultas que retornam os
SQL tenta parametrizar a maior dados dos funcionários, com base no ID
quantidade de consultas possíveis. Existe especificado na cláusula where. Como a
uma lista de instruções que impedem o coluna ID é a chave primária da tabela
uso de parametrização. Esta lista pode ser Funcionarios, os valores de ID não podem
acessada no help do SQL Server. se repetir. Isso caracteriza esta consulta
Durante o processo de parametrização o como segura para reutilização do plano de
SQL Server tenta alterar o valor no where execução.
por uma variável, e futuramente ele altera Podemos observar na Tabela 2 que o SQL
este valor pelo novo valor informado na reutiliza o mesmo plano para as duas
consulta. consultas.

www.codificando.net Dez / Jan - 2010 | 63


Introdução ao Query Processor e-magazine

Use Cac Ob Comando_SQL um plano de execução “prepared” e ele foi


Cou heO jty
utilizado duas vezes.
nts bjT pe
ype As outras consultas continuam
aparecendo, mas elas não contem o plano
1 Compil Ad SELECT * FROM de execução, elas apontam para a linha
ed Plan hoc Funcionarios WHERE ID =
2 que tem o plano de execução “prepared”.
1 Compil Ad SELECT * FROM Infelizmente com as DMVs e recursos
ed Plan hoc Funcionarios WHERE ID = disponibilizados pelo SQL Server, não é
1
2 Compil Pre (@1 tinyint)SELECT * possível visualizar esta ligação entre os
ed Plan par FROM [Funcionarios] planos Adhoc e o plano Prepared, este é
ed WHERE [ID]=@1
um código interno do SQL. Estas
Tabela 2. Valores que estão em cache retornados pela
DMV sys.dm_exec_cached_plans.
consultas Adhoc são conhecidas como
Shell Queries, elas são armazenadas para
agilizar o processo de reutilização do
plano. Veja na Figura 7 um exemplo de
SELECT * FROM Funcionarios como estas consultas podem ajudar na
WHERE ID = 1
GO performance da execução do comando.
SELECT * FROM Funcionarios
WHERE ID = 2
GO

SELECT usecounts, cacheobjtype,


objtype, "text" AS Comando_SQL
FROM sys.dm_exec_cached_plans
CROSS APPLY sys.dm_exec_sql_text
(plan_handle)
WHERE cacheobjtype = 'Compiled
Plan'
AND "text" NOT LIKE '%
dm_exec%';

Listagem 7. Exemplo de consulta parametrizada.


Figura 8. Exemplo de consulta parametrizada.
Codificando.net e-magazine

Figura 7. Fluxograma de procura por plano de


execução em cache.

Como podemos observar nas colunas


UseCounts e Objtype, o SQL Server gerou

www.codificando.net Dez / Jan - 2010 | 64


Introdução ao Query Processor e-magazine

Nesta figura podemos observar que gráfico e modo texto. Por último foi
quando um mesmo comando for apresentado o conceito de Cache Plan e
executado, caso ele contenha um shell parametrização de consultas.
query no cache, o SQL pula uma etapa do
processo de localização do plano. Linked Server: É um mecanismo que
Observe na Tabela 2 que a linha 3 possui permite que o SQL Server execute
o plano de execução parametrizado, que é comandos em outro banco de dados OLE
o plano prepared. O plano prepared foi DB. Ao criar um linked Server o SQL cria
gerado baseado nas consultas executadas uma conexão com o banco de dados
pelo código da Listagem 7. Como destino, permitindo que os dados que
podemos observar, o SQL Server trocou o estão armazenados no banco destino sejam
valor no where por uma variável @1 e acessados a partir da própria instancia do
declarou a variável como datatype tinyint. SQL Server. Por exemplo, é possível abrir
Ao parametrizar uma consulta o SQL uma consulta no SSMS e fazer um update
tenta encontrar qual é a melhor opção de em uma tabela do SQL Server lendo os
variável a ser utilizada, neste caso, ele dados de uma base Oracle.
optou pelo tinyint por ela ocupar apenas 1 O banco utilizado no Linked Server pode
byte de armazenamento. ser remoto ou local. Podemos criar um
O datatype tinyint consegue tratar valores linked Server com um banco de dados
de 0 a 255, isto é, caso o valor informado Access, Oracle, MySQL, ou qualquer banco
no where seja 300 o SQL não conseguirá de dados que contenha um driver OLE DB.
utilizar este plano de execução, causando
uma nova recompilação do comando. OLE DB: (Object Linking and Embedding,
Na Figura 8 podemos visualizar como Database) é um pacote que contém as
funciona o conceito de parametrização. Ao informações necessárias para conexão e
parametrizar o valor de where Prikey, o gerenciamento da leitura dos registros
SQL consegue reutilizar o mesmo plano armazenados em uma fonte de dados
de execução para as três consultas apenas (arquivos txt, xls, entre outros) ou bancos
alterando o valor de “?”. de dados. Codificando.net e-magazine

Fabiano Neves Amorim


Conclusão
(fabiano_amorim@bol.com.br) Certificado MCP, MCTS e
Vimos neste artigo quais os métodos que o MCITP Database Developer em SQL Server 2000/2005,
Especialista em desenvolvimento de Data Warehouses e
SQL Server utiliza para executar uma Tunning de banco de dados SQL Server. Palestrante de
consulta SQL e como o Query Processor WebCasts para Microsoft Brasil, participante ativo de
fóruns MSDN e TechNet, escreve artigos sobre SQL Server
trabalha para acessar os dados
para as revistas SQL Magazine, Codificando.net e para o
armazenados nos arquivos de banco de site Simple-Talk. Mantenedor de blog técnico sobre
dados. Ao acessar os dados, estudamos Tecnologia e SQL Server
(http://fabianosqlserver.spaces.live.com).
um pouco dos operadores de acesso a
dados, bem como os tipos de operadores. Atualmente trabalha na CNPM empresa certificada
Também vimos como analisar um MPS.BR e Gold Certified Partner Microsoft.
plano de execução e as análises em modo

www.codificando.net Dez / Jan - 2010 | 65


e-magazine

Codificando.net e-magazine

www.codificando.net Dez / Jan - 2010 | 66


e-magazine

ASP.NET Core – Web Forms ou MVC?


Por: Alexandre Tarifa

Este artigo não tem como objetivo Este cenário é muito comum em sistemas
apresentar profundamente as questões internos (seja rodando na intranet ou internet).
técnicas sobre cada tecnologia e sim sobre o
ponto de vista de quais os melhores cenários As principais preocupações são:
para a aplicação delas. Para informações implementação dos requisitos de negócio,
técnicas, o site www.asp.net trás todo o segurança, performance de processamento,
conteúdo em diversos tipos de formatos infra-estrutura e distribuição. Dificilmente
(artigos, vídeos, passo-a-passo, etc). nesse cenário existe a figura de um designer.

Eu costumo dividir o desenvolvimento Web Na minha experiência de consultoria, esse é o


em dois tipos de desenvolvimentos: sistemas cenário mais comum nas empresas.
e sites.
Desenvolvimento de sites
Desenvolvimento de sistemas
A dificuldade é muito superior em relação a
Normalmente é executado dentro de um camada de apresentação e claro, as
ambiente conhecido e controlado, possui implementações de negócios devem ser
uma quantidade pequena de usuários (200 integras conforme as especificações e
pessoas por exemplo), é fácilmente definições de negócio de cada empresa.
controlado com pré-requisitos (para
executar utilize o Internet Explorer 7 ou Neste cenário existe a necessidade de se rodar
superior na resolução XYZ) e executa em qualquer lugar (navegador de mercado),
processos administrativos, comerciais com performance da camada de apresentação é
um foco muito grande na implementação do necessária, provavelmente poucos
negócio, ou seja, praticamente todo o processamentos pesados em servidor,
sistema está desenvolvido dentro de uma necessidade de seguir os padrões W3C,
camada de negócios/dados/banco de dados. recursos no client para melhorar a experiência
com o usuário, a figura do designer é presente,
Neste cenário, não existe preocupação até mesmo conhecimento pesado em HTML é
alguma com layout, HTML, resolução, etc necessário e a integridade do layout X
etc etc.. e até mesmo é totalmente ignorado aplicação é algo extremamente trabalhoso.
usuários com baixa velocidade de conexão
com internet, padrões W3C, etc. Web Forms ou MVC

www.codificando.net Abril
Dez//Maio
Jan -2009
2010 | 67
e-magazine

ASP.NET Core – plataforma ÚNICA da empresas será totalmente repreendido por


Microsoft para criação de aplicações Web. misturar o código HTML com o código da
Os recursos do ASP .NET estão lógica da interface (claro que se for seguido o
implementados aqui! Logo, Web Forms e padrão, estamos falando de pouco código
MVC oferecem os mesmos recursos Core. aqui!). Já para desenvolvimento de sites é a
plataforma ideal pois o desenvolvedor tem
Web Forms - temos uma plataforma todo o poder de controlar 100% as suas
extremamente produtiva em questões de necessidades.
controles prontos, validação de dados de
formulários, criação de formulários, etc. Versões
Além de total controle do ciclo de
Web Forms – Chega no framework 4.0 e
carregamento da página, oferece uma
Visual Studio 2010 na versão 4, a versão atual
plataforma para os
em produção é a 3.5.
desenvolvedores ideal para o
desenvolvimento de sistemas. Já para
MVC – Chega no framework 4.0 e Visual
desenvolvimento de sites, pode trazer
Studio 2010 na versão 2, a versão atual em
algumas dificuldades, principalmente no
produção é a 1.0.
controle do HTML (em alguns casos temos
que abrir mão da produtividade para
Resumo
controlar 100%), missão complicada de
A Microsoft está criando um leque, hoje temos
controlar/diminuir o tamanho do View
duas possibilidades, Web Forms e MVC, e
State, que pode ser muito ruim em sites,
quem sabe futuramente não teremos mais...
resumindo, para desenvolvimento de sites
vale sempre lembrar que o Core será o mesmo,
podemos considerar que é uma
proporcionando uma evolução constante nas
plataforma boa porém com restrições de
duas tecnologias
controle e produtividade.

MVC – temos uma plataforma que pode ser


totalmente controlada pelo desenvolvedor,
porém algumas implementações de
produtividade disponíveis no Web Forms
ainda não estão disponíveis. Sugere a
utilização de um padrão, no caso o MVC
(divisão de papeis, testável,etc), mas claro,
não garante de forma alguma que isso será
seguido, mas já faz com que as pessoas
pensem em usá-lo. Para desenvolvimento de
sistemas considero uma plataforma boa,
porém com alguns prejuizos de
produtividade e que talvez em algumas

www.codificando.net Abril
Dez//Maio
Jan -2009
2010 | 68

Potrebbero piacerti anche