Por que eu devo ler este artigo:

A SQL é uma linguagem de consulta estruturada utilizada nos bancos relacionais. Ela permite a definição de bancos de dados, sua manipulação e também a restrição de acesso a seus recursos. Seu leque de opções é bastante amplo. Neste artigo focaremos em facilidades que ela disponibiliza para realização de consultas.

Assim, este artigo descreve em exemplos práticos a eficiência da linguagem de consultas SQL, demonstrando formas diferentes de recuperar a informação nos bancos de dados do mercado. Estes exemplos serão úteis àqueles que pretendem extrair do banco de dados, por meio de consultas e subconsultas, os dados, aplicando diferentes técnicas para obter a informação desejada.

A linguagem SQL surgiu junto com os modelos de bancos de dados relacionais, e sua principal característica foi inspirada nas teorias matemáticas, mais precisamente na álgebra relacional.

Também conhecida como Structured Query Language, é uma linguagem de consulta estruturada, que foi desenvolvida nos laboratórios da IBM na década de 70. Esta linguagem tem como objetivo fazer consultas em tabelas de um banco de dados, e atualmente é usada em todos os bancos de dados relacionais do mercado.

Atualmente a linguagem SQL é usada em muitas aplicações espalhadas pelo mundo e sua função principal é buscar a informação armazenada nas tabelas dos databases, retornando assim em forma de texto o resultado dos dados que estão organizados nestas tabelas. As aplicações usam comandos SQL internamente para manipulação de dados em gráficos, relatórios, telas e principalmente em consultas.

Sendo assim, basicamente todo sistema de computação que armazena seus dados em um banco de dados relacional, possui consultas que usam algum comando SQL para buscar a informação. Atualmente, com o surgimento de outros tipos de armazenamento, como é o caso dos Big Data (veja o BOX 1), a linguagem SQL ganhou ainda mais poder, afinal a tecnologia Hadoop (veja o BOX 2) possui os componentes que interpretam comandos SQL para fazer pesquisas no mundo Big Data. Exemplos destes componentes são Hive e Pig.

BOX 1: Big Data

Big Data refere-se a uma tecnologia de armazenamento de dados em grande escala que tem como principais características o arquivamento de dados estruturais e dados pessoais/contextuais de uma forma não relacional.

BOX 2: Hadoop

Hadoop é uma plataforma desenvolvida na linguagem Java, que tem características o processamento de grande volume de dados. É um projeto originário da empresa Apache que tem como grande parceiro a empresa Yahoo em sua difusão. O Hadoop é considerado um tipo de tecnologia Big data que se caracteriza pela sua persistência e o seu processamento distribuído.

Em grandes organizações que possuem sistemas transacionais e sistemas de data warehouses, nos requisitos de conhecimentos dos analistas e desenvolvedores, ter em seus aprendizados a linguagem SQL é, sem dúvida, de suma importância no dia a dia. Afinal, desenvolver e manter aplicações em projetos que usam esta tecnologia, tem sido o grande desafio das empresas na área de tecnologia nos últimos anos.

A manipulação de dados que estão armazenados em databases pode ser infinita, e as formas de extrair estas informações precisa estar alinhada a uma boa performance. Afinal, em um sistema transacional, por exemplo, que usa seus processos para vendas em varejo, se analisarmos a demanda que ocorre no dia a dia, o fluxo pode ser muito grande. Uma consulta SQL que não está performática, pode tornar o tempo de resposta muito lento.

Em uma outra situação, por exemplo, um sistema Web, que é acessado por centenas de pessoas, se cada uma delas faz uma busca ou consulta neste site, esse número pode ser grande, e sendo assim este resultado pode ficar comprometido.

Em todos os projetos de software, logicamente que os DBAs e os analistas de infraestrutura estão atentos e disponibilizam recursos que podem ajudar e muito no tempo destas consultas, mas acima de tudo o desenvolvedor não pode deixar de se atentar para que estas consultas sejam bem escritas.

Quando o assunto é desempenho, as análises devem ser contínuas, e o fato da linguagem SQL possibilitar fazer a mesma consulta de várias formas, nem sempre a forma ideal é a forma que acaba sendo realizada no ambiente de produção.

Em aspectos de aperfeiçoamento, a linguagem SQL não é diferente das outras linguagens. A prática é muito importante no caminho da perfeição, e apesar do fato de ser uma linguagem interpretada pelo sistema de banco de dados, ela é bastante simples e de fácil compreensão.

