Вы находитесь на странице: 1из 28

SEFAZ-BA Secretaria da Fazenda do Estado da Bahia

SGF Superintendência da Gestão Fazendária


DTI Diretoria de Tecnologia da Informação
GETEC Gerência de Tecnologia

BOAS PRÁTICAS DE
PROGRAMAÇÃO
TRANSACT-SQL
Versão 01.04.00

Salvador (Ba), outubro de 2012


Secretaria da Fazenda do Estado da Bahia 27/10/2019
DTI - Diretoria de Tecnologia da Informação

CONTROLE DE VERSÃO
Versão Data Responsável Histórico
1. Substituição de “Departamento”
por “Diretoria” no cabeçalho;
2. Padronização da capa;
3. Transferência do Manual de Padrões Banco
para o Manual de Boas Práticas de
Programação SQL do conteúdo que provê
Equipe AD orientações sobre quando e como utilizar
01.01.00 29/12/2006
(Padrões) as views de linked server;
4. Criação do tópico “TABELAS DE
HISTÓRICO” e inclusão neste tópico da
recomendação para armazenar as datas de
início e fim de vigência nas tabelas de
histórico, quando fizer sentido.

1. Incluir conteúdo relacionado aos recursos


do SQL Server 2005 (Tabelas
Equipe AD
01.02.00 15/01/2009 Particionadas, Novos Tipos de Dados,
(Padrões)
Service Broker, Campos XML).

Equipe AD 1. Inclusão do item “Controle de Execução de


01.03.00 18/04/2011
(Padrões) Scripts” no tópico “OBSERVAÇÕES”.

Equipe AD 1. Inclusão do item “SET NOCOUNT ON” no


01.04.00 01/10/2012
(Padrões) tópico “OBSERVAÇÕES”.

Página 2 444017568.doc
Secretaria da Fazenda do Estado da Bahia 27/10/2019
DTI - Diretoria de Tecnologia da Informação

ÍNDICE

1. OBJETIVO........................................................................................................................................4

2. TABELAS TEMPORÁRIAS.........................................................................................................4

3. TRANSAÇÕES...............................................................................................................................7

4. ÍNDICES..........................................................................................................................................9

5. PLANOS DE EXECUÇÃO..........................................................................................................11

6. VISÕES..........................................................................................................................................14

7. VERTICALIZAÇÃO DE TABELAS..........................................................................................16

8. FUNÇÕES DEFINIDAS PELO USUÁRIO...............................................................................18

9. REFERÊNCIA CRUZADA..........................................................................................................20

10. TABELAS DE HISTÓRICO...................................................................................................22

11. TABELAS PARTICIONADAS................................................................................................23

12. NOVOS TIPOS DE DADOS DO SQLSERVER 2005...........................................................24

13. SERVICE BROKER................................................................................................................24

14. CAMPOS XML........................................................................................................................25

15. OBSERVAÇÕES.......................................................................................................................26

16. CONCLUSÃO...........................................................................................................................28

17. REFERÊNCIAS.........................................................................................................................28

Página 3 444017568.doc
Secretaria da Fazenda do Estado da Bahia 27/10/2019
DTI - Diretoria de Tecnologia da Informação

1. OBJETIVO

Este documento reúne um conjunto de técnicas de programação em Transact-SQL que devem


ser adotadas para garantir um bom desempenho das aplicações no ambiente SEFAZ.

2. TABELAS TEMPORÁRIAS

Recomendação: Não utilizar tabela temporária em estado de transação.

Quando uma tabela temporária é construída, são gerados bloqueios em tabelas do catálogo
(sysobjects, sysindexes e syscolumns) no TEMPDB. O TEMPDB é um banco compartilhado
por todos os usuários de um servidor SQL Server e é um recurso extremamente utilizado na
geração de tabelas temporárias, cursores, etc. Se uma tabela temporária for criada em estado
de transação, os bloqueios serão mantidos até o final da transação, bloqueando outros usuários
e comprometendo a performance do servidor.

Tabelas temporárias podem ser substituídas por joins ou por tabelas derivadas em grande
parte das situações, evitando os bloqueios no TEMPDB e melhorando a performance das
aplicações. Seguem alguns exemplos de substituição de tabelas temporárias por joins e tabelas
derivadas:

Com tabelas temporárias:


(solução não recomendada)

CREATE TABLE #tipo_operacao (


cod_operacao int not null,
des_operacao char(20) not null
)
Resumo das operações:
INSERT INTO #tipo_operacao 2 criação/destruição de objetos
SELECT * FROM tipo_operacao 1 atualização
WHERE cod_operacao > 10 1 consulta

SELECT *
FROM operacao O INNER JOIN #tipo_operacao TO
ON (O.cod_operacao = TO.cod_operacao)

DROP TABLE #tipo_operacao

Com JOIN:
(solução recomendada)

SELECT cod_operacao, des_operacao


Resumo das operações:
FROM operacao O INNER JOIN tipo_operacao TO
1 consulta
ON (O.cod_operacao = TO.cod_operacao)
WHERE TO.cod_operacao > 10

Página 4 444017568.doc
Secretaria da Fazenda do Estado da Bahia 27/10/2019
DTI - Diretoria de Tecnologia da Informação

A seguir, analisaremos um exemplo mais trabalhado, semelhante à geração de relatórios.


Neste exemplo, a solução apresentada é o uso de uma tabela derivada que nada mais é do que
a substituição de uma tabela na cláusula FROM por uma consulta. O exemplo abaixo, assim
como outros exemplos e tópicos abordados podem ser encontrados no site
http://www.sql-server-performance.com

Com tabelas temporárias:


(solução não recomendada)

-- CREATE OUR TEMPORARY TABLE Resumo das operações:


2 criação/destruição de objetos
CREATE TABLE #Temp_Example ( 1 atualização
[CategoryID] INT NOT NULL, 1 consulta
[Category_Count] INT NOT NULL
)

-- INSERT THE VALUES WE LATER NEED INTO THE TEMP TABLE

INSERT INTO #Temp_Example (CategoryID, Category_Count)


SELECT C.CategoryID, COUNT(*) AS Category_Count
FROM Categories C
INNER JOIN Products P ON C.CategoryID = P.CategoryID
GROUP BY C.CategoryID, C.CategoryName

