QUERY TUNING Lílian Simão Oliveira Query Tuning Pode ser tentador para resolver um problema de desempenho exclusivamente pelo nível de sistema de ajuste de desempenho do servidor, por exemplo, tamanho da memória, tipo de sistema de arquivos, número e tipo de processadores, e assim por diante. A experiência tem mostrado que a maioria dos problemas de desempenho não podem ser resolvidos desta forma. Eles devem ser abordadas através da análise da aplicação, consultas e atualizações que o aplicativo apresenta ao banco de dados, e como essas consultas e atualizações de como interagir com o esquema do banco de dados. A longa duração consultas e atualizações podem ser causados por? Lenta comunicação de rede. Memória insuficiente no computador servidor, ou não há memória suficiente disponível para SQL Server. Falta de estatísticas úteis. A falta de índices úteis. Falta de distribuição de dados úteis. Quando uma consulta ou atualização leva mais tempo do que o esperado, use a seguinte lista para melhorar o desempenho. Observação: É recomendável que este checklist ser consultado antes de entrar em contato com seu provedor de suporte técnico. É o problema de desempenho relacionado a um outro componente do que as consultas? Por exemplo, é o problema de desempenho de rede lenta? Há outros componentes que possam estar causando ou contribuindo para a degradação do desempenho? Windows NT Performance Monitor pode ser usado para monitorar o desempenho do SQL Server e os componentes não-SQL Server relacionados. Se o problema de desempenho está relacionado às consultas, que consulta ou conjunto de consultas está envolvido? Use o SQL Profiler para ajudar a identificar a consulta lenta ou consultas. O desempenho de uma consulta de banco de dados pode ser determinado usando a instrução SET para permitir que o SHOWPLAN, STATISTICS IO, STATISTICS TIME, e as opções STATISTICS PROFILE. SHOWPLAN descreve o método escolhido pelo otimizador de consultas do SQL Server para recuperar dados. STATISTICS IO relata informações sobre o número de scans, leituras lógicas (páginas acessadas em cache), e leituras físicas (número de vezes que o disco foi acessado) para cada tabela referenciada na declaração. STATISTICS TIME exibe a quantidade de tempo (em milissegundos) necessária para analisar, compilar e executar uma consulta. STATISTICS PROFILE exibe um conjunto de resultados depois de cada consulta executada representa um perfil da execução da consulta. No SQL Query Analyzer, você também pode ativar a opção gráfica do plano de execução para ver uma representação gráfica de como o SQL Server recupera dados. As informações recolhidas por essas ferramentas lhe permite determinar como uma consulta é executada pelo otimizador de consulta SQL Server e quais índices estão sendo usados. Usando essa informação, você pode determinar se melhorias de desempenho pode ser feita por reescrever a consulta, alterando os índices nas tabelas, ou talvez modificando o projeto de banco de dados. A query foi otimizada com estatísticas úteis? Estatísticas sobre a distribuição dos valores em uma coluna são criados automaticamente em colunas indexadas pelo SQL Server. Eles também podem ser criados em colunas não indexadas ou manualmente, usando o SQL Query Analyzer ou a instrução CREATE STATISTICS, ou automaticamente, se o auto criar estatísticas opção de banco de dados é definida como true. Essas estatísticas podem ser usadas pelo processador de consultas para determinar a estratégia ideal para avaliar uma consulta. Manutenção de estatísticas adicionais em colunas não indexadas envolvidas em operações de junção pode melhorar o desempenho da consulta. Monitorar a consulta usando SQL Profiler ou o plano de execução gráfica no SQL Query Analyzer para determinar se a consulta tem estatísticas suficientes. São as estatísticas de consulta up-to-date? São as estatísticas atualizadas automaticamente? SQL Server cria e atualiza automaticamente estatísticas de consulta em colunas indexadas (contanto estatística consulta a atualização automática não está desativado). Além disso, as estatísticas podem ser atualizados em colunas não indexadas ou manualmente, usando o SQL Query Analyzer ou a instrução UPDATE STATISTICS, ou automaticamente, se a opção de atualização automática do banco de dados estatísticas é definida como true. Up-to-date estatísticas não são dependentes de dados de data ou hora. Se não houver operações UPDATE ter tido lugar, as estatísticas de consulta ainda estão up-to-date. Dicas de escrita de Query O uma query retorna os dados em menor tempo se forem descritos os nomes das colunas ao invés de '*'. Exemplo: Escreva a query assim: SELECT id, first_name, last_name, age, subject FROM student_details; Ao invés de : SELECT * FROM student_details; Cláusula HAVING é utilizada para filtrar as linhas depois de todas as linhas serem selecionadas. Nâo utilize o HAVING clause para outros propósitos. Exemplo: Escreva a query assim: SELECT subject, count(subject) FROM student_details WHERE subject != 'Science' AND subject != 'Maths' GROUP BY subject; Ao invés de: SELECT subject, count(subject) FROM student_details GROUP BY subject HAVING subject!= 'Vancouver' AND subject!= 'Toronto'; * Especifica um critério de pesquisa para um grupo ou uma agregação. HAVING pode ser usado somente com a instrução SELECT. HAVING é usado normalmente em uma cláusula GROUP BY. Quando GROUP BY não é usado, HAVING se comporta como uma cláusula WHERE. Quando tiver mais de uma subquery na sua consulta, tente minimizar a quantidade de subquery. Exemplo: Escreva a quey assim: SELECT name FROM employee WHERE (salary, age ) = (SELECT MAX (salary), MAX (age) FROM employee_details) AND dept = 'Electronics'; Ao invés de: SELECT name FROM employee WHERE salary = (SELECT MAX(salary) FROM employee_details) AND age = (SELECT MAX(age) FROM employee_details) AND emp_dept = 'Electronics'; Use o operador EXISTS, IN e joins adequadamente nas suas querys. a) Normalmente IN é a que demora mais tempo para concluir b) IN é eficiente quando a maioria dos critérios dos filtros são descritos na sub-query. c) EXISTS é eficiente quando a maioria dos critérios dos filtros estão na query raiz. Exemplo: Escreva uma query assim: Select * from product p where EXISTS (select * from order_items o where o.product_id = p.product_id) Ao invés de: Select * from product p where product_id IN (select product_id from order_items ) Use EXISTS ao invés de DISTINCT quando for usar joins que envolvam tabelas com mais de um para muitos relacionamentos. Exemplo: Escreva a query assim: SELECT d.dept_id, d.dept FROM dept d WHERE EXISTS ( SELECT 'X' FROM employee e WHERE e.dept = d.dept); Ao invés de: SELECT DISTINCT d.dept_id, d.dept FROM dept d,employee e WHERE e.dept = e.dept; Tente usar UNION ALL no lugar de UNION. Exemplo: Escreva a query assim: SELECT id, first_name FROM student_details_class10 UNION ALL SELECT id, first_name FROM sports_team; Ao invés de: SELECT id, first_name, subject FROM student_details_class10 UNION SELECT id, first_name FROM sports_team; Escreva query assim: SELECT id, first_name, age FROM student_details WHERE first_name LIKE 'Chan%'; Ao invés de: SELECT id, first_name, age FROM student_details WHERE SUBSTR(first_name,1,3) = 'Cha'; Escreva query assim: SELECT id, first_name, age FROM student_details WHERE first_name LIKE NVL ( :name, '%'); Ao invés de: SELECT id, first_name, age FROM student_details WHERE first_name = NVL ( :name, first_name); Escreva query assim: SELECT product_id, product_name FROM product WHERE unit_price BETWEEN MAX(unit_price) and MIN(unit_price) Ao invés de: SELECT product_id, product_name FROM product WHERE unit_price >= MAX(unit_price) and unit_price <= MIN(unit_price) Escreva query assim: SELECT id, name, salary FROM employee WHERE dept = 'Electronics' AND location = 'Bangalore'; Ao invés de: SELECT id, name, salary FROM employee WHERE dept || location= 'ElectronicsBangalore'; Use non-column expression on one side of the query because it will be processed earlier. Write the query as SELECT id, name, salary FROM employee WHERE salary < 25000; Instead of: SELECT id, name, salary FROM employee WHERE salary + 10000 < 35000; Write the query as SELECT id, first_name, age FROM student_details WHERE age > 10; Ao invés de: SELECT id, first_name, age FROM student_details WHERE age NOT = 10;