Resultados errados podem ser causados por corrupção, bugs e recursos que alteram silenciosamente as instruções SQL.
- Índice corrompido. Muito raramente um índice fica corrompido e os dados de um índice não correspondem aos dados de uma tabela. Isso causa resultados inesperados quando o plano de consulta é alterado e um índice é usado, mas tudo parece normal para consultas diferentes que usam acesso à tabela. Às vezes, simplesmente reconstruir objetos pode corrigir isso. Caso contrário, você precisará criar um caso de teste totalmente reproduzível (incluindo dados); poste-o aqui ou envie-o ao Suporte da Oracle. Pode levar muitas horas para rastrear isso.
- Erro. Muito raramente um bug pode fazer com que as consultas falhem ao retornar ou alterar dados. Novamente, um caso de teste totalmente reproduzível é necessário para diagnosticar isso e pode demorar um pouco.
- Recurso que alterna SQL Existem algumas maneiras de alterar de forma transparente as instruções SQL. Analise o Virtual Private Database (VPD), DBMS_ADVANCED_REWRITE e o SQL Translation Framework.
Para descartar o número 3, o código abaixo mostra uma das maneiras malignas de fazer isso e como detectá-la. Primeiro, crie o esquema e alguns dados:
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;
A princípio, tudo funciona como esperado:
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
Então alguém faz isso:
begin
sys.dbms_advanced_rewrite.declare_rewrite_equivalence(
'april_fools',
'SELECT COUNT(1) FROM TRACKING',
'SELECT 0 FROM TRACKING WHERE ROWNUM = 1',
false);
end;
/
Agora os resultados estão "errados":
SQL> ALTER SESSION SET query_rewrite_integrity = trusted;
Session altered.
SQL> SELECT COUNT(1) FROM TRACKING;
COUNT(1)
----------
0
Isso provavelmente pode ser detectado olhando para o plano de explicação. No exemplo abaixo, o Predicado
2 - filter(ROWNUM=1)
é uma pista de que algo está errado, já que esse predicado não está na consulta original. Às vezes, a seção "Notas" do plano de explicação lhe dirá exatamente por que ele foi transformado, mas às vezes apenas fornece pistas. 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.
(Em uma nota não relacionada - sempre use
COUNT(*)
em vez de COUNT(1)
. COUNT(1)
é um mito antigo que parece programação de culto de carga.)