-- JOIN ON THE TEMP TABLE TO GET OUR VALUES

SELECT C.CategoryID, C.CategoryName, P.ProductName, P.UnitPrice,


#Temp_Example.Category_Count
FROM Categories C
INNER JOIN Products P ON C.CategoryID = P.CategoryID
INNER JOIN #Temp_Example ON C.CategoryID = #Temp_Example.CategoryID
ORDER BY C.CategoryName

-- DROP TEMPORARY TABLE

DROP TABLE #Temp_Example

Com tabela derivada:


(solução recomendada)

SELECT C.CategoryID, C.CategoryName, P.ProductName, P.UnitPrice,


CT.Category_Count
FROM Categories C
INNER JOIN Products P ON C.CategoryID = P.CategoryID
INNER JOIN (
SELECT C.CategoryID, COUNT(*) AS Category_Count
FROM Categories C
INNER JOIN Products P ON C.CategoryID = P.CategoryID
GROUP BY C.CategoryID, C.CategoryName
)CT ON C.CategoryID = CT.CategoryID
ORDER BY C.CategoryName

Resumo das operações:


1 consulta

Página 5 444017568.doc
Secretaria da Fazenda do Estado da Bahia 27/10/2019
DTI - Diretoria de Tecnologia da Informação

De forma geral, o número de operações para implementação de uma solução com tabelas
temporárias é maior e as operações são mais custosas (criação e exclusão de objetos,
atualização de dados, etc.), logo, evite o uso de tabelas temporárias e procure trabalhar com
joins e tabelas derivadas sempre que possível. Uma outra alternativa é utilizar o tipo table
para armazenar os dados temporários de forma menos custosa.

Para maiores informações sobre tabelas derivadas, consulte “Derived Tables” no Books
Online. O tipo de dados table pode ser encontrado em “Table Data Type” também no Books
Online. Informações sobre performance de tabelas temporárias X tabelas derivadas podem ser
encontradas em http://www.sql-server-performance.com

Página 6 444017568.doc
Secretaria da Fazenda do Estado da Bahia 27/10/2019
DTI - Diretoria de Tecnologia da Informação

3. TRANSAÇÕES
Recomendação: Procurar definir as transações com o menor escopo possível.

Transações são utilizadas para garantir que um conjunto de comandos SQL seja executado
como uma unidade atômica de código. Isto significa que todos os comandos devem ser
executados juntos ou nenhum deles poderá ser executado. Além disso, o banco deve garantir
que os comandos de uma transação não interfiram no resultado de outras transações que
estejam executando concorrentemente.

Para garantir estas premissas, o custo para banco de dados pode ser altíssimo, por isso, as
transações devem ser definidas com bastante critério. Só precisam estar em estado de
transação comandos que devem ser executados de maneira conjunta e não podem ser
executados separados. Comandos que podem ser executados de forma independente não
devem ser executados em estado de transação.

Exemplos
comando2
Transações grandes: comando1
(solução não recomendada)
comando4
comando3

bloqueio

Tabela
comando2
comando1
bloqueio
comando4
comando3

comando6 comando2
comando5 comando1

comando4
comando3

Transações pequenas:
(solução recomendada) comando2
comando1

comando2 comando2
comando1 Tabela comando1

comando2 comando2
comando1 comando1

Página 7 444017568.doc
Secretaria da Fazenda do Estado da Bahia 27/10/2019
DTI - Diretoria de Tecnologia da Informação

O resultado da definição de transações com escopo muito grande é que uma quantidade menor
de processos poderá executar concorrentemente e a performance das aplicações diminuirá
consideravelmente. Por outro lado, se as transações forem definidas com escopo pequeno,
mais transações vão poder ser executadas concorrentemente e a performance das aplicações
será melhor.

Observações sobre finalização de transações:

a. Dentro de um trigger, todo ROLLBACK deve ser acompanhado por um RETURN, de


forma a garantir que o trigger será finalizado naquele ponto. Se um RETURN não for
executado, o trigger executará o ROLLBACK e continuará seguindo o fluxo normal
de execução, o que pode levar a inconsistências no banco de dados.
b. Dentro de stored procedures, todo ROLLBACK deve ser acompanhado por um
RAISERROR, garantindo que a aplicação será informada de que houve uma falha na
operação, dando o tratamento adequado. Se o RAISERROR não estiver presente, a
aplicação intepretará o resultado como sucesso e não fará nenhum tipo de tratamento.

Exemplos

Errado: Correto:

CREATE PROC up_errada AS CREATE PROC up_correta AS


... ...
IF @@error = 0 IF @@error = 0
commit transaction commit transaction
ELSE ELSE
rollback transaction BEGIN
... rollback transaction
raiserror 50001 ‘Erro na
procedure!!!’
END
...

Para maiores informações sobre transações, consulte “Transactions” no Books Online.


Informações sobre bloqueios (locks) podem ser encontradas no site
http://www.sql-server-performance.com

Página 8 444017568.doc
Secretaria da Fazenda do Estado da Bahia 27/10/2019
DTI - Diretoria de Tecnologia da Informação

4. ÍNDICES
Recomendação: Utilizar índices clustered em tabelas pouco atualizadas e índices
nonclustered nas demais.

a) Definição de Índice

Índices são estruturas de dados utilizadas para otimizar consultas em bancos de dados. Os
índices evitam a necessidade de uma leitura extensiva (table scan) em uma tabela para
localizar um ou mais registros. A figura abaixo ilustra a estrutura de um índice (ix_usuario01)
criado para o campo cod_usuario que armazena o código do usuário:

cod_usuario nome
1 1 Ana
5 2 Mario
10 3 Joao
... 4 Jose
5 Paula
6 Marcos
7 Joana
8 Simão
9 Pedro
10 Fernando
... ...

Com o índice acima, uma consulta como select nome from usuário where cod_usuario = 7
seguiria o caminho indicado pelas seta tracejada, ou seja, escolheria o apontador do índice que
mais se aproximasse do registro desejado e realizaria uma pequena busca na tabela de usuário
para encontrar o registro. Se o índice não existisse, o SQL Server seguiria o caminho indicado
pela seta pontilhada, ou seja, faria uma busca extensiva na tabela de usuário até encontrar o
registro desejado. As principais conseqüências da falta de um índice adequado seriam o
aumento no tempo da consulta e um aumento dos bloqueios na tabela de usuário.