Em muitos casos em nosso ambiente do dia-dia, é comum depararmos com alguma situação em que o uso da linguagem SQL causa algum tipo de dúvida em relação às formas de construir uma consulta. E em muitas vezes, quando analisamos com mais calma, chegamos à conclusão que era algo bem mais simples ou até mesmo podia ser construído de outra forma.

Visando demonstrar diferentes variações de uso da linguagem SQL, focaremos neste artigo apenas nos comandos de consulta, onde instruções SELECT são usadas. Assim, demonstraremos consultas complexas, e subconsultas, com as muitas formas de trazer os dados armazenados nas tabelas dos bancos de dados.

Os comandos usados neste artigo serão completamente independentes do banco de dados, e poderão ser usados para qualquer ferramenta de armazenamento relacional que usa a linguagem de consultas SQL.

Padrão ANSI

Com o aparecimento das diversas ferramentas de banco de dados no mercado, o uso da linguagem SQL passou a sofrer alterações. Isso porque cada fabricante criava particularidades na linguagem para atender ao seu mercado.

Com isso, a linguagem ficou diferente para cada analista que usasse Oracle, SQL Server, Postgre, MYSQL ou DB2. Este cenário estimulou a criação de um padrão em 1986, pela “American National Standards Institute”, também conhecida como ANSI.

Este padrão de linguagem SQL fazia valer um formato de definição desta linguagem que todo banco de dados relacional precisava atender. Embora cada empresa criasse a sua própria particularidade na linguagem, o padrão ANSI tinha que funcionar em todas que quisessem ser aceitas no mundo dos bancos de dados relacionais.

Este padrão ANSI foi revisto em 1992, 1999 e em 2003. Atualmente as duas ferramentas de mercado do mundo relacional mais usadas, T-SQL do SQL Server e o PL-SQL da Oracle, tem sim suas particularidades, mas eles também atendem ao padrão ANSI. Sendo assim, qualquer consulta que for construída no padrão SQL ANSI, pode ser executada no SQL Server e no Oracle, que vão funcionar perfeitamente.

Os outros fabricantes de bancos de dados (PostgreSQL, MYSQL, DB2) também aderiram ao padrão SQL ANSI.

Ambiente

Utilizaremos um banco de dados no ambiente SQL Server para demonstrar as consultas feitas para este artigo. O database em questão é o “AdventureWorks”, que é disponibilizado pela Microsoft para ambiente de teste. Na Figura 1 temos um modelo de dados criado no Enterprise Architect, e assim podemos conhecer melhor como as consultas serão construídas.

Modelo de dados do database AdventureWorks
Figura 1. Modelo de dados do database AdventureWorks

Extraindo dados

Para melhor abordarmos a linguagem SQL como um todo, demonstraremos e analisaremos cada comando apresentado neste artigo, de forma que à medida que forem apresentados, comentaremos e demonstraremos cada variação, citando como os exemplos podem ser usados no dia-dia.

Será feita uma abordagem prévia de cada instrução com um exemplo simples e logo em seguida mostraremos exemplos avançados. Vale lembrar que cada instrução usada nestes exemplos deve ser cuidadosamente estudada e revista, para uma melhor compreensão da linguagem.

A linguagem SQL é interpretada pelo banco de dados e funciona através da execução de scripts em linhas de comando, que a partir de um “SELECT” são apontadas para uma ou mais tabelas, e trazem o resultado dos dados selecionados naquele momento específico no banco de dados. Na Figura 2 demonstramos a divisão de comandos que podem ser implementados na linguagem SQL.

Hierarquia dos comandos
Figura 2. Hierarquia dos comandos

Nesta hierarquia o “Select” é início de todo comando SQL, dele partem todas as cláusulas que devem ser interpretadas pelo banco de dados. As cláusulas “hint” servem como dicas para os scripts, instruindo o processador para uma melhor execução como, por exemplo, controle de bloqueios.

Os comandos All, Distinct e Unique, são para instruir ao processador que traga todos os dados ou apenas dados únicos. Ainda na primeira linha da hierarquia temos “select_list” onde são designados os campos das tabelas que devem aparecer na consulta.

Posteriormente temos a cláusula From” que indica de onde os dados devem ser retornados: de uma tabela “table_reference”, ou um join de outra tabela. Esta cláusula “join” pode ter diferentes variações, como inner, left, right, cross, dentre outras.

