Meu problema (ou pelo menos a mensagem de erro) é muito semelhante ao processador de consultas que ficou sem recursos internos - consulta sql extremamente longa .
Meu cliente está trabalhando com uma consulta de seleção SQL, contendo uma cláusula where com exatamente 100.000 entradas.
A consulta está falhando com o erro 8632 e a mensagem de erro
Erro interno: um limite de serviços de expressão foi atingido. Procure expressões potencialmente complexas em sua consulta e tente simplificá-las.)
Acho muito peculiar que essa mensagem de erro seja lançada, exatamente com 100.000 entradas, então, me pergunto se esse é um valor configurável. É esse o caso e, no caso afirmativo, como posso aumentar esse valor para um valor mais alto?
No MSDN , existe a proposta de reescrever a consulta, mas eu gostaria de evitar isso.
Enquanto isso, descobri que a lista de entradas de que estou falando contém números naturais, alguns deles parecem ser seqüenciais (algo como (1,2,3,6,7,8,9,10,12, 13,15,16,17,18,19,20).
Isso torna a cláusula where do SQL algo como:
where entry in (1,2,3,6,7,8,9,10,12,13,15,16,17,18,19,20)
Eu poderia transformar isso em:
where (entry between 1 and 3) OR
(entry between 6 and 10) OR
(entry between 12 and 13) OR
(entry between 15 and 20)
Isso pode ser reduzido por:
where entry in (1,...,3,6,...,10,12,13,15,...,20)
... ou algo parecido? (Eu sei que é um tiro no escuro, mas isso tornaria as atualizações de software mais fáceis e legíveis)
Para sua informação: os dados na cláusula where são o resultado de um cálculo, feito em outra tabela: primeiro, as entradas dessa tabela são lidas e filtradas no início e, em seguida, algum processamento extra é feito (o que é impossível fazer usando SQL), o resultado desse processamento extra é mais filtrado e o resultado disso é usado na cláusula where. Como era impossível gravar a filtragem completa no SQL, o método mencionado foi usado. Obviamente, o conteúdo da cláusula where pode mudar a cada processamento, daí a necessidade de uma solução dinâmica.
fonte
WHERE IN
não suporta esse tipo de sintaxe de intervalo. Além disso, não deve serWHERE () OR () OR ()
AND. Mas, para usar a sugestão de Brent, na verdade você não precisa alterar a consulta inteira, basta fazê-loWHERE IN (SELECT myID FROM #biglist)
. E#biglist
pode ser uma tabela real (permanente) ou uma tabela temporária criada em tempo real.Respostas:
Para pesquisar mais de 100.000 valores, coloque-os em uma tabela temporária, uma linha por valor que você está procurando. Em seguida, ingresse sua consulta nessa tabela temporária para filtragem.
Algo com mais de 100.000 valores não é um parâmetro - é uma tabela. Em vez de pensar em aumentar o limite, considere a regra dos dez por cento de Swart : se você estiver chegando a 10% de um limite do SQL Server, provavelmente terá problemas.
fonte
Se você quiser alterar o aplicativo de qualquer maneira, considere
(a) usando um TVP para todo o conjunto de valores - você criaria um
DataTable
em C # e o passaria para um procedimento armazenado usandoStructuredType
, como demonstro aqui . (Espero que 100.000 entradas não sejam normais, pois a escalabilidade pode ser um problema, independentemente da abordagem usada).ou
(b) usando um TVP para passar nos limites superior e inferior dos intervalos e escrevendo uma junção ligeiramente diferente (obrigado @ypercube).
fonte
Não, não é configurável e você não pode aumentá-lo para um valor mais alto.
Existem soluções alternativas sugeridas no artigo do MSDN que você mencionou e em outros artigos. Mencionei dois aqui, mas você pode procurar mais.
fonte
Apenas meus 2 ¢ em relação a reduzir a condição da consulta: -
Se você puder determinar todos os valores possíveis
entry
antecipadamente, seria possível se você aceitasse o complemento de sua consulta?Antes
Depois de
fonte
É difícil descobrir o que você está tentando realizar sem conseguir ver a consulta, mas aqui vamos nós, supondo que sua consulta precise apenas de duas tabelas, uma com os dados e outra com os valores que você deseja evitar:
where entry in (<list of 100.000 values>)
é escandalosamente terrível, tanto do ponto de vista da eficiência quanto da manutenção.where entry in (select whatever from table)
é tão atrozmente horrível quanto o anterior. No entanto, dependendo da idiossincrasia das tabelas e do mecanismo SQL, ele pode funcionar bem, apesar do câncer de córnea. (Pode estar OK no Oracle, nunca estará no MySQL, não se lembra do MSSQL).Na minha opinião (sem conhecer a consulta), você deve reescrever a consulta da seguinte maneira:
Se esses 100.000 valores forem sempre os mesmos, sem depender do restante da consulta, você deverá fazer upload desses valores em uma tabela (table_fixed_values) e usar
Se esses 100.000 valores não forem os mesmos, deve haver algum tipo de lógica para selecionar esses 100.000, lógica que você deve incorporar na
ON
consulta anterior.fonte
LEFT JOIN table_fixed_values ON A.entry=B.entry WHERE B.entry IS NOT NULL
e não o equivalente, mais simples e mais fácil de lerINNER JOIN table_fixed_values ON A.entry=B.entry
?