Short Scripts – Junho 2017


Boa noite galera, olá comunidade de banco de dados.

Tudo bem? Graças a deus mais um final de semana se aproximando, finalzinho de noite de quinta – feira, acredito que neste momento minha linda esposa esta curtindo mais um episódio de uma das suas séries favoritas, ou lendo mais um dos seus intermináveis livros (kkkkkk), isso não é um crítica, muito ao contrário, a leitura faz bem para a alma e principalmente para a mente, mas posso dizer que minha pequena Fernanda é uma degustadora insaciável de livros.

Mudando de assunto, este é o segundo post deste ano dedicado exclusivamente a sessão Short Scripts, sessão criada a alguns anos que  esta atraindo um número interessante de visitantes, principalmente de profissionais da área de banco de dados na busca por exemplos de códigos que possam solucionar ou elucidar na resolução de um determinado problema.

O post de hoje

Para este post, selecionei como de costume os principais scripts armazenados recentemente na minha biblioteca de códigos, que apresentam os seguintes assuntos:

  • Check Constraint;
  • Common Table Expression;
  • Índices;
  • Information_schema.columns;
  • Monitoramento de Processos;
  • Network Protocol;
  • Operador Outer Apply;
  • Requisição de Disco;
  • Sys.dm_server_registry;
  • Sys.dm_tcp_listener_states;
  • sys.dm_exec_query_plan;
  • sys.dm_exec_sql_text;
  • sys.dm_exec_query_stats;
  • sys.types;
  • sys.tables;
  • sys.dm_db_index_usage_stats;
  • Sys.Identity_Columns; e
  • User Defined Function.

Então mãos no teclado, a seguir apresento os códigos e exemplos selecionados para o Short Script – Junho 2017. Vale ressaltar que todos os scripts publicados nesta sessão são devidamente testados, mas isso não significa que você pode fazer uso dos mesmo em seu ambiente de produção, vale sim todo cuidado possível para evitar maiores problemas.

Fique a vontade para compartilhar, comentar e melhorar cada um destes códigos.

Short Scripts

— Short Script 1  – Utilizando Check Constraint para cálculo de datas —

Create Table Alunos
(Codigo Int)
Go

— Adicionando a coluna e constraint —
Alter Table Alunos
Add DataNascimento DateTime
Constraint CK_Alunos_DataNascimento Check (DateDiff(Year,DataNascimento, GetDate()) >=18)
Go

— Adicionando somente a constraint —
Alter Table Alunos
Add Constraint CK_Alunos_DataNascimento
Check (DateDiff(Year,DataNascimento, GetDate()) >=18)
Go

— Default – Estado —
Alter Table Alunos
Add Constraint [DF_Estado] Default ‘SP’ for Estado
Go

— Short Script 2  – Aplicando o uso de Common Table Expression para inserir registros com valores de um registro anterior —

DECLARE @Metas TABLE ( Data DATE, Meta INT );

INSERT INTO @Metas
( Data, Meta )
VALUES ( DATEFROMPARTS(2017, 03, 29), 50 ),
( DATEFROMPARTS(2017, 04, 11), 35 ),
( DATEFROMPARTS(2017, 04, 13), 50 );

DECLARE @Producao TABLE
(
Data DATE ,
Quantidade INT
);

INSERT INTO @Producao
( Data, Quantidade )
VALUES ( DATEFROMPARTS(2017, 04, 10), 49 ),
( DATEFROMPARTS(2017, 04, 11), 35 ),
( DATEFROMPARTS(2017, 04, 12), 36 ),
( DATEFROMPARTS(2017, 04, 13), 50 ),
( DATEFROMPARTS(2017, 04, 14), 50 );

WITH DadosProduzidos
AS ( SELECT P.Data ,
Quantidade = SUM(P.Quantidade)
FROM @Producao AS P
GROUP BY P.Data
)
SELECT D.Data ,
[Produzido] = D.Quantidade ,
Meta = ( SELECT TOP 1 M.Meta
FROM @Metas AS M
WHERE M.Data <= D.Data
ORDER BY M.Data DESC
)
FROM DadosProduzidos D;

— Short Script 3  – Identificando a relação de todos os índices existentes em um banco de dados —

SELECT DB_NAME(Database_ID) DBName,
SCHEMA_NAME(schema_id) AS SchemaName,
OBJECT_NAME(ius.OBJECT_ID) ObjName,
i.type_desc,
i.name,
user_seeks,
user_scans,
user_lookups,
user_updates
FROM sys.dm_db_index_usage_stats ius INNER JOIN sys.indexes i
ON i.index_id = ius.index_id
AND ius.OBJECT_ID = i.OBJECT_ID
INNER JOIN sys.tables t
ON t.OBJECT_ID = i.OBJECT_ID
GO

— Short Script 4 – Obtendo informações de network protocols e device através da sys.dm_server_registry —

SELECT MAX(CONVERT(VARCHAR(15),value_data)) As ‘Default Port’ FROM sys.dm_server_registry
WHERE registry_key LIKE ‘%MSSQLServer\SuperSocketNetLib\Tcp\%’
AND value_name LIKE N’%TcpPort%’
AND CONVERT(float,value_data) > 0
Go

SELECT MAX(CONVERT(VARCHAR(15),value_data)) As ‘Dynamic Port ‘ FROM sys.dm_server_registry
WHERE registry_key LIKE ‘%MSSQLServer\SuperSocketNetLib\Tcp\%’
AND value_name LIKE N’%TcpDynamicPort%’
AND CONVERT(float,value_data) > 0
Go

— Short Script 5 – Obtendo informações de network protocols e device através da sys.dm_tcp_listener_states —

SELECT port As ‘Default Port’ FROM sys.dm_tcp_listener_states
WHERE is_ipv4 = 1
AND [type] = 0
AND ip_address <> ‘127.0.0.1’
Go

— Short Script 6 – Criando uma User Defined Function com operador Outer Apply —

CREATE FUNCTION AttributesOfTable (@tableToSearch nvarchar(500))
returns table
return SELECT TABLE_CATALOG, TABLE_SCHEMA, TABLE_NAME, COLUMN_NAME
from information_schema.columns
where TABLE_NAME = @tableToSearch;
go

Declare @tableToSearch table (nome_tabela varchar(50));
INSERT into @tableToSearch values (‘Customer’), (‘Order’), (‘Papagaio’);

SELECT T1.nome_tabela as [nome da tabela],
T2.TABLE_SCHEMA as [nome do esquema],
T2.COLUMN_NAME as [nome da coluna]
from @tableToSearch as T1
outer apply dbo.AttributesOfTable(T1.nome_tabela) as T2;

— Short Script 7 – Utilizando a DMV sys.identity_columns para identificar o valor identity de uma determinada coluna —

SELECT sys.tables.name AS [Table Name],
sys.identity_columns.name AS [Column Name],sys.types.name as Type,
last_value AS [Last Value]
FROM sys.identity_columns
INNER JOIN sys.tables
ON sys.identity_columns.object_id = sys.tables.object_id
Inner join sys.types on sys.types.user_type_id = sys.identity_columns.user_type_id
ORDER BY last_value DESC

— Short Script 8 – Consultando informações sobre o SQL Server armazenadas no Registro do Windows —

— A. Display the SQL Server services —
SELECT registry_key, value_name, value_data
FROM sys.dm_server_registry
WHERE key_name LIKE N’%ControlSet%’
Go

— B. Display the SQL Server Agent registry key values —
SELECT registry_key, value_name, value_data
FROM sys.dm_server_registry
WHERE key_name LIKE N’%SQLAgent%’
Go

— C. Display the current version of the instance of SQL Server —
SELECT registry_key, value_name, value_data
FROM sys.dm_server_registry
WHERE value_name = N’CurrentVersion’
Go

— D. Display the parameters passed to the instance of SQL Server during startup —
SELECT registry_key, value_name, value_data
FROM sys.dm_server_registry
WHERE registry_key LIKE N’%Parameters’
Go

— E. Return network configuration information for the instance of SQL Server —
SELECT registry_key, value_name, value_data
FROM sys.dm_server_registry
WHERE keyname LIKE N’%SuperSocketNetLib%’
Go

— Short Script 9 – Identificando a relação de querys que apresentam o maior consumo de disco durante seu período de processamento – 

SELECT TOP 20 SUBSTRING(qt.text,
(qs.statement_start_offset/2)+1,
((CASE
qs.statement_end_offset
WHEN -1 THEN DATALENGTH(qt.text)
ELSE
qs.statement_end_offset
END –
qs.statement_start_offset)/2)+1),
qs.execution_count,

qs.total_logical_reads, qs.last_logical_reads,
qs.min_logical_reads,
qs.max_logical_reads,
qs.total_elapsed_time,
qs.last_elapsed_time,
qs.min_elapsed_time,
qs.max_elapsed_time,
qs.last_execution_time,
qp.query_plan
FROM sys.dm_exec_query_stats
qs
CROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) qt
CROSS APPLY
sys.dm_exec_query_plan(qs.plan_handle) qp
WHERE qt.encrypted=0
ORDER BY
qs.total_logical_reads DESC

Legal, mais uma relação de short scripts acaba de ser compartilhada, mesmo sendo denominados short entre aspas “pequenos”, posso garantir que todos estes exemplos são de grande importância e apresentam um valor e conhecimento do mais alto nível.


Chegamos ao final de mais um Short Scripts, espero que este material possa lhe ajudar, ilustrando o uso de alguns recursos e funcionalidades do Microsoft SQL Server.

Acredito que você tenha observado que estes códigos são bastante conhecidos em meu blog, todos estão relacionados aos posts dedicados ao Microsoft SQL Server publicados no decorrer dos últimos anos.

Boa parte deste material é fruto de um trabalho dedicado exclusivamente a colaboração com a comunidade, visando sempre encontrar algo que possa ser a solução de um determinado problema, bem como, a demonstração de como se pode fazer uso de um determinado recurso.

Links

Caso você queira acessar os últimos posts desta sessão, não perca tempo acesse os links listados abaixo:

Agradecimento

Agradeço sua visita, com certeza é imenso prazer saber que você teve interesse em acessar este post.

Nos encontramos novamente no mês de setembro, para o próximo post dedicado a sessão Short Scripts.

Um grande abraço, boa noite, bom descanso.

Valeu.

Short Scripts – Março 2017


Hoje é sexta – feira, sexta – feira…

Salve, salve comunidade e amantes de bancos de dados e SQL Server, Tudo bem? Mais uma final de semana próximo após uma longa semana de muito trabalho, se eu for falar de muito trabalho, sinceramente  esta semana foi complicada, repleta de novidades e muita troca de conhecimento.

Conforme o prometido no final de 2016, estou retornando com o primeiro post da sessão Short Scripts, sessão criada a alguns anos no meu blog que lentamente esta conseguindo ajudar diversos profissionais da área de banco de dados na busca por exemplos de códigos que possam solucionar ou elucidar na resolução de um determinado problema.

O post de hoje

Como já destaquei acima, este é o primeiro post de 2017 dedicado exclusivamente a sessão Short Scripts, na relação de scritps selecionados para hoje, você vai poder encontrar códigos relacionados com os seguintes assuntos:

  • Auditoria,
  • Comando Intersect,
  • Comando OpenQuery,
  • Comando Order By,
  • Datatype Char,
  • Datatype Int,
  • DMF Sys.dm_exec_sessions,
  • DMV Sys.system_internals_partitions,
  • DMV Sys.system_internals_allocation_units,
  • Função Substring,
  • Índices,
  • Informações sobre conexão de usuário,
  • Páginas de Dados,
  • Trigger, e
  • Variáveis.

