Quando você tem uma consulta ou procedimento armazenado que precisa de ajuste de desempenho, quais são as primeiras coisas que você tenta?
Quando você tem uma consulta ou procedimento armazenado que precisa de ajuste de desempenho, quais são as primeiras coisas que você tenta?
Respostas:
Aqui está a lista prática de coisas que sempre dou a alguém que me pergunta sobre otimização.
Usamos principalmente o Sybase, mas a maioria dos conselhos se aplica a todos.
O SQL Server, por exemplo, vem com uma série de bits de monitoramento / ajuste de desempenho, mas se você não tiver nada parecido (e talvez até o faça), considerarei o seguinte ...
99% dos problemas que eu vi são causados por colocar muitas tabelas em uma junção . A correção para isso é fazer metade da junção (com algumas das tabelas) e armazenar em cache os resultados em uma tabela temporária. Em seguida, faça o restante da consulta ingressando nessa tabela temporária.
#temp
As tabelas podem ter um desempenho muito melhor que as @table
variáveis com grandes volumes (milhares de linhas).Um pouco fora do tópico, mas se você tiver controle sobre esses problemas ...
Alto nível e Alto impacto.
CREATE INDEX
Verifique se há índices disponíveis para suas cláusulas WHERE
e JOIN
. Isso agilizará bastante o acesso aos dados.
Se o seu ambiente é um data mart ou armazém, os índices deverão ser abundantes para quase todas as consultas possíveis.
Em um ambiente transacional , o número de índices deve ser menor e suas definições mais estratégicas, para que a manutenção do índice não arraste recursos. (A manutenção do índice é quando as folhas de um índice devem ser alteradas para refletir uma alteração na tabela subjacente, como acontece comINSERT, UPDATE,
e DELETE
operações.)
Além disso, lembre-se da ordem dos campos no índice - quanto mais seletivo (cardinalidade maior) um campo, mais cedo no índice ele deve aparecer. Por exemplo, digamos que você esteja consultando automóveis usados:
SELECT i.make, i.model, i.price
FROM dbo.inventory i
WHERE i.color = 'red'
AND i.price BETWEEN 15000 AND 18000
Preço geralmente tem maior cardinalidade. Pode haver apenas algumas dezenas de cores disponíveis, mas possivelmente milhares de preços diferentes.
Dessas opções de índice, idx01
fornece o caminho mais rápido para satisfazer a consulta:
CREATE INDEX idx01 ON dbo.inventory (price, color)
CREATE INDEX idx02 ON dbo.inventory (color, price)
Isso ocorre porque menos carros satisfazem o preço do que a escolha da cor, dando ao mecanismo de consulta muito menos dados para analisar.
Eu sou conhecido por ter dois índices muito semelhantes, diferindo apenas na ordem dos campos para acelerar as consultas (nome, sobrenome) em um e (sobrenome, nome) no outro.
Um truque que aprendi recentemente é que o SQL Server pode atualizar variáveis locais e campos em uma instrução de atualização.
UPDATE table
SET @variable = column = @variable + otherColumn
Ou a versão mais legível:
UPDATE table
SET
@variable = @variable + otherColumn,
column = @variable
Usei isso para substituir cursores / junções complicados ao implementar cálculos recursivos e também obtive muito desempenho.
A seguir, detalhes e código de exemplo que fizeram melhorias fantásticas no desempenho: http://geekswithblogs.net/Rhames/archive/2008/10/28/calculating-running-totals-in-sql-server-2005---the-optimal. aspx
Assumindo o MySQL aqui, use EXPLAIN para descobrir o que está acontecendo com a consulta, verifique se os índices estão sendo usados da maneira mais eficiente possível e tente eliminar as classificações de arquivos. MySQL de alto desempenho: otimização, backups, replicação e muito mais é um ótimo livro sobre esse tópico, assim como o Blog de desempenho do MySQL .
@Terrapin, existem algumas outras diferenças entre isnull e coalescer que merecem ser mencionadas (além da conformidade com a ANSI, que é importante para mim).
Geralmente, começarei com as junções - eliminarei cada uma delas da consulta, uma de cada vez, e executarei novamente a consulta para ter uma idéia se houver uma junção específica com a qual estou tendo problemas.
Em todas as minhas tabelas temporárias, gosto de adicionar restrições exclusivas (quando apropriado) para criar índices e chaves primárias (quase sempre).
declare @temp table(
RowID int not null identity(1,1) primary key,
SomeUniqueColumn varchar(25) not null,
SomeNotUniqueColumn varchar(50) null,
unique(SomeUniqueColumn)
)
Eu criei o hábito de sempre usar variáveis de ligação. É possível que as variáveis de ligação não ajudem se o RDBMS não armazenar em cache instruções SQL. Mas se você não usar variáveis de ligação, o RDBMS não terá chance de reutilizar planos de execução de consultas e instruções SQL analisadas. A economia pode ser enorme: http://www.akadia.com/services/ora_bind_variables.html . Eu trabalho principalmente com Oracle, mas o Microsoft SQL Server funciona da mesma maneira.
Na minha experiência, se você não sabe se está ou não usando variáveis de ligação, provavelmente não está. Se o idioma do seu aplicativo não os suportar, encontre um que suporte. Às vezes, você pode corrigir a consulta A usando variáveis de ligação para a consulta B.
Depois disso, converso com nosso DBA para descobrir o que está causando mais dor no RDBMS. Observe que você não deve perguntar "Por que essa consulta é lenta?" É como pedir ao seu médico para tirar seu apêndice. Certifique-se de que sua consulta possa ser o problema, mas é provável que algo esteja errado. Como desenvolvedores, tendemos a pensar em termos de linhas de código. Se uma linha estiver lenta, corrija-a. Mas um RDBMS é um sistema realmente complicado e sua consulta lenta pode ser o sintoma de um problema muito maior.
Muitas dicas de ajuste de SQL são ídolos de cultos de carga. Na maioria das vezes, o problema não está relacionado ou está minimamente relacionado à sintaxe usada, portanto, normalmente é melhor usar a sintaxe mais limpa possível. Em seguida, você pode começar a procurar maneiras de ajustar o banco de dados (não a consulta). Apenas ajuste a sintaxe quando isso falhar.
Como qualquer ajuste de desempenho, sempre colete estatísticas significativas. Não use o tempo do relógio de parede, a menos que seja a experiência do usuário que você está ajustando. Em vez disso, observe coisas como tempo de CPU, linhas buscadas e blocos lidos no disco. Muitas vezes as pessoas otimizam para a coisa errada.
Executar a consulta usando WITH (NoLock) é praticamente uma operação padrão em meu lugar. Qualquer um que for pego executando consultas nas tabelas de dezenas de gigabytes sem que seja retirado e filmado.
Converta as consultas NOT IN para JOYS OUTER ESQUERDA, se possível. Por exemplo, se você deseja encontrar todas as linhas na Tabela1 que não são usadas por uma chave estrangeira na Tabela2, você pode fazer isso:
SELECT *
FROM Table1
WHERE Table1.ID NOT IN (
SELECT Table1ID
FROM Table2)
Mas você obtém um desempenho muito melhor com isso:
SELECT Table1.*
FROM Table1
LEFT OUTER JOIN Table2 ON Table1.ID = Table2.Table1ID
WHERE Table2.ID is null
@ DavidM
Supondo que o MySQL aqui, use EXPLAIN para descobrir o que está acontecendo com a consulta, verifique se os índices estão sendo usados da maneira mais eficiente possível ...
No SQL Server, o plano de execução oferece a mesma coisa: informa quais índices estão sendo atingidos, etc.
Não necessariamente um truque de desempenho do SQL em si, mas definitivamente relacionado:
Uma boa idéia seria usar o memcached sempre que possível, pois seria muito mais rápido buscar os dados pré-compilados diretamente da memória do que obtê-los do banco de dados. Há também uma versão do MySQL que foi incorporada ao memcached (de terceiros).
Verifique se o comprimento do seu índice é o menor possível. Isso permite que o banco de dados leia mais chaves de cada vez no sistema de arquivos, acelerando suas junções. Suponho que isso funcione com todos os bancos de dados, mas sei que é uma recomendação específica para o MySQL.
Eu procuro:
SET NOCOUNT ON
Normalmente, a primeira linha dentro dos meus procedimentos armazenados, a menos que eu realmente precise usar @@ROWCOUNT
.
No SQL Server, use a diretiva nolock. Ele permite que o comando select seja concluído sem ter que esperar - geralmente outras transações serão concluídas.
SELECT * FROM Orders (nolock) where UserName = 'momma'
Remova os cursores sempre que não forem necessários.
Remova as chamadas de função nos Sprocs, onde muitas linhas chamarão a função.
Meu colega usou chamadas de função (obtendo lastlogindate do userid como exemplo) para retornar conjuntos de registros muito amplos.
Com a otimização, substituí as chamadas de função no sproc pelo código da função: reduzi o tempo de execução de muitos sprocs de> 20 segundos para <1.
Eu gosto de usar
isnull(SomeColThatMayBeNull, '')
Sobre
coalesce(SomeColThatMayBeNull, '')
Quando não preciso do suporte a múltiplos argumentos que a coalescência oferece.
http://blog.falafel.com/2006/04/05/SQLServerArcanaISNULLVsCOALESCE.aspx
Não prefixe os nomes dos Procedimentos armazenados com "sp_" porque todos os procedimentos do sistema começam com "sp_", e o SQL Server terá que procurar mais para encontrar seu procedimento quando for chamado.
set transaction isolation level read uncommitted
Impede bloqueios mortos onde a integridade transacional não é absolutamente necessária (o que geralmente é verdadeiro)
Eu sempre vou primeiro ao SQL Profiler (se é um procedimento armazenado com muitos níveis de aninhamento) ou ao planejador de execução de consulta (se são algumas instruções SQL sem aninhamento). 90% do tempo, você pode encontrar o problema imediatamente com uma dessas duas ferramentas.