O que é uma Table variable?

O que é uma table variable (variável do tipo table) no SQL Server?

É uma variável como qualquer outra com um tipo de dados especial (table) que pode ser usado para armazenar um result set qualquer.

Como criar/declarar uma table variable?


DECLARE @produto TABLE
(
id int,
valor money
)

Como consultar uma table variable?

SELECT id, valor FROM @produto;

Quando usar?

Utilize variáveis do tipo TABLE apenas para armazenar poucos registros (Até 100 registros de preferência).

Curiosidades

  • Não possuem estatísticas;
  • Não podem ser alteradas depois de criadas;
  • Não são afetadas por ROLLBACK, pois elas não suportam transações;
  • Não existe garantia que estarão residentes apenas em memória. Sob pressão de memória as páginas pertencentes a uma variável do tipo TABLE podem ser transferidas para a database tempdb;
  • Em consultas que façam junções em uma table variable considere utilizar o hintRECOMPILE para fazer com que o otimizador use a cardinalidade correta para ela.

Referências:

https://docs.microsoft.com/en-us/sql/t-sql/language-elements/declare-local-variable-transact-sql

https://docs.microsoft.com/en-us/sql/t-sql/data-types/table-transact-sql

Anúncios

Como transferir logins e senhas entre instâncias do SQL Server

Simples.

Basta criar as stored procedures sp_hexadecimal e sp_help_revlogin na database master do servidor de origem com a ajuda do código abaixo:

USE master
GO
IF OBJECT_ID ('sp_hexadecimal') IS NOT NULL
DROP PROCEDURE sp_hexadecimal
GO
CREATE PROCEDURE sp_hexadecimal
@binvalue varbinary(256),
@hexvalue varchar (514) OUTPUT
AS
DECLARE @charvalue varchar (514)
DECLARE @i int
DECLARE @length int
DECLARE @hexstring char(16)
SELECT @charvalue = '0x'
SELECT @i = 1
SELECT @length = DATALENGTH (@binvalue)
SELECT @hexstring = '0123456789ABCDEF'
WHILE (@i <= @length)
BEGIN
DECLARE @tempint int
DECLARE @firstint int
DECLARE @secondint int
SELECT @tempint = CONVERT(int, SUBSTRING(@binvalue,@i,1))
SELECT @firstint = FLOOR(@tempint/16)
SELECT @secondint = @tempint - (@firstint*16)
SELECT @charvalue = @charvalue +
SUBSTRING(@hexstring, @firstint+1, 1) +
SUBSTRING(@hexstring, @secondint+1, 1)
SELECT @i = @i + 1
END</pre>
SELECT @hexvalue = @charvalue
GO

IF OBJECT_ID ('sp_help_revlogin') IS NOT NULL
DROP PROCEDURE sp_help_revlogin
GO
CREATE PROCEDURE sp_help_revlogin @login_name sysname = NULL AS
DECLARE @name sysname
DECLARE @type varchar (1)
DECLARE @hasaccess int
DECLARE @denylogin int
DECLARE @is_disabled int
DECLARE @PWD_varbinary varbinary (256)
DECLARE @PWD_string varchar (514)
DECLARE @SID_varbinary varbinary (85)
DECLARE @SID_string varchar (514)
DECLARE @tmpstr varchar (1024)
DECLARE @is_policy_checked varchar (3)
DECLARE @is_expiration_checked varchar (3)

DECLARE @defaultdb sysname

IF (@login_name IS NULL)
DECLARE login_curs CURSOR FOR

SELECT p.sid, p.name, p.type, p.is_disabled, p.default_database_name, l.hasaccess, l.denylogin FROM
sys.server_principals p LEFT JOIN sys.syslogins l
ON ( l.name = p.name ) WHERE p.type IN ( 'S', 'G', 'U' ) AND p.name <> 'sa'
ELSE
DECLARE login_curs CURSOR FOR

&nbsp;

