2012-10-22 9 views
6

Ho una domanda abbastanza standard SQL come segue:Perché Oracle sta perdendo dati durante il commit?

TRUNCATE TABLE TABLE_NAME; 
INSERT INTO TABLE_NAME 
(
UPRN, 
SAO_START_NUMBER, 
SAO_START_SUFFIX, 
SAO_END_NUMBER, 
SAO_END_SUFFIX, 
SAO_TEXT, 
PAO_START_NUMBER, 
PAO_START_SUFFIX, 
PAO_END_NUMBER, 
PAO_END_SUFFIX, 
PAO_TEXT, 
STREET_DESCRIPTOR, 
TOWN_NAME, 
POSTCODE, 
XY_COORD, 
EASTING, 
NORTHING, 
ADDRESS 
) 
SELECT 
BASIC_LAND_AND_PROPERTY_UNIT.UPRN, 
LAND_AND_PROPERTY_IDENTIFIER.SAO_START_NUMBER AS SAO_START_NUMBER, 
LAND_AND_PROPERTY_IDENTIFIER.SAO_START_SUFFIX AS SAO_START_SUFFIX, 
LAND_AND_PROPERTY_IDENTIFIER.SAO_END_NUMBER AS SAO_END_NUMBER, 
LAND_AND_PROPERTY_IDENTIFIER.SAO_END_SUFFIX AS SAO_END_SUFFIX, 
LAND_AND_PROPERTY_IDENTIFIER.SAO_TEXT AS SAO_TEXT, 
LAND_AND_PROPERTY_IDENTIFIER.PAO_START_NUMBER AS PAO_START_NUMBER, 
LAND_AND_PROPERTY_IDENTIFIER.PAO_START_SUFFIX AS PAO_START_SUFFIX, 
LAND_AND_PROPERTY_IDENTIFIER.PAO_END_NUMBER AS PAO_END_NUMBER, 
LAND_AND_PROPERTY_IDENTIFIER.PAO_END_SUFFIX AS PAO_END_SUFFIX, 
LAND_AND_PROPERTY_IDENTIFIER.PAO_TEXT AS PAO_TEXT, 
STREET_DESCRIPTOR.STREET_DESCRIPTOR AS STREET_DESCRIPTOR, 
STREET_DESCRIPTOR.TOWN_NAME AS TOWN_NAME, 
LAND_AND_PROPERTY_IDENTIFIER.POSTCODE AS POSTCODE, 
BASIC_LAND_AND_PROPERTY_UNIT.GEOMETRY AS XY_COORD, 
BASIC_LAND_AND_PROPERTY_UNIT.X_COORDINATE AS EASTING, 
BASIC_LAND_AND_PROPERTY_UNIT.Y_COORDINATE AS NORTHING, 
decode(SAO_START_NUMBER,null,null,SAO_START_NUMBER||SAO_START_SUFFIX||' ') 
||decode(SAO_END_NUMBER,null,null,SAO_END_NUMBER||SAO_END_SUFFIX||' ') 
||decode(SAO_TEXT,null,null,SAO_TEXT||' ') 
||decode(PAO_START_NUMBER,null,null,PAO_START_NUMBER||PAO_START_SUFFIX||' ') 
||decode(PAO_END_NUMBER,null,null,PAO_END_NUMBER||PAO_END_SUFFIX||' ') 
||decode(PAO_TEXT,null,null,'STREET RECORD',null,PAO_TEXT||' ') 
||decode(STREET_DESCRIPTOR,null,null,STREET_DESCRIPTOR||' ') 
||decode(POST_TOWN,null,null,POST_TOWN||' ') 
||Decode(Postcode,Null,Null,Postcode) As Address 
From (Land_And_Property_Identifier 
     Inner Join Basic_Land_And_Property_Unit 
     On Land_And_Property_Identifier.Uprn = Basic_Land_And_Property_Unit.Uprn) 
Inner Join Street_Descriptor 
    On Land_And_Property_Identifier.Usrn = Street_Descriptor.Usrn 
Where Land_And_Property_Identifier.Postally_Addressable='Y'; 

