I risultati errati possono essere causati da danneggiamenti, bug e funzionalità che modificano silenziosamente le istruzioni SQL.
- Indice danneggiato. Molto raramente un indice viene danneggiato ei dati di un indice non corrispondono ai dati di una tabella. Ciò provoca risultati imprevisti quando il piano di query cambia e viene utilizzato un indice, ma tutto sembra normale per query diverse che utilizzano l'accesso alla tabella. A volte semplicemente ricostruire oggetti può risolvere questo problema. In caso contrario, dovrai creare un test case completamente riproducibile (inclusi i dati); pubblicalo qui o invialo a Oracle Support. Possono essere necessarie molte ore per rintracciarlo.
- Blocco. Molto raramente un bug può causare il fallimento delle query durante la restituzione o la modifica dei dati. Anche in questo caso, per diagnosticare questo è necessario un test case completamente riproducibile e può volerci del tempo.
- Funzione che cambia SQL Esistono alcuni modi per modificare in modo trasparente le istruzioni SQL. Esamina Virtual Private Database (VPD), DBMS_ADVANCED_REWRITE e SQL Translation Framework.
Per escludere il numero 3, il codice seguente mostra uno dei modi malvagi per farlo e come rilevarlo. Innanzitutto, crea lo schema e alcuni dati:
CREATE TABLE TRACKING (
A_ID NUMBER,
D_CODE NUMBER,
HOD NUMBER,
ADR_CNT NUMBER,
TTL_CNT NUMBER,
CREATED DATE,
MODIFIED DATE
);
CREATE INDEX HOD_D_CODE_IDX ON TRACKING (HOD, D_CODE);
CREATE UNIQUE INDEX TRACKING_PK ON TRACKING (A_ID, D_CODE, HOD);
CREATE INDEX MOD_DATE_IDX ON TRACKING (MODIFIED);
ALTER TABLE TRACKING ADD CONSTRAINT TRACKING_PK PRIMARY KEY (A_ID, D_CODE, HOD);
insert into tracking values (1,2,3,4,5,sysdate,sysdate);
commit;
All'inizio, tutto funziona come previsto:
SQL> SELECT * FROM TRACKING;
A_ID D_CODE HOD ADR_CNT TTL_CNT CREATED MODIFIED
---------- ---------- ---------- ---------- ---------- --------- ---------
1 2 3 4 5 17-JUN-16 17-JUN-16
SQL> SELECT COUNT(1) FROM TRACKING;
COUNT(1)
----------
1
Poi qualcuno fa questo:
begin
sys.dbms_advanced_rewrite.declare_rewrite_equivalence(
'april_fools',
'SELECT COUNT(1) FROM TRACKING',
'SELECT 0 FROM TRACKING WHERE ROWNUM = 1',
false);
end;
/
Ora i risultati sono "sbagliati":
SQL> ALTER SESSION SET query_rewrite_integrity = trusted;
Session altered.
SQL> SELECT COUNT(1) FROM TRACKING;
COUNT(1)
----------
0
Questo può essere probabilmente rilevato guardando il piano di spiegazione. Nell'esempio seguente, il predicato 2 - filter(ROWNUM=1)
è un indizio che qualcosa non va, poiché quel predicato non è nella query originale. A volte la sezione "Note" del piano di spiegazione ti dirà esattamente perché è stato trasformato, ma a volte fornisce solo indizi.
SQL> explain plan for SELECT COUNT(1) FROM TRACKING;
Explained.
SQL> select * from table(dbms_xplan.display);
PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------------
Plan hash value: 1761840423
------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 2 | 1 (0)| 00:00:01 |
| 1 | VIEW | | 1 | 2 | 1 (0)| 00:00:01 |
|* 2 | COUNT STOPKEY | | | | | |
| 3 | INDEX FULL SCAN| HOD_D_CODE_IDX | 1 | | 1 (0)| 00:00:01 |
------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - filter(ROWNUM=1)
15 rows selected.
(In una nota non correlata:usa sempre COUNT(*)
invece di COUNT(1)
. COUNT(1)
è un vecchio mito che sembra una programmazione cult del cargo.)