Temos adiante a cláusula where serve como filtros. Esta cláusula é muito importante para uma boa performance na query, afinal ela pode demonstrar que serão trazidos apenas registros de um mês ou de uma região, ao invés de toda a tabela “hierarchial_query_clause”. Teremos ainda nesta hierarquia a cláusula de agrupamento group_by_clause” e as condições (condition) do agrupamento having.

Operadores lógicos e matemáticos

A linguagem de consulta SQL tem uma grande quantidade de operados lógicos e matemáticos, estes operadores podem ser associados a datas e valores numéricos. Quando uma informação precisa atender a critérios e filtros com datas, operadores são muito úteis e usar estes operadores faz com que o analista possa limitar as suas consultas, trazendo um número muito menor de linhas em uma tabela.

Por exemplo, uma tabela de uma empresa que foi criada em 2000, tem dados desde a sua criação, os filtros de datas permitem que os dados sejam apresentados apenas no último ano, por exemplo, ou até mesmo em um limite de datas especificadas na consulta.

Demonstramos na Listagem 1 como realizar uma consulta contendo datas e cálculo de valores numéricos. Podemos observar que as colunas fazem cálculos, onde são usados operadores matemáticos de multiplicação, divisão e subtração. Foram usados abaixo nos filtros (where), datas, onde foram adicionados operadores lógicos (maior e diferente). Ainda nesta consulta podemos observar o uso da instrução Between, que filtra as datas entre os valores nela contidos.

Foi apresentado no exemplo o uso do Like que filtra todos os nomes que começam com a letra A, (A%), ou a letra C, (C%). Finalizando, ainda foi mostrado o filtro que seleciona apenas os valores não nulos (is not null) na coluna Size, e foi filtrada a exceção do nome “AWC Logo Cap”, como aparece na última linha da consulta.


  SELECT Name AS Nome, StandardCost AS Preco,
    (StandardCost * 10)/100 AS Desconto, 
    StandardCost - ((StandardCost * 10)/100) AS Restante, 
    SellEndDate AS Data
  FROM  SalesLT.Product
  WHERE (SellEndDate BETWEEN 
  '2002-06-01 00:00:00.000' AND '2002-06-10 00:00:00.000'
  AND   SellEndDate BETWEEN 
  '2002-06-20 00:00:00.000' AND '2002-06-25 00:00:00.000')
  AND   SellEndDate > '2002-06-28 00:00:00.000' 
  AND   SellEndDate <> '2002-06-07 00:00:00.000'
  OR    (Name LIKE 'A%' or Name Like 'C%')
  AND    Size IS NOT NULL
  AND   Name NOT IN ('AWC Logo Cap')
Listagem 1. Exemplo de cálculo com datas e valores numéricos

Essa consulta faz cálculos em campos numéricos e filtros com intervalos de datas, são usados ainda operados matemáticos e operadores lógicos.

Sumarizar e agrupar

Em um banco de dados relacional, a junção e o agrupamento de tabelas são comuns em uma extração de dados. Tabelas se completam com outras tabelas e geram a informação. Os dados por si só não demonstram o que diretores e usuários precisam entender do negócio, e geralmente precisam ser completados por outros dados armazenados em outro objeto (tabela), assim que funciona a lógica da integridade referencial.

Duas tabelas são ligadas por uma Foreign Key e se completam em informações, onde o registro de uma tabela A pode se relacionar com um ou com vários registros da outra tabela B. E no mundo relacional as cláusulas de inner join, left join, right join, dentre outras, são muito usadas no dia a dia.

Quando agrupamos uma tabela, ela geralmente atende a um requisito de alguma função matemática imposta a ela. Um bom exemplo de agrupamento seriam as vendas de uma empresa agrupadas por região, ou as vendas das regiões agrupadas por um ou por vários tipos de produtos. Ou ainda as vendas da empresa agrupadas por regiões que estão localizadas no lado sul do país.

Na Listagem 2 apresentamos uma query que tem um select na cláusula “having” do agrupamento. A cláusula group by especifica os grupos em resumo na saída da consulta SQL, este agrupamento pode ser feito por uma ou mais de uma consulta. Em alguns casos, uma cláusula having pode ser usada, e este comando funciona como um filtro nas classes agrupadas. O having se comporta da mesma forma que uma cláusula where, porém atendendo ao group by.

