Limite prático para o tamanho da consulta SQL (especificamente MySQL)

É particularmente ruim ter uma consulta SQL muito grande com muitas cláusulas WHERE (potencialmente redundantes)?

Por exemplo, aqui está uma consulta que eu gerenciei do meu aplicativo da web com tudo desativado, que deve ser a maior consulta possível para este programa gerar:

SELECT * 
FROM 4e_magic_items 
INNER JOIN 4e_magic_item_levels 
  ON 4e_magic_items.id = 4e_magic_item_levels.itemid 
INNER JOIN 4e_monster_sources 
  ON 4e_magic_items.source = 4e_monster_sources.id 
WHERE (itemlevel BETWEEN 1 AND 30)  
  AND source!=16 AND source!=2 AND source!=5 
  AND source!=13 AND source!=15 AND source!=3 
  AND source!=4 AND source!=12 AND source!=7 
  AND source!=14 AND source!=11 AND source!=10 
  AND source!=8 AND source!=1 AND source!=6 
  AND source!=9  AND type!='Arms' AND type!='Feet' 
  AND type!='Hands' AND type!='Head' 
  AND type!='Neck' AND type!='Orb' 
  AND type!='Potion' AND type!='Ring' 
  AND type!='Rod' AND type!='Staff' 
  AND type!='Symbol' AND type!='Waist' 
  AND type!='Wand' AND type!='Wondrous Item' 
  AND type!='Alchemical Item' AND type!='Elixir' 
  AND type!='Reagent' AND type!='Whetstone' 
  AND type!='Other Consumable' AND type!='Companion' 
  AND type!='Mount' AND (type!='Armor' OR (false )) 
  AND (type!='Weapon' OR (false )) 
 ORDER BY type ASC, itemlevel ASC, name ASC

Parece funcionar bem o suficiente, mas também não é particularmente alto tráfego (algumas centenas de visitas por dia ou mais), e eu me pergunto se valeria a pena tentar otimizar as consultas para remover redundâncias e tal.

0
adicionado editado
Visualizações: 1
1. Obrigado por responder a pergunta, acho que o tamanho da consulta não deve ser um problema para mim agora. 2. Obrigado a todos pelas dicas sobre como formatar o SQL. Eu sou novo para ele e há um monte de truques que eu não conheço (por exemplo, "digite não em (...)") 3. Assim como um adendo, este é um aplicativo PHP/MySQL
adicionado o autor Asmor, fonte
Aqui está um formatador SQL útil: sqlinform.com
adicionado o autor micahwittman, fonte
Quando você e tenta usar o site, parece lento? Se houver apenas algumas centenas de acessos por dia, acho que você não poderia se preocupar com isso. Você espera que o tráfego aumente? Por quanto? Se você não é pressionado pelo tempo, você pode fazê-lo para tornar o site à prova do futuro. Mas, então, é o tempo necessário para encontrar e remover redundâncias de forma programada, maior do que o tempo que leva para executar a consulta?
adicionado o autor Matt Blaine, fonte

6 Respostas

Ler sua consulta me faz querer jogar um RPG.

Isso definitivamente não é muito longo. Desde que estejam bem formatados, eu diria que um limite prático é de cerca de 100 linhas. Depois disso, é melhor você quebrar as subconsultas em pontos de vista apenas para evitar que seus olhos se cruzem.

Já trabalhei com algumas consultas com mais de 1000 linhas e isso é difícil de depurar.

A propósito, posso sugerir uma versão reformatada? Isso é principalmente para demonstrar a importância da formatação; Eu confio que isso será mais fácil de entender.

select *  
from
  4e_magic_items mi
 ,4e_magic_item_levels mil
 ,4e_monster_sources ms
where mi.id = mil.itemid
  and mi.source = ms.id
  and itemlevel between 1 and 30
  and source not in(16,2,5,13,15,3,4,12,7,14,11,10,8,1,6,9)  
  and type not in(
                  'Arms' ,'Feet' ,'Hands' ,'Head' ,'Neck' ,'Orb' ,
                  'Potion' ,'Ring' ,'Rod' ,'Staff' ,'Symbol' ,'Waist' ,
                  'Wand' ,'Wondrous Item' ,'Alchemical Item' ,'Elixir' ,
                  'Reagent' ,'Whetstone' ,'Other Consumable' ,'Companion' ,
                  'Mount'
                 )
  and ((type != 'Armor') or (false))
  and ((type != 'Weapon') or (false))
order by
  type asc
 ,itemlevel asc
 ,name asc

