Arquivo

Arquivo do Autor

Data por Extenso – DateName

24 de abril de 2008 2 comentários

Script para retornar uma data por extenso.

 

SET LANGUAGE Português

 

SELECT DATENAME(weekday, GetDate()) + ‘, ‘   +

       DATENAME(day, GetDate())     + ‘ de ‘ +

       DATENAME(month, GetDate())   + ‘ de ‘ +

       DATENAME(year, GetDate())

 

 

Lembrar de utilizar o SET LANGUAGE para retornar a data no idioma desejado, para verificar o idioma padrão de sua sessão execute “DBCC UserOptions”

 

Para visualizar qual é o nome dos idiomas existentes no SQL verifique na coluna name da tabela sysLanguages.

select * from master.dbo.syslanguages

 

Obs.: Evite usar SET LANGUAGE dentro de procedures pois isso irá causar RECOMPILE.

Categorias:SQL Server

Ler dados de um arquivo Excel

22 de abril de 2008 Deixe um comentário

Hoje precisei ler os dados direto de uma planilha excel, normalmente jogo os dados que quero trabalhar para uma tabela temporária, para isso utilizei o seguinte comando.

 

— Comando para habilitar recurso – OPENROWSET

EXEC sp_configure ‘show advanced options’, 1;

GO

RECONFIGURE;

GO

EXEC sp_configure ‘Ad Hoc Distributed Queries’, 1;

GO

RECONFIGURE;

GO

 

— Select para ler dados direto da planilha excel.

SELECT * INTO #TMP FROM OPENROWSET (‘Microsoft.Jet.OLEDB.4.0’, ‘Excel 8.0;Database=c:\teste.xls;’,

‘SELECT * FROM [Plan1$]’)

GO

 

SELECT * FROM #TMP

 

Isso pode ser bem útil._________________________________________________________________

Categorias:SQL Server

Compressão de dados SQL Server 2008

17 de abril de 2008 Deixe um comentário

SQL Server 2008 e compactação de dados.

 

Sinceramente eu não sei porque o time de desenvolvimento do SQL Server demorou tanto para pensar em compactação de dados, não fazia o menor sentido um campo Integer com o valor ‘2’ utilizar 4 bytes de espaço sendo que um campo VarChar(8000) com o mesmo valor ‘2’ utilizar apenas 1 byte de espaço.

 

O conceito de valores variáveis tinha que ser aplicado para todos os data-types, deixando o passado de lado a boa noticia é que no SQL Server 2005 SP2 foi introduzido um novo conceito de armazenamento de dados chamado VarDecimal, este que seria o percussor de todo o conceito de compactação do SQL2008.

Para ler um pouco sobre o VarDecimal visite o link http://msdn2.microsoft.com/en-us/library/bb508963.aspx.

 

Em poucas palavras o que foi feito é o seguinte, se você grava o valor ‘1’ em um campo Decimal(18,4) este campo irá ocupar 13 bytes de dados porem se você habilitar VarDecimal para esta tabela o campo iria ocupar apenas 2 bytes, leia o artigo acima vale a pena.

 

Agora se você foi um cara esperto e já migrou para SQL Server 2005 já instalou o SP2 e utiliza o VarDecimal, parabéns, mas só tem um detalhe, no Books Online do SQL2008 ele já avisam “Avoid using this feature in new development work” pois isso já vai ser removido de futuras versões do SQL.

A compactação de dados veio para substituir o conceito do VarDecimal que só funciona nos campos Numeric e Decimal para expandir está tecnologia para todos os data-types do SQL Server. Existem 2 tipos de compactação de dados no SQL 2008, são eles: Compactação por página e por Linhas.

 

Compactação por linha significa que o SQL irá controlar todos os data-types de sua tabela como variáveis, ou seja, se você utilizar um BigInt e gravar 0 nele ele irá ocupar 1 byte. Este comportamento valerá para todas as colunas de sua tabela.

Compactação por página significa que o SQL irá gravar apenas uma vez uma informação na página de dados, quando a mesma informação for inserida novamente ele irá apenas alocar um ponteiro para a informação já existente. O responsável por controlar este comportamento é um algoritmo chamado LZ78(Lempel-Ziv) Lempel e Ziv são 2 malucos que criaram o algoritmo, o mesmo utilizado para compactação de imagens por exemplo arquivos gif. Isso significa que se eu tiver uma tabela chamada Clientes e na coluna nome tiver o valor “Silva” se na mesma página de dados já existir um “Silva”o SQL não irá alocar espaço na página para gravar novamente este valor, e sim irá incluir um ponteiro para o valor já existente. Show de bola.

 