Quando a consulta usa uma função, o comando group by calculará aquele valor da função para cada grupo selecionado.


  SELECT P.Name, COUNT(P.ProductID) 
  FROM SalesLT.Product P
    INNER JOIN SalesLT.ProductModel M
      ON P.ProductModelID = M.ProductModelID
    RIGHT JOIN SalesLT.ProductModelProductDescription MD
      ON MD.ProductModelID = M.ProductModelID
    LEFT JOIN SalesLT.ProductDescription D
      ON D.ProductDescriptionID = MD.ProductDescriptionID
  WHERE D.ModifiedDate BETWEEN '2003-06-01 00:00:00.000' AND '2003-06-30 00:00:00.000'
  GROUP BY P.Name 
  HAVING P.Name IN(SELECT P.Name 
  FROM SalesLT.Product P
    INNER JOIN SalesLT.ProductModel M
      ON P.ProductModelID = M.ProductModelID
  WHERE P.ProductCategoryID = 6)
Listagem 2. Exemplo de select em uma cláusula having

Subqueries

Uma subconsulta se caracteriza por fazer uma consulta, em outra consulta, ou até mesmo juntar duas consultas em uma cláusula “Join”. A ideia de fazer uma subquery, assim também conhecida, é fazer uma seleção de dados dentro de uma seleção. Em outra operação de união de duas consultas, este recurso pode ser usado quando se precisa fazer uma união ou Join, da mesma forma que é feita em tabelas, porém em consultas.

As subqueries podem ser usadas sem limites, e uma subquery pode estar dentro de outra. Evidentemente que este recurso deve ser bem analisado, afinal para cada query escrita o banco de dados fará um novo processamento, e isso tem um custo para o resultado final da consulta. Na Listagem 3, temos uma query onde duas tabelas são selecionadas e associadas por uma cláusula “inner join”.

Na Listagem 4 temos uma query associada a várias subqueries, porém podemos observar que a query da Listagem 3 é usada na Listagem 4, como o último nível da consulta, onde ela faz o último select.


  SELECT C.FirstName AS NOME,CA.ModifiedDate AS ALTERACAO 
  FROM SalesLT.Customer C
    INNER JOIN SalesLT.CustomerAddress CA 
      ON C.CustomerID = CA.CustomerID 
Listagem 3. Exemplo de consulta simples com Inner join

  SELECT NOMES.QTDE_NOME, DATAS.QTDE_DATA
  FROM(
    SELECT NOME.QTDE AS QTDE_NOME
    FROM (
      SELECT COUNT(A.ALTERACAO) AS QTDE, 
        A.NOME AS NOME
      FROM(
        SELECT C.FirstName AS NOME,
          CA.ModifiedDate AS ALTERACAO 
        FROM SalesLT.Customer C
          INNER JOIN SalesLT.CustomerAddress CA 
            ON C.CustomerID = CA.CustomerID)AS A
      GROUP BY A.NOME
      HAVING COUNT(A.ALTERACAO) > 1) AS NOME) AS NOMES
  INNER JOIN(
    SELECT DATA.QTDE AS QTDE_DATA
    FROM (
      SELECT COUNT(A.NOME) AS QTDE, 
        A.ALTERACAO AS DATA
      FROM(
      SELECT C.FirstName AS NOME,
        CA.ModifiedDate AS ALTERACAO 
      FROM SalesLT.Customer C
        INNER JOIN SalesLT.CustomerAddress CA 
          ON C.CustomerID = CA.CustomerID
      )AS A
      GROUP BY A.ALTERACAO
      HAVING COUNT(A.NOME) > 1) AS DATA) AS DATAS
  ON NOMES.QTDE_NOME = DATAS.QTDE_DATA
Listagem 4. Exemplo com múltiplas consultas usando subqueries

A Listagem 4 faz a comparação de duas subconsultas unindo-as por um “inner join”. Este tipo de consulta pode ser usado em relatórios e geralmente subconsultas podem ser associadas a comparações de um conjunto de informações. Evidentemente que uma consulta deste tipo em alguns casos pode ter um custo bem elevado para o SGBD, cabe ao analista e ao DBA observar as melhores opções de extrair a informação da forma mais performática possível.

Filtros de Consultas

Pode-se dizer que a cláusula WHERE é o fator determinante em uma consulta, a ela pode-se definir o tempo de resposta do processamento do banco de dados. Um comando WHERE serve como um filtro, e através dele o número de linhas que a consulta retornará pode ser limitado.

