Lição 3: Aplicando funções de rank

julho 2, 2011

 

As funções de rank são utilizadas para prover uma simples visão analítica como também uma ordenação estatística ou segmentação.

Classificando dados

Há quatro funções de rank disponíveis no SQL Server, são elas: ROW_NUMBER, RANK, DENSE_RANK E NTILE.

ROW_NUMBER retorna um número de 1 a n baseado na ordenação definida pelo usuário. Caso haja valores duplicados o ROW_NUMBER irá atribuir uma nova numeração, ignorando a repetição.

SELECT P.FirstName
            ,P.LastName
            ,ROW_NUMBER() OVER(ORDER BY S.SalesYTD DESC) AS ‘RowNumber’
            ,S.SalesYTD, A.PostalCode
FROM  Sales.SalesPerson S INNER JOIN Person.Person P
           ON S.BusinessEntityID = P.BusinessEntityID
       INNER JOIN Person.BusinessEntityAddress BA ON P.BusinessEntityID = BA.BusinessEntityID
        INNER JOIN Person.Address A ON A.AddressID = BA.AddressID
WHERE S.TerritoryID IS NOT NULL

image

Você pode utilizar o ROW_NUMBER com um agrupamento para que a numeração seja feita de acordo com os grupos. Para conseguir esse resultado você precisará utilizar a cláusula opcional PARTITION BY.

SELECT P.FirstName
,P.LastName
,S.TerritoryID,ROW_NUMBER() OVER(PARTITION BY S.TerritoryID ORDER BY S.SalesYTD DESC) AS ‘RowNumber’
,S.SalesYTD, A.PostalCode
FROM Sales.SalesPerson S INNER JOIN Person.Person P
ON S.BusinessEntityID = P.BusinessEntityID
INNER JOIN Person.BusinessEntityAddress BA ON P.BusinessEntityID = BA.BusinessEntityID
INNER JOIN Person.Address A ON A.AddressID = BA.AddressID
WHERE S.TerritoryID IS NOT NULL

image

Se você quiser numerar o resultado em camadas você precisará utilizar o RANK, caso não haja camadas o RANK produzirá o mesmo resultado do ROW_NUMBER.

Caso haja camadas o RANK irá repetir a mesma numeração para cada linha, deixando uma lacuna na sequência numérica correspondente ao número de linhas da camada.

SELECT A.ProductID
        ,B.Name
        ,A.LocationID
        ,A.Quantity
        ,RANK() OVER(PARTITION BY A.LocationID ORDER BY a.Quantity DESC) AS ‘Rank’
FROM Production.ProductInventory A INNER JOIN  Production.Product B
            ON A.ProductID = B.ProductID
ORDER BY B.Name

image

SELECT A.ProductID
,B.Name
,A.LocationID
,A.Quantity
,RANK() OVER(PARTITION BY A.LocationID ORDER BY a.Quantity DESC) AS ‘Rank’
FROM Production.ProductInventory A INNER JOIN Production.Product B
ON A.ProductID = B.ProductID
ORDER BY A.LocationID,‘Rank’

image

Caso não queira lacunas na numeração você pode utilizar a função DENSE_RANK. DENSE_RANK atribui o mesmo valor para cada valor duplicado mas não deixa lacuna na sequência numérica.

SELECT A.ProductID
,B.Name
,A.LocationID
,A.Quantity
,DENSE_RANK() OVER(PARTITION BY A.LocationID ORDER BY a.Quantity DESC) AS ‘DenseRank’
FROM Production.ProductInventory A INNER JOIN Production.Product B
ON A.ProductID = B.ProductID
ORDER BY A.LocationID,‘DenseRank’

 

image

NTILE divide o resultado da consulta em grupo, por exemplo , se você quiser  dividir um resultado  em quatro grupos com o aproximadamente o mesmo número de linhas em cada grupo, você pode utilizar o NTILE(4).

SELECT P.FirstName
            ,P.LastName
            ,NTILE(4) OVER(ORDER BY S.SalesYTD DESC) AS ‘Grupo’
            ,S.SalesYTD, S.TerritoryID
FROM  Sales.SalesPerson S INNER JOIN Person.Person P
            ON S.BusinessEntityID = P.BusinessEntityID
        INNER JOIN Person.BusinessEntityAddress BA ON P.BusinessEntityID = BA.BusinessEntityID
       INNER JOIN Person.Address A ON A.AddressID = BA.AddressID
WHERE S.TerritoryID IS NOT NULL

image

 

SELECT P.FirstName
,P.LastName
,NTILE(2) OVER(PARTITION BY S.TerritoryID ORDER BY S.SalesYTD DESC) AS ‘Grupo’
,S.SalesYTD, S.TerritoryID
FROM Sales.SalesPerson S INNER JOIN Person.Person P
ON S.BusinessEntityID = P.BusinessEntityID
          INNER JOIN Person.BusinessEntityAddress BA  ON   P.BusinessEntityID = BA.BusinessEntityID
          INNER JOIN Person.Address A ON A.AddressID = BA.AddressID