SELECT p.sid, p.name, p.type, p.is_disabled, p.default_database_name, l.hasaccess, l.denylogin FROM
sys.server_principals p LEFT JOIN sys.syslogins l
ON ( l.name = p.name ) WHERE p.type IN ( 'S', 'G', 'U' ) AND p.name = @login_name
OPEN login_curs

FETCH NEXT FROM login_curs INTO @SID_varbinary, @name, @type, @is_disabled, @defaultdb, @hasaccess, @denylogin
IF (@@fetch_status = -1)
BEGIN
PRINT 'No login(s) found.'
CLOSE login_curs
DEALLOCATE login_curs
RETURN -1
END
SET @tmpstr = '/* sp_help_revlogin script '
PRINT @tmpstr
SET @tmpstr = '** Generated ' + CONVERT (varchar, GETDATE()) + ' on ' + @@SERVERNAME + ' */'
PRINT @tmpstr
PRINT ''
WHILE (@@fetch_status <> -1)
BEGIN
IF (@@fetch_status <> -2)
BEGIN
PRINT ''
SET @tmpstr = '-- Login: ' + @name
PRINT @tmpstr
IF (@type IN ( 'G', 'U'))
BEGIN -- NT authenticated account/group

SET @tmpstr = 'CREATE LOGIN ' + QUOTENAME( @name ) + ' FROM WINDOWS WITH DEFAULT_DATABASE = [' + @defaultdb + ']'
END
ELSE BEGIN -- SQL Server authentication
-- obtain password and sid
SET @PWD_varbinary = CAST( LOGINPROPERTY( @name, 'PasswordHash' ) AS varbinary (256) )
EXEC sp_hexadecimal @PWD_varbinary, @PWD_string OUT
EXEC sp_hexadecimal @SID_varbinary,@SID_string OUT

-- obtain password policy state
SELECT @is_policy_checked = CASE is_policy_checked WHEN 1 THEN 'ON' WHEN 0 THEN 'OFF' ELSE NULL END FROM sys.sql_logins WHERE name = @name
SELECT @is_expiration_checked = CASE is_expiration_checked WHEN 1 THEN 'ON' WHEN 0 THEN 'OFF' ELSE NULL END FROM sys.sql_logins WHERE name = @name

SET @tmpstr = 'CREATE LOGIN ' + QUOTENAME( @name ) + ' WITH PASSWORD = ' + @PWD_string + ' HASHED, SID = ' + @SID_string + ', DEFAULT_DATABASE = [' + @defaultdb + ']'

IF ( @is_policy_checked IS NOT NULL )
BEGIN
SET @tmpstr = @tmpstr + ', CHECK_POLICY = ' + @is_policy_checked
END
IF ( @is_expiration_checked IS NOT NULL )
BEGIN
SET @tmpstr = @tmpstr + ', CHECK_EXPIRATION = ' + @is_expiration_checked
END
END
IF (@denylogin = 1)
BEGIN -- login is denied access
SET @tmpstr = @tmpstr + '; DENY CONNECT SQL TO ' + QUOTENAME( @name )
END
ELSE IF (@hasaccess = 0)
BEGIN -- login exists but does not have access
SET @tmpstr = @tmpstr + '; REVOKE CONNECT SQL TO ' + QUOTENAME( @name )
END
IF (@is_disabled = 1)
BEGIN -- login is disabled
SET @tmpstr = @tmpstr + '; ALTER LOGIN ' + QUOTENAME( @name ) + ' DISABLE'
END
PRINT @tmpstr
END

FETCH NEXT FROM login_curs INTO @SID_varbinary, @name, @type, @is_disabled, @defaultdb, @hasaccess, @denylogin
END
CLOSE login_curs
DEALLOCATE login_curs
RETURN 0
GO
<pre>

Importante: Sempre consulte o código mais atualizado destas procedures e leia todas as observações e detalhes direto no KB original da Microsoft: https://support.microsoft.com/en-us/help/918992/how-to-transfer-logins-and-passwords-between-instances-of-sql-server