Em muitos casos em que o analista não se preocupa com este detalhe, uma consulta traz todo o conteúdo da tabela em questão. Isso faz toda a diferença no tempo de resposta de uma query.

Em uma cláusula WHERE, podem ser usados vários comandos que ajudam ao analista fazer um filtro mais elaborado, dentre estes comandos temos os comandos in, like, between.

Na Listagem 5 temos uma query que fixa um valor igual em produtos baseado em uma outra query e que atende a um filtro que é um “select”. Posteriormente usa uma cláusula and para filtrar apenas produtos da categoria que começa com a letra “C”.


  SELECT DISTINCT C.Name AS CATEGORIA,
  (SELECT COUNT(P.ProductID) 
  FROM SalesLT.Product P
    INNER JOIN SalesLT.ProductModel M
      ON P.ProductModelID = M.ProductModelID
    RIGHT JOIN SalesLT.ProductModelProductDescription MD
      ON MD.ProductModelID = M.ProductModelID
    LEFT JOIN SalesLT.ProductDescription D
      ON D.ProductDescriptionID = MD.ProductDescriptionID
  WHERE D.ModifiedDate BETWEEN '2003-06-01 00:00:00.000' AND '2003-06-30 00:00:00.000')AS VALOR
  FROM SalesLT.Product P
    INNER JOIN SalesLT.ProductCategory C
      ON P.ProductCategoryID = C.ProductCategoryID
  WHERE (SELECT COUNT(P.ProductID) 
  FROM SalesLT.Product P
    INNER JOIN SalesLT.ProductModel M
      ON P.ProductModelID = M.ProductModelID) < 1000
  AND C.Name LIKE 'C%'
Listagem 5. Exemplo de consulta com select em uma cláusula where

Todos os SGBDs possuem uma coleção de funções. As funções podem e devem ser usadas quando forem necessárias, porém deve-se ter uma certa coerência, afinal uma função é um processo a parte que demanda muito processamento do banco de dados. Quando existe uma função que se repete ao longo do script, deve-se usar a função com uma variável. Afinal quando uma variável é usada, o banco de dados deixa de processar aquela operação mais de uma vez. Isso pode trazer um ganho razoável na performance do script como um todo.

Na Listagem 6 apresentamos uma consulta com um inner join simples, onde o filtro usa outra consulta que tem uma função SUM, função de soma na linguagem SQL.


  SELECT P.Name AS NOME, P.ListPrice AS PRECO, C.Name AS CATEGORIA
  FROM SalesLT.Product P
    INNER JOIN SalesLT.ProductCategory C
      ON P.ProductCategoryID = C.ProductCategoryID
  WHERE P.ListPrice < ALL (SELECT SUM(ListPrice) FROM SalesLT.Product)
Listagem 6. Exemplo de consulta simples usando Inner Join com um filtro em outro select

A cláusula between especifica um intervalo com dois valores, este comando é similar ao uso de operados < and >, ou seja, limita dois valores, em que o SGBD faz duas operações de um valor menor que, e outro valor maior que.

Independente da opção escolhida pelo analista, deve-se sempre verificar o plano de execução do banco de dados, e analisar qual foi a melhor forma de fazer a consulta.

Na Listagem 7 temos uma consulta com o select na cláusula “between”, limitando a consulta em dois valores.


  SELECT DISTINCT P.Name AS NOME, P.ListPrice AS PRECO, C.Name AS CATEGORIA
  FROM SalesLT.Product P
    INNER JOIN SalesLT.ProductCategory C
      ON P.ProductCategoryID = C.ProductCategoryID
  WHERE P.StandardCost BETWEEN '400' AND '800'
  AND P.ListPrice BETWEEN (SELECT AVG(ListPrice) FROM SalesLT.Product) AND '1000'
Listagem 7. Exemplo de consulta com select em uma cláusula between

União e Interseção

Uma cláusula union funciona diferente de uma junção de tabelas (join), o union faz uma união de duas ou mais consultas, trazendo o resultando em um conjunto. Esta união inclui todas as linhas pertencentes às consultas desejadas.

Em uma consulta que usa estes comandos, os campos e a ordem destes campos devem ser idênticos no script. Ainda em relação a união de consultas, podemos usar a cláusula intersect, que apresenta os valores distintos pelas consultas.

