Грешните резултати могат да бъдат причинени от повреда, грешки и функции, които тихо променят SQL изразите.
- Повреден индекс. Много рядко даден индекс се поврежда и данните от индекс не съвпадат с данните от таблица. Това води до неочаквани резултати, когато планът на заявката се промени и се използва индекс, но всичко изглежда нормално за различни заявки, които използват достъп до таблица. Понякога простото повторно изграждане на обекти може да поправи това. Ако не стане, ще трябва да създадете напълно възпроизводим тестов случай (включително данни); или го публикувайте тук, или го изпратете на поддръжката на Oracle. Проследяването на това може да отнеме много часове.
- Грешка. Много рядко грешка може да причини неуспех на заявките при връщане или промяна на данни. Отново е необходим напълно възпроизводим тестов случай, за да се диагностицира това и може да отнеме известно време.
- Функция, която превключва SQL Има няколко начина за прозрачна промяна на SQL изрази. Разгледайте Virtual Private Database (VPD), DBMS_ADVANCED_REWRITE и SQL Translation Framework.
За да изключите #3, кодът по-долу ви показва един от злите начини да направите това и как да го откриете. Първо създайте схемата и някои данни:
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;
Отначало всичко работи според очакванията:
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
Тогава някой прави това:
begin
sys.dbms_advanced_rewrite.declare_rewrite_equivalence(
'april_fools',
'SELECT COUNT(1) FROM TRACKING',
'SELECT 0 FROM TRACKING WHERE ROWNUM = 1',
false);
end;
/
Сега резултатите са "грешни":
SQL> ALTER SESSION SET query_rewrite_integrity = trusted;
Session altered.
SQL> SELECT COUNT(1) FROM TRACKING;
COUNT(1)
----------
0
Това вероятно може да се открие, като се погледне планът за обяснение. В примера по-долу предикатът 2 - filter(ROWNUM=1)
е улика, че нещо не е наред, тъй като този предикат не е в оригиналната заявка. Понякога разделът „Бележки“ на плана за обяснение ще ви каже точно защо е бил трансформиран, но понякога дава само улики.
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.
(Несвързана бележка - винаги използвайте COUNT(*)
вместо COUNT(1)
. COUNT(1)
е стар мит, който прилича на карго култ към програмирането.)