Nesprávné výsledky mohou být způsobeny poškozením, chybami a funkcemi, které tiše mění příkazy SQL.
- Index poškození. Velmi zřídka se index poškodí a data z indexu se neshodují s daty z tabulky. To způsobí neočekávané výsledky, když se změní plán dotazů a použije se index, ale vše vypadá normálně pro různé dotazy, které používají přístup k tabulce. Někdy to může vyřešit jednoduchá přestavba objektů. Pokud ne, budete muset vytvořit plně reprodukovatelný testovací případ (včetně dat); buď jej zveřejněte zde, nebo jej odešlete podpoře Oracle. Vysledování může trvat mnoho hodin.
- Chyba. Velmi zřídka může chyba způsobit selhání dotazů při návratu nebo změně dat. K diagnóze je opět nutný plně reprodukovatelný testovací případ a může to chvíli trvat.
- Funkce, která přepíná SQL Existuje několik způsobů, jak transparentně změnit příkazy SQL. Podívejte se na Virtual Private Database (VPD), DBMS_ADVANCED_REWRITE a SQL Translation Framework.
Abychom vyloučili číslo 3, níže uvedený kód vám ukáže jeden ze zlých způsobů, jak toho dosáhnout, a jak to zjistit. Nejprve vytvořte schéma a některá data:
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;
Zpočátku vše funguje podle očekávání:
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
Pak někdo udělá toto:
begin
sys.dbms_advanced_rewrite.declare_rewrite_equivalence(
'april_fools',
'SELECT COUNT(1) FROM TRACKING',
'SELECT 0 FROM TRACKING WHERE ROWNUM = 1',
false);
end;
/
Nyní jsou výsledky "špatné":
SQL> ALTER SESSION SET query_rewrite_integrity = trusted;
Session altered.
SQL> SELECT COUNT(1) FROM TRACKING;
COUNT(1)
----------
0
To lze pravděpodobně zjistit pohledem na plán vysvětlení. V níže uvedeném příkladu je predikát 2 - filter(ROWNUM=1)
je vodítko, že něco není v pořádku, protože tento predikát není v původním dotazu. Někdy vám část "Poznámky" plánu vysvětlení řekne přesně, proč byl transformován, ale někdy poskytuje pouze vodítka.
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.
(Nesouvisející poznámka - vždy použijte COUNT(*)
místo COUNT(1)
. COUNT(1)
je starý mýtus, který vypadá jako programování kultu nákladu.)