Este tipo de consulta é bastante usado em vários ambientes, e nele pode-se ter uma noção exata da teoria dos conjuntos que é aplicada no campo da matemática.

A Listagem 8 apresenta o uso da cláusula union e intersect, denominadas pela união de tabelas e valores distintos entre elas respectivamente.


  SELECT DISTINCT P.Name AS NOME, P.ListPrice AS PRECO, C.Name AS CATEGORIA
  FROM SalesLT.Product P
    INNER JOIN SalesLT.ProductCategory C
      ON P.ProductCategoryID = C.ProductCategoryID
  WHERE P.StandardCost > 1000
  INTERSECT
  SELECT DISTINCT P.Name AS NOME, P.ListPrice AS PRECO, C.Name AS CATEGORIA
  FROM SalesLT.Product P
    INNER JOIN SalesLT.ProductCategory C
      ON P.ProductCategoryID = C.ProductCategoryID
    INNER JOIN SalesLT.ProductCategory D
      ON D.ProductCategoryID = C.ParentProductCategoryID
  WHERE P.StandardCost > (SELECT AVG(P.ListPrice) FROM SalesLT.Product P)
  UNION
  SELECT DISTINCT P.Name AS NOME, P.ListPrice AS PRECO, C.Name AS CATEGORIA
  FROM SalesLT.Product P
    INNER JOIN SalesLT.ProductCategory C
      ON P.ProductCategoryID = C.ProductCategoryID
  WHERE P.ListPrice < 100
Listagem 8. Exemplo de consulta com a cláusula union e intersect

Pertence ou Não Pertence

Um exists tem um processamento diferente de uma consulta que usa uma cláusula in, por exemplo. Quando a consulta usa a cláusula in, o processador recupera todo o conjunto antes de fazer um join. Usando a cláusula exists, o processador faz o join linha a linha. Obviamente que usar um ou o outro vai depender principalmente do tamanho da tabela, e da quantidade de dados envolvida na consulta e na subconsulta.

É apresentada na Listagem 9 o uso da cláusula not exists, e na Listagem 10 a cláusula exists.


  SELECT DISTINCT P.Name AS NOME, SUM(P.ListPrice) AS PRECO, C.Name AS CATEGORIA
  FROM (((SalesLT.Product P
    FULL OUTER JOIN SalesLT.ProductCategory C
      ON P.ProductCategoryID = C.ProductCategoryID)
    LEFT JOIN SalesLT.SalesOrderDetail S
      ON S.ProductID = P.ProductID)
    INNER JOIN SalesLT.SalesOrderHeader H
      ON S.SalesOrderID = H.SalesOrderID)
  FULL OUTER JOIN SalesLT.Customer C2
      ON H.CustomerID = C2.CustomerID
  WHERE NOT EXISTS (SELECT ListPrice 
       FROM SalesLT.Product P2
       INNER JOIN SalesLT.ProductModel M ON P2.ProductModelID = M.ProductModelID
       WHERE P2.Name LIKE '%C' 
       AND P2.SellEndDate < '1998-06-01 00:00:00.000')
    GROUP BY C.Name, P.Name
Listagem 9. Exemplo de consulta com a cláusula not exists

  SELECT DISTINCT C.FirstName AS Nome, C.LastName AS Sobrenome 
  FROM SalesLT.Customer C
  LEFT JOIN (SELECT A.CustomerID 
    FROM SalesLT.CustomerAddress A 
      INNER JOIN SalesLT.Address D 
        ON A.AddressID = D.AddressID
    WHERE D.City IN ('Dallas', 'Phoenix')) AS CONSULTA ON C.CustomerID = CONSULTA.CustomerID
  WHERE EXISTS (SELECT DISTINCT C2.FirstName 
    FROM SalesLT.Customer C2
    INNER JOIN SalesLT.SalesOrderHeader H 
      ON H.CustomerID = C2.CustomerID
    RIGHT JOIN SalesLT.SalesOrderDetail O 
      ON H.SalesOrderID = O.SalesOrderID
    INNER JOIN SalesLT.Product P
      ON P.ProductID = O.ProductID
    WHERE P.ListPrice > 2000)
Listagem 10. Exemplo de consulta com a cláusula exists

Consultas diferentes e resultados iguais

Separamos este tópico para demonstrar alguns exemplos em que o resultado pode ser o mesmo, porém construído de forma diferente. A linguagem SQL nos proporciona fazer a mesma consulta de diferentes maneiras.