b) Tipos de Índice

Existem 2 tipos de índices, Clustered e Nonclustered:

 Nos índices Clustered existe uma relação direta entre a ordenação do índice e a
ordenação física dos dados da tabela. Essa organização maximiza a performance de
consultas que retornam dados ordenados pelo(s) campo(s) do índice (exemplo 1) e
consultas que trabalham com intervalos de valores (exemplo 2).

Exemplo 1 - Índice clustered no campo cod_usuario:

SELECT cod_usuario, nom_usuario FROM usuario ORDER BY cod_usuario

Exemplo 2 - Índice clustered no campo dtc_atualizacao

SELECT nom_usuario FROM usuario


WHERE dtc_atualizacao BETWEEN ‘2003/04/01’ AND ‘2003/07/01’

Página 9 444017568.doc
Secretaria da Fazenda do Estado da Bahia 27/10/2019
DTI - Diretoria de Tecnologia da Informação

Apesar dos benefícios citados, os índices clustered geram um custo adicional durante
a atualização porque os dados precisam ser reordenados fisicamente a cada
atualização. Em virtude disso, índices clustered devem ser criados somente em
tabelas que não são atualizadas ou que tenham uma freqüência de atualização
muito baixo.

Obs.: Pelo fato de exigir uma ordenação física dos dados, somente um índice
clustered pode ser criado para cada tabela.

 Nos índices Nonclustered não existe uma relação direta entre a ordenação do índice e
a ordenação física dos dados da tabela. Existe um custo em operações de atualização
de tabelas que utilizem índices nonclustered, mas o overhead é muito menor do que
ocorre com os índices clustered. A criação de índices nonclustered deve ser avaliada
pelo desenvolvedor seguindo as recomendações sobre planos de execução
documentadas neste manual.

Obs.: Pelo fato de não exigir uma ordenação física dos dados, vários índices
nonclustered podem ser criados para cada tabela.

c) Chaves Primárias x Índices Secundários

Quando uma constraint do tipo chave primária é criada para uma tabela, o SQL Server cria
automaticamente um índice na tabela. Este índice por padrão é CLUSTERED, portanto,
quando não houver necessidade de criação de um índice do tipo clustered, é importante
especificar explicitamente a cláusula NOCLUSTERED no comando ALTER TABLE. Os
exemplos a seguir ilustram o fato:

ALTER TABLE usuario ADD CONSTRAINT ix_usuario01


PRIMARY KEY (cod_usuario)

Será criado automaticamente um índice chamado ix_usuario01 do tipo clustered.

ALTER TABLE usuario ADD CONSTRAINT ix_usuario01


PRIMARY KEY NONCLUSTERED (cod_usuario)

Será criado automaticamente um índice chamado ix_usuario01 do tipo nonclustered.

Além da chave primária podem ser criados diversos índices por tabela, chamados de índices
secundários. Vale ressaltar que quanto maior for a quantidade de índices em uma tabela, maior
será o overhead de atualização. Índices secundários são criados por padrão como
nonclustered, devendo ser usada a cláusula CLUSTERED somente quando for avaliada a
necessidade de criação de um índice do tipo clustered.

Para maiores informações sobre índices, consulte “Indexes” no Books Online.

Página 10 444017568.doc
Secretaria da Fazenda do Estado da Bahia 27/10/2019
DTI - Diretoria de Tecnologia da Informação

5. PLANOS DE EXECUÇÃO
Recomendação: Analisar periodicamente os planos de execução dos comandos SQL,
avaliando a necessidade de criação de índices para otimização.

A partir da versão 7.0, o SQL Server disponibilizou uma ferramenta para avaliação do plano
de execução de comandos SQL, em modo gráfico. Esta ferramenta está embutida no Query
Analyzer (antigo ISQL/W) e será detalhada a seguir. Vamos tomar como exemplo uma tabela
“usuario” que contém a estrutura abaixo:

cod_usuario int not null


nom_usuario varchar(30) not null

Esta tabela já contém um índice primário no campo cod_usuario. No primeiro exemplo será
executada a seguinte consulta no banco:

SELECT * FROM usuario

Para gerar o plano de execução estimado dessa consulta, basta selecionar o(s) comando(s) em
questão e usar CTRL+L. O plano de execução da consulta acima é o seguinte:
Neste caso, o plano
estimado indica que
houve um table
scan, ou seja, uma
varredura em toda a
tabela para retornar
os registros
desejados. O table
scan é uma operação
que deve ser evitada
porque consome uma quantidade grande de recursos para ser efetivada, diminuindo a
performance das consultas. Na consulta acima houve table scan por dois motivos:

 Não foi determinado um filtro (join, cláusula WHERE ou HAVING); 


 A lista de campos não foi colocada na consulta e foi usado * para retornar todos os
campos. 

Vamos modificar um pouco a consulta, supondo que só será necessário o campo cod_usuario:

SELECT cod_usuario FROM usuario

O plano de execução da consulta passa a ser o seguinte:

Para uma visão detalhada do que ocorreu em cada etapa, basta apontar com o mouse para o
ícone da etapa desejada. Um
resumo da etapa será exibido
com informações sobre a
operação realizada, o custo de
I/O, CPU e dados adicionais.
(figura ao lado)

Página 11 444017568.doc
Secretaria da Fazenda do Estado da Bahia 27/10/2019
DTI - Diretoria de Tecnologia da Informação

Neste caso foi realizado um Index Scan devido aos seguintes motivos:

 Não foi determinado um filtro (isto justifica o scan); 


 A lista de campos foi colocada na consulta (neste caso só o campo cod_usuario). 

Como existe um índice no campo cod_usuario, o índice é utilizado, mas ainda permanece o
scan (varredura). A situação é melhor do que a primeira consulta porque o table scan foi
transformado em index scan, ou seja, a varredura deixou de ser na tabela e passou a ser no
índice. De qualquer forma, esta ainda não é uma situação ideal, como veremos adiante.