WHERE S.TerritoryID IS NOT NULL                                                     ORDER BY S.TerritoryID, ‘Grupo’

image

 

Dica para o exame

Você precisa entender a diferença entre os quatro funções de rank e quando produzem o mesmo resultado.

 

Quick Check

1 – Qual a diferença entre RANK e DENSE_RANK?

2 – Quando o ROW_NUMBER, RANK e DENSE_RANK produzem o mesmo resultado?

Respostas:

1 – RANK atribui o mesmo valor para as camadas porém deixa lacunas na sequência numérica. DENSE_RANK atribui o mesmo valor para as camadas e não deixa lacunas na sequência.

2-ROW_NUMBER, RANK e DENSE_RANK produzem o mesmo resultado quando as colunas ordenadas não possuem valores duplicados.


Lição 2: Implementando SubConsultas

junho 26, 2011

 

As subconsultas são úteis para construir consultas complexas e para obter resultados que antes pareciam impossíveis.

Existem dois tipos de subconsultas:

Correlacionada:  é uma consulta que depende e faz referência às colunas da consulta externa a qual está contida.

Não correlacionada: é uma consulta independente da consulta externa na qual está contida.

Ambos os tipos de subconsultas podem retornar uma ou mais linhas. Quando o retorno é escalar, somente um valor,  pode ser definido em qualquer lugar de dentro do SELECT onde um ou zero valores são esperados, quando o retorno é múltiplo a subconsulta pode ser utilizada em onde o resultset é esperado.

 

Consultas não correlacionadas

O principal objetivo de consultas não correlacionadas é permitir a escrita de códigos mais dinâmicos. Por exemplo, você precisa listar os produtos onde o nome da categoria inicia com a letra C, porém você desconhece todas as subcategorias necessárias para especificar na cláusula where, veja o exemplo abaixo:

SELECT P.Name, P.Color
FROM Production.Product P
     INNER JOIN Production.ProductSubcategory S
       ON P.ProductSubcategoryID = S.ProductSubcategoryID
WHERE S.ProductCategoryID IN( SELECT C.ProductCategoryID       FROM Production.ProductCategory C
WHERE Name LIKE ‘C%’)

Outro exemplo, supondo que você gostaria de retornar todos os produtos onde o preço de lista está acima da média geral, ao invés de obter o valor e armazenar em uma variável, você pode fazer como no exemplo abaixo:

 
SELECT A.ProductID, A.Name, A.ListPrice
FROM Production.Product A
WHERE A.ListPrice> (
SELECT AVG(B.ListPrice)
                    FROM Production.Product B
)
 
Tabelas derivadas 

Ao invés de armazenar dados em tabelas temporárias para fazer joins e retornar um determinado conjunto de resultados, você pode utilizar as tabelas derivadas.

Tabelas derivadas são consultas realizadas dentro da clausula from de uma consulta externa, é necessário que todos os campos calculados sejam nomeados, a consulta deve estar contida entre parênteses e possuir um apelido.

Veja o exemplo abaixo:

 
SELECT B.BusinessEntityID, B.JobTitle, A.QtdeLinhas
FROM (SELECT E.JobTitle, COUNT(*) QtdeLinhas
      FROM HumanResources.Employee E

      GROUP BY JobTitle) A

INNER JOIN HumanResources.Employee B on A.JobTitle=B.JobTitle

O príncipal benefício de uma tabela derivada é o fato de que o resultado está armazenado inteiramente na memória, resultando em um ganho de desempenho.

Agrupamentos

Você pode realizar agrupamentos dentro de tabelas derivadas e combiná-los externamente.

Como no exemplo abaixo:

SELECT SH3.SalesPersonID,SH3.OrderDate, SH3.DailyTotal, SUM(SH4.DailyTotal) RunningTotal
FROM    (SELECT SH1.SalesPersonID, SH1.OrderDate, SUM(SH1.TotalDue) DailyTotal
                FROM Sales.SalesOrderHeader SH1
                WHERE SH1.SalesPersonID  IS NOT NULL
                GROUP BY SH1.SalesPersonID, SH1.OrderDate) SH3
INNER JOIN  (SELECT SH2.SalesPersonID, SH2.OrderDate, SUM(SH2.TotalDue) DailyTotal
                FROM Sales.SalesOrderHeader SH2
                WHERE SH2.SalesPersonID  IS NOT NULL
                GROUP BY SH2.SalesPersonID, SH2.OrderDate)SH4
ON SH3.SalesPersonID = SH4.SalesPersonID
    AND SH3.OrderDate>SH4.OrderDate
GROUP BY SH3.SalesPersonID, SH3.OrderDate, SH3.DailyTotal
ORDER BY SH3.SalesPersonID, SH3.OrderDate

