Pergunta

Eu estou usando uma consulta SQL que é semelhante à seguinte forma:

SELECT col1, col2
FROM table1
LEFT OUTER JOIN table2
ON table1.person_uid = table2.person_uid
AND table1.period = table2.period

E é de qualquer forma muito lenta ou deadlocking de alguma coisa, porque é preciso pelo menos 4 minutos para retorno. Se eu fosse para alterá-lo para isto:

SELECT col1, col2
FROM table1
LEFT OUTER JOIN table2
ON table1.person_uid = table2.person_uid
WHERE table1.period = table2.period

, em seguida, ele funciona muito bem (embora não retornar o número correto de colunas). Existe alguma maneira de acelerar isso?

Atualizar : Ele faz a mesma coisa se eu mudar as duas últimas linhas da última consulta:

SELECT col1, col2
FROM table1
LEFT OUTER JOIN table2
ON table1.period = table2.period
WHERE table1.person_uid = table2.person_uid

UPDATE 2: Estes são realmente vê que eu estou juntando. Infelizmente, eles estão em um banco de dados que eu não tenho controle sobre, por isso não posso (facilmente) fazer qualquer alteração para a indexação. Estou inclinado a concordar que este é um problema indexação embora. Vou esperar um pouco antes de aceitar uma resposta no caso de haver alguma maneira mágica para sintonizar essa consulta que eu não sei sobre. Caso contrário, eu vou aceitar uma das respostas atuais e tentar descobrir outra maneira de fazer o que eu quero fazer. Obrigado pela ajuda de todos até agora.

Foi útil?

Solução

Tenha em mente que as declarações 2 e 3 são diferentes para o primeiro.

Como? Bem, você está fazendo uma junção externa esquerda e sua cláusula WHERE não está levando isso em conta (como a cláusula ON faz). No mínimo, tente:

SELECT col1, col2
FROM table1, table2
WHERE table1.person_uid = table2.person_uid (+)
AND table1.period = table2.period (+)

e veja se você tem o mesmo problema de desempenho.

O que índices que você tem sobre estas mesas? É esta relação definida por uma restrição de chave estrangeira?

O que você provavelmente necessidade é um índice composto em ambos person_uid e período (em ambas as tabelas).

Outras dicas

Eu acho que você precisa entender por que os dois últimos não são a mesma consulta como a primeira. Se você fizer uma associação à esquerda e depois adicionar uma cláusula onde referncing um campo na tabela no lado direito da junção (o que nem sempre pode ter um registro para coincidir com a primeira tabela), então você tem efetivamente mudou a juntar-se a uma junção interna. Há uma exceção a esta e que é se você faz referência a algo como

SELECT col1, col2
FROM table1
LEFT OUTER JOIN table2
ON table1.person_uid = table2.person_uid
WHERE table2.person_uid is null

Neste caso, você perguntar para o registro que não têm um registro na segunda tabela. Mas para além deste caso especial, você está mudando a esquerda se unem para uma junção interna se você refence um campo em table2 na cláusula where.

Se a consulta não é rápido o suficiente, gostaria de olhar para a sua indexação.

Qualquer coisa qualquer um lhe diz com base na informação fornecida é uma suposição.

Olhe para o plano de execução para a consulta. Se você não vê uma razão para a lentidão no plano, o cargo o plano aqui.

http://download.oracle .com / docs / cd / B28359_01 / server.111 / b28274 / ex_plan.htm # PFGRF009

Você tem cobrindo índices em person_uid e period para ambas as tabelas?

Se não, adicione-os e tente novamente.

Dê uma olhada no plano de execução e ver o que a consulta está realmente fazendo.

Além disso: Quais são os tipos de dados dos campos? eles são os mesmos em ambas as tabelas? Uma conversão implícita pode coisas realmente lento.

Será que estas tabelas têm índices nas colunas que você está juntando? Instalar produto SQLDeveloper livre da Oracle e usá-lo para fazer um "explicar" nessa consulta e ver se ele está fazendo varreduras seqüenciais de ambas as tabelas.