Vamos adicionar um filtro à consulta e observar o resultado do plano de execução:

SELECT cod_usuario FROM usuario


WHERE cod_usuario >1000

Plano estimado:

Com o filtro o index scan passou a ser


index seek, ou seja, o otimizador trabalhará
somente com o conjunto de registros
especificado no filtro. Note que o index
seek consumiu menos recursos de I/O e
CPU do que o index scan. Essa diferença
pode ser ainda maior quando a tabela
consultada tiver um número elevado de registros. O index seek é a operação ideal na maioria
dos casos e deve ser um dos objetivos de toda otimização de consulta.

Obs.: Nem sempre o index seek pode ser alcançado numa otimização. Se o número de
registros que você está pesquisando for muito grande em relação ao total de registros da
tabela, o otimizador tende a fazer um index scan ou table scan, independentemente da
existência de filtros e índices. Outros fatores que contribuem para a execução de scans
são o uso de funções (datepart, convert, etc) na cláusula WHERE e o uso indevido de
aspas em comparações (exemplo: WHERE num_inscicao_estad = ‘334’, sendo
num_inscricao_estad um campo do tipo INT.

Vamos analisar agora um exemplo com mais um campo na consulta:

SELECT cod_usuario, nom_usuario FROM usuario


WHERE cod_usuario >1000

Plano estimado:

Página 12 444017568.doc
Secretaria da Fazenda do Estado da Bahia 27/10/2019
DTI - Diretoria de Tecnologia da Informação

No plano de execução da consulta acima, surgiu uma nova etapa chamada Bookmark Lookup,
indicando que, apesar da pesquisa no índice, campos adicionais correspondentes aos registros
procurados serão lidos diretamente da tabela. Esta operação gera um custo adicional para a
consulta.

Para eliminar esta etapa teremos que criar um índice que contenha todos os campos desejados
e todos os campos do filtro. Isto nem sempre é possível porque consultas complexas utilizam
muitos campos tanto na cláusula SELECT quanto na cláusula WHERE. Nestes casos o lookup
é inevitável.

Existem outros tipos de operações que podem aparecer no plano de execução estimado, mas
as operações citadas acima são as que mais interferem na peformance das consultas no banco
de dados. Para maiores informações sobre planos de execução, procure “Execution Plan” no
Books Online.

Página 13 444017568.doc
Secretaria da Fazenda do Estado da Bahia 27/10/2019
DTI - Diretoria de Tecnologia da Informação

6. VISÕES
Recomendações:
 Utilizar visões para consultas com algum grau de complexidade e quando existir
a possibilidade de reutilização;
 Verificar o código da visão antes de utilizá-la numa consulta.

Uma visão (ou view) é um mecanismo usado pelo servidor de banco de dados para encapsular
o código de uma consulta. Esse encapsulamento traz 2 grandes benefícios: simplicidade de
uso e possibilidade de reutilização de código. Apesar disso, a complexidade de uma consulta
pode ser camuflada através de uma visão, logo, a clareza fica comprometida. De uma forma
geral, visões devem ser utilizadas para consultas com um certo grau de complexidade e que
possam ser reutilizadas no mesmo sistema ou por uma equipe de desenvolvedores. Criar
visões indiscriminadamente adiciona complexidade ao ambiente desnecessariamente,
portanto, é importante ter bom senso para decidir se uma visão deve ou não ser criada. É
importante também verificar o código da visão antes de utilizá-la numa consulta, para ter uma
noção da complexidade da consulta como um todo.

Visões Indexadas

Recomendação: Utilizar visões indexadas em consultas complexas e quando a tabela for


atualizada com pouca freqüência.

Quando uma visão é criada, seu código é gravado no banco de dados e executado a cada
chamada à visão. Para visões mais complexas, com diversos joins e filtros, o tempo da
consulta pode ser consideravelmente alto, prejudicando a performance da aplicação. Para
minimizar esse problema, a partir do SQL Server 2000, foi adicionado o conceito de Visão
Indexada (Indexed View). Para criar uma visão indexada, é necessária a criação de um índice
clustered em uma visão. O grande benefício das visões indexadas é o fato do resultado da
consulta que gera a visão ficar armazenado em disco, permitindo a criação de índices. Apesar
disso, visões indexadas não devem ser criadas em tabelas com atualizações constantes ou
pesadas, pois a interação entre a tabela fonte e a visão ficará comprometida.

Para maiores informações sobre visões indexadas, consulte “Indexed Views” no Books
Online.

Visões de Linked Server

Recomenda-se utilizar visões de linked server quando todas as situações abaixo


ocorrerem:

 Quando for necessário prover acesso a tabelas de outros servidores;

A visão de linked server servirá para garantir a independência das aplicações em


relação aos nomes dos servidores

 Quando o volume de dados transferido for pequeno;

A adoção de visões de linked server para volumes grandes de dados acarreta um


tráfego indesejado entre os servidores e aumenta os riscos de perda de conexão.

Página 14 444017568.doc
Secretaria da Fazenda do Estado da Bahia 27/10/2019
DTI - Diretoria de Tecnologia da Informação

 Quando a dependência do servidor remoto for pequena.

Para essa dependência ser pequena, a visão de linked server envolvida deve ser
chamada com uma freqüência baixa (seja através de um trigger, seja através de uma
stored procedure).

As funcionalidades críticas devem evitar o uso de visões de linked server, pois estas
representariam um fator a mais de risco para a aplicação.

Observações:

 Quando houver um procedimento de alta complexidade no servidor remoto com


retorno reduzido para o servidor de origem, pode-se utilizar chamadas remotas a
procedures em lugar de views de linked server.

 Quando houver um procedimento e este não for de alta complexidade, o analista deve
escolher entre uma chamada remota a procedure (caso a lógica do procedimento
dependa de objetos do servidor remoto), uma visão chamada de uma procedure local
(caso o procedimento possa estar inteiramente no servidor local) ou replicação (em
último caso).

 A decisão sobre utilizar views de linked server, chamadas remotas a stored


procedures, replicação ou, ainda, múltiplas conexões deve ser sempre alinhada com a
GETEC.

Características:

 Não podem ter qualquer filtro;

 O número de campos retornados deve ser o menor possível;

 Deve existir no máximo uma visão de linked server por tabela;

 Cada visão de linked server só pode referenciar uma única tabela.

 Um dos seguintes nomes deve ser utilizado como nome do servidor remoto:
“CORPORATIVO” (para o SSED03W, SSED09W e SSED20W) e “FINANCEIRO”
(para o SSED26W, SSED09W_02 e SSED20W_02).

Caso haja a necessidade de acesso via linked server (visão ou stored procedure), para
um servidor diferente dos citados, a GETEC deve ser consultada.

Página 15 444017568.doc
Secretaria da Fazenda do Estado da Bahia 27/10/2019
DTI - Diretoria de Tecnologia da Informação

7. VERTICALIZAÇÃO DE TABELAS
Recomendação: Utilizar uma estrutura vertical para armazenar consolidados.

Algumas tabelas, entre elas boa parte dos consolidados, estão modeladas com uma estrutura
semelhante a que segue:

ano val01 val02 val03 val04 ...


2000 86 56 54 89 ...
2001 23 65 78 50 ...
2002 49 74 95 47 ...
2003 76 15 12 34 ...
... ... ... ... ... ...

Nesta estrutura existe uma chave (o ano) e uma coluna para cada mês. Quando se deseja
somar todos os valores de um determinado ano, basta localizar o registro a partir da chave e
somar os campos val01, val02, val03, etc. Por exemplo, para somar os valores
correspondentes ao ano 2003 seria necessário executar a seguinte consulta:

SELECT val01 + val02 + ...


FROM consolidado
WHERE ano = 2003

Apesar de funcionar bem para consultas desse tipo, esta estrutura possui uma série de
limitações:

 Quando o valor de um determinado mês ainda é desconhecido (por exemplo, os


valores de 2003 correspondentes aos meses de agosto, setembro, outubro...), há
desperdício de espaço em disco pois está sendo reservado espaço para armazenar um
valor que ainda não existe.

 Para consultas que fogem ao padrão citado, a estrutura acima é deficiente do ponto de
vista de performance. Se for necessário, por exemplo, consolidar os resultados de
dezembro de 2002 a fevereiro de 2003 seria necessária uma consulta mais complexa
com CASE, IFs, cursores, ou o uso de variáveis. Além disso, como o período a ser
consultado pode variar, seria necessária a utilização de consultas dinâmicas,
degradando ainda mais a performance.

 A criação de índices nesse caso fica limitada à chave (ano), pois, para otimizar filtros
nos campos val01, val02, etc, seria necessário criar índices para todas as combinações
possíveis dos campos e isso geraria um overhead de atualização altíssimo.

Página 16 444017568.doc
Secretaria da Fazenda do Estado da Bahia 27/10/2019
DTI - Diretoria de Tecnologia da Informação

Uma alternativa para atender às diversas demandas de consultas em consolidados desse tipo é
utilizar uma estrutura vertical semelhante a que segue:
dtr val
200207 77 Nesta estrutura o período é representado por uma data reduzida,
200208 54 composta por ano e mês, permitindo que consultas de períodos possam
200209 13 ser realizadas de forma direta, como no exemplo abaixo:
200210 89
200211 104 SELECT val
200212 63 FROM consolidado
200301 76 WHERE dtr BETWEEN 200212 AND 200302
200302 15
200303 12
... ...

As principais vantagens deste modelo são:


 Melhor aproveitamento de espaço: os espaço em disco só será ocupado quando o
valor de um determinado mês for conhecido. Não existirão, por exemplo, registros
para agosto, setembro, outrubro, novembro e dezembro de 2003 porque estes valores
ainda não foram calculados;

 Facilidade de otimização: com poucos índices é possível otimizar a maioria das


consultas no formato citado. Um índice para o campo dtr seria usado para consultas
diretas (dtr = xxxxyy) ou por períodos (dtr between xxxxyy and aaaabb). Outro
índice, em val, garantiria consultas rápidas por intervalos de valores (val > n, por
exemplo).

Observação sobre datas reduzidas: O modelo para datas reduzidas (ano+mês = AAAAMM)
traz benefícios em consultas por períodos e minimiza a
necessidade de operações aritméticas durante a execução
das consultas. Apesar disso, é importante que seja
sempre avaliado como as datas serão representadas para
evitar redundâncias.

A estrutura vertical pode ser utilizada não só em consolidados, mas em diversas outras tabelas
que sigam o modelo acima. O modelo vertical deve ser utilizado como padrão, podendo
ser usada uma abordagem horizontal em casos específicos. Dúvidas a respeito da escolha
do modelo a ser utilizado devem ser discutidas com a GETEC.

Página 17 444017568.doc
Secretaria da Fazenda do Estado da Bahia 27/10/2019
DTI - Diretoria de Tecnologia da Informação

8. FUNÇÕES DEFINIDAS PELO USUÁRIO


Recomendação: Desenvolver funções com códigos simples, para funcionalidades
genéricas ou para substituir determinados tipos de visões ou stored procedures.

O SQL Server possui um conjunto de funções, chamadas BUILT-IN Functions, amplamente


utilizadas para programação em Transact-SQL. Alguns exemplos dessas funções são convert,
getdate, datepart, dateadd, datediff, left, right, max, count, etc. Essas funções não podem ser
modificadas.

A partir da versão 2000 do SQL Server, tornou-se possível a criação de Funções Definidas
pelo Usuário (User-Defined Functions) onde a lógica da função é determinada pelo
desenvolvedor. Existem 3 tipo de funções definidas pelo usuário:

 Escalares
 Tabulares “Inline”
 Tabulares “Multistatement”

Funções escalares retornam um valor pontual, enquanto as funções tabulares retornam uma
tabela. Seguem alguns exemplos dessas funções:

Exemplo 1 Função Escalar que retorna somente a data a partir de um campo


SMALLDATETIME ou DATETIME.

Recomendação: Utilizar funções escalares para substituir rotinas simples e genéricas


como up_dia_util, conversão de moeda, etc.

CREATE FUNCTION uf_somente_data (@data_hora datetime)


RETURNS CHAR(10)
AS
BEGIN
DECLARE @data CHAR(10)
SELECT @data = LEFT(CONVERT(CHAR(10),@data_hora,101),10)
RETURN(@data)
END

Depois de criada, a função poderia ser utilizada da seguinte forma:

SELECT dbo.uf_somente_date(dtc_atualizacao)
FROM bd_contribuinte..contribuinte_inscrito
WHERE num_inscricao_estad = 334

Exemplo 2 Função Tabular “Inline” que retorna informações sobre os usuários de um


determinado grupo passado como parâmetro.

Recomendação: Utilizar funções tabulares inline para substituir visões que necessitem
de passagem de parâmetros. Valem as mesmas recomendações sobre
visões descritas neste documento.

Página 18 444017568.doc
Secretaria da Fazenda do Estado da Bahia 27/10/2019
DTI - Diretoria de Tecnologia da Informação

Segue...

CREATE FUNCTION uf_usarios_grupo (@cod_grupo int)


RETURNS table
AS
RETURN (
SELECT nom_usuario, dtc_criacao
FROM usuario
WHERE cod_grupo = @cod_grupo
)

Perceba a mudança na sintaxe da função tabular. A cláusula RETURNS deve


obrigatoriamente ser preenchida pelo tipo table e os delimitadores de bloco (BEGIN e END)
não são utilizados. A função acima é inline, ou seja, o retorno da função se resume ao
resultado de comando SELECT especificado pela cláusula RETURN( ).

Depois de criada, a função poderia ser utilizada da seguinte forma:

SELECT nom_usuario, dtc_criacao


FROM uf_usuarios_grupo(17652)

É possível ainda a criação de funções tabulares “multistatement”, ou seja, o código da função


será composto por um conjunto de comandos que preencherão uma tabela a ser retornada pela
função. O uso de funções desse tipo deve ser negociado com a GETEC.

Funções definidas pelo usuários trazem flexibilidade à programação em Transact-SQL, mas


devem ser utilizadas com cautela, pois, assim como as visões, as funções encapsulam um
código Trasact-SQL e conseqüentemente camuflam sua complexidade. Criar códigos
complexos para funções pode gerar problemas sérios de performance, portanto, é essencial
que as funções sejam desenvolvidas com códigos simples, de preferência quando a
funcionalidade puder ser reaproveitada por diversas aplicações.

Para maiores informações sobre funções definidas pelo usuário, consulte “User-Defined
Functions” no Books Online.

Página 19 444017568.doc
Secretaria da Fazenda do Estado da Bahia 27/10/2019
DTI - Diretoria de Tecnologia da Informação

9. REFERÊNCIA CRUZADA
Determinados tipos de aplicações precisam, em alguns casos, gerar relatórios de referência
cruzada, como no exemplo abaixo:
Faturamento Resultado Desejado

ano bimestre valor


1990 1 1,1
1990 2 1,2 ano semestre 1 semestre 2
1990 3 1,3 1990 2,3 2,7
1990 4 1,4 1991 4,3 4,7
1991 1 2,1
1991 2 2,2
1991 3 2,3
1991 4 2,4

Problema:

A tabela de faturamento citada, armazena o faturamento em milhões de uma determinada


empresa, a cada bimestre. Foi solicitado um relatório que cruzasse o faturamento por
semestre, a cada ano.

Solução 1
(solução não recomendada)

Para chegar ao resultado desejado é comum a utilização de cursores e atualizações em tabelas


temporárias, aumentando o custo da consulta.

CREATE TABLE #ref_cruzada (


ano SMALLINT NOT NULL,
semestre1 DECIMAL(5,2) NULL,
semestre2 DECIMAL(5,2) NULL
)