As tabelas derivadas foram combinadas para retornar todos os pedidos de um vendedor que possuir mais de um pedido por dia. O join por SalesPersonID (vendedor) assegura que você esta acumulando linhas do mesmo vendedor. O join sem igualdade determina que somente os pedidos do vendedor onde data do pedido é anterior à data do pedido dentro do resultset serão retornados.

 

Consultas correlacionadas

As consultas correlacionadas dependem de valores da consulta externa. No exemplo abaixo será listado o Id do Produto e o preço de lista, porém será retornado apenas os produtos que já foram vendidos anteriormente.

SELECT a.ProductID, a.ListPrice 
FROM Production.Product A
WHERE EXISTS (SELECT 1 FROM Sales.SalesOrderDetail B
WHERE B.ProductID=A.ProductID)

Usando um Join ou uma cláusula where será retornado o produto para cada vez que ele foi vendido, já o comando EXISTS provém melhor desempenho, pois procura será por uma única ocorrência na tabela.

 

[]’s

Andressa Alves Martins

Twitter: Dre_Martins Skype: Dre.alvesm

Blog: http://sqlgo.wordpress.com


Lição 1: Construindo consultas recursivas com CTE

junho 1, 2011

 

O conceito de CTE é muito similar a tabelas derivadas, porém com CTEs você pode cruzar com outros resultados para resolver um ou mais problemas, executando consultas recursivas.

 

Expressão de Tabela Comum (Common Table Expressions)

 

Sintaxe:

WITH – Cláusula onde contém o comando válido de select.

Select – Consulta que será realizada utilizando a CTE.

 

WITH EmpTitle AS

(SELECT JobTitle, COUNT(*) NumTitles

FROM HumanResources.Employee

GROUP BY JobTitle)

 

SELECT b.BusinessEntityID, b.JobTitle, a.NumTitles

FROM EmpTitle a INNER JOIN HumanResources.Employee b ON b.JobTitle = a.JobTitle

GO

 

Uma CTE recursiva expande a definição de uma expressão de tabela e consiste em duas partes:

– Uma consulta âncora, que é a fonte da recursividade, juntamente com a declaração “UNION ALL” e uma segunda consulta.

– Uma consulta externa que referencia a rotina e especifica o numero de níveis de recursão.

Por exemplo, a consulta abaixo permite que você especifique um employee e retorna  os niveis da gerencia acima desse empregado na organização, com um limite de 25 niveis de organização.

 

DECLARE @EmployeeToGetOrgFor INT=126;

WITH EMP_cte(BusinessEntityID, OrganizationNode, FirstName, LastName, JobTitle, RecursionLevel)

AS (SELECT E.BusinessEntityID, E.OrganizationNode, P.FirstName, P.LastName, E.JobTitle, 0

       FROM HumanResources.Employee e INNER JOIN Person.Person AS p

           ON P.BusinessEntityID = E.BusinessEntityID

       WHERE E.BusinessEntityID = @EmployeeToGetOrgFor

  UNION ALL

      SELECT E.BusinessEntityID, E.OrganizationNode, P.FirstName, P.LastName,     E.JobTitle, RecursionLevel+1

    FROM HumanResources.Employee E INNER JOIN EMP_cte

           ON E.OrganizationNode = EMP_cte.OrganizationNode.GetAncestor(1)

       INNER JOIN Person.Person P ON P.BusinessEntityID = E.BusinessEntityID)

 

SELECT EMP_cte.RecursionLevel, EMP_cte.BusinessEntityID, EMP_cte.FirstName, EMP_cte.LastName,   EMP_cte.OrganizationNode.ToString() AS OrganizationNode,

P.FirstName AS ‘ManagerFirstName’, P.LastName AS ‘ManagerLastName’

FROM EMP_cte INNER JOIN HumanResources.Employee E

                         ON EMP_cte.OrganizationNode.GetAncestor(1) = E.OrganizationNode

                      INNER JOIN Person.Person P ON P.BusinessEntityID = E.BusinessEntityID

ORDER BY RecursionLevel,EMP_cte.OrganizationNode.ToString()

OPTION (MAXRECURSION 25);

 

image

 

A primeira consulta com a cláusula WITH define o resultado ancora. A segunda consulta executada recursivamente até o nível máximo de recursão contra a consulta âncora.

A recursividade é realizada pelo INNER JOIN na CTE:

INNER JOIN EMP_cte

A consulta externa é então utilizada para retornar o resultado da operação recursiva enquanto dados adicionais são necessários. A cláusula “OPTION” especifica o número máximo de níveis de recursão serão permitidos.

Dica para o exame:

Caso haver um bloco de comando antes da palavra chave “WITH” utilizar “;” para finalizar o bloco de comando anterior.

 

[]’s

Andressa Alves Martins

Twitter: Dre_Martins Skype: Dre.alvesm

Blog: http://sqlgo.wordpress.com


Lição 2: Declarativa de Integridade de dados

maio 25, 2011

 

Validação de dados é uma das rotinas mais comum de um desenvolvedor.

Validação de dados

Há duas formas de validar a integridade dos dados, usando a integridade de dados declarativa ou integridade de dados procedural.

