Arquivo

Archive for the ‘Não categorizado’ Category

Série Mentes Brilhantes – Parte 3

9 de maio de 2010 5 comentários

O que fazer quando você não gosta do SQL Server e dos desenvolvedores que irão dar manutenção no seu código?

 

Crie uma consulta simples pra eles

DECLARE @Col1  Integer,

        @Col2  Integer,

        @Col3  Integer;

 

SET @Col1 = <Input1>;

SET @Col2 = <Input2>;

SET @Col3 = <Input3>;

 

IF (@Col3 = 0)

BEGIN

  SELECT Tab1.Col1,

         Tab1.Col2,

         Tab1.Col3,

         Tab1.Col7,

         Tab1.Col8,

         Tab1.Col6,

         Tab1.Col9,

         Tab1.Col10,

         CASE WHEN ((Tab2.Col11 IS NOT NULL) AND

                    (Tab3.Col12 = ‘P’) AND

                    (Tab3.Col13 = ‘G’))

 

              THEN CASE WHEN (Tab2.Col11 = ‘LL’)

                        THEN (SELECT CASE WHEN (Tab4.Col15 = ‘Q’)

                                          THEN Tab4.Col16

                                          ELSE Tab4.Col17

                                     END

                         FROM Tab4(NOLOCK)

                         WHERE Tab4.Col1 = Tab1.Col1 AND

                               Tab4.Col2 = Tab1.Col2 AND

                               Tab4.Col3 = Tab1.Col3 AND

                               Tab4.Col4 IN(SELECT Col4

                                               FROM Tab5(NOLOCK)

                                               WHERE Tab5.Col1 = Tab1.Col1 AND

                                                     Tab5.Col5 = Tab1.Col6))

                        ELSE CASE WHEN (Tab2.Col11 = ‘LF’)

                                  THEN (SELECT CASE WHEN (Tab4_Fixos.Col15 = ‘Q’)

                                                    THEN Tab4_Fixos.Col16

                                                    ELSE Tab4_Fixos.Col17

                                                END

                                        FROM Tab4_Fixos(NOLOCK)

                                        WHERE Tab4_Fixos.Col1 = Tab1.Col1 AND

                                              Tab4_Fixos.Col2 = Tab1.Col2 AND

                                              Tab4_Fixos.Col3 = Tab1.Col3 AND

                                              Tab4_Fixos.Col4 IN(SELECT Col4

                                                                    FROM Tab5(NOLOCK)

                                                                    WHERE Tab5.Col1 = Tab1.Col1 AND

                                                                          Tab5.Col5 = Tab1.Col6))

                                  ELSE CASE WHEN (Tab2.Col11 = ‘2F’)

                                       THEN (SELECT CASE WHEN (Tab6.Col15 = ‘Q’)

                                                         THEN Tab6.Col16

                                                         ELSE Tab6.Col17

                                                     END

                                             FROM Tab6(NOLOCK)

                                             WHERE Tab6.Col1 = Tab1.Col1 AND

                                                   Tab6.Col2 = Tab1.Col2 AND

                                                   Tab6.Col3 = Tab1.Col3 AND

                                                   Tab6.Col4 IN(SELECT Col4

                                                                   FROM Tab5(NOLOCK)

                                                                   WHERE Tab5.Col1 = Tab1.Col1 AND

                                                                         Tab5.Col5 = Tab1.Col6))

                                       ELSE (SELECT CASE WHEN (Tab4_Lim.Col15 = ‘Q’)

                                                         THEN Tab4_Lim.Col16

                                                         ELSE Tab4_Lim.Col17

                                                     END

                                             FROM Tab4_Lim(NOLOCK)

                                             WHERE Tab4_Lim.Col1 = Tab1.Col1 AND

                                                   Tab4_Lim.Col2 = Tab1.Col2 AND

                                                   Tab4_Lim.Col3 = Tab1.Col3 AND

                                                   Tab4_Lim.Col4 IN(SELECT Col4

                                                                       FROM Tab5(NOLOCK)

                                                                       WHERE Tab5.Col1 = Tab1.Col1 AND

                                                                             Tab5.Col5 = Tab1.Col6))

                                       END

                             END

                   END

              ELSE Tab1.Col18

         END AS Col19,

         Tab1.Col18,

         Tab1.Col20,

         Tab7.Col21,

         Tab8.Col22,

         Tab3.Col23,

         Tab1.Col24,

         CASE WHEN (Tab2.Col11 = ‘LL’)

              THEN (SELECT Tab4.Col15

                    FROM Tab4(NOLOCK)

                    WHERE Tab4.Col1 = Tab1.Col1 AND

                          Tab4.Col2 = Tab1.Col2 AND

                          Tab4.Col3 = Tab1.Col3 AND

                         Tab4.Col4 IN(SELECT Col4

                                         FROM Tab5(NOLOCK)

                                        WHERE Tab5.Col1 = Tab1.Col1 AND

                                               Tab5.Col5 = Tab1.Col6))

              WHEN (Tab2.Col11 = ‘LI’)

              THEN (SELECT Tab4_Lim.Col15

                    FROM Tab4_Lim(NOLOCK)

                    WHERE Tab4_Lim.Col1 = Tab1.Col1 AND

                          Tab4_Lim.Col2 = Tab1.Col2 AND

                          Tab4_Lim.Col3 = Tab1.Col3 AND

                          Tab4_Lim.Col4 IN(SELECT Col4

                                              FROM Tab5(NOLOCK)

                                              WHERE Tab5.Col1 = Tab1.Col1 AND

                                                    Tab5.Col5 = Tab1.Col6))

              WHEN (Tab2.Col11 = ‘LF’)

              THEN ‘F’

              WHEN (Tab2.Col11 = ‘2F’)

              THEN ‘2’

         END AS Col15,

        Tab1.Col25

  FROM Tab1(NOLOCK)

  INNER JOIN Tab7(NOLOCK)

     ON Tab7.Col26 = Tab1.Col26 AND

           Tab7.Tipo = Tab1.Tipo

  INNER JOIN Tab8(NOLOCK)

     ON Tab8.Col7 = Tab1.Col7

  INNER JOIN Tab3(NOLOCK)

     ON Tab1.Col1 = Tab3.Col1

  RIGHT OUTER JOIN Tab2(NOLOCK)

     ON Tab2.Col1 = Tab1.Col1 AND

           Tab2.Col2 = Tab1.Col2 AND

           Tab2.Col3 = Tab1.Col3 AND

           Tab2.Col4 IN(SELECT Col4

                           FROM Tab5(NOLOCK)

                          WHERE Tab5.Col1 = Tab1.Col1 AND

                                Tab5.Col5 = Tab1.Col6)

  WHERE Tab1.Col1 = @Col1 AND

        Tab1.Col2 = @Col2 AND

        Tab1.Col3 = @Col3 AND

        Tab1.Col10 > 0 AND

        Tab1.Col8 IS NOT NULL

