Pergunta

Estou recebendo algum comportamento estranho de uma instância Oracle que estou trabalhando. Esta é 11gR1 em Itanium, sem RAC, nada extravagante. Finalmente eu estou movendo dados de uma instância Oracle para outra em um cenário de armazenamento de dados.

Eu tenho uma visão semi-complexo rodando sobre um link DB; 4 associações internas tabelas sobre grandes-ish e 5 esquerda junta-se sobre as mesas de médio porte.

Aqui está o problema: quando eu testar a exibição em SQL Developer (ou SQL * Plus) parece bem, sem qualquer duplicação. No entanto, quando eu realmente usar a visão para inserir dados em uma tabela que eu obter um grande número de tolos.

EDIT: - Os dados está entrando em uma mesa vazia. Todas as tabelas na consulta estão no link banco de dados. A única coisa que passou para a consulta é uma data (por exemplo INSERT INTO alvo SELECT * DE vista onde view.datecol = dQueryDate) -

Eu tentei adicionar uma função ROW_NUMBER () para a instrução SELECT, dividida pela PK para a vista. Todas as linhas voltam numerada como 1. Mais uma vez, porém, a mesma declaração run como uma inserção gera os mesmos bobos como antes e agora convenientemente numerada. O número de linhas duped não é o mesmo por chave. existem alguns registros 4 tempos, alguns só existem uma vez.

Eu acho que isso comportamento a ser extremamente desconcertante. :) Isso me lembra de trabalhar com Teradata onde você tem tabelas SET (linhas exclusivas apenas) e mesas MULTISET (linhas duplicadas permitidas), mas a Oracle não tem essa funcionalidade.

A escolha que retorna linhas para o cliente deve se comportar de forma idêntica a uma que insere essas linhas para outro local. Eu não posso imaginar uma razão legítima para que isso aconteça, mas talvez eu estou sofrendo de uma falta de imaginação. ;)

Gostaria de saber se alguém já experimentou este ou se é um bug nesta plataforma.

Solução

Graças à @Gary, eu era capaz de chegar ao fundo deste usando "explain plan para {minha consulta};" e "SELECT * FROM TABLE (dbms_xplan.display);". O explicar que realmente se acostuma para o INSERT é muito diferente do SELECT.

Para o SELECT a maioria das operações do plano são 'QUADRO DE ACESSO POR ROWID INDEX' e 'UNIQUE INDEX SCAN'. O bloco 'Informações predicado' contém todas as associações e filtros da consulta. No final ele diz que "Nota - declaração totalmente remota" .

Para o INSERT não há nenhuma referência aos índices. bloco 'Informações predicado' está a apenas três linhas e uma nova 'SQL remoto' mostra bloco 9 instruções SQL pequenas.

O banco de dados dividir minha consulta em 9 subqueries e tenta se juntar a eles localmente. Ao executar as seleciona menores Eu localizei a origem das duplicatas.

Eu acredito que este é erro no compilador da Oracle em torno das ligações remotas. Ele cria falhas lógicas quando re-escrever o SQL. Basicamente, o compilador não está aplicando corretamente a cláusula WHERE. Eu estava apenas testando-o e deu-lhe uma lista IN de 5 chaves para trazer de volta. SELECIONAR traz de volta 5 linhas. puts ENVIE 77,000+ linhas em alvo e totalmente ignora a lista IN.

{Ainda à procura de uma maneira de forçar o comportamento correto, eu possa ter de pedir a vista a ser criado no banco de dados remoto apesar de que não é o ideal do ponto de vista do desenvolvimento. Vou editar isso quando eu tenho que trabalhar ...}

Foi útil?

Solução

Parece ser o Oracle Bug, nós encontramos este seguinte workarround: Se você quiser que seu trabalho "insert into select ..." como o seu "select ...", você pode embalar a sua escolha em uma sub selecionar.

Por exemplo:

select x,y,z from table1, table2, where ...

-> não duplicado

insert into example_table
select x,y,z from table1, table2, where ...

-> erro duplicado

insert into example_table
select * from (
       select x,y,z from table1, table2, where ...
)