INSERT INTO #ref_cruzada (ano)


SELECT DISTINCT ano Resumo das operações:
FROM tab_fonte 2 criação/destruição de objetos
3 atualização
UPDATE #ref_cruzada 1 consulta
SET semestre1 = SUM(F.valor)
FROM faturamento F INNER JOIN #ref_cruzada R
ON F.ano = R.ano
WHERE F.bimestre <= 2

UPDATE #ref_cruzada
SET semestre2 = SUM(F.valor)
FROM faturamento F INNER JOIN #ref_cruzada R
ON F.ano = R.ano

Página 20 444017568.doc
Secretaria da Fazenda do Estado da Bahia 27/10/2019
DTI - Diretoria de Tecnologia da Informação

WHERE F.bimestre >= 3


Segue...

SELECT ano, semestre1, semestre2


FROM #ref_cruzada

DROP TABLE #ref_cruzada

Comentário: a solução acima é extremamente custosa pois é necessário criar uma tabela
temporária, executar uma série de atualizações para preenchê-la, ler a tabela para retornar o
resultado e depois destruí-la. A quantidade de atualizações ainda poderá aumentar se o
número de colunas da tabela de referência cruzada aumentar.

Solução 2
(solução recomendada)

SELECT ano,

SUM(CASE bimestre WHEN 1 THEN Valor


WHEN 2 THEN Valor
ELSE 0
END) AS semestre1,