Para nós pobre mortais do mundo real só nos resta esperar chegar 2010 para começarmos a ver nossos clientes migrando para SQL Server 2008, para enfim poder utilizar novos conceitos como estes. L

Categorias:SQL Server

Performance – Caso Real – Parte2

17 de abril de 2008 Deixe um comentário

O segundo problema foi mais interessante e vou explicar porque, normalmente focamos nossas forças em otimizar o SELECTs, mas neste caso o maior problema estava em um DELETE, operações de DELETE são muito pesadas para o banco de dados, mais ainda caso a tabela que esta sendo deletada tenha uma primary key que é referenciada em outras tabelas(foreign keys). Antes de efetuar o DELETE o SQL terá que consultar cada tabela referenciada pra verificar se o DELETE não está violando nenhuma constraint. No meu caso a tabela que estava sendo apagada tinha relacionamento com outras 15 tabelas, portanto antes de apagar os dados o SQL tinha que ler as outras 15 tabelas para verificar se o DELETE era valido. Para piorar, em 3 dessas tabelas referenciadas a coluna da Foreign Key não estava indexada conclusão, Clustered Scan. Para resolver o problema bastou criar os devidos índices nas colunas da Foreign Key e pronto.

 

Para baixar o arquivo com um exemplo clique no link abaixo,  

 http://cid-52eff7477e74caa6.skydrive.live.com/embedrowdetail.aspx/Publica/DELETEComForeignKeyssemIndice.sql

Performance – Caso Real – Parte1

17 de abril de 2008 Deixe um comentário

Esta semana tivemos um problema de performance em uma rotina que estava funcionando normalmente e começou a apresentar lentidão chegando a exibir uma mensagem de timeout para o usuário. Comecei a analisar as query da procedure e encontrei o 1º problema. Segue um exemplo:

 

USE TempDB

GO

 

CREATE TABLE TesteA(ID_TesteA Int IDENTITY(1,1) PRIMARY KEY,

                    Data      DateTime DEFAULT GETDATE())

 

CREATE TABLE TesteB(ID_TesteB   Int IDENTITY(1,1),

                    Nome        VarChar(200) DEFAULT NEWID(),

                    ID_TesteA   Int REFERENCES TesteA(ID_TesteA),

                    Primary Key(ID_TesteB, Nome))

GO

 

SET NOCOUNT ON

DECLARE @I INT

— Insere 5000 linhas nas tabelas

SET @I = 0

WHILE @I < 5000

BEGIN

  INSERT INTO TesteA DEFAULT VALUES

  INSERT INTO TesteB(ID_TesteA) VALUES(@@IDENTITY)

  SET @I = @I + 1;

END

GO

 

— Por causa de statisticas desatualizadas e o TOP + Order By DESC

— o SQL estava fazendo Scan na tabela TesteA

— No exemplo abaixo ele não irá fazer Scan, porem irá gerar um Sort

— por causa do TesteA.Data DESC. Como a tabela não está ordenada por Data e sim por

— ID_TesteA(Primary key e indice cluster) ele tem que ordenar a tabela por Data.

SELECT TOP 1 TesteA.Data

    FROM TesteB

   INNER JOIN TesteA

      ON TesteB.ID_TesteA = TesteA.ID_TesteA

   WHERE TesteB.ID_TesteB = 1

   ORDER BY TesteA.Data DESC

GO

 

— A solução encontrada foi alterar a consulta acima para esta abaixo

— A idéia é pegar o ultimo registro incluido na tabela, portanto simplismente

— troquei o TOP 1 + Desc por MAX. No exemplo abaixo ele geou um Stream Aggregate na coluna

— TesteA.Data ordenando o resultado por TesteA.ID que é o indice Cluster e já está ordedado

— fisicamente.

SELECT MAX(TesteA.Data)

    FROM TesteB

   INNER JOIN TesteA

      ON TesteB.ID_TesteA = TesteA.ID_TesteA

   WHERE TesteB.ID_TesteB = 1

 

 

/*

O Edvaldo que trabalha junto comigo fez uma observação importante:

 

Cuidado em utilizar funções de agregação (MAX, MIN, COUNT…) com EXISTS pois sempre vai existir valor.

Exemplo:

IF EXISTS (SELECT MAX(campo) FROM tabela WHERE condição que não encontrou nenhum registro)

BEGIN

   

END

ELSE

BEGIN

 

END

Sempre vai passar no IF e nunca no ELSE.

*/

 

 

Continua…

SQL2005 Service Pack 3

16 de abril de 2008 Deixe um comentário

Good News sobre SQL Server 2005, Microsoft anuncia que o Service Pack 3 ta no forno e até o final deste ano será liberado.

 

Mais informações no link abaixo:

http://blogs.technet.com/dataplatforminsider/archive/2008/04/15/sql-server-2005-sp3-coming-soon.aspx

 

Bom também,

Categorias:SQL Server

Extents

10 de abril de 2008 Deixe um comentário

Extents são unidades de alocação de dados do SQL Server, para cada extent podemos ter 8 pages de dados.

Se você achar melhor antes de continuar a leitura deste post leia um pouco mais sobre extents no artigo que escrevi estes dias.

 

Vamos analisar mais um comportamento bem interessante da Engine do SQL Server.

 

Os dados das tabelas de um Banco de Dados o SQL Server ficam alocados em extents e dentro de cada extent temos 8 pages, o dado físico que você escrever em uma tabela fica salvo nestas pages que por sua vez estão nos extents.

As vezes fica um pouco confuso entender estes tal de Pages e Extents, para tentar simplificar vamos imaginar o seguinte, um livro(file do SQL Server), dentro de um livro temos várias páginas(Pages) e cada página está dentro de um determinado capítulo(extents), o SQL Server é trabalha exatamente como este livro para armazenar os dados.

 

Voltando ao assunto da Engine, o interessante na história é que quando os dados de uma tabela são apagados e novos dados são inseridos o SQL Server não reutiliza os extents que não estão mais sendo utilizados, isso por questão de Performance, o SQL é otimizado para alocar novos extents ao invés de ficar dando manutenção nos extents que seus dados  foram anteriormente excluídos.

 

Para cada arquivo do SQL Server ele mantém um ponteiro dizendo qual é o próximo extent livre, sendo assim ele simplesmente vai no ponteiro e aloca os dados neste extent. E após alocar os dados ele atualiza este ponteiro com a informação do próximo extent disponível. O SQL só irá marcar este ponteiro com a informação do Extent que teve seus dados apagados quanto ele chegar no fim do arquivo do SQL ou então quando não conseguir mais alocar extents por falta de espaço no arquivo ou ocorrer um Auto-Grow por exemplo um ShrinkDatabase.

 

A razão para este comportamento é que se o SQL tiver que ficar voltando para verificar quais extents estão vazios ele iria perder muito mais tempo do que simplesmente alocar outro novo extent e também por questões de fragmentação já que um extent no inicio do arquivo seria utilizado logo depois outro extent no final do arquivo depois outro no meio e por ai vai…

 

Chega de blablabla e vamos ver um pouco de código para comprovar este comportamento:

 

USE Master

 

— Caso exista um banco chamado DBTesteExtent, apaga ele.

IF (SELECT DB_ID(‘DBTesteExtent’)) IS NOT NULL

BEGIN

  USE Master

  ALTER DATABASE DBTesteExtent SET SINGLE_USER WITH ROLLBACK IMMEDIATE

  DROP DATABASE DBTesteExtent

END

GO

 

— Criar um banco de dados chamado DBTesteExtent

IF (SELECT DB_ID(‘DBTesteExtent’)) IS NULL

BEGIN

  CREATE DATABASE DBTesteExtent

END

GO

 

USE DBTesteExtent

 

— Vamos criar uma tabela para utilizar nos testes.

CREATE TABLE TesteExtent(ID Int Identity(1,1),

                         Nome char(8000) default ‘8000 Bytes’)

GO

 

— Vamos inserir uma linha na tabela para verificar as pages e extents que foram alocadas

INSERT INTO TesteExtent DEFAULT VALUES

 

— Utiliza a unDocumented Database Console Commands for SQL Server – DBCC EXTENTINFO

— Podemos visualizar que foi alocada uma page de dados em um extent misto

DBCC EXTENTINFO(DBTesteExtent, ‘TesteExtent’,-1)

 

 

— Vamos inserir mais dados para forçar a alocação de um extent uniforme

INSERT INTO TesteExtent DEFAULT VALUES

INSERT INTO TesteExtent DEFAULT VALUES

INSERT INTO TesteExtent DEFAULT VALUES

INSERT INTO TesteExtent DEFAULT VALUES

INSERT INTO TesteExtent DEFAULT VALUES

INSERT INTO TesteExtent DEFAULT VALUES

INSERT INTO TesteExtent DEFAULT VALUES

INSERT INTO TesteExtent DEFAULT VALUES

 

— Podemos visualizar que foram alocadas várias páginas e 2 extents

DBCC EXTENTINFO(DBTesteExtent, ‘TesteExtent’,-1)

 

— Agora vamos apagar os dados da tabela e verificar novamente os extents

DELETE FROM TesteExtent

 

— Os extents continuam aparecendo, assim como a informação do tamanho da tabela.

