Author: Leka
Date: 2011-08-30
Tags:
2000,
2005,
2008,
diferenca,
microsoft,
programa,
server,
sql,
t-sql,
tabela,
tablediff
Imagine a situação do post Corrompendo um Banco SQLmas na vida real,,,
Você chega um belo dia na empresa e, lê nos seus emails que, o SQL apresentou falha na estrutura de dados e algumas páginas de dados podem ter sido corrompidas,,,
Como um bom DBA, você corre para ver se o backup da noite foi feito, se os backups de transaction log também estão sendo feitos e descobre que sim,,,, todos os arquivos necessários para restaurar o banco estão lá,,,
Legal,,, mas,,, e agora? dependendo da utilização do banco você pode restaurar o backup da madrugada, os de log até o horário do problema e dali pra frente o que der pra fazer…
Em outros casos,,, você não pode se dar ao luxo de perder informação,,,,
Uma das formas seria executar o restore do banco em outro lugar, ou na mesma instância mas com outro nome, executar o checkdb e remover a página com problema e trazer a diferença dos dados,,, até aqui nada tão complicado,,, tirando o fato de se a tabela for muito grande, ou muito complexa e a query para mostrar essa diferença for muito complicado…
Para ajudar a resolver esse problema, o SQL possui uma ferramenta bem interessante chamada TableDiff.
O conceito dela é bem simples: Instância de origem, base de origem, tabela de origem, Instância de destino, base de destino, tabela de destino e o que você quer fazer…
Ex:
"C:\Program Files\Microsoft SQL Server\90\COM\tablediff.exe" -sourceserver MyServer1
-sourcedatabase MyDatabase1
-sourcetable MyTable1
-destinationserver MyServer1
-destinationdatabase MyDatabase1
-destinationtable MyTable2
-et DiffsTable
Nesse outro exemplo ele gera um arquivo com INSER/UPDATE/DELETE
"C:\Program Files\Microsoft SQL Server\90\COM\tablediff.exe" -sourceserver MyServer1
-sourcedatabase MyDatabase1
-sourcetable MyTable1
-destinationserver MyServer1
-destinationdatabase MyDatabase1
-destinationtable MyTable2
-et DiffsTable
-f d:\MyTable1_MyTable2_diff.sql
Simples certo? em teoria não é muito complicado…
Da pra deixar mais fácil? sim,,, com certeza…
O Sr. Mladen Prajdic (Blog | Twitter) desenvolveu uma interface bem interessante para ajudar na utilização do executável…
O link para download pode ser encontrado no post aqui, ou diretamente aqui.
O aplicativo é bem simples de usar, o ponto de atenção é que você precisa indicar onde está o executável do TableDiff.exe.