Em uma associação à esquerda você estaria digitalização table1 para cada combinação única de (person_uid, período), em seguida, à procura table2 para todos os registros correspondentes lá. Se table2 não tem um índice apropriado, isso pode envolver a digitalização de toda aquela mesa também.

Meu melhor palpite, sem ver um plano de execução, é que a primeira consulta (o único que parece ser correto) é ter de mesa table2 varredura, bem como table1.

Como você diz que você não pode mudar os índices, você precisa mudar a consulta. Tanto quanto eu posso dizer, só há uma alternativa realista ...

SELECT
   col1, col2
FROM
   table2
FULL OUTER JOIN
   table1
      ON table1.person_uid = table2.person_uid
      AND table1.period = table2.period
WHERE
   table1.person_uid IS NOT NULL

A esperança aqui é que você table2 varredura para cada combinação única de (person_uid, período), mas fazer uso de índices na tabela 1. (Ao contrário de digitalização table1 e fazendo uso de índices em table2, que o que eu esperava de sua consulta.)

Se table1 não tem índices apropriados, no entanto, você vai ser muito provável que vejamos uma melhoria de desempenho em todos os ...

Dems.

Em uma das atualizações dos estados OP que ele é realmente consultando opiniões não mesas. Neste caso, o desempenho poderia ser aumentada por meio de consulta diretamente as tabelas que ele precisa, especialmente se os pontos de vista são complexas e junte-se a muitas outras tabelas que não contêm informações que ele precisa ou são vistas que os pontos de vista de chamadas.

junção ANSI sintaxe fornece uma distinção muito clara entre condições de junção e predicados filtro; isso é muito importante quando se escreve junções externas. Usando o emp / mesas Dept, olhar para os resultados dos dois exterior a seguir une

Q1

SELECT dname, d.deptno, e.ename, e.mgr, d.loc
FROM dept d
LEFT OUTER JOIN emp e
on  d.deptno = e.deptno
and loc in ('NEW YORK','BOSTON' )
;

DNAME              DEPTNO ENAME             MGR LOC
-------------- ---------- ---------- ---------- -------------
ACCOUNTING             10 CLARK            7839 NEW YORK
ACCOUNTING             10 KING                  NEW YORK
ACCOUNTING             10 MILLER           7782 NEW YORK
RESEARCH               20                       DALLAS
SALES                  30                       CHICAGO
OPERATIONS             40                       BOSTON

====

Q2
SELECT dname, d.deptno, e.ename, e.mgr, d.loc
FROM dept d
LEFT OUTER JOIN emp e
on  d.deptno = e.deptno
where loc in ('NEW YORK','BOSTON' )
;

DNAME              DEPTNO ENAME             MGR LOC
-------------- ---------- ---------- ---------- -------------
ACCOUNTING             10 CLARK            7839 NEW YORK
ACCOUNTING             10 KING                  NEW YORK
ACCOUNTING             10 MILLER           7782 NEW YORK
OPERATIONS             40                       BOSTON

O primeiro exemplo, mostra Q1 é um exemplo de "ingressar em uma constante". Essencialmente, a condição do filtro é aplicada antes de se efectuar a junção externa. Então você eliminar linhas, que são posteriormente adicionados de volta como parte da junção externa. Não é necessariamente errado, mas é que a consulta que você realmente pediu? Muitas vezes é os resultados mostrados na Q2 que são exigidas, em que o filtro é aplicado após o (exterior) juntar-se.

Há também uma implicação desempenho também, para grandes conjuntos de dados. Em muitos casos, juntando-se em um constante tem de ser resolvida internamente pelo otimizador, criando uma vista lateral, que normalmente só pode ser otimizado através de um loop aninhado em vez de um hash

Para os desenvolvedores que estão familiarizados com o exterior do Oracle sintaxe JOIN, a consulta provavelmente teria sido escrito como

SELECT dname, d.deptno, e.ename, e.mgr, d.loc
FROM dept d
        ,emp e
where  d.deptno = e.deptno(+)
and loc in ('NEW YORK','BOSTON' )

Esta consulta é semanticamente equivalente Q2 acima.

Então, em resumo, é extremamente importante o que você entenda a diferença entre a cláusula JOIN e a cláusula WHERE ao escrever ANSI associações externas.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top