DBCC EXTENTINFO(DBTesteExtent, ‘TesteExtent’,-1)

GO

EXEC sp_spaceUsed TesteExtent

 

— Vamos criar uma nova tabela e inserir alguns registros nela,

— repare que os extents da tabela TesteExtent não são reutilizados

— na verdade o SQL aloca novo extents para a tabela.

CREATE TABLE TesteExtent2(ID Int Identity(1,1),

                          Nome char(8000) default ‘8000 Bytes’)

GO

 

— Vamos inserir uma linha na tabela para verificar as pages e extents que foram alocadas

INSERT INTO TesteExtent2 DEFAULT VALUES

 

— Repare que o page_id é diferente dos page_id da tabela TesteExtent

DBCC EXTENTINFO(DBTesteExtent, ‘TesteExtent2’,-1)

GO

DBCC EXTENTINFO(DBTesteExtent, ‘TesteExtent’,-1)

 

— Ao executar o SHRINKDATABASE os extents da tabela TesteExtent são apagados.

— e a informção do tamanho é atualizada

DBCC SHRINKDATABASE (DBTesteExtent);

 

DBCC EXTENTINFO(DBTesteExtent, ‘TesteExtent’,-1)

GO

EXEC sp_spaceUsed TesteExtent

GO

 

— Vamos inserir mais dados para forçar a alocação de um extent uniforme na tabela TesteExtent2

INSERT INTO TesteExtent2 DEFAULT VALUES

INSERT INTO TesteExtent2 DEFAULT VALUES

INSERT INTO TesteExtent2 DEFAULT VALUES

INSERT INTO TesteExtent2 DEFAULT VALUES

INSERT INTO TesteExtent2 DEFAULT VALUES

INSERT INTO TesteExtent2 DEFAULT VALUES

INSERT INTO TesteExtent2 DEFAULT VALUES

INSERT INTO TesteExtent2 DEFAULT VALUES

 

— Verifique que os page_id que pertenciam a tabela TesteExtent foram reutilizados.

DBCC EXTENTINFO(DBTesteExtent, ‘TesteExtent2’,-1)

 

Fonte – How It Works: SQL Server Page Allocations

_________________________________________________________________
Fabiano Neves Amorim – MCITP DBD / MCTS / MCP – SQLServer

* fabiano@cnpm.com.br – http://fabianosqlserver.spaces.live.com/

 

Categorias:SQL Server

Bug Fevereiro e SQL Server 2008

Corrigiram o erro que acontecia ao iniciar o Serviço do SQL 2008 no dia 29 de fevereiro,

 

http://sqlserver-qa.net/blogs/sql2008/archive/2008/04/07/3987.aspx

 

Fico mais calmo! J

Categorias:SQL Server

Quiz SQL Server

Muito legal este teste de 7 perguntas sobre SQL Server feito pelo Rainer Stropek,

 

São pegadinhas muito bem feitas, vale a pena se surpreender com as respostas J.

 

Segue o link http://www.codeproject.com/KB/database/SQLChamp.aspx

Categorias:SQL Server

IsNumeric

Cuidado ao utilizar a função IsNumeric para verificar se valores String são realmente números. Segue um exemplo de como a função pode retornar alguns valores não desejados.

 

— Cria uma tabela de teste

CREATE TABLE #Teste (ID Int Identity(1,1) Primary Key,

                    Numero VarChar(200))

 

INSERT INTO #Teste VALUES(‘$55.69’)

INSERT INTO #Teste VALUES(‘1.4e35’)

INSERT INTO #Teste VALUES(‘2d4’)

INSERT INTO #Teste VALUES(‘3.7’)

INSERT INTO #Teste VALUES(‘412’)

INSERT INTO #Teste VALUES(‘0e2155’)

INSERT INTO #Teste VALUES(CHAR(9)) –Tab

GO

 

SELECT * FROM #Teste

— Cuidado ao usar IsNumeric com colunas VarChar

SELECT ISNUMERIC(Numero) [Numeric ?],

       ISNUMERIC(Numero + ‘e0’) AS [Numeric], Numero AS Valor

FROM #Teste

GO

 

— Criei uma função chamada IsNumber que valida o valor utilizando o ‘e0’

CREATE FUNCTION dbo.IsNumber(@Value VarChar(200))

RETURNS BIT

AS

BEGIN

  RETURN (SELECT IsNumeric(@Value + ‘e0’))

END

GO

–Ex de uso da função

SELECT dbo.IsNumber(Numero) AS [Numeric], Numero AS Valor

FROM #Teste

 

DROP TABLE #Teste

 

Fonte – http://sqlblog.com/blogs/denis_gobo/archive/2007/08/23/2311.aspx

Categorias:SQL Server