Agora no servidor de origem conectado na database master execute o comando abaixo:


EXEC sp_help_revlogin

Pronto. O resultado deste comando será o script pronto de todos os logins e senhas da sua instância de SQL Server mantendo os SIDs e senhas originais.

Agora no servidor de destino apenas execute o script gerado com a ajuda da procedure sp_help_revlogin.

Por hoje é isso pessoal. Espero que tenham gostado.

Como estimar o tempo de backup e restore no SQL Server

Já passou mais de 1 hora, seu BACKUP ou RESTORE ainda não finalizou e você está querendo uma estimativa do tempo de conclusão?

Fácil.

Basta executar o comando abaixo na sua instância de SQL Server utilizando a DMV (Dynamic Management View) dm_exec_requests para retornar as colunas percent_complete e estimated_completion_time e a DMF (Dynamic Management Function) dm_exec_sql_text para retornar o comando/TSQL de BACKUP/RESTORE executado.

SELECT
session_id as SPID,
command, s.text AS Query,
start_time,
percent_complete,
dateadd(second,estimated_completion_time/1000, getdate()) as estimated_completion_time
FROM sys.dm_exec_requests r
CROSS APPLY sys.dm_exec_sql_text(r.sql_handle) s
WHERE r.command in ('BACKUP DATABASE','RESTORE DATABASE')
GO

Retorno:

Screen Shot 2017-08-24 at 03.08.44

Pronto! Até a próxima.

Descobrindo se os seus planos de execução estão sendo reutilizados no SQL Server

Quer saber se os seus planos de execução que estão em cache no SQL Server estão sendo reutilizados?

Para visualizar a quantidade e porcentagem de planos de execução que estão sendo reutilizados basta executar a consulta abaixo:


DECLARE @singleExec BIGINT;
DECLARE @multipleExec BIGINT;
DECLARE @totalExec BIGINT;

SELECT @singleExec = COUNT(*)
FROM sys.dm_exec_query_stats s
WHERE execution_count = 1
SELECT @totalExec = COUNT(*)
FROM sys.dm_exec_query_stats s

SET @multipleExec = @totalExec - @singleExec

SELECT @totalExec AS totalExec, @multipleExec AS multipleExec, @singleExec AS singleExec
UNION ALL
SELECT 100 AS totalExec, ((@multipleExec * 100) / @totalExec) AS multipleExec, ((@singleExec * 100) / @totalExec) AS singleExec

Resultado:

Screen Shot 2017-08-24 at 03.21.28

Primeira linha: #

Segunda linha: %

totalExec: Total de planos de execução em cache.

multipleExec: Total de planos de execução em cache que foram reutilizados.

singleExec: Total de planos de execução em cache que foram utilizados apenas uma única vez.

Se este script foi útil para você avalie na galeria de scripts da TechNet por gentileza: https://gallery.technet.microsoft.com/SQL-Server-Get-Plan-Reuse-412de376

Obrigado! Espero que tenham gostado. Até a próxima!

Mapeando uma instância de SQL Server para uma instância de MSDTC

Precisando mapear uma instância de SQL Server para uma instância específica do MSDTC?

Aí vão algumas dicas e comandos para facilitar a sua vida.

Listar todos os mapeamentos do MSDTC:


msdtc.exe -tmMappingView *

Adicionar um mapeamento de uma instância do SQL server para uma instância do MSDTC:


msdtc -tmMappingSet -name "nomeDoMapeamento" -service 'MSSQL$nomeInstancia' -clusterResourceName "nomeDoRecursoDoMsdtcDentroDoCluster"

Screen Shot 2017-08-24 at 01.59.58

Importante: Se você adicionar um mapeamento incorreto o comando de criação será bem sucedido, mas o seu mapeamento não irá funcionar corretamente.

Remover um mapeamento realizado anteriormente:


msdtc.exe -tmMappingClear -name "nomeDoMapeamento"

Mais informações, dicas e boas práticas sobre MSDTC/SQL Server podem ser encontradas nas documentações abaixo:

https://blogs.msdn.microsoft.com/cindygross/2009/02/22/how-to-configure-dtc-for-sql-server-in-a-windows-2008-cluster/

https://blogs.msdn.microsoft.com/alwaysonpro/2014/01/15/msdtc-recommendations-on-sql-failover-cluster/

É isso galera. Espero que tenham gostado.

Como remover um plano de execução específico do cache do SQL Server

Tudo está indo bem, o seu servidor de SQL está com baixa utilização de CPU, PLE alto, poucos índices fragmentados e as estatísticas atualizadas, quando de repente a utilização de CPU sobe para 100% e você nota que existem várias sessões de uma mesma aplicação executando a mesma consulta, que até então nunca tinha apresentado problema, demorando demais para retornar o resultado e estão bombardeando o SQL Server.

Screen Shot 2016-06-17 at 11.53.55 PM

Respire fundo. Muita calma. Há uma saída.

Primeiramente você precisa do conteúdo do campo sql_handle ou plan_handle da consulta que está com problemas para remover o seu plano de execução do cache.

Para capturar o sql_handle ou plan_handle da consulta você pode utilizar apenas uma DMV e uma DMFsys.dm_exec_query_statssys.dm_exec_sql_text. Você pode filtrar utilizando um trecho da consulta que você sabe que está com problemas e/ou até mesmo ordenar por um dos campos de total de utilização de CPU ou de tempo de duração, conforme exemplo abaixo:


SELECT TOP 10
execution_count,
total_elapsed_time / 1000 as totalDurationms,
total_worker_time / 1000 as totalCPUms,
total_logical_reads,
total_physical_reads,
t.text,
sql_handle,
plan_handle
FROM sys.dm_exec_query_stats s
CROSS APPLY sys.dm_exec_sql_text(s.sql_handle) as t
WHERE t.text LIKE '%linq%'
ORDER BY total_elapsed_time DESC

Screen Shot 2016-06-17 at 11.52.10 PM

Copie o conteúdo do campo plan_handle ou sql_handle da consulta exata que está com problemas.

Insira o conteúdo copiado dentro dos parênteses do comando DBCC FREEPROCCACHE, conforme exemplo abaixo:


DBCC FREEPROCCACHE (0x0600060020527003B0928B53CC01000001000000000000000000000000000000000000000000000000000000)

Screen Shot 2016-06-18 at 12.24.18 AM

Pronto! O plano de execução da sua consulta foi removido com sucesso do cache do SQL Server e provavelmente o seu servidor irá diminuir a alta utilização de recursos e voltar a responder normalmente. Depois deste susto procure melhorar o desempenho da sua consulta e entender o que fez com que o plano de execução tenha sofrido alteração.

Observações:

  1. Utilize este procedimento como uma solução de contorno e não como uma solução definitiva para o problema. Procure melhorar o desempenho da consulta e entender o que está fazendo com que o plano de execução sofra alteração ou tenha um desempenho ruim.
  2. Nunca utilize o comando DBCC FREEPROCCACHE sem nenhum conteúdo dentro dos parênteses, principalmente em ambientes de produção, pois isto irá remover TODOS os planos de execução do cache.

 

É isso galera! Espero que tenham gostado. Até a próxima!

Como utilizar o recurso Registered Servers no SQL Server Management Studio

Galera,
Sejam bem-vindos! Vamos ao primeiro post com uma dica básica, mas que pode ajudar muito no dia-a-dia e na organização de um DBA.

Dependendo da quantidade de servidores administrados, fica cada vez mais difícil de manter a organização e também de não esquecer daquele SQL Server de criticidade baixa que quase nunca é utilizado. Para resolver esse problema, vou mostrar um recurso bem simples do SQL Server que auxilia na organização dos servidores existentes.

O recurso é chamado de Registered Servers (Servidores Registrados). Para acessar o recurso no SQL Server Management Studio, você pode ir até o menu View > Registered Servers ou utilizar as teclas de atalho Ctrl + Alt + G:

