Só tenho uma coisa pra dizer…
| SQL Server 2008 Microsoft Certified Master: Knowledge Exam PATH ITTS INFORMATION TECHNOLOGY E TELECOM SERVICE XD4LAM50D9 |
Microsoft (088-970) |
Passed 17-Sep-2014 11:59 PM |
agora que venha o LAB…
Só tenho uma coisa pra dizer…
| SQL Server 2008 Microsoft Certified Master: Knowledge Exam PATH ITTS INFORMATION TECHNOLOGY E TELECOM SERVICE XD4LAM50D9 |
Microsoft (088-970) |
Passed 17-Sep-2014 11:59 PM |
agora que venha o LAB…
Esse script é uma modificação de um script do simple-talk apenas adicionar a opção de função para facilitar a vida
o importante para este script funcionar é:
#https://www.simple-talk.com/sql/database-administration/automated-script-generation-with-powershell-and-smo/
function global:Script-DBObjectsIntoFolders([string]$server, [string]$dbname, [string]$DirectoryToSave){
# set "Option Explicit" to catch subtle errors
set-psdebug -strict
$DirectoryToSaveTo=$DirectoryToSave # local directory to save build-scripts to
$servername=$server # server name and instance
$Database=$dbname # the database to copy from
$ErrorActionPreference = "stop" # you can opt to stagger on, bleeding, if an error occurs
Trap {
# Handle the error
$err = $_.Exception
write-host $err.Message
while( $err.InnerException ) {
$err = $err.InnerException
write-host $err.Message
};
# End the script.
break
}
# Load SMO assembly, and if we're running SQL 2008 DLLs load the SMOExtended and SQLWMIManagement libraries
$v = [System.Reflection.Assembly]::LoadWithPartialName( 'Microsoft.SqlServer.SMO')
if ((($v.FullName.Split(','))[1].Split('='))[1].Split('.')[0] -ne '9') {
[System.Reflection.Assembly]::LoadWithPartialName('Microsoft.SqlServer.SMOExtended') | out-null
}
$My='Microsoft.SqlServer.Management.Smo'
$s = new-object ("$My.Server") $ServerName # get the server.
$Server=$s.netname -replace '[\\\/\:\.]',' ' # remove characters that can cause problems
$instance = $s.instanceName -replace '[\\\/\:\.]',' ' # ditto
$DatabaseName =$database -replace '[\\\/\:\.]',' ' # ditto
$DirectoryToSaveTo=$DirectoryToSaveTo+$Server+'\'+$Instance+'\' # database scripts are local on client
if (!( Test-Path -path "$DirectoryToSaveTo" )) # create it if not existing
{$progress ="attempting to create directory $DirectoryToSaveTo"
Try { New-Item "$DirectoryToSaveTo" -type directory | out-null }
Catch [system.exception]{
Write-Error "error while $progress. $_"
return
}
}
<# now we will use the canteen system of SMO to specify what we want from the script. It is best to have a list of the defaults to hand and just override the defaults where necessary, but there is a chance that a later revision of SMO could change the defaults, so beware! #>
$CreationScriptOptions = new-object ("$My.ScriptingOptions")
$CreationScriptOptions.ExtendedProperties= $true # yes, we want these
$CreationScriptOptions.DRIAll= $true # and all the constraints
$CreationScriptOptions.Indexes= $true # Yup, these would be nice
$CreationScriptOptions.Triggers= $true # This should be included when scripting a database
$CreationScriptOptions.ScriptBatchTerminator = $true # this only goes to the file
$CreationScriptOptions.Filename = "$($DirectoryToSaveTo)$($DatabaseName)_Build.sql";
# we have to write to a file to get the GOs
$CreationScriptOptions.IncludeHeaders = $true; # of course
$CreationScriptOptions.ToFileOnly = $true # no need of string output as well
$CreationScriptOptions.IncludeIfNotExists = $true # not necessary but it means the script can be more versatile
$transfer = new-object ("$My.Transfer") $s.Databases[$Database]
$transfer.options=$CreationScriptOptions # tell the transfer object of our preferences
$scripter = new-object ("$My.Scripter") $s # script out the database creation
$scripter.options=$CreationScriptOptions # with the same options
$scripter.Script($s.Databases[$Database]) # do it
"USE $Database" | Out-File -Append -FilePath "$($DirectoryToSaveTo)$($DatabaseName)_Build.sql"
"GO" | Out-File -Append -FilePath "$($DirectoryToSaveTo)$($DatabaseName)_Build.sql"
# add the database object build script
$transfer.options.AppendToFile=$true
$transfer.options.ScriptDrops=$true
$transfer.EnumScriptTransfer()
$transfer.options.ScriptDrops=$false
$transfer.EnumScriptTransfer()
"All written to $($DirectoryToSaveTo)$($DatabaseName)_Build.sql"
}
Teremos um grande evento da comunidade SQL no Brasil…. o SQL Saturday #245…
O SQL Saturday é totalmente gratuito e focado em SQL Server, um dia inteiro de palestras técnicas. No momento o evento encontra-se com o Call for Speakers aberto, ou seja, recebendo inúmeras propostas de palestras, tendo até agora já recebido propostas de palestrantes de vários locais do Brasil e inclusive de outros países !!!
Trata-se da 2a edição do evento, que ocorreu com muito sucesso em abril de 2012, contando na época com mais de 300 participantes.
SQL Saturday é uma marca de eventos já conhecida mundialmente pela alta qualidade técnica. A marca pertence a uma organização chamada SQL PASS, cujo trabalho envolve apoiar grupos de usuários de SQL Server – denominados de PASS Chapter – por todo o mundo.
O SQL PASS cede a marca, bem como algumas ferramentas on-line, patrocinio e orientação para que o PASS Chapter da região realize o evento. No Rio de Janeiro o evento está sendo realizado pelo PASS Chapter devSQL, o mais antigo PASS Chapter do Brasil, liderado por Dennes Torres (t | b).
As inscrições para o evento estão abertas e, como citado antes, é totalmente gratuito. Trata-se do 2o evento realizado no Brasil. O primeiro, realizado em São Paulo por outro PASS Chapter, ficou totalmente lotado antes mesmo da grade de palestras ser definida.
Evento : SQL Saturday #245 – Rio de Janeiro
Data : 31/08
Horário : Abertura as 08:00hs, inicio das palestras as 09:00hs até as 18hs
Local : Universidade Veiga de Almeida
Endereço : Rua Ibituruna, 108, tijuca, próximo a estação São Cristóvão do metrô
Site do Evento : http://www.sqlsaturday.com/245/eventhome.aspx