Mas fazer eficiente, cabe a cada analista no momento da construção da consulta. Para isso, ele deve efetuar uma análise detalhada do modelo de dados a fim de usar os melhores caminhos para chegar ao resultado final.

Na Listagem 11, apresentamos duas queries simples, e que trazem o mesmo resultado, usando as cláusulas distinct e group by, respectivamente.


  SELECT DISTINCT Name FROM SalesLT.Product
  WHERE Size <> '58' OR Color <> 'Blue'
   
  SELECT Name FROM SalesLT.Product
  WHERE Size <> '58' OR Color <> 'Blue'
  GROUP BY Name
Listagem 11. Exemplo de consulta com a cláusula distinct e group by

Na Listagem 12, apresentamos duas queries simples, e que trazem o mesmo resultado, usando as cláusulas “in” e uma subquery com a cláusula exists.


    SELECT Name FROM SalesLT.Product
    WHERE Color in ('Blue')
     
    SELECT Name FROM SalesLT.Product p
    WHERE exists (SELECT Name FROM SalesLT.Product p1 
    WHERE p.ProductID = p1.ProductID AND Color = 'Blue')
Listagem 12. Exemplo de consulta com a cláusula in e exists

Boas práticas no uso da linguagem SQL

Se tratando da linguagem de consultas SQL, existem dicas que se observadas, podem melhorar muito a performance das consultas. Listamos na sequências algumas destas dicas para a construção das queries:

  1. A normalização é uma boa prática, afinal os dados ficam distribuídos e organizados melhor em tabelas menores;
  2. Nas instruções Select, evite o uso de "*". Procure utilizar apenas os campos necessários;
  3. Para obter maior performance, utilize chaves primárias numéricas ou ainda campos pequenos nas chaves;
  4. Evite o uso de cursores, pois eles têm um custo elevado, já que navegam registro por registro;
  5. Stored procedures no banco de dados têm um melhor desempenho do que queries escritas diretas no código do programa, além de contribuir para uma melhor segurança;
  6. Sempre que puder use cláusulas where, afinal os filtros diminuem o tamanho da consulta;
  7. Evite o uso de funções, pois cada função tem um custo considerável no banco de dados;
  8. Procure usar índices com coerência. Em alguns casos o excesso de índices pode atrapalhar a consulta;
  9. Em instruções SQL idênticas use variáveis, dessa forma o SGBD compila a instrução apenas uma vez;
  10. É sempre bom analisar o plano de execução do SGBD em questão;
  11. Evite o uso da cláusula “like”. Este comando tem um custo considerável para o SGBD;
  12. Compare o custo das instruções que podem trazer resultados compatíveis, um bom exemplo seriam as cláusulas "exists" e "in";
  13. Use sempre referência nas colunas ao fazer um join;
  14. Evite a comparação de dados de tipos incompatíveis;
  15. Sempre na construção de uma consulta SQL procure conhecer o modelo de dados.

Este artigo apresentou conceitos e exemplos relativos à construção de consultas SQL. Foi apresentado o padrão ANSI de comandos SQL e foi demonstrado o modelo de dados usado nos exemplos do artigo.

Em seguida foram demonstradas formas de recuperar a informação com diferentes comandos, considerando exemplos de sumarização, agrupamento e subqueries. Nos exemplos foram demonstrados os operadores lógicos e matemáticos, além de comandos diversos.

Construir uma consulta SQL pode ser simples, porém o simples pode se tornar problemático quando é aliado a um consumo de vários usuários usando o mesmo banco de dados.

Portanto, é sempre bom ter em mente que uma consulta pode ser simples, mas deve-se fazer as perguntas, “Como ela será executada?”, ou “Quantas vezes ela será executada simultaneamente?”.

A performance é a alma das consultas, porém vale a pena ter as outras variáveis também em mente, como segurança e arquitetura. Na criação de um modelo de dados é bom saber mais ou menos como serão as consultas ou, pelo menos, saber quais as entidades serão mais consultadas, e tentar criar o modelo de dados baseado nisso.

O desempenho de um banco de dados depende de vários fatores, mas as consultas ocupam um lugar considerável. Sendo assim, avaliar e sempre reavaliar estas consultas é uma boa prática, afinal em relação à performance, é sempre bom saber que o que foi ajustado e hoje possui um bom desempenho, pode não funcionar da mesma forma no futuro.

Confira também