Série Mentes Brilhantes – Parte 2

7 de maio de 2010 1 comentário

O que fazer quando você não gosta da clausula WHERE?

 

Use a clausula HAVING

SELECT Cliente, Vendedor

  FROM Pedido

GROUP BY Cliente, Vendedor, Data

HAVING Data BETWEEN ‘20090101’ AND ‘20090201’

Série Mentes Brilhantes – Parte 1

6 de maio de 2010 4 comentários

Vou começar a publicar uma série que chamei de “Mentes Brilhantes”… espero que gostem 🙂 ….

O que fazer quando você precisa que o resultado de uma consulta não retorne linhas duplicadas?

Use o DISTINCT

SELECT DISTINCT Cliente, Vendedor

  FROM Pedido

 

O que fazer quando você precisa que o resultado de uma consulta não retorne nenhuma linha duplicada?

 

Use o GROUP BY

SELECT Cliente, Vendedor

  FROM Pedido

GROUP BY Cliente, Vendedor

O que fazer quando você precisa que o resultado de uma consulta não retorne nenhuma linha duplicada meeeesmo?

 

Use DISTINCT + GROUP BY. J

SELECT DISTINCT Cliente, Vendedor

  FROM Pedido

GROUP BY Cliente, Vendedor

SQL Server em Português