Captura de Tela 2016-01-11 às 22.24.25

Isto irá habilitar a aba de servidores registrados no canto esquerdo da janela do Management Studio:

Captura de Tela 2016-01-11 às 22.41.12

Acessando esta nova aba de servidores registrados temos duas opções: Armazenar a lista de servidores de forma local (perfil do usuário) ou em um servidor específico de forma centralizada.

Captura de Tela 2016-01-11 às 22.26.02

Recomendo o armazenamento em um servidor centralizado. Desta forma, independente do cliente que você esteja utilizando, você pode se conectar a este servidor e ter a sua lista de servidores pronta e disponível. A única limitação que temos no caso do servidor centralizado é que todos os servidores que iremos registrar devem utilizar a forma de autenticação Windows Authentication. Se você possuir um servidor que só tenha acesso com autenticação SQL, deve optar pelo armazenamento local (Local Server Groups).

Para cadastrar um servidor de gerenciamento centralizado, devemos clicar com o botão direito de Central Management Servers e navegar até a opção Register Central Management Server.

Captura de Tela 2016-01-11 às 22.41.32

Na nova janela aberta devemos apenas informar o nome do servidor que irá centralizar a lista de servidores existentes no ambiente.

Captura de Tela 2016-01-11 às 22.26.55

Com o servidor central configurado podemos iniciar a organização da lista dos servidores de SQL Server criando grupos e registrando os servidores abaixo destes grupos.

Para criar um novo grupo podemos navegar até o servidor central, clicar com o botão direito em cima dele e escolher a opção New Server Group e por fim informar um nome e uma descrição para o novo grupo.

Captura de Tela 2016-01-11 às 22.41.43

Captura de Tela 2016-01-11 às 22.28.48

Captura de Tela 2016-01-11 às 22.29.07

Para registrar um servidor abaixo de um grupo podemos navegar até o grupo criado, clicar com o botão direito em cima dele, navegar até a opção New Server Registration, e por fim informar o nome do servidor e suas credenciais de acesso.

Captura de Tela 2016-01-11 às 22.42.10

Captura de Tela 2016-01-11 às 22.32.55

Com isso você pode ir cadastrando todos os seus servidores de SQL e organizá-los por tipo de ambiente, localização, versões, etc.

Captura de Tela 2016-01-11 às 22.35.27

É possível também exportar os servidores registrados para um arquivo para serem usados posteriormente ou importados em outro servidor. Para exportar um grupo de servidores clique com o botão direito em cima do grupo e navegue até o item Tasks > Export, em seguida escolha o local e o nome do arquivo de destino.

Captura de Tela 2016-01-11 às 23.45.33

Captura de Tela 2016-01-11 às 23.47.34

Captura de Tela 2016-01-11 às 23.48.53

Com isso o grupo de servidores foi exportado com sucesso. Tá mas e agora como importa em outro servidor?

Praticamente do mesmo jeito. Clicando com o botão direito em cima do servidor de gerenciamento, navegando até o item Tasks > Import e selecionando o arquivo criado na exportação.

Captura de Tela 2016-01-11 às 23.53.04

Captura de Tela 2016-01-11 às 23.52.38

Captura de Tela 2016-01-11 às 23.52.45

Um benefício bacana que o recurso Registered Servers proporciona é realizar uma consulta em um grupo de servidores de uma forma bem simples. Clicando com o botão direito em cima de um grupo de servidores ou até mesmo do servidor de gerenciamento central e navegando até o item New query podemos executar uma consulta ao mesmo tempo em todos os servidores de um grupo.

Captura de Tela 2016-01-11 às 23.02.02

Veja abaixo dois exemplos de uma consulta feita em cima do grupo PRD e outra em cima do servidor de gerenciamento central utilizando a função SERVERPROPERTY().

Captura de Tela 2016-01-11 às 22.54.38

Captura de Tela 2016-01-11 às 22.55.16

É isso pessoal. Espero que tenham gostado!