SUM(CASE bimestre WHEN 3 THEN Valor


WHEN 4 THEN Valor
ELSE 0
END) AS semestre2 Resumo das operações:
FROM vendas 1 consulta
GROUP BY Ano

Comentário: o segredo da solução acima é utilizar o comando CASE em conjunto com a


função SUM para consolidar os resultados de cada semestre. A solução se resume a uma
consulta e é muito menos custosa que a primeira.

Para maiores informações sobre referência cruzada, consulte “Cross-tab Reports” no Books
Online.

Página 21 444017568.doc
Secretaria da Fazenda do Estado da Bahia 27/10/2019
DTI - Diretoria de Tecnologia da Informação

10. TABELAS DE HISTÓRICO


Armazenar na mesma tabela dados freqüentemente atualizados e dados históricos é uma
política bastante perigosa do ponto de vista de performance. O ideal é armazenar dados
históricos em uma tabela separada, gerenciando a transferência de dados entre as tabelas
envolvidas. Vale ressaltar que esta solução só é viável quando existe uma clara distinção entre
o que é histórico (somente leitura) e o que é atualizado.

Recomenda-se armazenar nas tabelas de histórico a data de inclusão de cada uma de suas
linhas, como forma de diferenciá-las. Com o objetivo de maximizar a performance das
consultas às tabelas de histórico, recomenda-se também armazenar as datas de início e fim de
vigência, desde que faça sentido para essas tabelas o conceito de vigência oficial. Em certas
situações, pode-se conhecer apenas a data de inclusão de uma linha em uma tabela de
histórico, que não corresponderá necessariamente à data oficial de fim de vigência dos dados
em questão.