6 de maio de 2010 1 comentário

 

SQL Server em português só podia dar nisso…

image001

Categorias:Não categorizado

Cuidado com Views…

29 de abril de 2010 Deixe um comentário

 

Pessoal já faz um tempo que estou sem blogar né?… Bom mesmo sem escrever para o blog por um tempo, isso não significa que fiquei sem escrever sobre SQL… na verdade bastante coisa aconteceu desde meu último post. Vamos as novidades:

· Tenho escrito bastante para o Simple Talk, a cada semana escrevo sobre um operador dos planos de execução, se você ainda não viu, segue o link para os artigos http://www.simple-talk.com/author/fabiano-amorim/… Ainda tem muito pela frente e eu estou adorando J, espero que eu consiga manter a meta de 1 por semana.

· O tão falado Marília Tech Day foi realmente um sucesso, foi uma honra pra mim poder participar e logo estarei no Prudente TechDay…

Tenho as gravações de minhas palestras e a palestra do Fabricio Catae. Eu fiz duas sessões uma sobre Joins no SQL Server e outra sobre índexação. Acabei sendo pego de surpresa pois o nosso amigo Rodrigo Fernandes teve um imprevisto e não conseguiu pegar o Vôo para o evento, então aproveitei o horário dele e falei sobre Índices no SQL Server, eu achei que ficou legal com bastante exemplos e boas perguntas da galera.

Ainda estou brigando para achar um programa decente para edição dos vídeos, assim que eu conseguir vou subir pro YouTube e coloco os links aqui no blog.

· Eu já havia sido convidado para falar sobre SQL Server em uma faculdade daqui de Tupã, então logo após o Marília TechDay falei sobre Certificações e SQL Server 2008 aqui na FACAT. Foi bem legal, é sempre bom ver a galera entusiasmada com as funcionalidades do SQL J.

Bom acabando a conversa fiada, vamos para o que interessa mais SQL Server.

Eu sempre me surpreendo com as situações que encontro no dia a dia… Hoje eu estava trabalhando em uma procedure que lia alguns dados a partir de uma view, e a consulta não utilizava um determinado índice de jeito nenhum. Fui olhar com calma e encontrei o seguinte cenário.

Vamos criar umas tabelas de teste para entender o problema.

IF OBJECT_ID(‘Pedidos’) IS NOT NULL

BEGIN

DROP TABLE Clientes

DROP TABLE Pedidos

END

GO

CREATE TABLE Pedidos(ID_Pedido   Integer Identity(1,1),

                     ID_Cliente  Int,

                     Data_Pedido DateTime,

                     Valor       Numeric(18,2),

CONSTRAINT xpk_Pedidos PRIMARY KEY (ID_Pedido))

GO

CREATE TABLE Clientes(ID_Cliente    Integer Identity(1,1),

                      Nome_Cliente  VarChar(300)

CONSTRAINT xpk_Clientes PRIMARY KEY (ID_Cliente))

GO

CREATE INDEX ix_teste ON Clientes(Nome_Cliente)

GO

DECLARE @i Integer

SET @i = 0

WHILE @i < 10000

BEGIN

INSERT INTO Pedidos(ID_Cliente,

Data_Pedido,

                      Valor)

VALUES(ABS(CheckSum(NEWID()) / 10000000),

GetDate() – ABS(CheckSum(NEWID()) / 10000000),

ABS(CheckSum(NEWID()) / 1000000))

INSERT INTO Clientes(Nome_Cliente)

VALUES (NEWID())

SET @i = @i + 1

END

GO

SELECT * FROM Pedidos

SELECT * FROM Clientes

Segue um exemplo dos dados incluidos

clip_image002

Tenho uma tabela simples de pedidos e os dados de clientes, agora vou criar uma view que me retorna os dados dos pedidos com o nome do cliente.

CREATE VIEW vw_Teste

AS SELECT Pedidos.*, ISNULL(Clientes.Nome_Cliente,’Não Existe’) AS Nome_Cliente

FROM Pedidos

LEFT OUTER JOIN Clientes

ON Clientes.ID_Cliente = Pedidos.ID_Cliente

