Nieprawidłowe wyniki mogą być spowodowane przez uszkodzenie, błędy i funkcje, które po cichu zmieniają instrukcje SQL.
- Uszkodzony indeks. Bardzo rzadko indeks ulega uszkodzeniu, a dane z indeksu nie pasują do danych z tabeli. Powoduje to nieoczekiwane wyniki, gdy zmienia się plan kwerend i jest używany indeks, ale wszystko wygląda normalnie w przypadku różnych kwerend korzystających z dostępu do tabeli. Czasami wystarczy przebudować obiekty, aby to naprawić. Jeśli tak się nie stanie, musisz stworzyć w pełni odtwarzalny przypadek testowy (w tym dane); opublikuj go tutaj lub prześlij do Oracle Support. Wyśledzenie tego może zająć wiele godzin.
- Błąd. Bardzo rzadko błąd może spowodować niepowodzenie zapytań podczas zwracania lub zmieniania danych. Ponownie, aby to zdiagnozować, wymagany jest w pełni odtwarzalny przypadek testowy, który może trochę potrwać.
- Funkcja przełączająca SQL Istnieje kilka sposobów na przejrzyste zmienianie instrukcji SQL. Zajrzyj do wirtualnej prywatnej bazy danych (VPD), DBMS_ADVANCED_REWRITE i SQL Translation Framework.
Aby wykluczyć #3, poniższy kod pokazuje jeden ze złych sposobów na zrobienie tego i jak go wykryć. Najpierw utwórz schemat i trochę danych:
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;
Na początku wszystko działa zgodnie z oczekiwaniami:
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
Wtedy ktoś to robi:
begin
sys.dbms_advanced_rewrite.declare_rewrite_equivalence(
'april_fools',
'SELECT COUNT(1) FROM TRACKING',
'SELECT 0 FROM TRACKING WHERE ROWNUM = 1',
false);
end;
/
Teraz wyniki są „błędne”:
SQL> ALTER SESSION SET query_rewrite_integrity = trusted;
Session altered.
SQL> SELECT COUNT(1) FROM TRACKING;
COUNT(1)
----------
0
Można to prawdopodobnie wykryć, patrząc na plan wyjaśnienia. W poniższym przykładzie predykat 2 - filter(ROWNUM=1)
jest wskazówką, że coś jest nie tak, ponieważ tego predykatu nie ma w pierwotnym zapytaniu. Czasami sekcja „Uwagi” planu wyjaśniania powie dokładnie, dlaczego został przekształcony, ale czasami zawiera tylko wskazówki.
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.
(W przypadku niepowiązanej uwagi - zawsze używaj COUNT(*)
zamiast COUNT(1)
. COUNT(1)
to stary mit, który wygląda jak kultowe programowanie cargo.)