Então mãos no teclado, a seguir apresento os códigos e exemplos selecionados para o Short Script – Março 2017. Vale ressaltar que todos os scripts publicados nesta sessão são devidamente testados antes de serem publicados, mas isso não significa que você pode fazer uso dos mesmo em seu ambiente de produção, vale sim todo cuidado possível para evitar maiores problemas. Fique a vontade para compartilhar, comentar, melhorar cada um destes códigos.

Short Scripts

— Short Script 1 – Realizando Auditoria in Live —

SELECT [Spid] = session_Id
, ecid
, [Database] = DB_NAME(sp.dbid)
, [User] = nt_username
, [Status] = er.status
, [Wait] = wait_type
, [Individual Query] = SUBSTRING (qt.text,
er.statement_start_offset/2,
(CASE WHEN er.statement_end_offset = -1
THEN LEN(CONVERT(NVARCHAR(MAX), qt.text)) * 2
ELSE er.statement_end_offset END –
er.statement_start_offset)/2)
,[Parent Query] = qt.text
, Program = program_name
, Hostname
, nt_domain
, start_time
FROM sys.dm_exec_requests er
INNER JOIN sys.sysprocesses sp ON er.session_id = sp.spid
CROSS APPLY sys.dm_exec_sql_text(er.sql_handle)as qt
WHERE session_Id > 50              — Ignore system spids.
AND session_Id NOT IN (@@SPID)     — Ignore this current statement.
ORDER BY 1, 2
Go

— Short Script 2 – Utilizando comando Intersect com Datatypes Char e Int —