Sim, eu fiz o LEFT OUTER JOIN de propósito pois pode acontecer de um registro da Pedidos.ID_Cliente não estar na tabela de Clientes. Estou apenas usando um cenário para exemplo.

Existe um índice por Clientes.Nome_Cliente, vamos ver ele na prática. A consulta abaixo utiliza o mesmo select da view porém desta vez estamos fazendo um filtro por nome_cliente.

SELECT Pedidos.*, ISNULL(Clientes.Nome_Cliente,’Não Existe’) AS Nome_Cliente

FROM Pedidos

LEFT OUTER JOIN Clientes

ON Clientes.ID_Cliente = Pedidos.ID_Cliente   

WHERE Clientes.Nome_Cliente like ‘A%’

clip_image004

Como podemos ver, o plano acima utilizou o índice ix_teste para filtrar os dados

Porem se efetuarmos o mesmo select utilizando a view temos o seguinte plano.

SELECT * FROM vw_Teste

WHERE Nome_Cliente like ‘A%’

clip_image006

Bem, a esta altura você já deve ter identificado qual é o problema. Mas pra quem ainda não pegou, fica a pergunta, porque o SQL faz o seek quando uso o código da view mas quando uso a view ele não faz o seek?

O que acontece é que na view estamos alterando o valor da coluna Nome_Cliente, repare que estou utilizando a function ISNULL para validar se os dados foram retornados, e isso impede que o SQL utilize o índice.

Para resolver este problema, poderiamos retornar duas colunas na view uma com o ISNULL e outra sem o ISNULL efetuar nenhuma alteração nela. Outra forma seria incluir outra coluna que faz parte da tabela Clientes no resultado da view e utilizar esta coluna.

Bom fica a dica.

Abraços

Categorias:Não categorizado

Novo artigo Simple Talk

18 de março de 2010 Deixe um comentário

Galera, saiu outro artigo que escrito pro ST,

Acessem lá…

http://www.simple-talk.com/sql/sql-tools/sql-server-intellisense-vs.-red-gate-sql-prompt/

Valeu

Categorias:Não categorizado

Fabiano vs DeadLock Paralelism

8 de fevereiro de 2010 4 comentários

Galera, espero que este post sirva como ajuda para quem vai para o google a procura de uma resposta…

Pergunta, pode ocorrer um erro de deadlock em um select ?

Resposta: Sim. Um deadklock ocorre quando uma sessão esta esperando para acessar um determinado recurso que esta sendo utilizado por outra sessão. Estes recursos podem ser locks, paralelismo, sessões em espera, ou uma combinação destes itens.

Meu problema foi justamente este de paralelismo, eu tenho uma consulta que estava utilizando paralelismo e as vezes ela apresentava o seguinte erro:

Transaction (Process ID 55) was deadlocked on thread | communication buffer resources with another process and has been chosen as the deadlock victim. Rerun the transaction.

Repare no item em negrito e veja que o recurso que esta sendo acessado é esse tal de “communication buffer” que é o que? Paralelismo.

Resumo da ópera, como não sou DBA do ambiente e não posso mexer e nem ver a cor do servidor onde o SQL está instalado, tive que apelar para um OPTION(MAXPDOP 1) na minha proc. Desta forma evito o paralelismo e por consequencia o deadlock.

Abraços

Categorias:Não categorizado

sys.fn_PhysLocFormatter(%%physloc%%)

3 de fevereiro de 2010 Deixe um comentário

Sensacional a dica do Paul Randal sobre uma nova function não documentada… quem já usou o DBCC Page para ver os dados gravados nas páginas sabe do que estou falando.

http://www.sqlskills.com/BLOGS/PAUL/post/SQL-Server-2008-New-%28undocumented%29-physical-row-locator-function.aspx

Pena que só funciona pro SQL2008.

Abraço

Categorias:Não categorizado

TOP 100

1 de fevereiro de 2010 1 comentário

