Só estou curioso para saber por que uma consulta agregada é executada muito mais rápido com uma GROUP BY
cláusula do que sem uma.
Por exemplo, esta consulta leva quase 10 segundos para ser executada
SELECT MIN(CreatedDate)
FROM MyTable
WHERE SomeIndexedValue = 1
Enquanto este leva menos de um segundo
SELECT MIN(CreatedDate)
FROM MyTable
WHERE SomeIndexedValue = 1
GROUP BY CreatedDate
Há apenas um CreatedDate
neste caso, portanto, a consulta agrupada retorna os mesmos resultados que a consulta não agrupada.
Percebi que os planos de execução para as duas consultas são diferentes - a segunda consulta usa paralelismo, enquanto a primeira consulta não.
É normal que o SQL Server avalie uma consulta agregada de maneira diferente se não tiver uma cláusula GROUP BY? E há algo que eu possa fazer para melhorar o desempenho da 1ª consulta sem usar umGROUP BY
cláusula?
Editar
Acabei de aprender que posso usar OPTION(querytraceon 8649)
para definir o custo adicional do paralelismo como 0, o que faz com que a consulta use algum paralelismo e reduz o tempo de execução para 2 segundos, embora eu não saiba se há alguma desvantagem em usar essa dica de consulta.
SELECT MIN(CreatedDate)
FROM MyTable
WHERE SomeIndexedValue = 1
OPTION(querytraceon 8649)
Eu ainda preferiria um tempo de execução mais curto, pois a consulta deve preencher um valor na seleção do usuário, portanto, idealmente, deve ser instantânea como a consulta agrupada. No momento, estou apenas encapsulando minha consulta, mas sei que essa não é realmente uma solução ideal.
SELECT Min(CreatedDate)
FROM
(
SELECT Min(CreatedDate) as CreatedDate
FROM MyTable WITH (NOLOCK)
WHERE SomeIndexedValue = 1
GROUP BY CreatedDate
) as T
Editar # 2
Em resposta ao pedido de Martin para obter mais informações :
Ambos CreatedDate
e SomeIndexedValue
têm um índice não exclusivo e não agrupado em separado.SomeIndexedValue
é na verdade um campo varchar (7), mesmo que armazene um valor numérico que aponte para o PK (int) de outra tabela. O relacionamento entre as duas tabelas não está definido no banco de dados. Não devo alterar o banco de dados e só posso escrever consultas que consultam dados.
MyTable
contém mais de 3 milhões de registros e a cada registro é atribuído um grupo ao qual ele pertence ( SomeIndexedValue
). Os grupos podem ter de 1 a 200.000 registros
MAXDOP
define o grau máximo de paralelismo, que limita o número de processadores que a consulta pode usar. Isso basicamente faria com que a 2ª consulta fosse tão lenta quanto a 1ª, pois está removendo seus recursos para usar o paralelismo, o que não é o que eu quero.Na minha opinião, o motivo do problema é que o otimizador de servidor sql não está procurando o plano BEST, mas sim um bom plano, como é evidente pelo fato de que, após forçar o paralelismo, a consulta foi executada muito mais rapidamente, algo que o otimizador tinha não feito por si próprio.
Também vi muitas situações em que reescrever a consulta em um formato diferente era a diferença entre paralelizar (por exemplo, embora a maioria dos artigos sobre SQL recomende a parametrização, eu achei que algumas vezes causava paralelismo, mesmo quando os parâmetros farejavam eram os mesmos que não - um paralelizado ou combinando duas consultas com UNION ALL às vezes pode eliminar a paralelização).
Como tal, a solução correta pode estar tentando maneiras diferentes de escrever a consulta, como tentar tabelas temporárias, variáveis de tabela, cte, tabelas derivadas, parametrizar etc. e também brincar com os índices, visualizações indexadas ou índices filtrados em para obter o melhor plano.
fonte