Ele é bem auto-explicativo, pequeno e o principal,,, é de graça !!!
Vale gastar uns minutos para aprender a usar ele, vai que em um dia de emergência você precisa de uma ajuda rápida para solucionar um problema, ou ver a diferenças nas tabelas do seu logshipping….
Author: Leka
Date: 2011-08-22
Esse código faz parte daquele tipo de código para gerar documentação.
Não faz nada muito complexo, apenas mostra o objeto, quem é dono, que tipo e quando foi criado.
SELECT [NAME] AS OBJECT_NAME,
USER_NAME(UID) AS OWNER,
TYPE = CASE
WHEN XTYPE = 'u' THEN 'table'
WHEN XTYPE = 'c' THEN 'check constraint'
WHEN XTYPE = 'd' THEN 'default constraint'
WHEN XTYPE = 'f' THEN 'foreign key constraint'
WHEN XTYPE = 'fn' THEN 'scalar function'
WHEN XTYPE = 'if' THEN 'inline table function'
WHEN XTYPE = 'p' THEN 'stored procedure'
WHEN XTYPE = 'pk' THEN 'primary key'
WHEN XTYPE = 'tf' THEN 'table function'
WHEN XTYPE = 'tr' THEN 'trigger'
WHEN XTYPE = 'uq' THEN 'unique constraint'
WHEN XTYPE = 'v' THEN 'view'
END,
CRDATE AS CREATION_DATE
FROM SYSOBJECTS
WHERE XTYPE IN ('u','c','d','f',
'fn','if','p','pk',
'tf','tr','u','uq',
'v')
ORDER BY XTYPE
Author: Leka
Date: 2011-08-20
Tags:
2005,
2008,
conversao,
cte,
denali,
implicita,
index,
microsoft,
scan,
script,
server,
sqlComplementando o Post Procurando por conversão implícita sobre a apresentação do Marcos Freccia (Blog | Twitter) “10 coisas que todo desenvolvedor deveria saber sobre SQL Server”
Um dos grandes problemas dessa conversão é o SQL utilizar index scan ao invés de index seek.
Esse código mostra consultas que estão executado Index Scan por motivos de Conversões Implícitas.
with XMLNAMESPACES
('http://schemas.microsoft.com/sqlserver/2004/07/showplan' as sql)
select
total_worker_time/execution_count AS AvgCPU
, total_elapsed_time/execution_count AS AvgDuration
, (total_logical_reads+total_physical_reads)/execution_count AS AvgReads
, execution_count
, SUBSTRING(st.TEXT, (qs.statement_start_offset/2)+1 , ((CASE
qs.statement_end_offset WHEN -1 THEN datalength(st.TEXT) ELSE
qs.statement_end_offset END - qs.statement_start_offset)/2) + 1) AS txt
, qs.max_elapsed_time
, db_name(qp.dbid) as database_name
, quotename(object_schema_name(qp.objectid, qp.dbid)) + N'.' +
quotename(object_name(qp.objectid, qp.dbid)) as obj_name
, qp.query_plan.value(
N'(/sql:ShowPlanXML/sql:BatchSequence/sql:Batch/sql:Statements/sql:StmtSimple[@StatementType = "SELECT"]/sql:QueryPlan/sql:RelOp/descendant::*/sql:ScalarOperator[contains(@ScalarString, "CONVERT_IMPLICIT")])[1]/@ScalarString', 'nvarchar(4000)' ) as scalar_string
, qp.query_plan
from sys.dm_exec_query_stats as qs
cross apply sys.dm_exec_query_plan(qs.plan_handle) as qp
cross apply sys.dm_exec_sql_text(qs.sql_handle) st
where qp.query_plan.exist(
N'/sql:ShowPlanXML/sql:BatchSequence/sql:Batch/sql:Statements/sql:StmtSimple[@StatementType = "SELECT"]/sql:QueryPlan/sql:RelOp/sql:IndexScan/descendant::*/sql:ScalarOperator[contains(@ScalarString, "CONVERT_IMPLICIT")]' ) = 1;
Author: Leka
Date: 2011-08-19
Esse é um código antigo que estava escondido no HD.
Bem simples e usual.
/*
Versao: 1.0
Data: 20100302
Por: Ricardo Leka
Site: https://leka.com.br
email: ricardo@leka.com.br
twitter: @bigleka
*/
/*
Gerador de Senhas
Pode gerar senhas com quantidades minima e maxima de caracteres
com numeros ou complexidade
*/
DECLARE
@complex tinyint
, @minlen tinyint
, @maxlen tinyint
SET @minlen = 4 --tamanho minimo da senha
SET @maxlen = 8 --tamanho maximo da senha
SET @complex = 4
-- 1 todas as letras minusculas
-- 2 inclui letras maiusculas
-- 3 inclui numeos
-- 4 inclui caracteres especiais
DECLARE
@password varchar(12)
, @len tinyint
, @type tinyint
, @type2 tinyint
SET @len = 0
SET @password = ''
WHILE @len NOT BETWEEN @minlen and @maxlen
BEGIN
SET @len = ROUND(1 + (RAND(CHECKSUM(NEWID())) * @maxlen), 0) + 1
END
WHILE @len > 0
BEGIN
DECLARE @newchar CHAR(1)
SET @type = ROUND(1 + (RAND(CHECKSUM(NEWID())) * (@complex - 1)), 0)
IF @type = 1
SET @newchar = CHAR(ROUND(97 + (RAND(CHECKSUM(NEWID())) * 25), 0))
IF @type = 2
SET @newchar = CHAR(ROUND(65 + (RAND(CHECKSUM(NEWID())) * 25), 0))
IF @type = 3
SET @newchar = CHAR(ROUND(48 + (RAND(CHECKSUM(NEWID())) * 9), 0))
IF @type = 4
BEGIN
SET @type2 = ROUND(1 + (RAND(CHECKSUM(NEWID())) * 3), 0)
IF @type2 = 1
SET @newchar = CHAR(ROUND(33 + (RAND(CHECKSUM(NEWID())) * 14), 0))
IF @type2 = 2
SET @newchar = CHAR(ROUND(58 + (RAND(CHECKSUM(NEWID())) * 6), 0))
IF @type2 = 3
SET @newchar = CHAR(ROUND(91 + (RAND(CHECKSUM(NEWID())) * 5), 0))
IF @type2 = 4
SET @newchar = CHAR(ROUND(123 + (RAND(CHECKSUM(NEWID())) * 3), 0))
END
-- remove caracteres que podem ser confundidos com outros
IF @newchar NOT IN ('b', 'l', 'o', 's', 'I', 'O', 'S', '0', '1', '!', '''', '.', ',', '/', '`', '\', '|')
BEGIN
SET @password = @password + @newchar
SET @len = @len - 1
END
END
SELECT @password as Senha
Author: Leka
Date: 2011-08-18
Tags:
2000,
2005,
2008,
denali,
file,
initialization,
instant,
microsoft,
server,
sql,
video,
windowsJá vou logo avisando:
- Não assista esse vídeo depois das 22h,,, não me responsabilizo por pesadelos,,,
- Não assista perto dos seus filhos,,, é mais feio que o bicho papão,,,
- Não assista no trabalho,,, seus colegas já sofrem tendo que trabalhar com você,,,,
- Meu primeiro vídeo,,, Gravei o vídeo as 4am,,, estava com muito sono,,,
Se, depois de tudo isso, clicar em Play não me responsabilizo por absolutamente nada,,,
[vimeo http://www.vimeo.com/27824432 w=701&h=438]
Instant file initialization from Ricardo Leka on Vimeo.
Author: Leka
Date: 2011-08-15
Tags:
1807,
2000,
2005,
2008,
banco,
base,
flag,
microsoft,
r2,
server,
sql,
traceAtualmente meu notebook (também conhecido como desktop porque a bateria já era) não tem muita capacidade de suportar alguns testes,,, (Acer Aspire 5050 – AMD Turion 1 core, 1.9GB RAM, 35GB HD),,,
Então tentei fazer uma coisa interessante,,,, criar um banco e apontar os arquivos para meu storage (QNAP TS-110),,,
Tenho 2 instâncias de SQL instaladas nesse note, 1 SQL Server 2008 R2 e 1 SQL Server 2005.
Claro que no 2008 R2 funcionou e no 2005 não…


Ai lembrei que para o SQL 2005 (e para o 2008 sem ser R2) criar uma base em local UNC eu precisava habilitar a trace flag 1807. Feito isso conseguir criar a base sem problema.

Achei interessante relembrar isso, pois vai que uma hora qualquer alguém precisa, ou para fazer um LAB ou por falta de espaço (meu caso) você sempre tem uma alternativa… e muita gente nem lembra dessa possibilidade…
Author: Leka
Date: 2011-08-10
Tags:
2005,
2008,
código,
cte,
denali,
microsoft,
script,
server,
sql,
t-sql,
tuesday
Dessa vez o anfitrião do T-SQL Tuesday é o próprio idealizador Adam Machanic (Blog | Twitter).
E de uma forma diferente, não é na Terça-feira,,, por quê?
Porque não importa, desde que funcione pode ser zuado mesmo,,, o tópico desse mês é sobre “mostrar seu código lixo para o mundo”,,,
Todo mundo já escreveu um código uma vez ou outra,,,, todo o DBA tem aquele conjunto de scripts que o ajudam a identificar alguns problemas, fazer um tunning, arrumar alguma coisa,,, E com certeza todo mundo tem aquele código que hoje, pega para olha e começa a dar risada de como é que teve coragem de fazer uma coisa como aquela…
Meu exemplo é bem simples, O código é horrível, demora demais mas, funciona,,,
Ele troca os dados de posição de uma coluna específica.
WITH cteTableTel AS (
SELECT
ROW_NUMBER() OVER (ORDER BY NEWID()) AS n,
SOBRENOME
FROM CLIENTES
)
UPDATE CLIENTES
SET ENDERECO = (
SELECT ENDERECO
FROM cteTableTel
WHERE cteTableTel.n = CLIENTES.ID)
Esse código funciona, não é nada bonito, não é performático, mas para a necessidade de uma base de treino com dados reais ele ajuda bastante,,,
Se você percebeu ele tem um problema,,, sabe qual é?
Como você garante que todas as linhas da tabela de clientes realmente estão em uma sequencia? Você pode ter apagado algum registro uma hora ou outra,,, Logo, haverá cliente que o endereço não vai ser atualizado,,
Já sei, você nem reparou nesse problema,,, você deve estar pensando: “por que ele esta fazendo um update na tabela de clientes se ele está usando uma CTE?”, ou também, “Legal, ele está fazendo isso em uma tabela que tem algum tipo de ID e quando tem aquelas tabelas que não da pra usar nada de referencia?”
Como eu disse, ele não é performático, e eu nem tinha me atentado nesses detalhes na época,,, Houveram duas situações que me refizeram rever esse código: o primeiro caso dos usuários que não tinham os dados alteradores e o último… ai com muita vontade resolvi reescrever,,,
E ele ficou mais ou menos assim:
;WITH cte AS (
SELECT
ROW_NUMBER() OVER (ORDER BY NEWID()) AS n1,
ROW_NUMBER() OVER (order by SOBRENOME) AS n2,
SOBRENOME
FROM CLIENTES
)
UPDATE c1
SET SOBRENOME = c2.SOBRENOME
from cte as c1
inner join cte as c2
on c1.n1 = c2.n2
Dessa vez não tem problema com o usuário sem o dado alterado, performance melhorada em quase 90% e pouco importa se a tabela em algum registro para referencia,,,
Eu comparei a execução dos 2 códigos em uma tabela com um pouco mais de 3 milhões de linhas e o segundo código demorou quase 4 horas para finalizar,,, já o primeiro código eu parei a execução dele depois de 2 SEMANAS executando.
Tenho códigos piores no meu repositório? claro que sim. Esse é apenas um exemplo de um dos piores que já fiz…
Qual é o seu? tem coragem mostrar?
Author: Leka
Date: 2011-08-03
Assistindo ontem a apresentação do Marcos Freccia (Blog | Twitter) sobre “10 coisas que todo desenvolvedor deveria saber sobre SQL Server” alguém perguntou como ver as conversões implícitas que estão sendo executadas no SQL,,, ou alguma coisa assim,,,
Então, segue um script rapidão que mostra as conversões,,, o chato desse script é que ele tem que ser executado por banco,,,
Vou tentar montar um outro que traga a informação de todos os bancos,,,
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
DECLARE @dbname SYSNAME
SET @dbname = QUOTENAME(DB_NAME());
WITH XMLNAMESPACES
(DEFAULT 'http://schemas.microsoft.com/sqlserver/2004/07/showplan')
SELECT
stmt.value('(@StatementText)[1]', 'varchar(max)'),
t.value('(ScalarOperator/Identifier/ColumnReference/@Schema)[1]', 'varchar(128)'),
t.value('(ScalarOperator/Identifier/ColumnReference/@Table)[1]', 'varchar(128)'),
t.value('(ScalarOperator/Identifier/ColumnReference/@Column)[1]', 'varchar(128)'),
ic.DATA_TYPE AS ConvertFrom,
ic.CHARACTER_MAXIMUM_LENGTH AS ConvertFromLength,
t.value('(@DataType)[1]', 'varchar(128)') AS ConvertTo,
t.value('(@Length)[1]', 'int') AS ConvertToLength,
query_plan
FROM sys.dm_exec_cached_plans AS cp
CROSS APPLY sys.dm_exec_query_plan(plan_handle) AS qp
CROSS APPLY query_plan.nodes('/ShowPlanXML/BatchSequence/Batch/Statements/StmtSimple') AS batch(stmt)
CROSS APPLY stmt.nodes('.//Convert[@Implicit="1"]') AS n(t)
JOIN INFORMATION_SCHEMA.COLUMNS AS ic
ON QUOTENAME(ic.TABLE_SCHEMA) = t.value('(ScalarOperator/Identifier/ColumnReference/@Schema)[1]', 'varchar(128)')
AND QUOTENAME(ic.TABLE_NAME) = t.value('(ScalarOperator/Identifier/ColumnReference/@Table)[1]', 'varchar(128)')
AND ic.COLUMN_NAME = t.value('(ScalarOperator/Identifier/ColumnReference/@Column)[1]', 'varchar(128)')
WHERE t.exist('ScalarOperator/Identifier/ColumnReference[@Database=sql:variable("@dbname")][@Schema!="[sys]"]') = 1