Aqui estou, de volta a rotina, no ônibus a caminho de São Paulo… tempo para ler e escrever um pouco. Por falar em ler vou aproveitar para deixar uma dica ai pra vocês, caso gostem de leitura não deixem de aproveitar a oportunidade de comprar os livros da Série Deixados para Trás no Submarino, a série toda (13 livros) esta em promoção, não, não ganho nada com do Submarino, mas quem gosta de leitura tem que aproveitar… os livros são muito bons, eu li até o oitavo, agora comprei a série toda vou começar a ler tudo denovo… vale muito a pena.

Anyway, vamos logo ao assunto que interessa pra vocês SQL Server.

Entendendo o Problema

Quero compartilhar com vocês um problema bem interessante em uma consulta utilizando TOP e ORDER BY para tabelas com muitos registros.

O problema é o seguinte:  Tenho uma consulta que faz um TOP em uma tabela utilizando a clausula ORDER BY por uma coluna diferente da chave cluster. Quando uso TOP 100 o SQL utiliza 550mb de memória, 9875 de CPU e retorna a consulta em 40 segundos, quando uso TOP 101 o SQL utiliza 798mb de memória, 42745 de CPU e retorna a consulta em 1 minuto e 20 segundos.

A pergunta que não quer calar, porque a inclusão de apenas 1 registro degrada tanto o desempenho?

TOP <= 100 VS TOP > 100

Bom, vamos entender como eu cheguei à conclusão abaixo.

O Operador TOP aplica um SORT para limitar a quantidade de linhas de duas formas, uma utilizando um algoritmo otimizado para ordenar poucas linhas, e outro para ordenar muitas linhas que é o operador de sort normal que conhecemos.

Suponha uma consulta SELECT TOP <N> * FROM TABELA, caso o <N> for >= 100 então o QO utiliza o algoritmo otimizado se o TOP N for > que 100 então ele utiliza o SORT no tempdb. Li esta explicação neste link no connect.

Configuração Ambiente

Entendendo isso, fui realizar os testes para medir a performance, para fazer isso medi o uso CPU, Memória  e Tempo execução das consultas. Utilizei o Profiler para ler o uso de CPU e o Perfom para ler o contador “Total Server Memory”. A cada execução das consultas eu parava e iniciava o banco de dados para obter os valores de uso de memória.

Estou utilizando o SQL Server 2008 versão developer com Service Pack 1, e ele esta configurado para utilizar até 2 gb de memória. Segue a tela de configuração:

clip_image002

Como vocês podem observar nos prints abaixo, criei duas consultas. Ambas fazendo um select com TOP em uma tabela do meu banco de dados, a diferença entre as consultas é justamente o TOP 100 para o TOP 101.

Veja que para o primeiro plano de execução(TOP 100) o SQL Server reservou 1024 kb de memória, e para no segundo plano(TOP 101) ele reservou 224920 kbs de memória.

clip_image004

clip_image006

Veja o gráfico de memória utilizada pelo SQL Server ao rodar a primeira consulta. Repare que o SQL utilizou 553mb de memória e rodou a consulta em 44 segundos(veja no SSMS atrás do PerfMon).

clip_image008

clip_image010

 Agora veja a diferença para a segunda consulta com o TOP 101. Bem diferente não?

clip_image012

clip_image014

Bom galera fica ai a dica… Vale a pena ficar de olho nos TOPs que retornem mais de 100 registros…

Ok ok, eu sei que faltou um item aqui de Conclusão, masss estou cansado, vou tentar dormir um pouco, depois quem sabe não escrevo mais sobre isso?…

Abraços

Categorias:Não categorizado

Datas, Backups

27 de janeiro de 2010 1 comentário

Pessoal, post rápido…

Ontem tivemos um problema no banco de dados que estamos utilizando em ambiente de desenvolvimento. A empresa que fez e nos disponibilizou o backup do baco de dados, jurava que o backup havia sido feito no dia 09/01/2010 as 3 horas da manhã.

Bom para verificar quando o backup havia sido finalizado foi fácil, bastou acessar o servidor e verificar a coluna backup_finish_date da msdb.dbo.backupset. Lá identifiquei que o backup havia terminado as 00:24 e não as 03 como estavam falando.

Fica ai a dica, caso um dia precisem analisar quando um backup foi feito, existem algumas tabelas no banco msdb que gravam varias informações sobre os backups.

Abraço

Categorias:Não categorizado