Existindo as datas de início e fim de vigência oficial em uma tabela de histórico, bastará que
se use na cláusula WHERE das consultas uma expressão do tipo “@dtc_pesquisada between
dtc_inicio_vigencia and dtc_fim_vigencia”, o que dispensará o uso de subselects para obter
(deduzir, derivar) a data de início de vigência em uma linha diferente e, portanto, melhorará a
performance dessas consultas.

Página 22 444017568.doc
Secretaria da Fazenda do Estado da Bahia 27/10/2019
DTI - Diretoria de Tecnologia da Informação

11. TABELAS PARTICIONADAS


(Solução de particionamento oferecida pelo SQL Server 2005)

Os dados de tabelas e índices particionados são divididos em unidades que podem ser
difundidas por mais de um grupo de arquivos em um banco de dados. Os dados são
particionados horizontalmente, de forma que os grupos de linhas são mapeados em partições
individuais. A tabela (ou índice) é tratada como uma única entidade lógica quando são
executadas consultas ou atualizações nos dados. Todas as partições de um único índice ou de
uma única tabela devem residir no mesmo banco de dados.

Tabelas ou índices particionados suportam todas as operações suportadas por tabelas e índices
convencionais. Durante a análise para decisão de particionar ou não um objeto, devemos levar
em consideração o tamanho atual e o desempenho esperado das consultas.

A utilização de objetos particionados diminui a complexidade de manutenção de objetos com


altíssima taxa de crescimento que normalmente causam baixa performance em consultas
devido ao grande volume de dados.

Existem dois fatores a considerar ao planejar uma função de partição: a coluna cujos valores
determinam como uma tabela é particionada, conhecida como coluna de particionamento, e o
intervalo de valores da coluna de particionamento para cada partição. Esse intervalo de
valores determina o número de partições que compõem sua tabela. Uma tabela poderá ter
1.000 partições, no máximo.

As opções que você tem para as colunas de particionamento e para o intervalo de valores são
determinados, basicamente, pela extensão na qual seus dados podem ser agrupados de forma
lógica, como por exemplo, por data; e, se este agrupamento lógico é adequado para gerenciar
subconjuntos de dados.

Resumo:

Objetivo:
 Aumento de Performance
 Facilidade de administração

Composição dos 2 fatores do particionamento:


 Função de particionamento (Partition Function) que define as fronteiras das partições;
 Distribuição física das partições (Patition Scheme) que determina onde cada partição
será armazenada.

Página 23 444017568.doc
Secretaria da Fazenda do Estado da Bahia 27/10/2019
DTI - Diretoria de Tecnologia da Informação

12. NOVOS TIPOS DE DADOS DO SQLSERVER 2005

Large-Value Data Types:


 Varchar(max), NVarchar(max), Varbinary(max);
 Permitem armazenar até 2GB de dados
 Substituem os antigos, Text, NText e Image, garantindo maior flexibilidade
XML
 Permite o armazenamento de um documento ou fragmento XML em variáveis ou
campos de tabelas;
 Vantagens:
o Permite a criação de índices específicos para esse tipo de dado;
o Suporta consultas através da linguagem X-Query
o A estrutura do conteúdo XML pode ser validada
 Limitação:
o O conteúdo XML original não é plenamente preservado.

13. SERVICE BROKER


O Serviço Broker é responsável pelo processo de envio e recebimento de mensagens
assíncronas em diferentes processos no SQL Server 2005. A linguagem TSQL é utilizada para
o envio de mensagens para uma fila no banco de dados do remetente ou para outro banco de
dados do SQL Server, ou outro servidor/instância remoto. No processo do Service Broker são
envolvidas filas de espera, os diálogos e a ativação.

Consultando filas

Às vezes pode ser necessário inspecionar o conteúdo de uma fila como um todo. Você pode
querer saber quantas mensagens a fila contém ou assegurar que o aplicativo processou todas
as mensagens de um serviço que está prestes a se tornar off-line. Você pode precisar descobrir
por que as mensagens não estão sendo processadas por um aplicativo.

Para obter essas informações, use o nome da fila como a tabela de origem de uma instrução
SELECT. Uma instrução SELECT em uma fila tem o mesmo formato que uma instrução
SELECT em uma exibição ou uma tabela.

NOTA:

O Agente de Serviços é projetado para permitir que vários leitores de fila recebam
mensagens eficientemente de uma fila. Porém, uma instrução SELECT em uma fila
pode causar bloqueio. Ao usar uma instrução SELECT em uma fila, especifique a
dica NOLOCK para evitar o bloqueio de aplicativos que usam a fila

A seguir, está uma instrução SELECT de exemplo para descobrir o número de mensagens na
fila ExpenseQueue:

SELECT COUNT(*) FROM dbo.ExpenseQueue WITH (NOLOCK) ;

Página 24 444017568.doc
Secretaria da Fazenda do Estado da Bahia 27/10/2019
DTI - Diretoria de Tecnologia da Informação

14. CAMPOS XML


O padrão XML ( eXtensible Markup Language) é um meio de transferir informações de
forma semi-estruturada, usa marcadores (tags) e atributos. Ele usa os marcadores apenas para
delimitar os trechos de dados, deixando sua interpretação completamente à cargo da aplicação
de front-end.

O XML permite maior flexibilidade, auxilia na camada de transporte e permite a


interoperabilidade entre diferentes plataformas. Adicionalmente, existem padrões de
transformação para convertê-lo em um formato mais adequado (XSL) e para validar sua
sintaxe (XSD).

No SQL Server 2005, é possível especificar alguns métodos para consultar dados em
estruturas XML. Os métodos de consulta em estruturas XML são:

query() - Realiza consultas em estruturas XML que retornam XML;


value() - Realiza consultas em estruturas XML que retornam tipos SQL;
exist() - Realiza consultas para determinar a existência de um valor dentro de uma estrutura
XML;
nodes() - Utiliza para segmentar uma estrutura XML em vários registros

