1. Globalcode – Open4education
As boas praticas de programação
para SQL Server
Marcelo Fernandes
MVP - MCDBA – MCSA – MCTS – MCITP – MCT - MTA
E-mail: fernandes_dba@hotmail.com
Twitter: @marcelodba
2. Globalcode – Open4education
Begin Transaction
SP_WHO
Especialista em Banco de Dados
Co-autor dos livros:
SQL Server 2014: Alta Disp. na Prática com AlwaysOn Failover Cluster
Instances
SQL Server: Além do conceito SQL Server Blog Post Collection
Palestrante
Blog
http://marcelodba.wordpress.com
https://www.mcdbabrasil.com.br
Contatos
@marcelodba
Fernandes_dba@hotmail.com
3. Globalcode – Open4education
Agenda
Como o SQL executa uma Query
Conceitos de Heaps e Indexação
Tipos de Índices Clustered, Nonclusterd
Conceito de Estatísticas
Conceitos de Plano de Execução
Bloqueios e Concorrência
SARG - Não SARG
4. Globalcode – Open4education
Como o SQL executa uma
Query
NETWORK
NETWORK
Task
Task
Task
Tasks Queue
Workers (threadpool)
Worker Worker Worker Worker
Task Execution
Cache
Parsing,
Compilation,
Optimization
Query Execution
Plan Cache Data Cache
(Buffer pool)
database
1. Request
creates a new
Task
2. Idle Worker
picks up a
pending Task
3. An execution
plan is compiled
4. The Query plan is
executed. Operators
access data through
Buffer Pool
5. Result set is
returned during
execution
6. Task is complete,
Worker returns to idle
8. Globalcode – Open4education
Estatísticas
Conceitos de Estatísticas
Estatísticas são utilizadas pelo query optimizer para
determinar a distribuição dos dados de uma colunas
São armazenadas separadamente dos dados
Precisam ser mantidas
Tem três características
Cardinalidade (ajuda a calcular a quantidade de linhas)
Densidade (ajuda a entender quantos valores únicos existem)
Seletividade (ajuda a entender quantos registros atendem a
busca)
11. Globalcode – Open4education
Planos de Execução
Principais atributos de um plano de Execução.
Como os dados são acessados
Como os dados são agregados nas operações
Se está usando objeto temporários
Ordenações
Estimativa de linhas
Paralelismo
CUSTO !!!!!
12. Globalcode – Open4education
Planos de Execução
Como interpretar um Plano de Execução
Tabela 1Tabela 1
Tabela 2Tabela 2
• Resultset 1 and 2 são unidos utilizando um nested loops join, criando o resultset 3
11
22
33
44
• Resultset 3 and 4 são unidos utilizando um hash match join, criando o resultset 5
55
66
• Resultset 5 and 6 são unidos utilizando nested loops join, criando o resultset de retorno
13. Globalcode – Open4education
Bloqueios e Concorrência
Modos de Bloqueio
Compartilhado – (SH)
Exclusivo – (EX)
Atualização – (U)
Tipos de Bloqueio
Linha
Página
Tabela
14. Globalcode – Open4education
Bloqueios e Concorrência
Niveis de Isolamento
Níveis de Isolamento de transação
Read Commited.
Read Uncommited.
Repeatable Read.
Read Serializable.
Snapshot.
15. Globalcode – Open4education
Bloqueios e Concorrência
Niveis de Isolamento
Níveis de Isolamento de transação
Read Commited.
Read Uncommited.
Repeatable Read.
Read Serializable.
Snapshot.
Linha 1
Linha 2
Linha 5
Linha 3
Linha 6
16. Globalcode – Open4education
Bloqueios e Concorrência
Níveis de Isolamento de transação
Read Commited.
Read Uncommited.
Repeatable Read.
Read Serializable.
Snapshot.
Linha A
Linha B
Linha C
Linha A
Linha B
Linha C
Linha X
Linha Y
Linha Z
Niveis de Isolamento
Linha D
Linha E
Linha F
18. Globalcode – Open4education
DEMO
• Na sessão 2, o comando SELECT realiza uma operação de leitura de T1
enquanto que, no exato momento, a sessão 1 está apagando o registro
de T1. Acessos concorrentes e sem bloqueios! Do ponto de vista do SQL
Server, um erro de consistência pode ocorrer a qualquer instante. Qual
explicação?
• Analisando microscopicamente, o comando SELECT iniciou a operação de
Table Scan em T1, realizando a leitura do registro k=0, e depois ficou
bloqueado na tabela T2. Antes de avançar na leitura da tabela, uma outra
sessão apagou o registro k=0 e liberou o bloqueio em T2. SELECT
continua a operação de Table Scan fazendo a leitura a partir do registro
k=0 para buscar k=1, mas… cade o registro k=0? Ele foi apagado. Nesse
momento, o table scan foi cancelado com o erro 601 – severity 12.
NOLOCK: solicitamos que nenhum lock seja obtido na tabela.
ALTER DATABASE <Database> SET READ_COMMITTED_SNAPSHOT
ON
By Fabricio Catae, http://blogs.msdn.com/b/fcatae/archive/2010/04/28/efeitos-colaterais-do-with-nolock-parte-i.aspx
19. Globalcode – Open4education
Boas Práticas de
Desenvolvimento
Uso do Asterisco
Dificuldade no uso de índices, devido a quantidade de informação retornada.
Inclusão de novas colunas na tabela podem afetar a aplicação
Cláusula ORDER BY
Use ORDER BY apenas quando absolutamente necessário. Ao especificar a
cláusula ORDER BY, não utilize o número das colunas:
-- ORDER BY usando o número da coluna
SELECT OrderID, OrderDate FROM Orders ORDER BY 2
-- ORDER BY usando o nome da coluna, mais legível
SELECT OrderID, OrderDate FROM Orders ORDER BY OrderDate
SELECT * FROM TABELA
20. Globalcode – Open4education
Boas Práticas de
Desenvolvimento
Search Arguments (SARG)
WHERE Nome = 'José'
WHERE Salario > 2500
WHERE 2500 < Salario
WHERE Nome = 'José'
AND Salario > 5000
WHERE Nome LIKE 'Fab%'
WHERE Nome LIKE ‘%Fab'
WHERE ABS(Preco) > 100
WHERE dbo.FnMask(Col) = ’10.330’
WHERE YEAR(Data) = 2011
By Fabiano Amorim
22. Globalcode – Open4education
Boas Práticas de
Desenvolvimento
Exemplos nonSARGS
SELECT ... FROM ... WHERE Year(myDate) = 2008
WHERE myDate >= '01-01-2008' AND myDate < '01-01-2009'
Select ... WHERE isNull(FullName,'Ed Jones') = 'Ed Jones'
Select ... WHERE ((FullName = 'Ed Jones') OR (FullName IS NULL))
Select ... WHERE SUBSTRING(DealerName,4) = 'Ford'
Select ... WHERE DealerName Like 'Ford%'
Select ... WHERE DateDiff(mm,OrderDate,GetDate()) >= 30
Select ... WHERE OrderDate < DateAdd(mm,-30,GetDate())
25. Globalcode – Open4education
Referências
Como o SQL Executa uma Query?
http://rusanu.com/2013/08/01/understanding-how-sql-server-executes-a-
query/
Arquitetura de estruturas de dados de índice e tabela
https://technet.microsoft.com/pt-br/library/ms180978(v=sql.105).aspx
Blog do Catae
http://blogs.msdn.com/b/fcatae/archive/2010/10/05/como-usar-select-
with-nolock-para-melhorar-a-performance.aspx
Blog do Fabiano Amorim
http://blogfabiano.com/
Heap é uma tabela sem índice clusterizado. Heaps têm uma linha em sys.partitions, com index_id = 0
A coluna first_iam_page da exibição de sistema sys.system_internals_allocation_units aponta para a primeira página IAM na cadeia de páginas IAM que gerencia o espaço alocado para o heap em um particionamento específico. O SQL Server usa as páginas IAM para se movimentar pelo heap. As páginas de dados e as linhas dentro delas não estão em nenhuma ordem específica e não estão vinculadas. A única conexão lógica entre as páginas de dados são as informações registradas nas páginas IAM.
Os exames de tabela ou as leituras consecutivas de um heap podem ser executados examinando as páginas IAM para localizar as extensões que estão mantendo páginas do heap. Como o IAM representa extensões na mesma ordem que elas existem nos arquivos de dados, isso significa que esses exames de heap consecutivo progridem seqüencialmente em cada arquivo. O uso das páginas IAM para definir a seqüência de exame também significa que as linhas do heap não são retornadas normalmente na ordem em que foram inseridas.
Data is not stored in any particular order
Specific data can not be retrieved quickly, unless there are also non-clustered indexes
Data pages are not linked, so sequential access needs to refer back to the index allocation map (IAM) pages
Since there is no clustered index, additional time is not needed to maintain the index
Since there is no clustered index, there is not the need for additional space to store the clustered index tree
These tables have a index_id =0 in the sys.indexes catalog view
No SQL Server, os índices são organizados como B-tree. Cada página em um indice B-tree é chamada de nó do índice. O nó superior do B-tree é chamado de nó raiz. O nível inferior dos nós no índice é chamado de nó folha. Quaisquer níveis de índice entre os nós raiz e folha são coletivamente conhecidos como níveis intermediários.
Em um índice clusterizado, os nós folha contêm as páginas de dados da tabela subjacente.
Os nós de nível intermediário e raiz contêm páginas de índice com linhas de índice.
Data is stored in order based on the clustered index key
Data can be retrieved quickly based on the clustered index key, if the query uses the indexed columns
Data pages are linked for faster sequential access
Additional time is needed to maintain clustered index based on INSERTS, UPDATES and DELETES
Additional space is needed to store clustered index tree
These tables have a index_id =1 in the sys.indexes catalog view
Os índices Nonclustered têm a mesma estrutura B-tree que os índices clusterizados, com exceção das seguintes diferenças significativas:
As linhas de dados da tabela subjacente não são classificadas nem armazenadas em ordem com base nas suas chaves não clusterizadas.
A camada de folha de um índice Nonclustered é constituída de páginas de índice, em vez de páginas de dados.
Os índices Nonclustered podem ser definidos em uma tabela ou uma View com um índice clusterizado ou heap.
Cada linha no índice Nonclustered contém o valor de chave Nonclustered e um localizador de linha. Esse localizador aponta para a linha de dados no índice clusterizado ou no heap que possui o valor de chave.
Se a tabela for um heap, ou seja, se não tiver um índice clusterizado, o localizador de linha será um ponteiro para a linha. O ponteiro é criado a partir do ID (identificador), do número da página e do número da linha na página do arquivo. O ponteiro inteiro é conhecido como RID (Identificação de Linha).
Se a tabela tiver um índice clusterizado, ou o índice estiver em uma view indexada, o localizador de linha será a chave de índice clusterizado da linha. Se o índice clusterizado não for um unique index, o SQL Server tornará quaisquer chaves duplicadas exclusivas ao adicionar um valor gerado internamente chamado indicador de exclusividade (uniqueifier). Esse valor de quatro bytes não é visível aos usuários. Ele é adicionado somente quando há necessidade de tornar a chave clusterizada exclusiva para uso em índices não clusterizados.
Os índices não clusterizados têm uma linha em sys.indexes com index_id &gt;0
O que é o Custo de Execução ?
Indicador criado para ajudar o Otimizador do Banco de dados a entender qual a dificuldade em executar cada uma das querys
Que fatores contribuem para gerar o custo de uma query ?
Quantidade de linhas afetadas
Memória utilizada
Quantidade de I/Os
Tempo estimado que a query irá utilizar a CPU
Níveis de Isolamento de transação
Compartilhado (S)
Usado para operações de leitura que não alteram ou atualizam dados, como uma instrução SELECT.
Exclusivo (X)
Usado para operações da modificação de dados, como INSERT, UPDATE ou DELETE. Assegura que várias atualizações não sejam realizadas no mesmo recurso e ao mesmo tempo.
Atualização (U)
Um bloqueio de atualização é um misto de Compartilhado e Exclusivo.
Um bloqueio compartilhado é adquirido para operações de leitura para impedir que os dados que estão sendo lidos sejam alterados durante a leitura.
Processos Obstruídos
Os níveis de isolamento afetam a maneira como o SQL Server manipula as transações, assim como a duração dos bloqueios.
READ COMMITTED
Specifies that statements cannot read data that has been modified but not committed by other transactions. This prevents dirty reads. Data can be changed by other transactions between individual statements within the current transaction, resulting in nonrepeatable reads or phantom data. This option is the SQL Server default.
The behavior of READ COMMITTED depends on the setting of the READ_COMMITTED_SNAPSHOT database option:
If READ_COMMITTED_SNAPSHOT is set to OFF (the default), the Database Engine uses shared locks to prevent other transactions from modifying rows while the current transaction is running a read operation. The shared locks also block the statement from reading rows modified by other transactions until the other transaction is completed. The shared lock type determines when it will be released. Row locks are released before the next row is processed. Page locks are released when the next page is read, and table locks are released when the statement finishes.
Note
If READ_COMMITTED_SNAPSHOT is set to ON, the Database Engine uses row versioning to present each statement with a transactionally consistent snapshot of the data as it existed at the start of the statement. Locks are not used to protect the data from updates by other transactions.
Snapshot isolation supports FILESTREAM data. Under snapshot isolation mode, FILESTREAM data read by any statement in a transaction will be the transactionally consistent version of the data that existed at the start of the transaction.
When the READ_COMMITTED_SNAPSHOT database option is ON, you can use the READCOMMITTEDLOCK table hint to request shared locking instead of row versioning for individual statements in transactions running at the READ COMMITTED isolation level.
Note
When you set the READ_COMMITTED_SNAPSHOT option, only the connection executing the ALTER DATABASE command is allowed in the database. There must be no other open connection in the database until ALTER DATABASE is complete. The database does not have to be in single-user mode.
READ UNCOMMITTED
Specifies that statements can read rows that have been modified by other transactions but not yet committed.
Transactions running at the READ UNCOMMITTED level do not issue shared locks to prevent other transactions from modifying data read by the current transaction. READ UNCOMMITTED transactions are also not blocked by exclusive locks that would prevent the current transaction from reading rows that have been modified but not committed by other transactions. When this option is set, it is possible to read uncommitted modifications, which are called dirty reads. Values in the data can be changed and rows can appear or disappear in the data set before the end of the transaction. This option has the same effect as setting NOLOCK on all tables in all SELECT statements in a transaction. This is the least restrictive of the isolation levels.
In SQL Server, you can also minimize locking contention while protecting transactions from dirty reads of uncommitted data modifications using either:
The READ COMMITTED isolation level with the READ_COMMITTED_SNAPSHOT database option set to ON.
The SNAPSHOT isolation level.
Reference
https://msdn.microsoft.com/pt-br/library/ms173763.aspx
REPEATABLE READ
Specifies that statements cannot read data that has been modified but not yet committed by other transactions and that no other transactions can modify data that has been read by the current transaction until the current transaction completes.
Shared locks are placed on all data read by each statement in the transaction and are held until the transaction completes. This prevents other transactions from modifying any rows that have been read by the current transaction. Other transactions can insert new rows that match the search conditions of statements issued by the current transaction. If the current transaction then retries the statement it will retrieve the new rows, which results in phantom reads. Because shared locks are held to the end of a transaction instead of being released at the end of each statement, concurrency is lower than the default READ COMMITTED isolation level. Use this option only when necessary.
SERIALIZABLE
Specifies the following:
Statements cannot read data that has been modified but not yet committed by other transactions.
No other transactions can modify data that has been read by the current transaction until the current transaction completes.
Other transactions cannot insert new rows with key values that would fall in the range of keys read by any statements in the current transaction until the current transaction completes.
Range locks are placed in the range of key values that match the search conditions of each statement executed in a transaction. This blocks other transactions from updating or inserting any rows that would qualify for any of the statements executed by the current transaction. This means that if any of the statements in a transaction are executed a second time, they will read the same set of rows. The range locks are held until the transaction completes. This is the most restrictive of the isolation levels because it locks entire ranges of keys and holds the locks until the transaction completes. Because concurrency is lower, use this option only when necessary. This option has the same effect as setting HOLDLOCK on all tables in all SELECT statements in a transaction.
Reference
https://msdn.microsoft.com/pt-br/library/ms173763.aspx
SNAPSHOT Especifica que os dados lidos por qualquer instrução em uma transação serão a versão transacionalmente consistente que existia no início da transação. A transação pode reconhecer apenas modificações de dados que estavam confirmadas antes do início da transação. Modificações de dados efetuadas por outras transações após o início da transação atual não são visíveis para as instruções em execução na transação atual. O efeito será como se as instruções em uma transação obtivessem um Snapshot dos dados confirmados conforme existiam no início da transação.
Exceto quando um banco de dados está sendo recuperado, as transações SNAPSHOT não exigem bloqueios ao ler dados. Transações SNAPSHOT que leem dados não bloqueiam outras transações de gravar dados. Transações que gravam dados não bloqueiam transações SNAPSHOT de ler dados.
Durante a fase de reversão de uma recuperação de banco de dados, as transações SNAPSHOT solicitarão um bloqueio se houver uma tentativa de ler dados que se encontram bloqueados por outra transação que está sendo revertida. A transação SNAPSHOT será bloqueada até que aquela transação seja revertida. O bloqueio será liberado tão logo seja concedido.
A opção de banco de dados ALLOW_SNAPSHOT_ISOLATION deve ser definida como ON para que uma transação que usa o nível de isolamento SNAPSHOT seja iniciada. Se uma transação que usa o nível de isolamento SNAPSHOT acessar dados em vários bancos de dados, ALLOW_SNAPSHOT_ISOLATION deve ser definida como ON em cada banco de dados.
Uma transação iniciada com outro nível de isolamento não pode ser definida com o nível de isolamento SNAPSHOT; isso causaria a anulação da transação. Se uma transação for iniciada no nível de isolamento SNAPSHOT, você poderá alterar seu nível de isolamento e retorná-la para o SNAPSHOT. Uma transação é iniciada na primeira vez em que ela acessa dados.
Uma transação em execução sob o nível de isolamento SNAPSHOT pode exibir as alterações feitas por essa transação. Por exemplo, se a transação executar um UPDATE em uma tabela e, em seguida, emitir uma instrução SELECT na mesma tabela, os dados modificados serão incluídos no conjunto de resultados.