Create Table #A (x Char(2));
Go
Insert Into #A Values (‘1’);
Insert Into #A Values (‘6’);
Insert Into #A Values (‘2’);
Insert Into #A Values (‘3’);
Insert Into #A Values (‘5’);
Insert Into #A Values (‘5’);
Insert Into #A Values (‘6’);
Insert Into #A Values (‘9’);
Go
Create Table #B (M BigInt);
Go
Insert Into #B Values(5);
Insert Into #B Values(5);
Insert Into #B Values(6);
Insert Into #B Values(7);
Insert Into #B Values(7);
Go
— (Select #1)
SELECT x AS ‘Select #1’ FROM #A
INTERSECT SELECT M FROM #B
Go
— (Select #2)
SELECT DISTINCT(x) AS ‘Select #2’
FROM #A LEFT OUTER JOIN #B
ON #A.x = #B.M
Go
— (Select #3)
SELECT DISTINCT(x) AS ‘Select #3’
FROM #A LEFT OUTER JOIN #B
ON #A.x = #B.M
Go
— (Select #4)
SELECT DISTINCT(x) AS ‘Select #4’
FROM #A INNER JOIN #B
ON #A.x = #B.M
Go
— (Select #5)
SELECT x AS ‘Select #5’
FROM #A INNER JOIN #B
ON #A.x = #B.M
Go
— Short Script 3 – Utilizando comando OpenQuery com variáveis —
— Valores Básicos —
DECLARE @TSQL varchar(8000), @VAR char(2)
SELECT  @VAR = ‘teste’
SELECT  @TSQL = ‘SELECT * FROM OPENQUERY(MeuLinkedServer,”SELECT * FROM MinhaTabela WHERE User = ””’ + @VAR + ”””’)’
EXEC (@TSQL)
Go
— Query Complexa —
DECLARE @OPENQUERY nvarchar(4000), @TSQL nvarchar(4000), @LinkedServer nvarchar(4000)
SET @LinkedServer = ‘MyLinkedServer’
SET @OPENQUERY = ‘SELECT * FROM OPENQUERY(‘+ @LinkedServer + ‘,”’
SET @TSQL = ‘SELECT au_lname, au_id FROM pubs..authors”)’
EXEC (@OPENQUERY+@TSQL)
— Use o Sp_executesql procedimento armazenado —
DECLARE @VAR char(2)
SELECT  @VAR = ‘CA’
EXEC MyLinkedServer.master.dbo.sp_executesql
N’SELECT * FROM pubs.dbo.authors WHERE state = @state’,
N’@state char(2)’,
@VAR
Go
— Short Script 4 – Realizando order by com base na função SubString —
Declare @Tabela Table
(Codigo VarChar(15))
Insert Into @Tabela Values(‘191-XXX-003’)
Insert Into @Tabela Values(‘192-XXX-003’)
Insert Into @Tabela Values(‘193-XXX-003’)
Insert Into @Tabela Values(‘194-XXX-003’)
Insert Into @Tabela Values(‘195-XXX-003’)
Insert Into @Tabela Values(‘191-XXX-001’)
Insert Into @Tabela Values(‘192-XXX-001’)
Insert Into @Tabela Values(‘193-XXX-001’)
Insert Into @Tabela Values(‘194-XXX-001’)
Insert Into @Tabela Values(‘195-XXX-001’)
Insert Into @Tabela Values(‘191-XXX-002’)
Insert Into @Tabela Values(‘192-XXX-002’)
Insert Into @Tabela Values(‘193-XXX-002’)
Insert Into @Tabela Values(‘194-XXX-002’)
Insert Into @Tabela Values(‘195-XXX-002’)
Select * from @Tabela
Order By SubString(codigo,Len(Codigo)-2,3) Asc
Go
— Short Script 5 – Monitorando querys em execução —
SELECT
DES.SESSION_ID,
DES.CPU_TIME,
DES.READS,
DES.WRITES,
DES.LOGICAL_READS,
DES.ROW_COUNT,
DER.SESSION_ID,
DES.STATUS,
DES.HOST_NAME,
DES.PROGRAM_NAME,
DES.LOGIN_NAME,
DES.ORIGINAL_LOGIN_NAME,
DEC.CLIENT_NET_ADDRESS,
DEC.AUTH_SCHEME,
DEC.NET_TRANSPORT,
SUBSTRING(T.[TEXT], DER.[STATEMENT_START_OFFSET] / 2,
COALESCE(NULLIF(DER.[STATEMENT_END_OFFSET], – 1) / 2, 2147483647)) AS COMANDO
FROM
SYS.DM_EXEC_SESSIONS AS DES
INNER JOIN SYS.DM_EXEC_REQUESTS DER
ON DER.BLOCKING_SESSION_ID = DES.SESSION_ID
INNER JOIN SYS.DM_EXEC_CONNECTIONS DEC
ON DEC.SESSION_ID = DES.SESSION_ID
INNER JOIN SYS.DM_EXEC_REQUESTS DER2
ON DER2.SESSION_ID = DES.SESSION_ID
CROSS APPLY SYS.DM_EXEC_SQL_TEXT(DER.[SQL_HANDLE]) AS T
GO
— Short Script 6 – Identificando tabelas e suas respectivas páginas de dados —
— Exemplo 1: —
SELECT P.partition_id,
OBJECT_NAME(P.object_id) As ObjectName,
U.allocation_unit_id,
SU.First_Page,
SU.Root_Page,
SU.First_IAM_Page
From Sys.Partitions As P INNER JOIN Sys.Allocation_Units As U
ON P.hobt_id = U.container_id
Inner Join Sys.system_internals_allocation_units SU
On u.allocation_unit_id = su.allocation_unit_id
Go
— Exemplo 2: —
SELECT SIP.partition_id,
OBJECT_NAME(SIP.object_id) As ObjectName,
sip.rows,
SU.First_Page,
SU.Root_Page,
SU.First_IAM_Page
From Sys.system_internals_partitions As SIP Inner Join Sys.system_internals_allocation_units SU
On sip.partition_id = su.allocation_unit_id
Go
— Short Script 7 – Identificando índices com Escrita Excessiva —
— Quantidade de Índices com Escrita Excessiva em comparação a leitura —
SELECT  OBJECT_NAME(s.object_id),
i.name,
i.type_desc
FROM    sys.dm_db_index_usage_stats s WITH ( NOLOCK ) Inner JOIN sys.indexes i WITH (NOLOCK)
ON s.index_id = i.index_id
AND s.object_id = i.object_id
WHERE OBJECTPROPERTY(s.[object_id], ‘IsUserTable’) = 1
AND s.database_id = DB_ID()
AND s.user_updates > ( s.user_seeks + s.user_scans + s.user_lookups )
AND s.index_id > 1
Go
— Quantidade de Índices com Escrita Excessiva —
SELECT  COUNT(*)
FROM    sys.dm_db_index_usage_stats s WITH ( NOLOCK )
WHERE   OBJECTPROPERTY(s.[object_id], ‘IsUserTable’) = 1
AND s.database_id = DB_ID()
AND s.user_updates > ( s.user_seeks + s.user_scans + s.user_lookups )
AND s.index_id > 1
Go
— Short Script 8 – Identificando o espaço ocupado por conexões em uso —
SELECT A.session_id,
B.host_name, B.Login_Name ,
(user_objects_alloc_page_count + internal_objects_alloc_page_count)*1.0/128 as TotalalocadoMB,
D.Text
FROM sys.dm_db_session_space_usage A Inner JOIN sys.dm_exec_sessions B
ON A.session_id = B.session_id
Inner JOIN sys.dm_exec_connections C
ON C.session_id = B.session_id
CROSS APPLY sys.dm_exec_sql_text(C.most_recent_sql_handle) As D
WHERE A.session_id > 50
and (user_objects_alloc_page_count + internal_objects_alloc_page_count)*1.0/128 > 100 — Ocupam mais de 100 MB
ORDER BY totalalocadoMB desc
COMPUTE sum((user_objects_alloc_page_count + internal_objects_alloc_page_count)*1.0/128)
Go
— Short Script 9 – Obtendo a diferença de datas entre registro anterior e o próximo registro —
Create Table Datas
(ID Int Identity(1,1),
DataInicio Date,
DataFinal Date)
Go
Insert Into Datas Values (GETDATE(), GETDATE()+30)
Insert Into Datas Values (GETDATE()+1, GETDATE()+20)
Insert Into Datas Values (GETDATE()+2, GETDATE()+10)
Insert Into Datas Values (GETDATE(), GETDATE()+5)
Go
— Exemplo 1 —
Select I.ID, I.DataInicio, F.DataFinal,
DateDiff(D, I.DataInicio, F.DataFinal) As Intervalo
From Datas I Left Join Datas F
On I.ID = F.ID + 1

Go

— Exemplo 2 —
SELECT
[current].Id,
[current].Time CurrentValue,
[next].Time          NextValue
FROM #temp AS [current] LEFT JOIN #temp AS [next]
ON [next].Id = (SELECT MIN(Id) FROM #temp

                                 WHERE Id > [current].Id)
Go
— Short Script 10 – Criando um trigger condicional —
–Criando a Table de Novos Produtos–
Create Table NovosProdutos
(Codigo Int Identity(1,1),
Descricao VarChar(10))
–Criando a Table de Histórico Novos Produtos–
Create Table HistoricoNovosProdutos
(Codigo Int,
Descricao VarChar(10))
Go
–Inserindo valores —
Insert Into Novosprodutos Values(‘Arroz’)
Insert Into Novosprodutos Values(‘Arroz1’)
Insert Into Novosprodutos Values(‘Arroz2’)
Insert Into Novosprodutos Values(‘Arroz3’)
Go
–Criando a Trigger para controle de histórico–
Create TRIGGER T_Historico
ON NovosProdutos
for update
AS
IF (Select Descricao from Inserted) <> (Select Descricao from Deleted)
BEGIN
INSERT Into HistoricoNovosProdutos (Codigo, Descricao)
SELECT Codigo, Descricao FROM INSERTED
END
Go
–Fazendo os teste —
Update NovosProdutos
Set Descricao=’Arroz 4′
Where Codigo = 1
Go
Update NovosProdutos
Set Descricao=’Arroz1′
Where Codigo = 2
Go
Select * from NovosProdutos
Go

Muito bem, mais uma relação de short scripts acaba de ser compartilhada, mesmo sendo denominados short entre aspas “pequenos”, posso garantir que todos estes exemplos são de grande importância e apresentam um valor e conhecimento do mais alto nível.


Chegamos ao final de mais um Short Scripts, espero que este material possa lhe ajudar, ilustrando o uso de alguns recursos e funcionalidades do Microsoft SQL Server.

Acredito que você tenha observado que estes códigos são bastante conhecidos em meu blog, todos estão relacionados aos posts dedicados ao Microsoft SQL Server publicados no decorrer dos últimos anos.

Boa parte deste material é fruto de um trabalho dedicado exclusivamente a colaboração com a comunidade, visando sempre encontrar algo que possa ser a solução de um determinado problema, bem como, a demonstração de como se pode fazer uso de um determinado recurso.

Links

Caso você queira acessar os últimos posts desta sessão, não perca tempo acesse os links listados abaixo:

Agradecimento

Mais uma vez obrigado por sua visita, um forte abraço…

Nos encontramos em breve nos próximos posts desta e outras sessões do meu blog, valeu.

#07 – Para que serve


Boa tarde comunidade, boa tarde Brasil!!!!

Começando mais uma tarde de sábado, neste primeiro final de semana do mês de agosto, clima olímpico e muito feliz em ver que o Brasil foi capaz de fazer uma linda festa ontem na abertura dos Jogos Olímpicos Rio 2016, desejo muito sucesso para todos os participantes principalmente aos atletas brasileiros.

O post dedicado a sessão Para que serve deste mês, também esta no clima olímpico, você pode estar se perguntando o porque eu destaquei na minha abertura este clima. Quando estamos pensando em esporte muitas vezes pensamos que não existem possibilidades ou possíveis situações de um determinado time ou atleta ser superado por outro mais fraco, pode ser definido como algo “Hipotético”, sim “Hipotético” na sua definição com base em diversos dicionários: fictício, figurado, imaginário, suposto. Na área de banco de dados isso também pode ser aplicado, principalmente no SQL Server.

Mas de que maneira podemos pensar em algo hipotético, fictício ou imaginário quando estamos trabalhando com banco de dados? Pergunta que inicialmente pode ser difícil de ser respondida, complexa ou simplesmente hipotético(kkkkk).

Foi então que eu comecei a buscar mais informações em um conceito que pra mim era realmente imaginário de ser adotado, e recentemente em um dos posts publicados nos fóruns de SQL Server aqui no Brasil veio a tona o chamado Índices Hipotéticos.

Essa é uma possível resposta quando estamos trabalhando com banco de dados, fazer uso de índices hipotéticos pode nos ajudar a identificar ou similar possíveis situações de impacto na performance de uma query durante sua execução, ainda mais se estivermos trabalhando com um conjunto volumoso de dados.

Para tentar compartilhar com você um pouco sobre este mistorioso recurso que podemos adotar em nosso ambiente, o post de hoje o próximo da sessão para que serve serão dedicados justamente ao entendimento, criação e uso dos índices hipotéticos.

E como de costume aquelas perguntas já conhecidas dos posts anteriores desta sessão:

E ai, você conhece esta funcionalidade? Já utilizou? Sabe para que ela serve?

Pois bem, estas e outras possíveis perguntas serão respondidas a partir de agora em mais este post da sessão Para que Serve!


Começa agora o #07 – Para que serve – Índices Hipotéticos – Parte I.

Mais um final de semana esta chegando, hoje sexta – feira, você já esta começando a se preparar para desligar sua estação de trabalho, pegar suas coisas e voltar para casa feliz por mais um dia de trabalho duro e gratificante e por saber que fez o melhor possível para manter tudo em ordem em seu local de trabalho, eis que após alguns minutos o seu ramal de telefone toca e no display aparece 2801 – Fernanda Galvão, meu deus você pensa, respira e atende sabendo que ela é a gerente de produção da empresa e para estar ligando no final do dia não deve ser nada muito simples, mesmo assim sabendo dos seus deveres e obrigações realiza o atendimento a ligação e escuta:

Junior Galvão, boa tarde!!!

Aqui é a Fernanda, tudo bem? Estamos com um pequeno problema na emissão do relatório de produção diária, estou aqui com o analista de produção João Pedro, você pode falar com ele?

Junior responde sim, claro!!!

Neste momento, João Pedro apresenta o cenário: Junior, olá boa tarde.

Estou com dificuldades para emitir o relatório de produção diária, ao tentar filtrar os dados por clientes e categoria de clientes, o sistema aparentemente entra em loop de processamento e os dados não são apresentados em tela. 

O que será que pode estar acontecendo? Alguns segundos se passam…. Junior começa a pensar e observa que seu final de semana aparentemente foi por água, ou melhor dizendo o final de semana não vai ser tão tranquilo.

Você responde: João Pedro, boa tarde, vou verificar o que pode esta acontecendo, sei que hoje realizamos algumas mudanças na estrutura da tabela de clientes e categoria de clientes, parece-me que o time de suporte adicionou um novo índice, vou tentar verificar.

João Pedro responde dizendo.

Ok! Junior, fico no aguardo, assim que você tiver uma posição por favor me informe.

Junior responde: Certo, perfeito, deixa comigo, vou verificar o que esta acontecendo garanto que hoje não vou conseguir dar uma resposta mais concreta!

Sabendo justamente que a equipe de suporte esta trabalhando para realizar alguns testes de performance nas tabelas de clientes e categoria de clientes, onde milhares de registros estão sendo processados diariamente, Junior chama um dos seus analistas de suporte Eduardo Galvão e pergunta:

Edu por acaso vocês realizaram alguma alteração na estrutura das tabelas de clientes ou categoria de clientes?

A resposta é simples e direta, sim Junior, estamos fazendo uso de um recurso que até então novo ou supostamente desconhecido para nossa equipe,  pelo que pesquisei é uma funcionalidade conhecida como índices que possuem somente estatíticas mas não existem fisicamente.

Junior responde: Índices somente com estatísticas, índices que não existem, que raio de recurso é esse, por acaso vocês estão se referindo a índices hipotéticos?

Eduardo responde, sim, sim, acredito que seja isso a analista de suporte de banco de dados Maria Luíza, esta fazendo um estudo sobre isso em nosso ambiente de testes e identificou que se fizermos a adoção deste recurso poderemos ter mais facilidade em reconhecer a necessidade de um novo índice ou se o mesmo realmente é útil mesmo após ter sido criado anteriormente.

Junior responde, certo Eduardo, mas este tipo de teste ou implementação deve ser planejada, não podemos simplesmente pesquisar um recurso na internet ou livros e já sair aplicando em nossos ambientes de teste, muito menos em produção, devemos sempre por em prática nosso check-list de boas práticas e principalmente ter um ambiente de contigência caso algo aconteça de errado.

Quero saber qual será a forma para identificar o que esta acontecendo e como vamos resolver este problema até segunda – feira, questiona Junior!!!”

Muito bem, este é nosso cenário, com base, nesta pequena estória que acabamos de conhecer, será criado nosso ambiente de testes para colocar em prática o conceito de índices hipotéticos, antes disso iremos comecer um pouco mais sobre este conceito.

Índices

Falando de uma maneira simples quando criamos um novo índice no SQL Server ou em qualquer outro banco de dados, estamos criando uma estrutura que basicamente servirá como caminho na busca e identificação de um ou mais dados solicitados pelos mecanismos de banco de dados durante o processamento de uma determinada query.

Ao realizar a criação deste elemento normalmente os índices físicos apresentam em sua estrutura os dados, distribuídos de maneira demográfica confome as manipulações são realizadas, além disso, apresentam densidade, granularidade e seletividade de acordo com seu conjunto de valores, com isso, temos um conjunto de informações técnicas conhecidas como estatísticas do índice o que permite servir como elemente auxiliar no obtenção mais ágil e simples dos dados solicitados.

Índices Hipotéticos

Ao se falar de índices hipotéticos, estamos se referindo a uma estrutura completamente oposta, sem qualquer tipo estrutura física, muito menos dados, um índice hipotético é conhecido como algo imaginário que não possue estrutura física, somente estrutura lógica ou seja, somente estatísticas que podem servir como recurso para tentar criar o mecanismo de banco de dados e também o plano de execução por parte do SQL Server na busca de um ou mais dados.

Como podemos criar um índice hipotético?

A partir do SQL Server 2008 R2 a Microsoft adicionou uma opção no comando Create Index conhecido como With Statistics_Only, traduzindo ao pé da letra para o português vamos encontrar ao similar à somente estatísticas. É com base nesta opção não documentada que temos a possibilidade de fazer uso de índices hipotéticos em nossos bancos de dados.

O uso desta opção é muito simples, basta ao final da linha de comando que referencia a criação de um novo índice adicionar a instrução With Statistics_Only = 0, onde o mecanismo de banco de dados vai entender que esta novo índice deverá ser criado possuindo somente uma estrutura lógica controlada e direcionada através dos dados estatísticos coletados durante as manipulações de dados ou execução de querys que fazem uso do mesmo. Quando criamos um novo índice e não informamos esta opção por padrão o mecanismo de banco de dados repassa internamente para processador de querys que este índice deve ser criado da maneira padrão ou seja, um índice que conterá estrutura física e lógica, e o valor correspondente a instrução With Statistics_Only será igual á -1, ou seja:

  • With Statistics_Only = 0 — Indica que o índice deve ser criado de maneira hipotética, índice forma somente por estrutura lógica, conhecida como estatíticas; e
  • With Statistics_Only = -1 — Indica que o índice deve ser criada da maneira clássica, índice formado por estrutura física e lógica.

Uma forma simples é fácil para saber se um ou mais índices apresentam esta diferença pode ser encontrada na visão de sistema sys.indexes através da coluna is_hypothetical, onde a mesma deverá apresentar os valores: 0(zero) ou 1(hum), sendo estes valores que identificam e diferenciam a ocorrência da existência de um ou mais índices clássicos e hipotéticos.

Mas não tudo sem flores como diria meu irmão, a criação de um índice hipotético é fácil, tranquila, sem muitos segredos. Agora, imagine se você deseja orientar otimizador de consultados existentes no SQL Server no uso deste tipo de índice durante o processamento de uma query, ou então se você deseja omitir o seu uso, situação que pode parecer muito comum de ser realizada ou automática, mas não é bem assim.

Temos a necessidade de dirigir isso mesmo, mostrar o caminho que deve ser seguido pelo Database Engine em conjunto com o Query Optimizer e posteriormente o Execution Plan, como deve ser feito o uso de um índice hipotético. Isso parece ser algo bastante complicado, não é bem assim, como sempre existe uma solução que a Microsoft muitas vezes também não reconhece como recurso documentado ou simplesmente não documento, e ai mais uma vez “Mister M de SQL Server” surge para nos ajudar e apresentar ao mundo como uma possível solução pode ser adotada maneira mais suave, mostrando como podemos  resolver este problema e sair desta sinuca de bico.

Pra variar surge para muitos um novo  DBCC – Database Command Console não documentado conhecido como DBCC AutoPilot e uma nova diretiva Set AutoPilot, onde:

  • Set AutoPilot – Orienta o query optimizer a considerar ou não o uso do índice hipotético no momento da criação do plano de execução da query; e
  • DBCC AutoPilot – Orienta o query optimizer fazer uso do índice hipotético de acordo com o conjunto de parâmetros a ser utilizado e posteriormente repassado para o plano de execução.

Preste atenção o nome dele não tem nada haver com piloto de Fórmula 1 (kkkk), vou repetir o seu nome DBCC AutoPilot e ele vai justamente nos ajudar e saber mais sobre os dados que estão relacionados com um determinado índice hipotético.

DBCC AUTOPILOT

Este comando DBCC é mais um dos diversos comandos de console de banco de dados que a Microsoft não reconhece como comando documentado ou suportado nativamente, através do conjunto de instruções “parâmetros” que compõem sua sintaxe o query optimizer vai se comportar de uma determinado maneira ou de outra.

Abaixo apresento a relação de parãmetros que formam o DBCC AutoPilot:

Parâmetro

Descrição
typeid Existem alguns valores, os mais utilizados basicamente são:
Type ID = 5: Iniciar a sessão ou comandos anteriores limpos;
Type ID = 0: Fazer uso de índices não clusterizados; e
Type ID = 6: Usar apenas índices clusterizados.
dbid Id do banco de dados habilitado para executar o comando.
maxQueryCost Supostamente definir um possível custo em relação ao processamento da query. “Sinceramente não entendi bem como usar (kkkk)”
tabid Id da Tabela a ser utilizada.
indid Id do índice a ser utilizado.
pages Ao executar o DBCC AutoPilot simular o comportamento e uso de páginas de dados.
flag Parâmetro desconhecido, não encontrei informações sobre ele….
rowcounts Parâmetro utilizado para definir o número de linhas de execução e processamento para alguns comandos.

Bom vou deixar você agora com um gostinho de quero mais, como destacado anteriormente este é a primeira parte deste Para que serve…. Na segunda parte vamos criar nossos índices hipotéticos e fazer uso da diretiva SET AutoPilot, posteriormente na terceira parte vamos utilizar a não documentada DBCC AutoPilot.


É isso ai galera, chegamos ao final de mais post da sessão Para que serve!

Espero que você tenha gostado, que as informações compartilhadas aqui possam lhe ajudar a se tornar cada vez um profissional de banco de dados reconhecido e valorizado, um dos papéis na área de tecnologia mais importantes para qualquer empresa.

Reconher o verdadeiro papel de um DBA dentro de sua estrutura, é reconhecer o verdadeiro valor de seus dados e como eles podem se tornar uma infomação valiosa para sua tomada de decisão.

Caso deseje acessar os posts anteriores desta sessão, utilize os links listados abaixo:

Short Scripts – Junho 2016


Salve, salve minha gente, boa tarde!!!

Mais uma segunda – feira começando e mais uma semana se iniciando, já passamos da metade do mês de Junho tão aguardado devido ao lançamento do novo Microsoft SQL Server 2016. Caso você tenha perdido alguma informação sobre este lançamento, aproveito para compartilhar aqui um dos diversos posts publicados no meu blog sobre esta nova versão:

Voltando a falar sobre o Short Scripts, esta é uma das sessões mas visitadas do meu blog, onde o objetivo  é compartilhar os scripts existentes em minha biblioteca de códigos  dedicados exclusivamente para o SQL Server. Muitos destes scripts são resultado de pesquisas, posts publicados nos fóruns MSDN e também de respostas encontradas em outros websites de profissionais, administradores de banco de dados, professores e comunidades.

Boa parte deste material é fruto de um trabalho dedicado exclusivamente a colaboração com a comunidade, visando sempre encontrar algo que possa ser a solução de um determinado problema, bem como, a demonstração de como se pode fazer uso de um determinado recurso. Todos os scripts publicados nesta sessão são devidamente testados antes de serem publicados, mas isso não significa que você pode fazer uso dos mesmo em seu ambiente de produção, vale sim todo cuidado possível para evitar maiores problemas.

Caso você não tenha acessado os últimos posts, não perca tempo, utilize os links publicados a seguir:

https://pedrogalvaojunior.wordpress.com/2016/03/22/short-scripts-marco-2016/

https://pedrogalvaojunior.wordpress.com/2015/12/14/short-script-dezembro-2015/

https://pedrogalvaojunior.wordpress.com/2015/10/21/short-scripts-outubro-2015/

https://pedrogalvaojunior.wordpress.com/2015/08/26/short-scripts-agosto-2015/

https://pedrogalvaojunior.wordpress.com/2015/06/03/short-script-junho-2015/

Para esta relação você vai encontrar scripts relacionados aos seguintes assuntos, conceitos, recursos ou funcionalidades:

  • Acesso a banco de dados;
  • Collation;
  • Comando Exec;
  • Comando Union;
  • Comando Union All;
  • Comando Create Table;
  • Comando Alter Table;
  • Common Table Expression;
  • DBCC CheckPrimaryFile;
  • DMV sys.dm_db_index_usage_stats;
  • DMV sys.dm_os_buffer_descriptors;
  • Índices Clustered e NonClustered;
  • Option MaxRecursion;
  • Plano de Execução;
  • Querys consideradas pesadas;
  • Tabela de sistema sys.allocation_units;
  • Tabela de sistema sys.partitions;
  • Tabela de sistema sys.indexes;
  • Tabela e caracteres Unicode; e
  • Recursividade.
A seguir, apresento a relação de short scripts:

— Short Script 1 – DBCC CheckPrimaryFile Verificando se o arquivo realmente é um Primary File —
DBCC CheckPrimaryFile (‘C:\Bancos\Laboratorio.MDF’,0)
Go

 

— Short Script 2 – DBCC CheckPrimaryFile – Retornando o conjunto completo de informações associados ao Primary File que formam a estrutura do respectivo Banco de Dados —
DBCC CheckPrimaryFile (‘C:\Bancos\Laboratorio.MDF’,1)
Go

 

— Short Script 3 – DBCC CheckPrimaryFile – Retornando o nome do banco de dados, versão e collation relacionados ao Primary File —
DBCC CheckPrimaryFile (‘C:\Bancos\Laboratorio.MDF’,2)
Go

— Short Script 4 – DBCC CheckPrimaryFile – Retornando o status, fileid, name e filename associados ao Primary File que formam a estrutura do respectivo Banco de Dados —
DBCC CheckPrimaryFile (‘C:\Bancos\Laboratorio.MDF’,3)
Go
— Short Script 5 – Informações sobre acesso ao Banco de Dados —
WITH agg AS
(SELECT last_user_seek,
                  last_user_scan,
                  last_user_lookup,
last_user_update
FROM sys.dm_db_index_usage_stats
WHERE database_id = DB_ID()
)
SELECT last_read = MAX(last_read),
                 last_write = MAX(last_write)
FROM
(SELECT last_user_seek, NULL FROM agg
UNION ALL
SELECT last_user_scan, NULL FROM agg
UNION ALL
SELECT last_user_lookup, NULL FROM agg
UNION ALL
SELECT NULL, last_user_update FROM agg
) AS x (last_read, last_write);
Go

 

— Short Script 6 – Observando a mudança de comportamento após a troca de Collation —

CREATE TABLE [dbo].[Authors]
([id] [INT] NULL,
   [author] [VARCHAR](50) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
   [dateposted] [DATE] NULL) ON [PRIMARY]
GO
INSERT Authors  VALUES (1, ‘Steve’, ‘20160101’),
                                                   (2, ‘STEVE’, ‘20160201’),
                                                   (3, ‘Andy’, ‘20160301’),
                                                   (4, ‘andy’, ‘20160401’)
GO
CREATE PROCEDURE GetAuthors @author VARCHAR(50)
AS
BEGIN
SELECT a.id, a.author FROM dbo.Authors a
WHERE a.author = @author
END
GO
— If I run the procedure with a parameter of ‘Steve’, it returns two rows. I then run this code:
Exec GetAuthors ‘Steve’
Go
ALTER TABLE dbo.Authors
ALTER COLUMN author VARCHAR(50) COLLATE SQL_Latin1_General_CP437_BIN2 NULL
— If I were to execute the stored procedure, what would happen?
Exec GetAuthors ‘Steve’
Go

 

— Short Script 7 – Descobrindo o código Unicode de um caracter ou String —

— Exemplo 1 —
DECLARE @n CHAR(10);
SET @n = N’Abc’;
SELECT UNICODE(@n);
Go
— Exemplo 2 —
DECLARE @n NCHAR(10);
SET @n = N’??????????’;
SELECT UNICODE(@n);
Go

 

— Short Script 8 – Criando CTEs —

— Exemplo 1 – Criando uma simples CTE —
;With Exemplo1(Valor, Nome)
As
(
Select 1, ‘Pedro Galvão’ As Nome
)
Select * from Exemplo1
Go
— Exemplo 2 – Criando uma CTE com Union de Selects —
;With Exemplo2(Valor)
As
( Select 10
Union
Select 50
Union
Select 8
Union
Select 10 + 2
)
Select Valor = (Select Max(valor) From Exemplo2) + (Select Sum(Valor) From Exemplo2)
Go
– Short Script 9 – Criando CTEs com Recursividade —
— Exemplo – Criando uma nova CTE Recursiva concatenando dados —
;With ConcatenarNomes(nome)
AS
( SELECT Nome = CONVERT(Varchar(4000),’Pedro Antonio’)
UNION ALL
SELECT CONVERT(Varchar(4000),nome + ‘ Galvão Junior’) FROM ConcatenarNomes
WHERE LEN(nome) < 30
)
SELECT Nome FROM ConcatenarNomes
Go
— Exemplo 2 – Criando uma CTE com Union + Recursividade – Simulando uma sequência de números pares —
;With CTENumerosPares(Numero)
As
( Select 0 As Numero
Union All
Select Numero + 2 As Numero From CTENumerosPares
Where Numero < 100
)
Select Numero From CTENumerosPares
Go
— Exemplo 3 – Criando uma CTE com Union + Recursividade – Simulando uma sequência de números —
;With CTENumerosSequenciais(Numero)
AS
(   SELECT 1 AS Numero
UNION ALL
SELECT Numero + 1 AS num FROM CTENumerosSequenciais
WHERE Numero < 1000
)
SELECT * FROM CTENumerosSequenciais
OPTION (MAXRECURSION 0)
Go
— Short Script 10 – Obtendo o tamanho de índices Clustered e NonClustered —
SELECT COUNT(*) AS cached_pages_count,
COUNT(*)/128.0000 MB,
name AS BaseTableName,
IndexName,
IndexTypeDesc
FROM sys.dm_os_buffer_descriptors AS bd
INNER JOIN (SELECT s_obj.name,
s_obj.index_id,
s_obj.allocation_unit_id,
s_obj.OBJECT_ID,
i.name IndexName,
i.type_desc IndexTypeDesc
FROM
(SELECT OBJECT_NAME(OBJECT_ID) AS name,
index_id,
allocation_unit_id,
OBJECT_ID
FROM sys.allocation_units AS au INNER JOIN sys.partitions AS p
ON au.container_id = p.hobt_id
AND (au.TYPE = 1 OR au.TYPE = 3)
UNION ALL
SELECT OBJECT_NAME(OBJECT_ID) AS name,
index_id,
allocation_unit_id,
OBJECT_ID
FROM sys.allocation_units AS au INNER JOIN sys.partitions AS p
ON au.container_id = p.partition_id
AND au.TYPE = 2
) AS s_obj LEFT JOIN sys.indexes i
ON i.index_id = s_obj.index_id
AND i.OBJECT_ID = s_obj.OBJECT_ID
) AS obj ON bd.allocation_unit_id = obj.allocation_unit_id
WHERE database_id = DB_ID()
and name not like ‘sys%’
and IndexName <> ‘null’
GROUP BY name, index_id, IndexName, IndexTypeDesc
ORDER BY cached_pages_count DESC;
Muito bem, mais uma relação de short scripts acaba de ser compartilhada, mesmo sendo denominados short entre aspas “pequenos”, posso garantir que todos estes exemplos são de grande importância e apresentam um valor e conhecimento do mais alto nível.

Chegamos ao final de mais um post, fique a vontade para compartilhar este conteúdo com seus contatos e redes sociais, contribua também enviando dicas, sugestões, dúvidas, críticas, enfim participe e ajude a melhorar cada vez mais esta sessão.

Mais uma vez obrigado por sua visita, nos encontramos em breve em mais um post da sessão Short Scripts.

Uma ótima semana, abraços.

Short Scripts – Agosto 2015


Boa tarde, Comunidade!!!!

Tudo em paz? Mas que loucura este tempo aqui em São Roque e Sorocaba, hoje ás 6:30hrs da manhã estava 8º graus, agora ás 13hrs sensação térmica de 20º graus e subindo……

Nos últimos meses acabei deixando de publicar alguns posts relacionadas a minha sessão Short Scripts devido a correria da vida profissional e acadêmica, mas hoje vou pagar este dívida, compartilhando com vocês alguns dos meus novos short scripts.

Muitos tem me perguntado o porque acabou guardando tantos scripts ou códigos de exemplo, a resposta é bem simples e direta, sempre existirá alguém ou algo no mundo que poderá necessitar deste recurso e isso é que me mantem nesta jornada em cultivar minha biblioteca de scripts a cada dia mais atualização e completa(tarefa muito, mas muito complicada de se realizar).

Os Short Scripts apresentados hoje, estão relacionandos com os seguintes assuntos:

  • Block Process;
  • CTE;
  • Claúsula Output;
  • Comando Select;
  • Comando SET;
  • Concatenação de Valores;
  • Extended Events;
  • Índices;
  • Junção de Tabelas
  • Fatorial;
  • Funções; e
  • Tipos de Dados.

É isso galera, a seguir você vai poder encontrar os blocos de código que representam os Short Scripts, fique a vontade para copiar, compartilhar, sugerir melhorias e fazer suas críticas também.

 

— Short Script 1 –  Uitlizando claúsula Output em Delete com Inner Join + Select —

DECLARE @t TABLE

(nDex INT IDENTITY(1,1),

valu VARCHAR(9),

keey UNIQUEIDENTIFIER)

INSERT @t

VALUES (‘a’,NEWID()) , (‘b’,NEWID()),

(‘c’,NEWID()) , (‘d’,NEWID()),

(‘e’,NEWID()) , (‘f’,NEWID()),

(‘g’,NEWID()) , (‘h’,NEWID()),

(‘i’,NEWID()) , (‘j’,NEWID()),

(‘k’,NEWID())

DELETE t

OUTPUT DELETED.*

FROM @t AS t INNER JOIN (SELECT TOP 9 nDex FROM @t ORDER BY NEWID()) AS b

ON b.ndex = t.nDex

GO

 

 

— Short Script 2 – Uitilizando – CTE para separar palavras —

DECLARE @s VARCHAR(8000), @d VARCHAR(10)

SET @s = ‘separar por espaço em branco’

SET @d = ‘ ‘

;WITH split(i,j) AS

(

SELECT i = 1, j = CHARINDEX(@d, @s + @d)

UNION ALL

SELECT i = j + 1, j = CHARINDEX(@d, @s + @d, j + 1) FROM split

WHERE CHARINDEX(@d, @s + @d, j + 1) <> 0

)

SELECT SUBSTRING(@s,i,ji)

FROM split

 

— Short Script 3 – Simulando – Cenários de utilização de índices —

USE TempDB;

— Criando a Tabela Funcionário —

CREATE TABLE Funcionario

(ID int primary key,

NomeFunc varchar(200),

DataNasc date,

DataADM date);

Go

— Consulta 1 – Fazendo uso do Operador Clustered Index Scan —

SELECT * from Funcionario

Where DataADM between Convert(date, ‘1/1/2012’, 103) and Convert(date, ’31/1/2012′, 103)

Go

— Criando um novo índice chamado Ind_NC_Funcionario_DataADM —

CREATE Nonclustered Index Ind_NC_Funcionario_DataADM On Funcionario (DataADM);

Go

— Consulta 2 – Fazendo uso do Operador Clustered Index Scan —

SELECT * from Funcionario

Where DataADM between Convert(date, ‘1/1/2012’, 103) and Convert(date, ’31/1/2012′, 103)

Go

— Consulta 3 – Forçando o uso do índice IND_NC_Funcionario_DataADM, gerando Index Seek, Key Lookup e Nested Loops —

SELECT * from Funcionario with (index=Ind_NC_Funcionario_DataADM)

Where DataADM between Convert(date, ‘1/1/2012’, 103) and Convert(date, ’31/1/2012′, 103)

Go

— Consulta 4 – Utilizando realmente o índice IND_NC_Funcionario_DataADM —

SELECT ID, DataADM

From Funcionario

Where DataADM between Convert(date, ‘1/1/2012’, 103) and Convert(date, ’31/1/2012′, 103)

Go

 

— Short Script 4 – Função – Concatenar valores em ordem decrescente —

CREATE FUNCTION dbo.ConcatenaValores (@C1 int, @C2 int, @C3 int, @C4 int, @C5 int)

returns int as

begin

declare @Concatenado varchar(5);

set @Concatenado= space(0);

SELECT @Concatenado+= Cast(N as char(1))

from (values (@C1), (@C2), (@C3), (@C4), (@C5)) as Numeros(N)

order by N desc;

return Cast(@Concatenado as int);

end;

go

Select Valor= dbo.ConcatenaValores(1, 2, 3, 4, 5);

 

— Short Script 5 – Criando tipo de dados NotNull mas Null sobrepondo Not Null —

CREATE TYPE NotNullType FROM VARCHAR(10) NOT NULL;

GO

— table create

CREATE TABLE Test(TestId INT, NullTest NotNullType NULL);

GO

— insert

INSERT INTO Test(TestId) VALUES(1);

SELECT NullTest FROM Test;

 

— Short Script 6 – Comparando comportamento entre os comandos SET e Select —

DECLARE @a INT= 0;

DECLARE @b INT= 0;

 

CREATE TABLE #tmpPrice ( Value INT );

SET @a = ( SELECT Value FROM #tmpPrice);

SELECT @b = Value FROM #tmpPrice;

SELECT @a AS, @b AS b

 

— Short Script 7 – Função para Calcular Fatorial com CTE encapsulada —

CREATE FUNCTION fatorial

(

@n INT

)

RETURNS INT

AS

BEGIN

DECLARE @val INT;

WITH fat(f, n) AS

(

SELECT CAST (1 as bigint) as f, 0 as n

UNION ALL

SELECT CAST (1 as bigint) as f, 1 as n

UNION ALL

SELECT f * (n + 1), n +1

FROM fat

WHERE n < 20 AND n <> 0

)

SELECT @val = f

FROM fat

WHERE n = @n

RETURN @val

END

GO

— Testando a função

SELECT dbo.fatorial(3);

SELECT dbo.fatorial(4);

SELECT dbo.fatorial(7);

 

— Short Script 8 –  CTE – Calculando fatorial —

WITH fat(f, n) AS

(

SELECT CAST (1 as bigint) as f, 0 as n — fat de 0 é 1

UNION ALL

SELECT CAST (1 as bigint) as f, 1 as n — fat de 1 é 1

UNION ALL

SELECT f * (n + 1), n +1

FROM fat

WHERE n < 20 AND n <> 0

— 20 é o limite neste caso, pois o fatorial de 21

— não cabe em um tipo bigint. O <> 0 é para cortar a recursão

— do primeiro âncora, senão repetiria tudo, faça o teste.

)

SELECT f

FROM fat

WHERE n = 12

 

— Short Script 9 – Capturar Blocked Process com Extended Events —

CREATE EVENT SESSION [Blocked] ON SERVER

ADD EVENT sqlserver.blocked_process_report

ADD TARGET package0.event_file

(SET filename=N’C:\xel\blocked.xel’)

GO

ALTER EVENT SESSION [Blocked]

ON SERVER

STATE = start;

GO

 

–Agora precisamos ler os arquivos .XEL gerados pela sessão e extrair os dados do XML para identificarmos as causas dos blocked process:

select theNodes.event_data.value(‘(//blocked-process/process)[1]/@spid’,‘int’) as blocking_process,

theNodes.event_data.value(‘(//blocked-process/process/inputbuf)[1]’,‘varchar(max)’) as blocking_text,

theNodes.event_data.value(‘(//blocked-process/process)[1]/@clientapp’,‘varchar(100)’) as blocking_app,

theNodes.event_data.value(‘(//blocked-process/process)[1]/@loginname’,‘varchar(50)’) as blocking_login,

theNodes.event_data.value(‘(//blocked-process/process)[1]/@isolationlevel’,‘varchar(50)’) as blocking_isolation,

theNodes.event_data.value(‘(//blocked-process/process)[1]/@hostname’,‘varchar(50)’) as blocking_host,

theNodes.event_data.value(‘(//blocking-process/process)[1]/@spid’,‘int’) as blocked_process,

theNodes.event_data.value(‘(//blocking-process/process/inputbuf)[1]’,‘varchar(max)’) as blocked_text,

theNodes.event_data.value(‘(//blocking-process/process)[1]/@clientapp’,‘varchar(100)’) as blocked_app,

theNodes.event_data.value(‘(//blocking-process/process)[1]/@loginname’,‘varchar(50)’) as blocked_login,

theNodes.event_data.value(‘(//blocked-process/process)[1]/@isolationlevel’,‘varchar(50)’) as blocked_isolation,

theNodes.event_data.value(‘(//blocking-process/process)[1]/@hostname’,‘varchar(50)’) as blocked_host

from

(select convert(xml,event_data) event_data

from

sys.fn_xe_file_target_read_file(‘c:\xel\blocked*.xel’, NULL, NULL, NULL)) theData

cross apply theData.event_data.nodes(‘//event’) theNodes(event_data)

 

Chegamos ao fim de mais um Short Scripts, espero que você tenha gostado destes códigos!!!

Nos encontramos em breve.

Até a próxima…..

Short Script – Maio – 2015


Bom dia, pessoal, mais uma semana começando.

Mantendo a tradição e escrita, estou começando mais um mês no meu blog, compartilhamento com todos vocês a minha relação de Scripts que atualmente esta crescendo muito graças ao SQLServerCentral.com.

Venho diariamente estudando e respondendo as questões diárias que são publicadas no SQLServerCentral.com, pelos principais nomes e especialistas em SQL Server do Mundo, estou seguindo nesta caminhada desde o final do mês de fevereiro. Posso dizer que esta sendo uma oportunidade fantástica de relembrar, conhecer, aprender e também descobrir muitos segredos, novidades e principalmente informações sobre o Microsoft SQL Server em todas as suas versões.

Aproveito a oportunidade para indicar e recomendar sua visita ao SQLServerCentral.com, principalmente a sessão de Question of the Day: http://www.sqlservercentral.com/Questions

Pois bem, na relação de Short Scripts que estou disponibilizando hoje, boa parte destes códigos são resultado das questões que eu respondi no SQLServerCentral.com e identifiquei como questões importantes ou relevantes para meus estudos, bem como, para repassar para meus alunos.

Nesta relação, você terá a oportunidade de conhecer e aprender um pouco mais sobre:

·         Análise e Lógica Condicional com operadores Not, And e Or;
·         Colunas Computadas;
·         Complexidade Lógica;
·         CTE Recursiva;
·         Declaração de variáveis do Tipo XML em conjunto com Select;
·         Função Coalesce em conjunto com Left Join e valores nulos; e
·         Funções Char(), NChar(), Unicode() e ASCII();
·         Identificando ausência de índices em tabelas;
·         Índices Clusterizados e Índices Chaves;
·         Índices com colunas duplicadas;
·         Operador Intersect;
·         Taxas de Fragmentação de Tabelas antes e depois do Rebuild;
·         Transações aninhadas;
·         Utilitário BCP para criação de arquivos XML.

 

Legal, a seguir você poderá encontrar os Short Scripts separados por seus respectivos conteúdos:

  • Análise, Precedência e Lógica Condicional com operadores Not, And e Or    VALUES ( 1, ‘Baseball Hat’ ),           ( 3, ‘Snowboard’ ),           ( 5, ‘Shows’ )SELECT ID   WHERE Product = ‘Bicycle’ OR Product = ‘Snowboard’ AND ID = 4

 

  1.    FROM @Logic
  2.            ( 4, ‘Goggles’ ),
  3.          ( 2, ‘Bicycle’ ),
  4. INSERT INTO @Logic
  5. DECLARE @Logic TABLE ( ID INT, Product VARCHAR(50) )

 

  • Colunas Computadas   (   , col1Computed AS LEFT(col1, 4)   , col2Computed AS LEFT(col2, 4)   , col3Computed AS LEFT(col3, 4)   , col4Computed AS LEFT(col4, 4) 

 

  1.    );
  2.    , col4 CHAR(8) NOT NULL
  3.    , col3 CHAR(8) NULL
  4.    , col2 VARCHAR(8) NOT NULL
  5.      col1 VARCHAR(8) NULL
  6. CREATE TABLE t
  7. Complexidade Lógica

DECLARE @AA VARCHAR(12) = ‘AAA’

,@XXX           VARCHAR(12) = ‘AAA’

,@YYY           VARCHAR(12) = ‘BBB’

,@ZZZ           VARCHAR(12) = ‘CCC’

,@AAXXX         VARCHAR(12) = ‘XXAAA’

,@AAYYY         VARCHAR(12) = ‘XXBBB’

,@AAZZZ         VARCHAR(12) = ‘XXCCC’

,@XXXCount       INT = 1

,@YYYCount       INT = 1

,@ZZZCount       INT = 1

,@AAXXXCount     INT = 1

,@AAYYYCount     INT = 1

,@AAZZZCount     INT = 1

,@Result       INT;

 

— Much to your chagrin, you encounter the following logic in a SQL SP.

— You may assume that each local variable is DECLAREd and @AA,

— @XXX, @YYY, @ZZZ, @AAXXX, @AAYYY, @AAZZZ each have a value assigned,

— with only @AA required to be NOT NULL. Each @xxxCount variable

— is also assigned an integer value.

SET @Result = 0;

 

IF @AA = @XXX

BEGIN

IF @XXXCount > @AAXXXCount SET @Result = 2

END

ELSE IF @AA = @YYY

BEGIN

IF @YYYCount > @AAYYYCount SET @Result = 2

END

ELSE IF @AA = @ZZZ

BEGIN

IF @ZZZCount > @AAZZZCount SET @Result = 2

END

ELSE IF @AA = @AAXXX

BEGIN

IF @XXXCount = @AAXXXCount SET @Result = 3

END

ELSE IF @AA = @AAYYY

BEGIN

IF @YYYCount = @AAYYYCount SET @Result = 3

END

ELSE IF @AA = @AAZZZ

BEGIN

IF @ZZZCount = @AAZZZCount SET @Result = 3

END

 

— Identify the equivalent logic from the options shown:

— Option 1:

SET @Result = 0;

 

IF @AA = @XXX AND @XXXCount > @AAXXXCount SET @Result = 2

ELSE IF @AA = @YYY AND @YYYCount > @AAYYYCount SET @Result = 2

ELSE IF @AA = @ZZZ AND @ZZZCount > @AAZZZCount SET @Result = 2

ELSE IF @AA = @AAXXX AND @XXXCount = @AAXXXCount SET @Result = 3

ELSE IF @AA = @AAYYY AND @YYYCount = @AAYYYCount SET @Result = 3

ELSE IF @AA = @AAZZZ AND @ZZZCount = @AAZZZCount SET @Result = 3

 

SELECT [Option 1:]=@Result

SELECT @Result = NULL;

 

 

— Option 2:

IF @AA = @XXX AND @XXXCount > @AAXXXCount SET @Result = 2

ELSE IF @AA = @YYY AND @YYYCount > @AAYYYCount SET @Result = 2

ELSE IF @AA = @ZZZ AND @ZZZCount > @AAZZZCount SET @Result = 2

ELSE IF @AA = @AAXXX AND @XXXCount = @AAXXXCount SET @Result = 3

ELSE IF @AA = @AAYYY AND @YYYCount = @AAYYYCount SET @Result = 3

ELSE IF @AA = @AAZZZ AND @ZZZCount = @AAZZZCount SET @Result = 3

ELSE SET @Result = 0;

 

SELECT [Option 2:]=@Result

SELECT @Result = NULL;

 

— Option 3:

SELECT @Result = CASE @AA

WHEN @XXX THEN CASE WHEN @XXXCount > @AAXXXCount THEN 2 ELSE 0 END

WHEN @YYY THEN CASE WHEN @YYYCount > @AAYYYCount THEN 2 ELSE 0 END

WHEN @ZZZ THEN CASE WHEN @ZZZCount > @AAZZZCount THEN 2 ELSE 0 END

WHEN @AAXXX THEN CASE WHEN @XXXCount = @AAXXXCount THEN 3 ELSE 0 END

WHEN @AAYYY THEN CASE WHEN @YYYCount = @AAYYYCount THEN 3 ELSE 0 END

WHEN @AAZZZ THEN CASE WHEN @ZZZCount = @AAZZZCount THEN 3 ELSE 0 END

END;

 

SELECT [Option 3:]=@Result          — Not identical

SELECT @Result = NULL;

 

— Option 4:

SELECT @Result = CASE @AA

WHEN @XXX THEN CASE WHEN @XXXCount > @AAXXXCount THEN 2 ELSE 0 END

WHEN @YYY THEN CASE WHEN @YYYCount > @AAYYYCount THEN 2 ELSE 0 END

WHEN @ZZZ THEN CASE WHEN @ZZZCount > @AAZZZCount THEN 2 ELSE 0 END

WHEN @AAXXX THEN CASE WHEN @XXXCount = @AAXXXCount THEN 3 ELSE 0 END

WHEN @AAYYY THEN CASE WHEN @YYYCount = @AAYYYCount THEN 3 ELSE 0 END

WHEN @AAZZZ THEN CASE WHEN @ZZZCount = @AAZZZCount THEN 3 ELSE 0 END

ELSE 0 END;

 

SELECT [Option 4:]=@Result

SELECT @Result = NULL;

 

— Option 5:

SELECT @Result = CASE @AA

WHEN @XXX THEN CASE WHEN @XXXCount > @AAXXXCount THEN 2 END

WHEN @YYY THEN CASE WHEN @YYYCount > @AAYYYCount THEN 2 END

WHEN @ZZZ THEN CASE WHEN @ZZZCount > @AAZZZCount THEN 2 END

WHEN @AAXXX THEN CASE WHEN @XXXCount = @AAXXXCount THEN 3 END

WHEN @AAYYY THEN CASE WHEN @YYYCount = @AAYYYCount THEN 3 END

WHEN @AAZZZ THEN CASE WHEN @ZZZCount = @AAZZZCount THEN 3 END

ELSE 0 END;

 

SELECT [Option 5:]=@Result   — Not identical

 

  • CTE Recursiva set @DataFim = ‘20150430’;with CTE_Datas as   select @DataIni as Data, @DataFim as DataFim   union all   select DATEADD(DAY, 1, Data), DataFim   where Data < DataFim 

 

  1. select Data from CTE_Datas
  2. )
  3.    from CTE_Datas
  4. (
  5. set @DataIni = ‘20150401’;
  6. declare @DataIni date, DataFim date;

 

  • Declaração de variáveis do Tipo XML em conjunto com Select

 

DECLARE @Xml XML = N’

<products>

<product id=”1″ name=”Adjustable Race” />

<product id=”879″ name=”All-Purpose Bike Stand” />

<product id=”712″ name=”AWC Logo Cap” />

<product id=”19910″ name=”Cozonac” />

</products>’;

 

SELECT

xt.xc.value(‘@id’, ‘INT’) AS ProductID,

xt.xc.value(‘@name’,’NVARCHAR(50)’) AS Name

FROM

@Xml.nodes(‘/products/product’) AS xt(xc);

 

  • Função Coalesce em conjunto com Left Join e valores nulos(a int null, c int null)(x int null, z int null)

 

  1. y int null,
  2. Create table #xyz
  3. b int null,
  4. Create table #abc

 

 

Insert Into #abc values(null, null, 3), (1,null,3),(1,null,null),(null,2,null)

 

Insert Into #xyz values(null,2,3),(null,null,1),(null,null,2)

 

— Q1

SELECT

*

FROM

#abc a

LEFT JOIN #xyz x

ON a.a = x.x

AND a.b = x.y;

 

— Q2

SELECT

*

FROM

#abc a

LEFT JOIN #xyz x

ON COALESCE(a.a, 9) = COALESCE(x.x, 9)

AND COALESCE(a.b, 9) = COALESCE(x.y, 9);

 

 

  • Funções Char(), NChar(), Unicode() e ASCII()SELECT ASCII(36)   SELECT NCHAR(10084)  

 

    1. SELECT UNICODE(10084)
    2. SELECT CHAR(36)
  • Identificando ausência de índices em tabelas             user_scans, ID.equality_columns, FROM sys.dm_db_missing_index_group_stats GS LEFT OUTER JOIN sys.dm_db_missing_index_groups IG                                                                                                                                                                                                                                LEFT OUTER JOIN sys.dm_db_missing_index_details ID Where ID.database_id = DB_ID(‘CycleCount’) 

 

    1. ORDER BY avg_total_user_cost * avg_user_impact * (user_seeks + user_scans)DESC
    2.                                                                                                                                                                                                                                On (ID.index_handle = IG.index_handle)
    3.                                                                                    On (IG.index_group_handle = GS.group_handle)
    4.              ID.inequality_columns, ID.included_columns, ID.statement
    5. SELECT avg_total_user_cost, avg_user_impact, user_seeks,
  • Índices Clusterizados e Índices Chaves

 

SELECT t.name, i.name, i.type_desc, c.name

FROM sys.tables t

INNER JOIN sys.indexes i

INNER JOIN sys.index_columns ic

INNER JOIN sys.columns c

ON ic.object_id = c.object_id AND ic.column_id = c.column_id

ON i.object_id = ic.object_id AND i.index_id = ic.index_id

ON t.object_id = i.object_id AND i.index_id = 1;

GO

 

  • Índices com colunas duplicadas   (select distinct object_name(i.object_id) tablename,i.name indexname,                                       from sys.index_columns ic1 inner join                                                              ic1.column_id=c.column_id                                           ic1.object_id=i.object_id and                                      order by index_column_id FOR XML PATH(”)),1,2,”)               where object_id=i.object_id and index_id=i.index_id) as columnlist        sys.index_columns ic on i.object_id=ic.object_id and            sys.objects o on i.object_id=o.object_id    (select distinct object_name(i.object_id) tablename,i.name indexname,                                       from sys.index_columns ic1 inner join                                                              ic1.column_id=c.column_id                                           ic1.object_id=i.object_id and                                     order by index_column_id FOR XML PATH(”)),1,2,”)               where object_id=i.object_id and index_id=i.index_id) as columnlist        sys.index_columns ic on i.object_id=ic.object_id and            sys.objects o on i.object_id=o.object_id        substring(t2.columnlist,1,len(t1.columnlist))=t1.columnlist and          (t1.columnlist=t2.columnlist and t1.indexname<>t2.indexname))

 

  1. Go
  2.        (t1.columnlist<>t2.columnlist or
  3. where o.is_ms_shipped=0) t2 on t1.tablename=t2.tablename and
  4.                                    i.index_id=ic.index_id inner join
  5.        from sys.indexes i inner join
  6.                from sys.index_columns ic
  7.                                            ic1.index_id=i.index_id
  8.                                      where ic1.index_id = ic.index_id and
  9.                                            sys.columns c on ic1.object_id=c.object_id and
  10.              (select distinct stuff((select ‘, ‘ + c.name
  11.      where o.is_ms_shipped=0) t1 inner join
  12.                                    i.index_id=ic.index_id inner join
  13.        from sys.indexes i inner join
  14.                from sys.index_columns ic
  15.                                            ic1.index_id=i.index_id
  16.                                      where ic1.index_id = ic.index_id and
  17.                                            sys.columns c on ic1.object_id=c.object_id and
  18.              (select distinct stuff((select ‘, ‘ + c.name
  19. select t1.tablename,t1.indexname,t1.columnlist,t2.indexname,t2.columnlist from

 

  • Operador Intersect

 

CREATE TABLE A ( x INT )

 

INSERT INTO A

VALUES ( 18 ),

( 20 ),

( 4 ),

( 1 ),

( 2 )

 

CREATE TABLE B ( Y INT )

 

INSERT INTO B

VALUES ( 1 ),

( 20 ),

( 2 ),

( 3 )

 

SELECT X AS ‘Intersecting’

FROM A

INTERSECT

SELECT Y

FROM B

 

  • Taxas de Fragmentação de Tabelas antes e depois do Rebuild

 

Select

object_name(ddips.object_id) [Table_name],

convert(decimal(5,2),isnull(ddips.avg_fragmentation_in_percent,0)) [Ext_frag],

ddips.page_count [Pages],

ddips.compressed_page_count

From sys.dm_db_index_physical_stats(db_id(), object_id(‘produtos’), null, null, ‘detailed’) ddips

  • Transações aninhadas

 

CREATE Table TranTable(col varchar(3))

GO

 

BEGIN TRAN A

INSERT INTO TranTable (col) Values (‘abc’)

BEGIN TRAN B

INSERT INTO TranTable (col) Values (‘def’)

SAVE TRAN B

BEGIN TRAN C

INSERT INTO TranTable (col) Values (‘ghi’)

COMMIT TRAN C

ROLLBACK TRAN B

INSERT INTO TranTable (col) Values (‘xyz’)

COMMIT TRAN A

GO

 

Select col from TranTable

GO

 

Drop TABLE TranTable

GO

 

  • Utilitário BCP para criação de arquivos XML

 

— Exemplo 1 —

 

DECLARE @FileName varchar(50),

@bcpCommand varchar(2000)

 

SET @FileName = ‘C:\Users\test.xml’

SET @bcpCommand = ‘bcp “SELECT

”CustomerID” AS ”Parameter/name”, CustomerID AS ”Parameter/value”,

”ContactName” AS ”Parameter/name”, ContactName AS ”Parameter/value”,

”CompanyName” AS ”Parameter/name”, CompanyName AS ”Parameter/value”

FROM Sales.Customers

FOR XML PATH(”T2Method”), ROOT(”Parking”), TYPE, ELEMENTS” queryout “‘

 

SET @bcpCommand = @bcpCommand + @FileName + ‘” -T -c -x’

 

print(@bcpCommand)

 

EXEC master..xp_cmdshell @bcpCommand

 

 

 

— Exemplo 2 —

Declare @Contador Int,

@FileName varchar(50),

@bcpCommand varchar(2000)

 

Set @Contador = 1

 

While @Contador <=(Select Count(IDdaSuaTabela) from SuaTabela)

Begin

 

SET @bcpCommand = ‘bcp “SELECT ”CustomerID” AS ”Parameter/name”, CustomerID AS ”Parameter/value”,

”ContactName” AS ”Parameter/name”,

ContactName AS ”Parameter/value”,

”CompanyName” AS ”Parameter/name”,

CompanyName AS ”Parameter/value”

FROM Sales.Customers

Where IDdaSuaTabela = @Contador

FOR XML PATH(”T2Method”), ROOT(”Parking”), TYPE, ELEMENTS” queryout “‘

 

SET @FileName = ‘C:\Users\test-arquivo-‘+Convert(Varchar(10),@Contador)+’.xml’

SET @bcpCommand = @bcpCommand + @FileName + ‘” -T -c -x’

 

EXEC master..xp_cmdshell @bcpCommand

 

Set @Contador += 1

End

Mais uma vez obrigado por sua visita, fique à vontade para compartilhar este material com seus contatos. Dúvidas, comentários, sugestões e críticas, envie seu comentário ou se preferir um e-mail.

Até mais.

Conhecendo o “Buffer Cache Database” no Microsoft SQL Server 2012 e 2014.


Boa tarde, Comunidade e Amantes do Microsoft SQL Server.

Meu Deus, como o tempo esta passando de forma avassaladora, já estamos no mês de Setembro e daqui a alguns dias estaremos falando sobre o que aconteceu neste ano de 2014, nossa isso acaba sendo assustador. Mesmo assim, vamos em frente ainda temos muito para conhecer e produzir até o final de 2014.

Falando em conhecer e produzir, estou novamente aqui no meu blog, compartilhando com vocês mais um dos milhares de segredos, recursos, funcionalidades e praticidades que o Fantásico Microsoft SQL Server nos apresenta e permita utilizar.

Dentre estes segredos e recursos, quero mostrar para vocês algo muito simples de ser utilizado e entendido, mas que pode ajudar em muito a vida de Administrador de Banco de Dados em suas atividades diárias, estou me referindo ao “Buffer Cache Database”.

É isso mesmo “Buffer Cache Database”!!! Você conhece? Já teve a necessidade de utilizar ou descobrir para que ele serve? Ele existe? Ou somente é uma expressão ou termo técnico?

Eu mesmo no primeiro momento que ouvi este termo e me apresentaram fiquei um pouco perdido, sem saber o que este elemento pode me apresentar de informações úteis, mas com o passar do tempo e necessidade foi possível analisar e entender o quanto este pequeno recurso pode nos ajudar, principalmente em situações de alocação de uso de memória por parte do SQL Server.

Pensando justamente neste tipo de necessidade, decidi escrever este pequeno artigo, para tentar mostrar a vocês uma possível como podemos obter informações sobre o “Buffer Cache Database” e o quanto este Buffer faz parte do nosso ambiente.

Então mãos a massa, vamos descobrir um pouquinho sobre o “Buffer Cache Database”, saber do que ele composto e como podemos trabalhar com ele.

Introdução

O nome “Buffer Cache Database” a princípio pode parecer um bicho de sete cabeças, mas na verdade esta muito longe disso, basicamente pode ser entendido ou tratado como um Cache: “Uma área de armazenamento onde dados ou processos freqüentemente utilizados são guardados para um acesso futuro mais rápido, poupando tempo e uso desnecessário do seu hardware.”

O SQL Server é composto por um grande conjunto de Caches, um dos mais conhecidos é o Bufer Pool: Buffer reponsável em definir a quantidade possível de memória que poderá ser utilizada pelo SQL Server. Através deste recuros, temos a capacidade de utilizar “endereçar” ou “instanciar” o máximo de memória possível disponível em nosso Sistema Operacional sem afetar sua performance. De uma forma bem simples, o Buffer Pool tem como função realizar um balanceamento “equilíbrio” e “compartilhamento” de memória entre uma instância ou Servidor SQL Server através do seu Sistema Operacional do SQL Server chamado SQLOS em conjunto com os Memory Brokers e o próprio Sistema Operacional.

Mas, então, o que seria o “Buffer Cache Database”? Ele Existe? Ou somente é uma expressão ou termo técnico? Como ele é formado?

A resposta é muito simples e direta. O “Buffer Cache Database” não existe, pode ser entendido ou tratado como uma termo ou expressão técnica se comparado com Database Cache existente no Oracle. Na verdade é a forma natural que o SQL Server trabalha para organizar, estruturar e armazenar em páginas de dados que compõem os bancos de dados. Algo que pode ocorrer em diversos momentos, tanto na inicialização de uma instância ou servidor SQL Server, como também, quando um banco de dados realiza o alocação de suas páginas de dados em memória.

Isso mesmo páginas de dados, pequenas estrutura lógicas que armazenam os dados de forma física e temporária. As páginas de dados são interpretados pelo SQL Server da seguinte forma:

  • As páginas de dados são numeradas em sequência, iniciando com zero (0) para a primeira página do arquivo.
  • O tamanho padrão de uma página é 8 KB. Isso significa que qualquer banco de dados criado no SQL Server terá 128 páginas por megabyte.
  • Cada página começa com um cabeçalho de 96 bytes usado para armazenar informações de sistema sobre a página. Essas informações incluem o número de página, o tipo de página, a quantidade de espaço livre na página e a ID de unidade de alocação do objeto que possui a página.
  • Para identificar de forma exclusiva uma página em um banco de dados, são necessários ID do arquivo e número de página. Cada arquivo em um banco de dados tem um número de ID de arquivo exclusivo. Para tentar ilustrar, o exemplo a Figura 1 seguir mostra os números de página em um banco de dados que tem um arquivo de dados primário de 1 MB:
  • Com isso, podemos dizer que o “Buffer Cache Database” é criado e mantido, decorrente da existência das páginas de dados que forma nosso banco, isso nos permite dizer que a partir do momento que realizamos a criação de um banco de dados com tamanho de 1 MB, já estaremos fazendo uso desta estrutura de alocação e nosso novo  banco já terá um “Buffer Cache Database” inicial de 128 páginas.

Buffer01

Figura 1 – Estrutura de Páginas de Dados que compõem a estrutura de Banco de Dados no Microsoft SQL Server.

Caso você queira saber mais sobre páginas de dados, acesse: http://technet.microsoft.com/pt-br/library/ms190969(v=SQL.105).aspx

 

Obtendo o “Buffer Cache Database”

Para obtermos o “Buffer Cache Database” que atualmente esta sendo gerado e consumido pelo nosso SQL Server, vamos fazer uso do Código denominado Parte 1, apresentando abaixo:

— Parte 1 – Obtendo Buffer Cache por Banco de Dados –

Select DB_NAME(database_id) As ‘Database’,

COUNT(*) * 8 / 1024.0 As ‘Cached Size (MB)’

From sys.dm_os_buffer_descriptors

Where database_id <> 32767

Group By DB_NAME(database_id)

Order By ‘Cached Size (MB)’ Desc

 

A Figura 2 apresentada abaixo ilustra o retorno dos “Buffer Cache Database” obtidos no meu SQL Server, observe que o Banco de Dados que neste momento esta gerando o maior Buffer Cache é o Banco Cars com 1.078 MBs.

Buffer02

Figura 2 – Relação de “Buffer Cache Database”.

Nosso próximo passo, será forçar o SQL Server a gerar um novo “Buffer Cache Database”, neste caso, criando o nosso próprio ambiente, para isso será necessário criar um novo banco de dados, denominado: BufferCacheDatabase e uma Tabela denominada BufferCacheDatabaseTable.

Gerando o “Buffer Cache Database”

Para criarmos nosso ambiente, vamos utilizar o Código denominado Parte 2, conforme apresenta abaixo:

— Parte 2 – Criando Ambiente para Gerar Buffer Cache Databae –

Create Database BufferCacheDatabase

Go

 

Use BufferCacheDatabase

Go

 

Create Table BufferCacheDatabaseTable

(BufferID Int Identity Primary Key Clustered,

BufferDescription Varchar(50) Default ‘Buffer Table’,

BufferDateTime DateTime Default GetDate())

Go

 

Observação: Vale ressaltar que este banco de dados esta criado com o tamanho de 3 Megabyte, pois o banco de dados de sistema Model existente no meu Servidor SQL Server, esta configurado neste momento justamente com este tamanho de arquivo, que representa o tamanho mínimo, sendo assim, os novos bancos de dados criados de forma rápida vão herdar esta configuração.

Legal, legal, nosso ambiente já esta criado e pronto para começarmos a brincar!!!! O próximo passo será obter o quando de Buffer Cache foi gerado após a criação deste novo banco de dados, onde vamos somente consultar o quantidade de cache deste Banco, para isso, iremos utilizar o Código denominado Parte 3.

— Parte 3 – Consultando o “Buffer Cache Database” gerado para este novo Banco –

Select DB_NAME(database_id) As ‘Database’,

COUNT(*) * 8 / 1024.0 As ‘Cached Size (MB)’

From sys.dm_os_buffer_descriptors

Where database_id = DB_ID()

Group By DB_NAME(database_id)

 

Ao executar este código, o SQL Server deverá retornar a quantidade de Buffer Cache, criado e alocado para o Banco de Dados: BufferCacheDatabase, conforme apresenta a Figura 3 a seguir:

Buffer03

Figura 3 – Total de “Buffer Cache Database” alocado para o Banco de Dados – BufferCacheDatabase.

Muito bem, como eu destaquei anteriormente, uma simples transação de criação de um novo banco de dados gera Buffer, neste caso nosso banco de dados esta apresentando o Buffer Cache de 1.304 MBs, isso nos faz pensar o quanto o SQL Server tem que trabalhar para controlar e manter em memória este recurso.

Nossa caminhada ainda não acabou mas esta quase lá, na sequência vamos obter as informações sobre “Buffer Cache Database” no nível de Tabela, onde nossa tabela: BufferCacheDatabaseTabela estará vazia e posteriormente após algumas transações de Inserção de dados.

Comecaremos pela Inserção de 2000 linhas de registro na tabela BufferCacheDatabaseTable, utilizando o Código denominado Parte 4, na sequência vamos consultar total estrutura de páginas de dados que é será alocado para esta tabela, o que nos dará mais comprovações do quanto o “Buffer Cache Database” é mantido pelo SQL Server.

— Parte 4 – Inserindo 2000 linhas na tabela BufferCacheDatabaseTable —

Insert Into BufferCacheDatabaseTable Default Values

Go 2000

 

Como você percebeu acabamos de inserir 2000 linhas de registro em nossa tabela, de forma simples e rápida, agora vamos consultar as informações sobre as páginas de dados que forma esta tabela, começando Código denominado Parte 5, onde teremos alguns detalhes, como quantidade de páginas de dados utilizadas e total de página de dados. A Figura 4, ilustra o resultado do processamento deste código.

— Parte 5 – Consultando informações sobre as páginas de dados –

Select ST.Name As ‘Tabela’,

SP.rows As ‘Linhas’,

SA.data_pages As ‘Páginas de Dados’,

SA.used_pages As ‘Páginas de Dados Utilizadas’,

SA.total_pages As ‘Total de Páginas de Dados’

from sys.tables ST Inner Join sys.partitions SP

On ST.object_id = SP.object_id

Inner Join sys.allocation_units SA

On SA.container_id = SP.partition_id

Go

Note que estamos utilizando as Visões de Sistema:

  • Sys.tables;
  • Sys.partitions; e
  • Sys. Allocations_Units.

Caso você queira saber mais sobre estas Views de Sistema, consulte as Referências no final deste artigo.

Buffer04

Figura 4 – Informações sobre as páginas de dados que forma a tabela BufferCacheDatabaseTable.

Perfeito, neste momento temos boa parte das informações do nosso ambiente, inclusive alguns detalhes sobre as páginas de dados. Mas se observarmos com cuidado a Figura 4, como podemos ter o Total de Páginas de Dados com o valor 17 se a coluna Páginas de Dados esta com o valor de 10?

Será que existe alguma coisa de errado? De forma alguma, este valor esta correto, esta diferença existe porque a coluna data_pages existente na System View: sys.allocation_units, apresenta como valor para quantidade de páginas de dados, somente as páginas que forma a tabela, excluíndo deste valor páginas de índice internas e páginas do gerenciamento de alocações. Por isso este valor, então podemos dizer que nossa tabela possui:

  • O total de 17 páginas de dados considerando páginas para índices e alocações internas; e
  • O Total de 10 páginas somente para armazenamento de dados que forma a tabela.

Para deixar mas claro esta constatação, vamos utilizar o Código denominado Parte 6, onde será possível ver todo detalhamento e distribuição das alocações de páginas de dados, registros por páginas e espaço livre em bytes para armazenamento de dados em cada página, conforme ilustra a Figura 5:

— Parte 6 – Detalhamento da Alocação de Dados por Página de Dados –

Select ST.Name As ‘Tabela’,

SB.page_id As ‘Id Página’,

SB.page_type As ‘Tipo da Página’,

SB.Row_Count As ‘Linhas por Página’,

SB.free_space_in_bytes As ‘Espaço Livre em Bytes’

from sys.tables ST Inner Join sys.partitions SP

On ST.object_id = SP.object_id

Inner Join sys.allocation_units SA

On SA.container_id = SP.partition_id

Inner Join sys.dm_os_buffer_descriptors SB

On SB.allocation_unit_id = SA.allocation_unit_id

Order By SB.page_type Asc

Go

 Buffer05

 

 

 

 

 

Figura 5 – Distribuição de dados alocados por página de dados, quantidade de linhas e espaço livre disponível.

Prontinho, sensacional, aqui esta a toda estrutura de alocação e distribuição de dados em suas respectivas páginas de dados que forma a nossa tabela BufferCacheDatabaseTable.

 

Ufa, é isso, conseguimos chegar vivos e salvos ao final de mais esta caminhada. Vou encerrar por aqui mais este artigo, as demais análises e observações vou deixar para você. Um detalhe importante, repita novamente a execução do Código Parte 3 e verifique que o valor calculado do “Buffer Cache Database” provavelmente foi alterado.

Conclusão

Falar deste tipo recurso que na verdade não existe no Microsoft SQL Server, mas esta presente devido a maneira que as páginas de dados são alocadas em memória pode parecer ser fácil, o duro o conseguir encontrar uma forma de demonstrar como ele acontece, de que forma o “Buffer Cache Database” é criado, gerado, alocado e mantido.

Como destacado o grande segredo de qualquer tipo de Cache é saber a forma correta de armazenar o dado ou conjunto de dados para que tanto o Software como também o Hardware não sejam impactos. O “Buffer Cache Database” faz justamente isso de uma forma muito simples, prática e elegante, além disso, ele nos permite saber e entender como o mesmo esta ocorrendo. Em conjunto com o grande conjunto de Visões de Sistemas e Visões de Gerenciamento Dinâmico existentes no SQL Sever desde a versão 2005, este caminho muito ainda mais tranquilo.

Trabalhando de forma invisível como os demais recursos de Buffer, o “Buffer Cache Database”, oferece para o Database Engine e também para toda estrutura de armazenamento de dados do SQL Server, a flexibilidade para pode ser trabalhar com objetos recêm criados, como também, com aqueles que estão em uso ou foram utilizados em um determinado período de tempo, com isso, podemos ter alguns ganhos de performance na busca por dados e funcionalidades do nosso dia-á-dia.

Entender o Buffer Pool e também o Buffer Cache Database é de grande importância para qualquer Administrador de Banco de Dados, pois ambos estão diretamente trabalhando com a memória existente tanto do SQL Server e também o Windows.

É neste cenário que o “Buffer Cache Database” faz o seu papel, instânciado porções de memória para alocação de seus objetos, neste caso, páginas de dados e índices para o melhor funcionamento do SQL Server.

Referências

– sys.tables: http://msdn.microsoft.com/pt-br/library/ms187406.aspx

– sys.allocation_units: http://msdn.microsoft.com/en-us/library/ms189792.aspx

– sys.dm_os_buffer_pool_extension_configuration: http://msdn.microsoft.com/en-us/library/dn133204.aspx

– sys.partitions: http://msdn.microsoft.com/en-us/library/ms175012.aspx

– sys.dm_os_buffer_descriptors:  http://msdn.microsoft.com/en-us/library/ms173442.aspx

——————————————————————————————————————————-

Agradeço a sua visita, espero que você tenha gostado e que este conteúdo possa te ajudar.

Um grande abraço.

Nos encontramos em breve.

Até mais.