-> não duplicado

Saudações

Outras dicas

Uma coisa que vem à mente é que geralmente um plano otimizador para um seleto vai preferir um FIRST_ROWS pretende dar linhas de volta para o chamador cedo, mas um INSERT ... SELECT vai preferir um plano ALL_ROWS como ele vai ter para entregar o conjunto de dados completo. Eu iria verificar os planos de consulta usando DBMS_XPLAN.DISPLAY_CURSOR (usando o sql_id de V $ SQL).

Eu tenho uma visão semi-complexo running através de uma ligação DB; 4 interior se une ao longo mesas grande ish e 5 esquerda junta-se ao longo mesas de médio porte. ... Todas as tabelas na consulta estão em o link de banco de dados

Mais uma vez, um potencial problema local. Se todas as tabelas SELECT estavam no outro extremo do link DB, toda a consulta seria enviado para o banco de dados remoto e o conjunto de resultados retornado. Uma vez que você jogar o INSERT, é mais provável que o banco de dados local vai assumir o comando da consulta e puxar todos os dados das crianças mesas mais. Mas isso pode depender se a exibição é definida no banco de dados local ou o banco de dados remoto. Neste último caso, na medida em que o otimizador local está em causa não é apenas um objeto remoto e obtém dados de que, e o banco de dados remoto irá fazer a junção.

O que acontece se você acabou de ir para o DB remoto e fazer a inserção em uma mesa lá?

Este é um erro no manuseio da Oracle junta através de ligações DB. Eu tenho uma situação mais simples que não envolve um INSERT contra SELECT. Se eu executar minha consulta remotamente, fico com linhas duplicadas, mas se eu executá-lo localmente, eu não sei. A única diferença entre as consultas é o "@ ..." anexado às tabelas na consulta remota. Eu estou consultando um banco de dados 9i a partir de um banco de dados de 10,2 usando o Oracle SQL Developer 3.0.

Esta ainda mais estúpido do que o bug no Oracle que o impede de associação de tabelas com mais de 1000 colunas totais, que é muito fácil de fazer ao consultar o sistema ERP. E não, a mensagem de erro não é nada sobre tabelas com muitas colunas.

É quase tão estúpido como esse outro erro de banco de dados Oracle que proíbe mesas consultando contendo localizadores LOB usando a sintaxe ANSI. Só a Oracle obras de sintaxe!

Várias opções ocorrer para mim.

  1. Os tolos que você vê já estavam na tabela de destino ??

  2. Se em seu Select, você faz referência a tabela que você está inserindo, (?), Então a inserção é interagir com a escolha em sua combinado

    Inserir ... Select ... De ...

De tal forma (produtos cartesianos?) Como para criar as duplicatas

Eu não posso ajudar, mas acho que talvez você está tendo um efeito colateral de alguma outra coisa relacionada com a tabela. Há algum gatilhos que podem ser manipulação de dados?

Como você determinou que não há ingênuos na tabela original?

Como outros já registou esta parece ser a explicação mais simples para este comportamento estranho.

Verifique se o seu JOINs cuidado. Potencialmente você não tem duplicados nas tabelas individuais, mas underspecified junta pode causar CROSS JOINs Inadvertant para que seu conjunto de resultados tem duplicatas devido à multiplicidade e, quando inserido, isso viola uma restrição de exclusividade em sua tabela de destino.

O que fazer neste caso é para aninhar a consulta em uma visão ou CTE e tentar detectar as duplicatas em linha reta do SELECT:

WITH resultset AS (
    -- blah, blah
)
SELECT a, b, c, COUNT(*)
FROM resultset
GROUP BY a, b, c
HAVING COUNT(*) > 1

Eu sugeriria começar um plano sobre a consulta que você está correndo e procurando uma junção cartesiana lá. Isso pode indicar uma condição de falta que está causando linhas duplicados.

AS @Pop já sugeriu este comportamento pode acontecer se você estiver usando um login diferente em SQLPlus para o login quando a sua inserção está em execução. (Isto é, se o outro login tem uma tabela / view / sinônimo com o mesmo nome)

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