Isso porque o cara tem que escolher explicitamente a instalação x86,,,
Aí você pergunta para o infeliz o motivo da escolha e ele responde que ou não sabe a diferença, ou que como o sistema dele é todo x86 ele instalou o banco desta forma para manter compatibilidade…
bom,,, não importa qual a desculpa,,, tem uma forma de alterar a instalação feita e converter o executável do serviço de x86 para x64,,,
para SER BEM CLARO não faça isso no seu ambiente de produção SEM TESTAR antes,,, é por sua total conta e risco…
vamos usar o powershell para executar uma chave encriptada,,, essa chave vai alterar algumas informações de chaves de registro que o executável do serviço do SQL utiliza para carregar os binários para o SQLOS .
$Key = (1..16)
$chave = ('76492d1116743f0423413b16050a5345MgB8ADYANwBTAEIAegBrADQASwBQAFEAKwBjAEUAMABaAE0AdgBiAFIARABMAEEAPQA9AHwANwAyADIANQBkADMANABjADUAYQAwAGUAMgAxADEAYQA1AGQAYQAyADIANAAwADYAYwAyADIAMQAwADIAZQA5AGMAOAA2ADAAZgA0ADIAOABlAGIAYwBlADEAYQA1AGIAZQBhADcAYgA5ADEAZAA3AGIAYQA4ADQAYwA3ADMAYQA=')
$chave1 = convertto-securestring $chave -key $key
Start-Sleep -s 5
$a = new-object -comobject wscript.shell
$b = $a.popup([Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($chave1)),0,”Conversao de x32 para x64”,1)
(new-object -com SAPI.SpVoice).speak($chave1)
Boas modificações !!!
Algumas vezes procurando por erros nos eventos de sistema, já me deparei com uma mensagem de informação bem estranha:
MSSQLSERVER Information System Event 17055 <SQL server Instance Name > “The description for Event ID ( 17055 ) in Source ( MSSQLSERVER ) cannot be found. The local computer may not have the necessary registry information or message DLL files to display messages from a remote computer. You may be able to use the /AUXSOURCE= flag to retrieve this description; see Help and Support for details. The following information is part of the event: 18265, Log backed up: Database: Database Name, creation date(time): 2012/07/11(09:38:17), first LSN: 720:282:1, last LSN: 720:282:1, number of dump devices: 1, device information: (FILE=1, TYPE=DISK: {‘\\ServerLog02\BACKUP\Backup123.TRN’}).
Eu sei que não é um erro de backup, se procurar os MSDB ou no job de backup não tem nenhum erro na geração do arquivo e o arquivo está no devido local.
Isso acontece porque o Event Viewer não consegue interpretar a mensagem colocada pelo SQL nos registros de eventos… A causa mais provável é que o caminho da biblioteca que passa a informação de como o Event Viewer deve interpretar a informação gravada está no lugar errado…
Como fazer para corrigir isso? até que é bem simples…
Isso se aplica a SQL 2000, 2005 e 2008,, ainda não tive esse tipo de problema com o 2012
Comecei alguns desafios com a equipe de banco da empresa pedindo algumas soluções para um problema…
Semana passada eles tinham que entregar um código que mostra-se uma tabuada… mas haviam algumas premissas:
O pessoal se empenhou e vieram com códigos interessantes…
um deles foi:
DECLARE @InicNum int, @FimcNum int SET @InicNum = 5 SET @FimcNum = 7 ;WITH numeros AS ( SELECT number AS N FROM master..spt_values WHERE type = 'P' AND number BETWEEN CAST(@InicNum AS varchar) AND CAST(@FimcNum AS varchar) ), F1 AS( select number as N from spt_values where type = 'P' AND number BETWEEN 1 AND 10 ), produto AS ( SELECT M = n2.N, F = n1.N, P = n1.N * n2.N FROM F1 n1 CROSS JOIN numeros n2 ) SELECT cast(M as varchar(2)) + ' x ' + cast(F as varchar(2)) + ' = ' + cast(P as varchar(3)) FROM produto order by M
outra opção:
DECLARE @CALC1 INT, @CALC2 INT DECLARE @NUM1 VARCHAR(500), @NUM2 VARCHAR(500) , @RESTO VARCHAR(500), @LINHA NVARCHAR(500) SET @CALC1 = 1 WHILE @CALC1 <= 10 -- AQUI BEGIN SET @LINHA = @CALC1 SELECT '" TABUADA DO ' + CONVERT(VARCHAR(15),@LINHA) + ' "' SET @CALC2 = 1 WHILE @CALC2 <= 10 -- BEGIN SET @NUM1 = @CALC1 SET @NUM2 = @CALC2 SET @RESTO = @CALC1 * @CALC2 SELECT @NUM1 + 'X' + @NUM2 + ' = ' + @RESTO AS 'TABUDA' SET @CALC2 = @CALC2 + 1 END SET @CALC1 = @CALC1 + 1 END
Mais uma…
SET nocount on go declare @i int set @i = 3 declare @f int set @f = 20 declare @1 int set @1 = 1 declare @2 int set @2 = 2 declare @3 int set @3 = 3 declare @4 int set @4 = 4 declare @5 int set @5 = 5 declare @6 int set @6 = 6 declare @7 int set @7 = 7 declare @8 int set @8 = 8 declare @9 int set @9 = 9 declare @10 int set @10 = 10 WHILE @i <= @f BEGIN BEGIN SELECT convert(varchar(2),@1)+'x'+convert(varchar(20),@i)+'='+convert(varchar(20),@i) SELECT convert(varchar(2),@2)+'x'+convert(varchar(20),@i)+'='+convert(varchar(20),@i) SELECT convert(varchar(2),@3)+'x'+convert(varchar(20),@i)+'='+convert(varchar(20),@i) SELECT convert(varchar(2),@4)+'x'+convert(varchar(20),@i)+'='+convert(varchar(20),@i) SELECT convert(varchar(2),@5)+'x'+convert(varchar(20),@i)+'='+convert(varchar(20),@i) SELECT convert(varchar(2),@6)+'x'+convert(varchar(20),@i)+'='+convert(varchar(20),@i) SELECT convert(varchar(2),@7)+'x'+convert(varchar(20),@i)+'='+convert(varchar(20),@i) SELECT convert(varchar(2),@8)+'x'+convert(varchar(20),@i)+'='+convert(varchar(20),@i) SELECT convert(varchar(2),@9)+'x'+convert(varchar(20),@i)+'='+convert(varchar(20),@i) SELECT convert(varchar(2),@10)+'x'+convert(varchar(20),@i)+'='+convert(varchar(20),@i) END SET @i = @i + 1 END
E a última…
declare @i int declare @y int declare @num varchar(max) declare @num2 varchar(max) declare @res varchar(max) -- Atribui @y = Tabuada começa do 1 - set @y=1 -- Enquanto @y menor ou igual a 10, vai ate tabuada do 10 - while @y<=10 -- Inicio 1 begin -- Atribui @i = 1 começa com x 1, no caso 1 x 1 ou então(@y x @i ) set @i=1 -- Enquanto @i menor ou igual a 10 - vai ate x 10 while @i<=10 -- Inicio 2 begin -- Atribui @num = @i set @num = @i; -- Atribui @num2 = @y set @num2 = @y; -- Atribui @res = @y * @i set @res = @y*@i -- Mostrando o Resultado da tabuada concatenando os resultados - print @num2+'x'+@num+'='+@res -- Atribui @s a ele mesmo + 1, 'próximo valor de @s' - soma para ir ao próximo numero - set @i=@i+1 -- Inicio 2 end -- Atribui @y a ele mesmo + 1, 'próximo valor de @y' - soma para ir a proxima tabuada - set @y=@y+1 -- Imprime enter e '---------' enter - só o espaçamento entre tabuadas print Char(13)+'----'+Char(13) -- Fim Inicio 1 end
Apenas para deixar claro: Não sou contra a utilização de CS e AS.
O desenvolvedor tem que lembrar que quando a base está com o collation em CS e ninguém alterou a coluna da pesquisa para CI ele vai ter resultados diferentes quando usa essa coluna em um distinct ou no where…
A algum tempo um desenvolvedor veio conversar comigo porque ele estava tendo problemas em um resultado de um select,,, coisa pouca, em uma tabela de uns 1kk de registros ele queria usar distinct para recuperar umas informações, quando ele usava o order by ele mostrava muitos resultados parecidos…
Lembrei ele que a base era CS e que ou teria que usar UPPER/LOWER ou passar um collation para a coluna da pesquisa ele ficou me olhando como se eu fosse louco…. ta certo,,, ele não estava errado,,, mas era uma solução rápida e indolor…
Exemplo:
CREATE DATABASE [BDTESTE] COLLATE Latin1_General_100_CS_AS GO USE BDTESTE GO create table tbl_teste( nome varchar(20) ) insert into tbl_teste select 'teste' union select 'Teste' union select 'tEstE union select 'TESTE' SELECT * from tbl_teste
select distinct(nome) from tbl_teste
select distinct(UPPER(nome)) from tbl_teste
select distinct(nome) COLLATE sql_latin1_general_cp1_ci_ai from tbl_teste
Existem outras formas de solucionar isso,,, trocar o collation da coluna direto na tabela, criar uma view, etc etc…
Olá pessoal, complementando o Webcast que apresentei em 11/04 estou disponibilizando os arquivos SQL de exemplo, arquivo PPT e o Dashboard em Excel.
[slideshare id=12617869&doc=waitstatseextendedevents-120420080039-phpapp02]
SkyDrive – WT_EE.RAR / MIrror – WT_EE.RAR
Link para a gravação do Webcast.
Lembrete:
Bom, por enquanto é isso.
Como todo o bom DBA você tem um plano de manutenção configurado para seu ambiente SQL.
Você costuma fazer rebuild/reindex, update statistics, backup, garante que o HA está funcionado,,,
Você provavelmente deve ter a opção de “auto update statistics” habilitada em suas
Bom,,, no bom e velho “by the book” o “auto update statistics” funciona assim:
Até aí nenhuma novidade certo? certo….
Com esse conceito em mente,,, imagine que você tem umas 40 tabelas com alguns 14.000.000 de registros cada, umas outras 200 tabelas com uns 30.000 registros cada,,, você sabe quem vai ser a próxima vítima do malévolo processo de “auto update statistics” ?
Acho que muito poucas pessoas tem a opção de “auto update statistics asynchronously” habilitada, então alguma query vai sofrer com a espera da atualização de uma estatística e alguém vai achar que é lentidão no sistema…
Então como monitorar a quantidade de alterações de uma tabela pra saber se ela está chegando aos malvados 20% +500 ?
Tá lá uma query:
/*SQL 2005*/ SELECT SO.NAME AS tableName, SC.NAME AS columnName, SSC.*, SSR.* FROM sys.sysrowsetcolumns SSC INNER JOIN sys.sysrowsets SSR ON SSC.rowsetID = SSR.rowsetID INNER JOIN sys.sysobjects SO ON SSR.idmajor = SO.id INNER JOIN sys.syscolumns SC on SSR.idmajor = SC.id AND SSC.rowsetcolid = SC.colid WHERE SO.xtype = 'U' ORDER BY so.name, sc.colid /*SQL 2008*/ SELECT SO.NAME AS tableName, SC.NAME AS columnName, SSC.*, SSR.* FROM sys.sysrscols SSC INNER JOIN sys.sysrowsets SSR ON SSC.rowsetID = SSR.rowsetID INNER JOIN sys.sysobjects SO ON SSR.idmajor = SO.id INNER JOIN sys.syscolumns SC on SSR.idmajor = SC.id AND SSC.rscolid = SC.colid WHERE SO.xtype = 'U' ORDER BY so.name, sc.colid
Não conseguiu executar??????? hehehehe
Precisa habilitar o DAC, as tabelas sysrscols, sysrowsetcolumns e sysrowsets só podem ser acessadas pelo DAC.
Outra coisa, não esqueça de mudar a base,,,
Mas até ai, o que tem de interessante no resultado?
O nome da tabela já sabemos, qual a coluna? grande coisa,,, o que importa é a coluna rcmodified e a coluna rcrows, quantidade de modificações e contagem de linhas respectivamente.
Agora sim,,, já começamos a ter alguma coisa legal…. mas tem como melhorar? sabemos as tabelas e as colunas… temos como saber quais as estatísticas que vão ser impactadas pela atualização? Claro…
/*SQL 2005*/ SELECT SO.NAME AS tableName, COL_NAME(sc.object_id, sc.column_id) AS columnName, A.name as stats_name, SSC.*, SSR.* FROM sys.sysrowsetcolumns SSC INNER JOIN sys.sysrowsets SSR ON SSC.rowsetID = SSR.rowsetID INNER JOIN sys.sysobjects SO ON SSR.idmajor = SO.id INNER JOIN sys.stats_columns SC on SSR.idmajor = SC.object_id AND SSC.rowsetcolid = SC.column_id INNER JOIN sys.stats as A ON A.object_id = SO.id WHERE SO.xtype = 'U' ORDER BY so.name, sc.column_id /*SQL 2008*/ SELECT SO.NAME AS tableName, COL_NAME(sc.object_id, sc.column_id) AS columnName, A.name as stats_name, SSC.*, SSR.* FROM sys.sysrscols SSC INNER JOIN sys.sysrowsets SSR ON SSC.rowsetID = SSR.rowsetID INNER JOIN sys.sysobjects SO ON SSR.idmajor = SO.id INNER JOIN sys.stats_columns SC on SSR.idmajor = SC.object_id AND SSC.rscolid = SC.column_id INNER JOIN sys.stats as A ON A.object_id = SO.id WHERE SO.xtype = 'U' ORDER BY so.name, sc.column_id
Isso é uma informação interessante,,, por que precisamos disso? Imagine uma tabela com alguns milhões de linhas, se a atualização de estatísticas ocorre apenas a cada 20%+500 modificações é bem provável que o intervalo entre uma atualização e a outra seja um pouco grande…
Aí você pergunta: mas eu faço rebuild dos meus índices com uma boa frequência e eu sei que, com esse processo, ele já faz a atualização das estatísticas, o que eu ganho com isso?
Ai eu respondo: Você pode ter estatísticas que são criadas automaticamente,,, lembra da opção do “auto create statistics” que costuma estar habilitada por padrão? da uma olhada na sua tabela, veja se existem estatísticas começando com _WA então,,, o rebuild de índices vai atualizas as estatísticas que ele utiliza e não todas as da tabela…
bom,,,, é isso,,, bom proveito…
A algumas semanas atrás eu estava ajudando um cliente a localizar problemas de lentidão no ambiente dele. Não havia um ponto exato, não era sempre na mesma aplicação, muitas vezes nem a mesma unidade, isso ajudava muito na localização do problema,,,
Um dos analistas de desenvolvimento me indagou se o servidor de SQL estava sofrendo com problemas de processador,,, em alguns momentos o servidor apresentava alguns picos em um dos núcleos mas nada muito longo muito menos alarmante.
Com a query abaixo, mostrei que não havia problemas de processamento,,, pelo menos naquele momento…
Select signal_wait_time_ms=sum(signal_wait_time_ms)<br>,'%signal (cpu) waits' = cast(100.0 * sum(signal_wait_time_ms) / sum (wait_time_ms) as numeric(20,2))<br>,resource_wait_time_ms=sum(wait_time_ms - signal_wait_time_ms)<br>,'%resource waits'= cast(100.0 * sum(wait_time_ms - signal_wait_time_ms) / sum (wait_time_ms) as numeric(20,2))<br>From sys.dm_os_wait_stats
O resultado é o seguinte:
Agora vem a pergunta: Legal, mas idaí?
O que nos interessa nesse resultado é o %signal (cpu) waits e o %resource waits.
A matemática é bem simples: quanto mais %recouce waits e menos %signal (cpu) waits melhor, quer dizer que, nesse momento não está havendo problemas de pressão com processador, não quer dizer que daqui a 1 segundo não comece a ter, mas no momento da execução dessa query não havia problema.
English version
A few weeks ago i was helping a client to find a slow problem on his environment. Don´t had a exact point, not always the same apllication, even the same place and this help a lot to find the problem.
One of the developers ask me if the SQL Server had problems with processos pressure,,, in a few moments on the day the server show a top processes in one of the cores, but was not the problem.
With the query below i show that we don´t have any problem with the processor, in that moment…
Select signal_wait_time_ms=sum(signal_wait_time_ms)<br>,'%signal (cpu) waits' = cast(100.0 * sum(signal_wait_time_ms) / sum (wait_time_ms) as numeric(20,2))<br>,resource_wait_time_ms=sum(wait_time_ms - signal_wait_time_ms)<br>,'%resource waits'= cast(100.0 * sum(wait_time_ms - signal_wait_time_ms) / sum (wait_time_ms) as numeric(20,2))<br>From sys.dm_os_wait_stats
The result was:
And then comes the question: Cool, but WTF?
The important is %signal (cpu) waits and %resource waits.
The mathematic is simple: more %recouce waits and lass %signal (cpu) waits is better, in that moment the server don´t have processos pressure.
Sorry about the poor English, i´ll fix at night.