Integridade de dados declarativa é um conjunto de regras que são aplicadas a uma tabela e suas colunas utilizando o comando ALTER TABLE e CREATE TABLE. Essas regras são conhecidas como constraints.

A integridade de dados procedural é implementada através de procedures com validações de dados ou de triggers que checam os dados.

Como implementar a Integridade de dados

Há cinco tipos de constraints, PRIMARY KEY, FOREIGN KEY, CHECK, UNIQUE e DEFAULT.

PRIMARY KEY e UNIQUE constraints

Uma coluna ou uma combinação de colunas criam um identificador único para uma linha, que é reforçada pela criação de um índice único e não aceita duplicidade. Devido a isso primary key e unique constraints possuem a mesma limitação de tamanho como uma chave ou índice, ou seja, não pode haver mais de 16 colunas ou 900 bytes de dados.

Quando nada é especificado o índice criado é clustered e o índice para um unique é do tipo non-clustered. Você pode alterar esse comportamento especificando o tipo de index, veja o exemplo:

–Primary key as clustered index

ALTER TABLE MyTable

ADD PRIMARY KEY (MyTableId)

–Primary key as a nonclustered index

ALTER TABLE MyTable

ADD PRIMARY KEY NONCLUSTERED (MyTableId)

FOREIGN KEY constraints

 

FOREIGN KEY constraints

Foreign key constraint identifica uma coluna ou combinação de colunas que devem existir na mesma tabela ou em outra tabela. A foreign key constraint gerencia a integridade referencial entre duas tabelas ou apenas uma. Para implementar uma foreign key constraint você deve seguir essas regras:

– As colunas referenciadas devem ter o mesmo tipo de dados nos dois locais.

– As colunas referenciadas devem possuir um índice único.

Devido ao índice único, as colunas da foreign key devem respeitar a mesma limitação da primary key.

Quando ocorre uma violação de integridade referencial devido a um delete ou update a linha em questão retorna uma mensagem de erro e desfaz o comando que provocou o erro. Você pode definir qual ação o SQL Server deve realizar nesses casos, veja abaixo:

– NO ACTION – Comportamento padrão do SQL Server, desfaz a ação e retorna um erro.

– SET NULL – Altera os valores referenciados para NULL, não retorna erro.

– SET DEFAULT – Altera os valores referenciados para o valor default da coluna, não retorna erro.

– CASCADE – Exclui linhas referenciadas em um comando delete (ON DELETE) e atualiza linhas referenciadas em um comando update (ON UPDATE), não retorna erro.

Veja como implantar essas ações:

 

CREATE TABLE Customers (

        CustomerID INT PRIMARY KEY );

CREATE TABLE Orders (

        OrderID INT PRIMARY KEY

        ,CustomerID INT NULL

               REFERENCES Customers

                  ON DELETE SET NULL

                  ON UPDATE CASCADE );

 

CHECK CONSTRAINTS

Check constraints são uma série de regras que validam o dado antes de incluir na coluna. Veja algumas vantagens:

– São de fácil implementação.

– São verificadas automaticamente.

– Podem melhorar a performance.

Veja o script de uma simples check constraint que verifica se o preço do produto não é negativo:

ALTER TABLE Products

ADD CHECK (Price>=0.0);

Essa simplicidade é uma grande vantagem sobre as triggers, porém há algumas desvantagens:

– As mensagens de erro são geradas automaticamente e não podem ser substituida.

– Uma check constraint não pode “enxergar” o valor anterior da coluna.

