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.
Acho que uma das piores coisas é chegar em um cliente e ver que ele tem recurso de Hardware mas alguém fez a infelicidade de instalar o SQL x86 ao invés de instalar a opção x64…
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 .
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…
Localize onde o SQL está instalado, procure dentro do diretório BINN um diretório chamado Resources e dentro dele outro diretório chamado 1033
Dentro deste diretório deve existir um arquivo chamadq sqlevn7.rll.
Abra o Editor de Registro (regedit), procure pela chave [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Eventlog\Application\MSSQLServer] ou [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Eventlog\Application\MSSQL$INSTANCE_NAME] em INSTANCE_NAME localize o nome da sua instância.
Do lado da direita localize uma entrada do tipo REG_SZ com o nome EventMessageFile
Compare o caminho para o diretório do arquivo sqlevn70.rll em relação ao local onde você localizou o arquivo na sua instalação, provavelmente são diferentes…
Faça um backup da chave de registro.
Substitua o caminho da chave EventMessageFile pelo caminho onde você localizou o arquivo sqlevn7.rll na sua instalação.
Feche e abra o Event Viewer,,,
Localize o evento que antes estava como o exemplo acima,,, e você terá a informação sendo mostrada corretamente.
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:
Eu poderia escolher de qual a qual número. Ex.: tabuada do 2 ao 10 ou do 5 ao 20…
em todos os casos o resultado deveria ser um texto que possuísse o símbolo de multiplicação X e o sinal de igual =…
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…
Lembre-se de trocar o local onde vai salvar o arquivo do evento;
Lembre-se de se estiver usando apenas o arquivo como saída parar o evento pare uma vez ou outra a captura, dependendo da quantidade de execuções e conexões o arquivo pode crescer muito e muito rápido.
se você não configurar o filtro corretamente, você pode para seu ambiente.
A conexao do powerpivot tem que ser alterado apontando para seu servidor.
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 bases e sabe como ela funciona,,, certo?
Bom,,, no bom e velho “by the book” o “auto update statistics” funciona assim:
Em uma tabela permanente:
se a tabela não tem linhas, as estatísticas são atualizadas quando uma alteração for executada na tabela
se o número de linhas for menor que 500, as estatísticas são atualizadas a cada 500 alterações na tabela
se o número de linhas for superior a 500, as estatísticas são atualizadas a cada 20% + 500 alterações na tabela
Tabelas temporárias:
se a tabela não tem linhas, as estatísticas são atualizadas quando uma alteração for executada na tabela
se a tabela possui menos de 6 linhas, as estatísticas são atualizadas a cada 6 alterações na tabela
se o número de linhas for menor que 500, as estatísticas são atualizadas a cada 500 alterações na tabela
se o número de linhas for superior a 500, as estatísticas são atualizadas a cada 20% + 500 alterações na tabela
Tabelas variáveis (ficou feio,,, eu sei)
Não existem estatísticas em variáveis de tabela (agora ficou menos pior)
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…
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.
Sou muito fã de ferramentas que ajudem a facilitar o dia a dia na administração do SQL, vocês já devem ter visto isso no Post Top 5 – Ferramentas Grátis,
Eu estava fazendo o download de umas ferramentas no site da RedGate e achei esse programa muito interessante,,, simples,,, gratuito,,, o SQL Index Manager,,,
Com apenas 2.4MB, ele promete uma análise de todos os índices de todas as bases que estão na sua instância e recomenda o rebuild ou reindex de cada um deles,,,
Fiz um teste em uma instância com 230 bases, com mais de 7000 índices e ele demorou aprox. 4 minutos.
A ferramenta possui uma interface extremamente simples:
Você pode deixar a ferramenta executar a manutenção para você, ou
Ela gera os scripts para que você execute manualmente
O tempo que ela demora para executar o rebuild ou reindex é o mesmo que o script ou algum plano de manutenção que você crie levaria para fazer, porque no final, a ferramenta faz a mesma coisa que você já deveria fazer…
Now in English…
I´m a fanatic about tools that help the day by day in SQL administration.
I was downloading a few tools from RedGate and find this very nice program, simple and free the SQL Index Manager,,,
With only 2.4MB, the program analyse all your indexes in all your databases and recomends a rebuild or reindex of each one.
I do a test in a server with 230 databases and more that 7000 indexes he toke 4 minutes.
The tool is extreme easy of use. (image1)
He can fix for you or generate the script. (image2)
The scripts are simples without a lot of comments (image3)
And take the same time of your Maintenance plan or custom script. (image4)
Todo mundo merece uma segunda chance,, ou para fazer melhor, ou para simplesmente não fazer,,, então,,, até no SQL temos uma segunda chance…
Dessa vez o Sr. David Howard (Blog | Twitter) deu a oportunidade de escrevermos novamente sobre algum tópico anterior do T-SQL Tuesday, ou para melhora-lo ou para fazer um se você não participou…
Eu resolvi melhorar o meu script para montar um Mirror com SQLCMD,,, na versão anterior (#25) se o banco de dados tiver mais que um datafile você tem que modificar o script na mão e compensar a criação desse outro arquivo… Nesta versão o script vai ler o arquivo de backup em uma temp table e montar o script de restore com todas as variáveis…
Vale lembrar que você precisa habilitar a opção de SQLCMD no SSMS e não esqueça de trocar o caminho do backup…
Everyone deserves a second chance, or to do better or to simply not do, then, even in SQL havea second chance…
This time Mr. David Howard (blog | twitter) gave us the opportunity to write again about a previous topic of Tuesday’s T-SQL, or to improve it or make one if you did not participate …
I decided to improve my script to create a Mirror with SQLCMD, in the previous version (#25) if the database has more than one datafile you have to modify the script and make the creation of another file … this version will read backup file in a temp table and mount the restore script with all the variables …
Remember that you need to enable the option of SQLCMD in SSMS and do not forget to change the backup path …
:SETVAR PrincipalServer (local)\INST01
:SETVAR MirrorServer (local)\INST02
:SETVAR SERVER (servername)
:SETVAR db DB_NAME
go
:ON ERROR EXIT
go
:CONNECT $(PrincipalServer)
ALTER DATABASE $(db)
SET RECOVERY FULL
go
CREATE ENDPOINT Mirroring
STATE=STARTED
AS TCP (LISTENER_PORT=5091)
FOR DATABASE_MIRRORING (ROLE=ALL)
GO
:CONNECT $(MirrorServer)
CREATE ENDPOINT Mirroring
STATE=STARTED
AS TCP (LISTENER_PORT=5092)
FOR DATABASE_MIRRORING (ROLE=ALL)
GO
:CONNECT $(PrincipalServer)
BACKUP DATABASE $(db)
TO DISK = 'D:\DB01\local\$(db).bak'
WITH INIT
GO
:CONNECT $(MirrorServer)
DECLARE @InstanceName sql_variant,
@InstanceDir sql_variant,
@SQLDataRoot nvarchar(512),
@ExecStr nvarchar(max)
SELECT @InstanceName = ISNULL(SERVERPROPERTY('InstanceName'), 'MSSQLServer')
EXECUTE master.dbo.xp_regread 'HKEY_LOCAL_MACHINE',
'SOFTWARE\Microsoft\Microsoft SQL Server\Instance Names\SQL',
@InstanceName, @InstanceDir OUTPUT
SELECT @ExecStr = 'EXECUTE master.dbo.xp_regread '
+ '''HKEY_LOCAL_MACHINE'', '
+ '''SOFTWARE\Microsoft\Microsoft SQL Server\'
+ convert(varchar, @InstanceDir)
+ '\Setup'', ''SQLDataRoot'', @SQLDataRoot OUTPUT'
EXEC master.dbo.sp_executesql @ExecStr
, N'@SQLDataRoot nvarchar(512) OUTPUT'
, @SQLDataRoot OUTPUT
IF @SQLDataRoot IS NULL
BEGIN
RAISERROR ('I can´t find where restore the Database... I going to stop...', 16, -1)
END
CREATE TABLE #BackupFileList
( LogicalName sysname NULL
, PhysicalName sysname NULL
, [Type] char(1)
, FileGroupName sysname NULL
, Size bigint
, MaxSize bigint
, FileId smallint
, CreateLSN numeric(25,0)
, DropLSN numeric(25,0)
, UniqueId uniqueidentifier
, ReadOnlyLSN numeric(25,0)
, ReadWriteLSN numeric(25,0)
, BackupSizeInBytes bigint
, SourceBlockSize bigint
, FileGroupId smallint
, LogGroupGUID uniqueidentifier
, DifferentialBaseLSN numeric(25,0)
, DifferentialBaseGUID uniqueidentifier
, IsReadOnly bit
, IsPresent bit
, TDEThumbPrint varbinary(32)
)
INSERT #BackupFileList
EXEC('RESTORE FILELISTONLY FROM DISK = ''D:\DB01\local\$(db).bak''')
UPDATE #BackupFileList
SET PhysicalName
= @SQLDataRoot
+ N'\Data\'
+ REVERSE(SUBSTRING(REVERSE(PhysicalName)
, 1, PATINDEX('%\%', REVERSE(PhysicalName)) -1))
DECLARE @LogicalName sysname
, @PhysicalName sysname
DECLARE FileListCursor CURSOR FAST_FORWARD FOR
SELECT LogicalName, PhysicalName
FROM #BackupFileList
OPEN FileListCursor
FETCH NEXT FROM FileListCursor INTO @LogicalName, @PhysicalName
SELECT @ExecStr = N'RESTORE DATABASE $(db)' +
N' FROM DISK = ''D:\DB01\local\$(db).bak''' +
N' WITH MOVE ''' + @LogicalName + N''' TO ''' + @PhysicalName + N''''
FETCH NEXT FROM FileListCursor INTO @LogicalName, @PhysicalName
WHILE @@FETCH_STATUS <> -1
BEGIN
SELECT @ExecStr = @ExecStr + N', MOVE ''' + @LogicalName
+ ''' TO ''' + @PhysicalName + ''''
FETCH NEXT FROM FileListCursor INTO @LogicalName, @PhysicalName
END
SELECT @ExecStr = @ExecStr + N' , NORECOVERY, REPLACE'
-- if you receive the error message because the script don´t found where he need to restore, you can uncomment the next line and get the restore command,,,
-- to restore manual...
-- SELECT @ExecStr
EXEC (@ExecStr)
DEALLOCATE FileListCursor
GO
:CONNECT $(PrincipalServer)
SELECT DATABASEPROPERTYEX(N'$(db)', N'Status') AS 'Principal Database State' -- Returns ONLINE
SELECT db_name(sd.[database_id]) AS [Database Name],
sd.mirroring_guid,
sd.mirroring_state,
sd.mirroring_state_desc,
sd.mirroring_partner_name,
sd.mirroring_witness_name,
sd.mirroring_witness_state,
sd.mirroring_witness_state_desc,
sd.mirroring_role,
sd.mirroring_role_desc,
sd.mirroring_role_sequence,
sd.mirroring_safety_level,
sd.mirroring_safety_level_desc,
sd.mirroring_safety_sequence,
sd.mirroring_failover_lsn
FROM sys.database_mirroring AS sd
WHERE sd.[database_id] = db_id(N'$(db)')
go
:CONNECT $(MirrorServer)
SELECT DATABASEPROPERTYEX(N'$(db)', N'Status') AS 'Mirror Database State' -- Returns RESTORING
SELECT db_name(sd.[database_id]) AS [Database Name],
sd.mirroring_guid,
sd.mirroring_state,
sd.mirroring_state_desc,
sd.mirroring_partner_name,
sd.mirroring_witness_name,
sd.mirroring_witness_state,
sd.mirroring_witness_state_desc,
sd.mirroring_role,
sd.mirroring_role_desc,
sd.mirroring_role_sequence,
sd.mirroring_safety_level,
sd.mirroring_safety_level_desc,
sd.mirroring_safety_sequence,
sd.mirroring_failover_lsn
FROM sys.database_mirroring AS sd
WHERE sd.[database_id] = db_id(N'$(db)')
go
:CONNECT $(PrincipalServer)
BACKUP LOG $(db)
TO DISK = 'D:\DB01\local\$(db)_Log.bak'
WITH INIT
GO
:CONNECT $(MirrorServer)
RESTORE LOG $(db)
FROM DISK = 'D:\DB01\local\$(db)_Log.bak'
WITH NORECOVERY
GO
ALTER DATABASE $(db)
SET PARTNER = 'TCP://$(server):5091'
GO
:CONNECT $(PrincipalServer)
ALTER DATABASE $(db)
SET PARTNER = 'TCP://$(server):5092'
GO
SELECT db_name(sd.[database_id]) AS [Database Name],
sd.mirroring_guid,
sd.mirroring_state,
sd.mirroring_state_desc,
sd.mirroring_partner_name,
sd.mirroring_witness_name,
sd.mirroring_witness_state,
sd.mirroring_witness_state_desc,
sd.mirroring_role,
sd.mirroring_role_desc,
sd.mirroring_role_sequence,
sd.mirroring_safety_level,
sd.mirroring_safety_level_desc,
sd.mirroring_safety_sequence,
sd.mirroring_failover_lsn
FROM sys.database_mirroring AS sd
WHERE sd.[database_id] = db_id(N'$(db)')
GO
let's make things better
Manage Cookie Consent
To provide the best experiences, we use technologies like cookies to store and/or access device information. Consenting to these technologies will allow us to process data such as browsing behavior or unique IDs on this site. Not consenting or withdrawing consent, may adversely affect certain features and functions.
Functional
Always active
The technical storage or access is strictly necessary for the legitimate purpose of enabling the use of a specific service explicitly requested by the subscriber or user, or for the sole purpose of carrying out the transmission of a communication over an electronic communications network.
Preferences
The technical storage or access is necessary for the legitimate purpose of storing preferences that are not requested by the subscriber or user.
Statistics
The technical storage or access that is used exclusively for statistical purposes.The technical storage or access that is used exclusively for anonymous statistical purposes. Without a subpoena, voluntary compliance on the part of your Internet Service Provider, or additional records from a third party, information stored or retrieved for this purpose alone cannot usually be used to identify you.
Marketing
The technical storage or access is required to create user profiles to send advertising, or to track the user on a website or across several websites for similar marketing purposes.
To provide the best experiences, we use technologies like cookies to store and/or access device information. Consenting to these technologies will allow us to process data such as browsing behavior or unique IDs on this site. Not consenting or withdrawing consent, may adversely affect certain features and functions.