/*
Some thoughts:
==============
0 - Formatting really matters, in SQL even more than most languages.
1 - consider selecting only the columns you need, not "*"
2 - use of table aliases makes it short & clear ("MI", "MIL" in my example)
3 - joins in the WHERE clause will un-clutter your FROM clause
4 - use NOT IN for long lists
5 - logically, the last two lines can be added to the "type not in" section.
    I'm not sure why you have the "or false", but I'll assume some good reason
    and leave them here.
*/
0
adicionado
Para o segundo pensamento de David B ... Minha experiência é principalmente Oracle/SQL Server, e ambos não sofrem com a limitação levantada por Aeon. Se o MySql realmente se comportar dessa maneira, você definitivamente desejará manter as junções no FROM. Eu sugiro tentar as duas maneiras e comparar os tempos de execução.
adicionado o autor JosephStyons, fonte
Isso porque armaduras (e armas) são filtradas por tipo. Por exemplo, se Pano e Ocultar estiverem selecionados, isso seria: (tipo! = 'Armadura' OU (FALSO OU restrições como 'C' OU restrições como 'H')) A página apenas adiciona "ou Restrições como 'qualquer' "dentro dos parênteses, é necessário um falso.
adicionado o autor Asmor, fonte
Juntas na cláusula FROM irão organizar sua cláusula WHERE. @Aeon - não deve haver diferença de desempenho com um otimizador de consulta adequado. O MySQL é tão ruim assim?
adicionado o autor Amy B, fonte
Na verdade, as junções irão acelerar as coisas, especialmente com índices adequados. A razão é que, se todas as suas cláusulas estiverem em WHERE, o MySQL buscará todos os dados e depois os filtrará; enquanto que com uma junção adequada, ele selecionará apenas os dados necessários, que podem ser algumas ordens de magnitude menores - mais rápido para filtrar.
adicionado o autor Aeon, fonte
Ah, e ... A menos que eu esteja sentindo falta de algo, (type! = 'Armor' OR (false)) vai ser avaliado como true ou false, mas em ambos os casos ele não afetará o resultado, então não é mesmo necessário.
adicionado o autor Aeon, fonte
downvote para desordenar a cláusula WHERE com condições de JOIN.
adicionado o autor longneck, fonte

Eu estou supondo que você quer dizer por 'desligado' que um campo não tem um valor?

Em vez de verificar se algo não é isso, e também não é isso, etc., você não pode simplesmente verificar se o campo é nulo? Ou defina o campo como 'off' e verifique se type ou o que for igual a 'off'.

0
adicionado

A maioria dos bancos de dados suporta procedimentos armazenados para evitar esse problema. Se o seu código é rápido o suficiente para ser executado e fácil de ler, você não precisa alterá-lo para reduzir o tempo de compilação.

Uma alternativa é usar instruções preparadas para que você receba o hit apenas uma vez por conexão do cliente e, em seguida, passe apenas os parâmetros para cada chamada

0
adicionado

A limitação do servidor padrão do MySQL 5.0 é " 1MB ", configurável em até 1GB.

Isso é configurado por meio da configuração max_allowed_packet em ambos cliente e servidor, e a limitação efetiva é o locador dos dois.

Ressalvas:

  • É provável que essa limitação de "pacote" não seja mapeada diretamente para caracteres em uma instrução SQL. Certamente você quer levar em consideração a codificação de caracteres dentro do cliente, alguns metadados de pacotes, etc.)
0
adicionado

De uma perspectiva prática, eu geralmente considero qualquer SELECT que termine tomando mais de 10 linhas para escrever (colocando cada cláusula/condição em uma linha separada) para ser muito longo para manter facilmente. Neste ponto, provavelmente deve ser feito como um procedimento armazenado de algum tipo, ou eu deveria tentar encontrar uma maneira melhor de expressar o mesmo conceito - possivelmente criando uma tabela intermediária para capturar algum relacionamento que pareço estar consultando freqüentemente.

Sua milhagem pode variar, e há algumas consultas excepcionalmente longas que têm um bom motivo para estar. Mas minha regra é de 10 linhas.

Example (mildly improper SQL):

SELECT x, y, z
FROM a, b
WHERE fiz = 1
AND foo = 2
AND a.x = b.y
AND b.z IN (SELECT q, r, s, t
            FROM c, d, e
            WHERE c.q = d.r
              AND d.s = e.t
              AND c.gar IS NOT NULL)
ORDER BY b.gonk

Isso é provavelmente muito grande; otimizar, no entanto, dependeria muito do contexto.

Apenas lembre-se: quanto mais longa e complexa a consulta, mais difícil será mantê-la.

0
adicionado

SELECT @@ global.max_allowed_packet

este é o único limite real que é ajustável em um servidor para que não haja uma resposta direta real

0
adicionado