Você pode enriquecer a check constraint utilizando funções de usuário, utilizando T-SQL ou ainda utilizar funções CLR (tanto em C# quanto em VB)

CHECK E FOREIGN KEY CONSTRAINTS VS. QUERY PERFORMANCE

Check e foreign key podem melhorar a performance, pois ambos são regras que o optimizer pode usá-los para criar planos de execução mais eficientes, o código abaixo é um simples exemplo de como isso acontece:

CREATE TABLE Customers (

                CustomerID INT PRIMARY KEY );

CREATE TABLE Orders (

               OrderID INT PRIMARY KEY

               ,CustomerID INT NOT NULL

                    CONSTRAINT FK_OrdersCustomers

                            REFERENCES Customers(CustomerID) );

Para entedermos melhor o que o SQL Server faz quando executa a consulta selecione a opçao Include Actual Execution Plan ou pressione Ctrl+M.

SELECT o.* FROM Orders AS o

WHERE

         EXISTS (SELECT * FROM Customers AS c

             WHERE c.CustomerID = o.CustomerID);

Perceba pelo plano de execução que a tabela Customers não foi acessada, apenas a tabela Orders, isto porque o optimizer sabe ela que não é necessaria para o operado EXISTS porque a foreign key constraint requer que todos os pedidos (orders) possuem referência com um cliente (customer), que é o que a cláusura where verifica.

 

clip_image001

 

Agora desabiliete a foreign key:

ALTER TABLE Orders NOCHECK CONSTRAINT FK_OrdersCustomers;

Execute a mesma consulta novamente e perceba que nesse caso o optimizer executa o operador EXISTS. Devido a foreign key constraint estar desabilitada o SQL Server não pôde ter certeza que todos os pedidos possuem clientes válidos. Em tabelas grandes isso pode fazer uma grande diferença.

clip_image002

Para habilitar novamente a utilize o seguinte código:

ALTER TABLE Orders CHECK CONSTRAINT FK_OrdersCustomers;

ALTER TABLE Orders

     WITH CHECK

       CHECK CONSTRAINT FK_OrdersCustomers

 

[]’s

Andressa Alves Martins

Twitter: Dre_Martins Skype: Dre.alvesm

Blog: http://sqlgo.wordpress.com


Lição 1: Trabalhando com Tabelas e Tipos de Dados

maio 17, 2011

 

Modelar, criar e manter tabelas é uma das funções mais importantes de um desenvolvedor de banco de dados.

Tipos de Dados

Antes de criar uma tabela você precisa entender as diferenças entre os tipos de dados que você pode utilizar em uma coluna. Há dois tipos diferentes de tipos de dados no Sql Server:

  • Tipos de dados de sistema.
  • Tipos de dados de usuários (User-Defined types – UDTs) ou Sql Common Language Runtime (CLR).

Cadeias de Caracteres

Existem alguns tipos de dados string no Sql Server, são eles: char, varchar, nchar, nvarchar, text, ntext.

A diferença entre char e varchar (assim como nchar e nvarchar) é fato do char possuir tamanho fixo e varchar tamanho variável, ou seja char sempre aloca o espaço suficiente em disco para armazenar o tamanho declarado e varchar armazena apenas o tamanho do dado inserido. A vantagem de utilizar char é que as atualizações feitas na coluna nunca requer o deslocamento da linha pois os dados inseridos sempre utilizam o mesmo tamanho, em contra partida varchar aloca muito menos espaço do que char.

Para os tipos de dados char e varchar a collation é utilizada para especificar o code page (conjunto de caracteres) do conteúdo da coluna. A collation também é utilizada para definir como ordenar e comparar os dados armazenados. A nomenclatura da collation especifica algumas características:

  • CI – Case Insensitive
  • CS – Case Sensitive
  • AI – Accent Insensitive
  • AS – Accent Sensitive

Nchar e nvarchar armazenam caracteres utilizando o Unicode universal code page (UCS-2). 

 

Tipos numéricos exatos

Os números numéricos exatos são inteiros ou decimais, produzem o mesmo resultados exceto pelo processamento ou pela magnetude (tamanho) dos números.

cbcpt5ok

 

Tipos numéricos aproximados

O sql server suporta dois tipos numéricos com pontos flutuantes o real e o float, assim como o decimal, ambos aceitam parâmetros. Os parâmetros definem o numero de bits que será utilizado para armazenar o dado.

image

 

Manipulando Data e Hora

A tabela abaixo possui um breve resumo sobre os tipos de dados de data e hora.

image

É necessário entender as diferenças entre smalldatetime e datetime pois há dois grandes problemas, um deles é que a hora e dia são armazenados juntos e isso precisa ser levado em consideração, veja o exemplo a seguir:

SELECT SalesOrderID

             ,CustomerID

             ,OrderDate

FROM Sales.SalesOrderHeader

WHERE OrderDate=‘20080818’

A Consulta apenas retorna pedidos realizados no dia 18/08/2008 exatamente as 00:00:00. Para resolver esse problema você precisa especificar o horário na consulta, como nos exemplos abaixo:

–Query #1

SELECT SalesOrderID ,CustomerID ,OrderDate

FROM Sales.SalesOrderHeader

WHERE OrderDate BETWEEN ‘2008-08-18T00:00:00’ and ‘2008-08-18T23:59:59.997’

 

–Query #2

SELECT SalesOrderID ,CustomerID ,OrderDate

FROM Sales.SalesOrderHeader

WHERE OrderDate>=‘20080818’ and OrderDate <‘20080819’

 

Ambas consultas produzem o mesmo resultado, porém considere utilizar o segundo exemplo pois o mesmo atende tanto datetime quanto datetime2.

O tipo de dados time aceita um parâmetro para especificar a precisão ou número de decimais por fração de segundo. Quando o parâmetro não é especificado a precisao é de 7 casas decimais.

 

Tabelas Básicas

No Sql Server há três tipos de variações de tabelas: permanentes, temporárias locais e temporárias globais, além dessa variações temos os tipos de tabelas e parâmetros da tabela.

 

Criando uma tabela

Antes de criar uma tabela é necessario especificar o schema. Schema é similar a namespace em diversas linguagens de programação, o Sql Server possui os schemas sys para objetos de sistema e dbo para novos objetos.

CREATE SCHEMA Sales;

GO 

CREATE TABLE Sales.Customers(

CustomerId INT NOT NULL,

Name NVARCHAR(50) NOT NULL);

Tabelas também podem ser criadas a partir de uma query utilizando o comando select into:

SELECT * INTO Sales.Customers_Copy from Sales.Customers

 

Nomenclatura de colunas e tabelas

Ambos, tabelas e colunas, são identificadores e precisam obedecer algumas regras de nomenclatura:

Identificadores Padrão (Standard)

  • O primeiro caracteres deve ser letra ou underscore (_).
  • Caracteres seguintes podem ser dígitos, @, $, # e _.
  • Não deve ser uma palavra reservada do T-SQL.
  • Espaços em branco não são aceitos.

 

Identificadores Delimitados

As mesmas caracteristas do Standard, com exceto que voce pode criar nomes com espaço em banco utilizando as aspas (“”) ou colchetes ([]). Precisa estar setado como ON a propriedade QUOTED_IDENTIFIER.

 

Criando a tabela

Agora vamos criar uma tabela, veja o exemplo:

CREATE TABLE HR.Employees(

EmployeeID INT IDENTITY(1000,2) NOT NULL

,FirstName NVARCHAR(50) NOT NULL

,LastName NVARCHAR(50) NOT NULL

,PhoneNumber VARCHAR(15) NULL

,BirthDate DATE NOT NULL );

Esse código cria a tabela Employees com cinco colunas. Podemos especificar o schema que será utilizado, nesse caso HR.

As colunas são definidas utilizando três propriedades básicas: nome da

coluna, tipo de dado e nullabilidade (se a coluna aceita null o ou não).

 

Nomenclatura

Ao escolher a nomenclatura de tabelas e colunas é importante seguir o padrão da organização ou algumas diretrizes. São elas:

  • Utilize PascalCasing (também conhecido como Camel Casing).
  • Evite abreviações.
  • Longos nomes que usuários entendem são preferíveis a nomes curtos que podem não ser entendidos.

 

Escolhendo Tipos de dados

A escolha do tipo de dado certo para cada coluna é muito importante, para ajudá-lo segue algumas diretrizes que você pode seguir:

  • Sempre utilize um tipo de dado que utilizar o mínimo de espaço em disco.
  • Mudar o tipo de dados posterior à criação da tabela pode ser muito custoso, não utilize um tipo de dado se o mesmo não atende as necessidades da aplicação.
  • Sempre que possível utilize tipos de dados com tamanho variável, como nvarchar e varchar.
  • Um dos poucos casos em que o char e nchar são indicados é quando o valor da coluna requer alteração constante, nesse caso o custo de mover a linha com tamanho variável é maior do que a com tamanho fixo.
  • Evite o uso dos tipos datetime e smalldatetime, pois ambos ocupam mais espaço em disco e provem menos precisão do que os tipos datetime2, date e time.
  • Utilize varchar (Max), nvarchar (Max) e varbinary (Max) ao invés de text, ntext e image, pois poderão ser descontinuados em futuras versões.
  • Use o tipo de dado rowversion ao invés de timestamp, pois poderá ser descontinuado em futuras versões.
  • Somente Utilize varchar (max), nvarchar(max) e varbinary(max) e xml, quando não há como especificar a quantidade de caracteres a ser utilizada, pois esses campos não podem ser utilizados para índices.
  • Use float e real apenas quando a precisão do decimal for insuficiente.

 

Nulo ou Não Nulo?

Você nunca deve utilizar valores no lugar do nulo (ex –1 para inteiro), isso pode causar problemas futuramente. Nulo é um valor desconhecido e será diferente de –1, em uma função de agregação, por exemplo, AVG, o –1 é incluso no cálculo e o nulo não.

 

Identity

Todas tabelas possuem uma coluna ou um conjunto de colunas que identificam a linha, a primary key . Não é fácil definir uma boa coluna para ser a primary key , pois esses dados podem variar com frequência. Para contornar essa situação você pode utilizar uma coluna que gere automaticamente uma chave. O comando IDENTITY é utilizado para determinar uma coluna por tabela onde o valor será acrescido ou decrescido automaticamente quando um valor novo é inserido, esse campo não aceita valores nulos.

Sintaxe:

CREATE TABLE HR.Employees(

EmployeeID INT IDENTITY(1000,2) NOT NULL

,FirstName NVARCHAR(50) NOT NULL

,LastName NVARCHAR(50) NOT NULL

,BirthDate DATE NOT NULL

);

A numeração irá iniciar do 1000 e será acrecido de 2 em 2,  o ser valor negativo também.

A propriedade IDENTITY  não poderá ser utilizada em um campo já existente, somente em campos novos.

Quando um insert  falha a coluna dará sequencia para o próximo valor, veja no exemplo:

clip_image002

 

Compressão

Na versão SQL Server 2008 Enterprise, você pode comprimir dados em tabelas e índices, essa compressão pode ser implementada em dois níveis: linha e página.

ALTER TABLE HR.Employees

REBUILD

WITH (DATA_COMPRESSION=PAGE);

Quando a compressão de dados é ativada, o SQL Server irá converter todos os tipos de dados para variable-length. Quando há mais tipos de dados de tamanho fixo (como Datetime2, int, decimal e char), utilize o nível de compressão por linha.

Compressão a nível de pagina inclui a compressão a nível de linha e utiliza um dicionário de paginas com os prefixos das colunas a fim de evitar redundância de dados. Considerando o exemplo abaixo:

Linha 01 | Andressa Martins

Linha 02 | Lucas Romão

Linha 03 | Andressa Martins

 

Utilizando o dicionário de pagina os dados serão armazenados assim:

Linha 01 | Andressa Martins

Linha 02 | Lucas Romão

Linha 03 | 01

 

[]’s

Andressa Alves Martins

Twitter: Dre_Martins Skype: Dre.alvesm

Blog: http://sqlgo.wordpress.com


Lição 3: GerenciandoTransações (Parte 2)

abril 28, 2011

 

Para evitar acessos múltiplos ao mesmo recurso o banco de dados utiliza um recurso chamando LOCK. O controle de concorrência do Sql Server é classificado como otimista ou pessimista.

Pessimista – Permite acesso para leitura e atualização do mesmo dado em concorrência, bloqueios são utilizados para prevenir problemas devido aos múltiplos acessos ao dado.

Otimista – Não há bloqueio de recurso durante a leitura, no caso de atualização, o sistema verifica o dado foi alterado antes de lido.

 

Entendendo bloqueios (locks)

O SQL Server pode bloquear diferentes tipos de recursos ou granularidades, esses tipos podem ser RID (Row Identifier), página, índices, objetos e banco de dados.

Modos de bloqueios:

Shared (S) – Bloqueio utilizado em consultas, compatível com outros bloqueios compartilhados.

Update (U) – Bloqueio utilizado em recursos que podem ser atualizados, apenas uma transação por vez pode obter o Update lock no recurso.

Exclusive (X) – Bloqueio utilizado para modificação de dados, ex: INSERT, UPDATE, ou DELETE, incompatível com outros bloqueios

Intent (IS, IX, SIX) – Executa um bloqueio de objeto de alto nível (ex:table) antes de realizar um bloqueio exclusive (X) ou shared (S) no baixo nível (ex: página).

Schema (Sch-M, Sch-S) – Bloqueio utilizado quando uma operação dependente do esquema de uma tabela está em execução. Há dois bloqueios, o schema modification (Sch-M) e o schema stability (Sch-S), os dois são incompatíveis entre si.

Bulk Update (BU) – Bloqueio utilizado ao copiar massa de dados dentro de uma tabela e quando TABLOCK é especificado.

Key-Range – Bloqueio utilizado para evitar inserções/exclusões fantasmas ou exclusões em um conjunto de registros acessados ​​por uma transação. Esse bloqueio é utilizando transações que operam no nível de isolamento serializável.

 

Entendendo cenários de Deadlock e Blocking

As transações podem bloquear uma a outra, isso pode ocorrer de acordo com o nível de isolamento utilizado.

Uma situação de Deadlock ocorre quando uma transação “A” aguarda a liberação de um recurso bloqueado pela transação “B” que por sua vez aguarda uma liberação de um recurso bloqueado pela transação “A”. Para resolver esse impasse o Sql Server baseado no custo estimado de Rollback “derruba” uma das transações, essa transação é chamada de vítima.

Melhores práticas para evitar Deadlock:

– Faça transações curtas

– Obtenha e verifique os dados de entrada antes de iniciar uma transação.

– Mantenha as transações em um único batch

– Acesse a quantidade mínima possível de dados em uma transação.

 

Entendendo relatórios sobre o estado do bloqueio

Há diversas opções para visualizar o status de um bloqueio em um servidor de Sql Server. São eles Sql Profiler, System Monitor (perfom), Dmv’s e Activity Monitor.

 

Sql Server Profiler

Captura informações de locks e blocks. O Profiler disponibiliza um template já apropriado para detecção de bloqueios.

clip_image002

 

Activity Monitor

Utilize o Activity Monitor para visualizar dados de bloqueios, usuários, conexões e etc.

clip_image004

 

DMV’s

As DMV’s provém informações detalhadas sobre todos os bloqueios ativos.

Segue alguns exemplos.

 

SELECT *

FROM sys.dm_tran_active_transactions

 

clip_image006

 

SELECT Resource_type,Request_mode, Request_status,request_owner_type

FROM sys.dm_tran_locks

 

clip_image008

 

Tipos de recursos

 

RID (Row Identifier) – Linha física em um Heap.

KEY – Linha em um índice.

PAGE – Página em um arquivo de dados.

EXTENT – Uma extensão de arquivo de dados. Uma extensão é um grupo de oito páginas contíguas.

HoBT – Bloqueio em um Heap de uma página de dados ou na estrutura B-tree de um índice.

TABLE – Uma tabela.

FILE – Um arquivo de banco de dados.

APPLICATION – Um recurso de aplicativo especificado.

METADATA – Informações de metadados.

ALLOCATION_UNIT – Uma unidade de alocação.

DATABASE – Um banco de dados

 

Utilizando Sql Server Extended Events

Esse recurso está incluso no Sql Server 2008, assim como FindBlocker and lock_count que podem ser utilizados em conjunto com o Windows Event Logs, Sql Profiler ou System Monitor.

 

Usando DBCC LOG

Comando não documentado o qual retorna informações sobre o transaction log.

Sintaxe:

DBCC LOG (<databasename>,<output identifier>)

 

Níveis de output identifier

0: Retorno apenas o mínimo de informações para cada operação – incluindo operation, context, transactID, e log block generation.

1: Retorna toda as informações do nível acima, incluindo flags e record length information

2: Retorna toda as informações do nível acima, incluindo Object name, index name, page ID e slot ID.

3: Retorna todas as informações sobre a operação.

4: Retorna todas as informações sobre a operação, incluindo o hex dump da linha atual de log de transações.

 

DBCC LOG (’70_433′,1)

clip_image010

 

Definindo Níveis de Isolamento de Transações

Os seguintes níveis podem ser definidos através do comando SET TRANSACTIONS ISOLATION LEVEL:

 

READ UNCOMMITTED Nível mais baixo de isolamento, permite leitura de transações não confirmadas (leitura suja)

READ COMMITTED – Nível de baixo de isolamento, porém só permite leitura de transações confirmadas.

REPEATABLE READ- Não permite leitura de transações não confirmadas e realiza um bloqueio compartilhado em um recurso de dados.

SNAPSHOT – Requer ALLOW_SNAPSHOT_ISOLATION setada com ON Não permite leitura de transações não confirmadas, quando a transação é iniciada o banco de dados obtém um snapshot dos dados confirmados.

SERIALIZABLE – Esse é o mais restritivo dos níveis de isolamento, pois ele bloqueia intervalos de chaves inteiros até que a transação seja concluída.

 

 

[]’s

Andressa Alves Martins

Twitter: Dre_Martins Skype: Dre.alvesm

Blog: http://sqlgo.wordpress.com


Lição 3: GerenciandoTransações (Parte 1)

abril 26, 2011

Transações podem ser definidas como um conjunto de ações e podem ser realizadas com sucesso ou não. São importantes para garantir a integridade e consistência dos dados em um banco de dados OLTP (Online Transaction Processing).

Entendendo Transações

As transações fornecem quanto principais funções (ACID):

Atomicidade – Uma transação deve ser uma unidade atômica de trabalho ou todas as suas modificações de dados são executadas ou nenhuma delas é executada.

Consistência – Quando concluída, uma transação deve deixar todos os dados em um estado consistente.

Isolamento – Modificações feitas por transações simultâneas devem ser isoladas das modificações feitas por qualquer outra transação simultânea.

Durabilidade – Depois que uma transação tiver sido concluída, seus efeitos ficam permanentemente no sistema. As modificações persistem até mesmo no caso de uma queda do sistema.

Definindo transações explicitas

Uma transação explicita inicia quando o comando BEGIN TRANSACTION é executado e finaliza quando o é executado um dos seguintes comandos COMMIT TRANSACTION ou ROLLBACK TRANSACTION.

Entendendo cenários especiais de ROLLBACK

Quando há transações aninhadas na mesma sessão, um comando ROLLBACK desfaz a transação aninhada. Isso acontece quando um comando COMMIT é executado antes do comando ROLLBACK. No exemplo a os dados são revertidos a primeira linha.

BEGIN TRANSACTION
INSERT
INTO TestTable
VALUES (1,‘a’,‘b
);

BEGIN TRANSACTION
UPDATE TestTable
SET Col2=‘c’
WHERE
Id = 1
    COMMIT TRANSACTION
ROLLBACK

Caso queira desfazer apenas uma parte da transação você pode definir savepoints usando o comando SAVE TRANSACTION nome_do_SavePoint, dessa forma a transação será desfeita até o último savepoint. Vale lembrar que você precisa definir o COMMIT.

Obtendo informação sobre transações

Quando trabalhamos com transações em stored procedures, tratamentos de erros devem ser realizados antes de fechar uma conexão.

Você pode utilizar o comando @@trancount para verificar a quantidade de transações ativas na sessão.

Para obter mais detalhes consulte as DMV’s abaixo:

sys.dm_tran_active_snapshot_database_transactions
sys.dm_tran_active_transactions
sys.dm_tran_current_snapshot
sys.dm_tran_current_transaction
sys.dm_tran_database_transactions
sys.dm_tran_locks
sys.dm_tran_session_transactions
sys.dm_tran_top_version_generators
sys.dm_tran_transactions_snapshot
sys.dm_tran_version_store

image

sys.dm_tran_active_transactions

[]’s

Andressa Alves Martins

Twitter: Dre_Martins  Skype: Dre.alvesm

Blog: http://sqlgo.wordpress.com