É uma seleção simples de uma tabela temporária, que permanece unida a uma tabela existente em sua chave primária, com duas sub-seleções usando o primeiro 1 referente à tabela unida.
Em código:
SELECT
TempTable.Col1,
TempTable.Col2,
TempTable.Col3,
JoinedTable.Col1,
JoinedTable.Col2,
(
SELECT TOP 1
ThirdTable.Col1 -- Which is ThirdTable's Primary Key
FROM
ThirdTable
WHERE
ThirdTable.SomeColumn = JoinedTable.SomeColumn
) as ThirdTableColumn1,
(
SELECT TOP 1
ThirdTable.Col1 -- Which is also ThirdTable's Primary Key
FROM
ThirdTable
WHERE
ThirdTable.SomeOtherColumn = JoinedTable.SomeColumn
) as ThirdTableColumn2,
FROM
#TempTable as TempTable
LEFT JOIN
JoinedTable
ON (TempTable.PKColumn1 = JoinedTable.PKColumn1 AND
TempTable.PKColumn2 = JoinedTable.PKColumn2)
WHERE
JoinedTable.WhereColumn IN (1, 3)
Esta é uma réplica exata da minha consulta.
Se eu remover as duas sub-seleções, ele funcionará bem e rapidamente. Com as duas sub-seleções, recebo cerca de 100 registros por segundo, o que é extremamente lento para esta consulta porque ela deve retornar quase um milhão de registros.
Eu verifiquei se todas as tabelas possuem uma chave primária, todas elas possuem. Todos eles têm índices E estatísticas para suas colunas importantes, como aquelas nessas cláusulas WHERE e as da cláusula JOIN. A única tabela sem chave primária definida nem índice é a tabela temporária, mas também não é o problema porque não é a que está relacionada às sub-seleções lentas e, como mencionei, sem sub-seleções, ela funciona muito bem.
Sem eles TOP 1
, retorna mais de um resultado e gera um erro.
Ajuda alguém?
EDIT :
Então, o plano de execução me disse que estava faltando um índice. Eu criei e recriei alguns dos outros índices. Depois de um tempo, o plano de execução os estava usando e a consulta agora é rápida. O único problema é que não estou conseguindo fazer isso novamente em outro servidor, para a mesma consulta. Portanto, minha solução será sugerir qual índice o SQL Server usará.
Respostas:
Eu acho que em uma consulta de um milhão de registros, você precisa evitar coisas assim
OUTER JOINS
. Eu sugiro que você use emUNION ALL
vez deLEFT JOIN
. Contanto que eu acheCROSS APPLY
mais eficiente que a subconsulta na cláusula select, modificarei a consulta escrita por Conard Frix, que acho correta.agora: quando comecei a modificar sua consulta notei que você tem uma cláusula WHERE dizendo:
JoinedTable.WhereColumn IN (1, 3)
. nesse caso, se o campo for nulo, a condição se tornará falsa. então por que você está usando LEFT JOIN enquanto filtra linhas com valor nulo? basta substituirLEFT JOIN
ComINNER JOIN
, eu garanto que ele vai se tornar mais rápido.sobre INDEX:
observe que, quando você tiver um índice em uma tabela, diga
e seu índice é:
e você quer fazer algo assim:
no seu índice, você não incluiu a coluna. O
b
que acontece?se o sql-server usar seu índice, ele terá que pesquisar no índice, chamado "Busca de Índice" e, em seguida, consultar a tabela principal para obter a coluna
b
, chamada "Pesquisar" . Este procedimento pode levar muito mais tempo do que digitalizar a tabela em si: "Digitalização de tabela" .mas com base nas estatísticas que o sql-server possui, nessas situações, ele pode não usar seu índice.
portanto, verifique primeiro
Execution Plan
se o índice é usado.se sim ou não, altere seu índice para incluir todas as colunas que você está selecionando. diga como:
nesse caso, a pesquisa não será necessária e sua consulta será executada muito mais rapidamente.
fonte
É o submarino na seleção da coluna que está causando o retorno lento. Você deve tentar usar suas sub-seleções nas junções esquerdas ou usar uma tabela derivada conforme definido abaixo.
Usando associações à esquerda em duas instâncias da terceira tabela
Usando uma tabela derivada
fonte
Tente aplicar uma cruz
Você também pode usar CTEs e row_number ou uma consulta embutida usando MIN
fonte
Mova os bits JOIN para fora da parte principal da cláusula e coloque-a como uma subseleção. Movê-lo para a seção WHERE e JOIN garante que você não precise SELECIONAR TOP 1 repetidamente, o que acredito ser o motivo da lentidão. Se você quiser verificar isso, examine o plano de execução.
fonte
As
ThirdTable
referências (sub-selecionadas no seu exemplo) precisam da mesma atenção do índice que qualquer outra parte de uma consulta.Independentemente de você usar sub-seleções:
LEFT JOINS (como proposto por John Hartsock):
CROSS APPLY (como proposto por Conrad Frix):
Você precisa se certificar
covering indexes
são definidos paraThirdTable.SomeColumn
eThirdTable.SomeOtherColumn
e os índices são únicos. Isso significa que você precisará qualificar ainda mais asThirdTable
referências para eliminar a seleção de várias linhas e melhorar o desempenho. A escolha desub selects
,LEFT JOIN
ouCROSS APPLY
não será realmente importante até que você melhore a seletividadeThirdTable.SomeColumn
eThirdTable.SomeOtherColumn
inclua mais colunas para garantir uma seletividade exclusiva. Até lá, espero que seu desempenho continue sofrendo.O
covering index
tópico é bem apresentado por Maziar Taheri; Embora não repita seu trabalho, enfatizo a necessidade de levar a sério o uso de índices de cobertura.Em suma: melhorar a selectividade para o
ThirdTable.SomeColumn
eThirdTable.SomeOtherColumn
consultas (ou une) adicionando relacionado colunas na tabela para garantir uma correspondência de linha única. Se isso não for possível, você continuará sofrendo problemas de desempenho, pois o mecanismo está ocupado puxando as linhas que são jogadas fora. Isso afeta seu I / O, CPU e, finalmente, o plano de execução.fonte