Se corro questa query in SQL Developer, funziona benissimo con 1,8 milioni di caratteristiche inseriti (select count(*) from TABLE_NAME all'interno della sessione lo conferma).

Ma quando eseguo il commit, i dati scompaiono! select count(*) from TABLE_NAME restituisce ora 0 risultati.

Abbiamo fatto una serie di cose da provare e vedere cosa sta succedendo:

  • Durante la Truncate, tabelle si libera, e durante la sua inserire di nuovo riempito. Non ci sono cambiamenti durante il commit. Questo implica che i dati siano nel database.

  • Se eseguo esattamente la stessa query ma con and rownum < 100 aggiunto alla fine, il commit funziona. Lo stesso con 1000.

  • Ho trovato questa domanda: oracle commit kills e il nostro DBA ha provato la "Traccia SQL". Questo ha prodotto un file> 4GB che, se analizzato con TKPROF, ha prodotto un report di 120 pagine, ma non sappiamo come leggerlo e non c'è niente di evidentemente sbagliato.

  • I nostri registri errori non contengono nulla. E ovviamente nessun errore durante il commit stesso.

  • C'è un trigger/sequenza che aumenta di 1,8 milioni durante il processo.

L'ho ripetuto circa 4 volte, ma il risultato è sempre lo stesso.

Quindi la mia domanda è semplice: cosa sta succedendo ai dati durante il commit? Come possiamo scoprirlo? Grazie.

Nota: questo ha funzionato bene in passato, quindi non credo ci sia qualcosa di sbagliato nella SQL per se.


Edit: Problema risolto ricreando la tabella da zero. Ora quando lo inserisco ci vogliono solo 500 secondi rispetto al 2000 precedente. Il commit è istantaneo; quando è stato rotto il commit ha impiegato 4000 secondi! Non ho ancora idea del perché sia ​​successo.


Per coloro che chiedono, la sintassi CREATE TABLE:

CREATE TABLE TABLE_NAME 
(
ADDRESS           VARCHAR2(4000), 
UPRN            NUMBER(12), 
SAO_START_NUMBER         NUMBER(4), 
SAO_START_SUFFIX         VARCHAR2(1), 
SAO_END_NUMBER          NUMBER(4), 
SAO_END_SUFFIX          VARCHAR2(1), 
SAO_TEXT           VARCHAR2(90), 
PAO_START_NUMBER         NUMBER(4), 
PAO_START_SUFFIX         VARCHAR2(1), 
PAO_END_NUMBER          NUMBER(4), 
PAO_END_SUFFIX          VARCHAR2(1), 
PAO_TEXT           VARCHAR2(90), 
STREET_DESCRIPTOR         VARCHAR2(100), 
TOWN_NAME           VARCHAR2(30), 
POSTCODE           VARCHAR2(8), 
XY_COORD           MDSYS.SDO_GEOMETRY, 
EASTING           NUMBER(7), 
NORTHING           NUMBER(7) 
) 

CREATE INDEX TABLE_NAME_ADD_IDX ON TABLE_NAME (ADDRESS); 
+11

: Controllare per lo script della tabella, potrebbe essere la sua una tabella temporanea globale, che troncano i dati su commit .'http: // www.oracle-base.com/articles/8i/temporary-tables.php' –

+4

Hai dei vincoli sulla tabella (specialmente i vincoli posticipati)? Hai definito la vista materializzata on-commit? Queste sono le uniche cose che posso pensare che possano far fallire un commit (anche se in ogni caso dovresti ricevere un messaggio di errore). –

+0

@GauravSoni - Grazie per il suggerimento. È stato creato come una normale tabella con una normale "creazione" in SQL Developer. Sintassi: 'CREATE TABLE TABLE_NAME (... alcune colonne ...)' –

risposta

0

Avete ancora perdere i dati se si avvolgono l'operazione in un blocco anonimo?

La mia ipotesi è che si aprano due finestre SQL in SQL Developer e ciò significa due sessioni separate. Eseguendo codice SQL nella finestra 1 e facendo commit; nella finestra 2 non verrà effettuato il commit delle modifiche apportate nella finestra 1.

La tabella troncata esegue un commit implicito. Quindi la tabella sarà vuota fino a quando insert + commit termina.

begin 
    execute immediate 'truncate table table_name reuse storage'; --use "reuse" if you know the data will be of similar size 
    -- implicit commit has occured and the table is empty for all sessions 
    insert into table_name (lots) 
    select lots from table2; 
    commit; 
end; 

Si dovrebbe usare troncare con stoccaggio riutilizzo, in modo che il database non va un libero tutti i blocchi solo per acquisire lo stesso numero di blocchi nella inserto.

Se vuoi/necessità di avere i dati disponibili in ogni momento un metodo migliore (ma più a lungo) è

begin 
    savepoint letsgo; 
    delete from table_name; 
    insert into table_name (lots) 
    select lots from table2; 
    commit; 
exception 
    when others then 
     rollback to letsgo; 
end; 
Problemi correlati