O SQL Server 2005 possui o tipo de dados XML que pode ser utilizado para simplicar
consideravelmente aplicações que possuam esse tipo de características. Nas versões anteriores
do SQL Server era necessário armazenar códigos XML em campos do tipo varchar.

Campos XML podem ser consultados via XQuery desta forma:

Retorna o XML do campo t do XML, o [p="d"] é um filtro para a propriedade p do marcador


part, retornará <t>NE</t>;

select CampoTipoXML.Query('//prev//part[p="d"]//t') from TabelaComDadosXML

Para retornar o valor do campo, sem o marcador envolvendo o texto, podemos usar a função
Data, o exemplo abaixo retorna o conteúdo do marcador, retornará NE;

select CampoTipoXML.Query('Data(//prev//part[p="d"]//t)') from TabelaComDadosXML

Para acessar uma propriedade do marcador como a parX, você deve utilizar o @ para indicar
o nome da propriedade;

select CampoTipoXML.Query('Data(//prev//part[p="d"]//@parX)') from


TabelaComDadosXML

Atenção, você está trabalhando com campos XML, então o retorno é sempre em XML, para
poder usar como texto em querys no SQL Server 2005 com tipos varchar por exemplo, você
tem que converter o dado XML, em texto, usando por exemplo a função convert.

select Convert( varchar(max), CampoTipoXML.Query('Data(//prev//part[p="d"]//t)') ) from


TabelaComDadosXML

Página 25 444017568.doc
Secretaria da Fazenda do Estado da Bahia 27/10/2019
DTI - Diretoria de Tecnologia da Informação

15. OBSERVAÇÕES
Seguem algumas observações importantes sobre Transact-SQL.

HINTS

O SQL disponibiliza cláusulas adicionais que podem ser utilizadas para mudar condições do
contexto em que uma consulta é executada. Estas cláusulas, chamadas HINTS, são muito
poderosas, mas devem ser utilizadas com muito cuidado. Seguem 4 dos hints mais
conhecidos:

tablockx Atribui um lock exclusivo em toda a tabela que está sendo


consultada. Ninguém poderá ler ou atualizar absolutamente nada
nesta tabela até o final da transação que gerou o tablockx.

holdlock Mantém os locks nas tabelas envolvidas numa operação até o final
da transação. O contexto da transação será definido pelo BEGIN
TRAN mais externo.

nolock Nenhum tipo de lock será respeitado na consulta. Os resultados


retornados poderão estar inconsistentes.

index Força a utilização de um determinado índice. Esta opção foi muito


utilizada na versão 6.5, mas tornou-se quase desnecessária a partir
da versão 7.0.

Importante: Hints podem influenciar muito a performance de uma aplicação e até mesmo do
servidor como um todo, por isso, o uso de hints deverá sempre ser negociado
com a GETEC.

Cursores

Cursores, assim como tabelas temporárias, têm um custo muito grande para o banco. É
aconselhável evitar o uso de cursores, procurando substituí-los por joins e/ou tabelas
derivadas.

 Quando for utilizar um cursor, procure selecionar os mais simples como FAST
FOWARD (este tipo mescla as opções FOWARD ONLY e READ ONLY)
 Só use cursores SCROLL se for realmente necessário
 Feche sempre os cursores depois da utilização com CLOSE e DEALLOCATE
 Lembre sempre de executar o FETCH dentro do WHILE que varre o cursor evitando
LOOPs infinitos.

ORDER BY

A cláusula ORDER BY é bastante conhecida e utilizada, mas compromete a performance nas


consultas. Esta cláusula só deve ser utilizada quando a ordenação não puder ser realizada no
cliente.

CONTROLE DE EXECUÇÃO DO SCRIPT

Ao elaborar um script com blocos de instruções dependentes, é recomendável utilizar o


RETURN ou declarar numa transação. Desta forma, é possível controlar as instruções que
serão executadas. Seguem abaixo, 2 exemplos:

Página 26 444017568.doc
Secretaria da Fazenda do Estado da Bahia 27/10/2019
DTI - Diretoria de Tecnologia da Informação

Exemplo 1:

IF @@SERVERNAME <> 'PCORPORATIVO\BDP_CORPORATIVO'


BEGIN
PRINT 'A instância não é de produção'
RETURN
END
ELSE
BEGIN
SELECT loginname as 'Logins de Produção:'
FROM master..syslogins
END;

Exemplo 2:

BEGIN TRANSACTION
UPDATE usuario_dba SET usuario = 'ab'
WHERE usuario = 'ad'

IF @@ERROR <> 0
ROLLBACK
ELSE
COMMIT

SET NOCOUNT ON

O SET NOCOUNT ON pode proporcionar um aumento significativo de desempenho,


pois o tráfego de rede é bastante reduzido.

Vale lembrar que SET NOCOUNT ON somente deve ser utilizado quando o retorno
da quantidade de registros afetados não for necessário. A função @@ROWCOUNT é
atualizada mesmo quando SET NOCOUNT é ON.

Página 27 444017568.doc
Secretaria da Fazenda do Estado da Bahia 27/10/2019
DTI - Diretoria de Tecnologia da Informação

16. CONCLUSÃO
Alguns dos tópicos acima foram indicados como recomendação ou simplesmente difusão de
conhecimento, outros devem ser seguidos à risca por terem conseqüências sérias para o banco
de dados e para as aplicações.

A programação em Transact-SQL, por envolver muitos fatores, deve ser realizada sempre de
maneira criteriosa, através da discussão de soluções, análise de planos de execução e
principalmente atualização de conhecimentos.

Este documento estará sendo atualizado sempre que algum fator importante for identificado,
portanto servirá como referência técnica e deverá ser consultado com freqüência.

17. REFERÊNCIAS
SQL Server Performance Tunning Tips http://www.sql-server-performance.com

Microsoft Sql Server 2000 Performance Tuning Edward Whalen, Marcilina Garcia, Steve
Adrien Deluca, Edward Whalen Reding,
Jamie Marcilina Garcia – Microsoft Press
ISBN: 0735612706

Microsoft SQL Server Books Online

Página 28 444017568.doc

Вам также может понравиться