Oracle
 sql >> Datenbank >  >> RDS >> Oracle

Oracle Select * gibt Zeilen zurück, aber Select count(1) gibt 0 zurück

Falsche Ergebnisse können durch Beschädigung, Fehler und Funktionen verursacht werden, die SQL-Anweisungen stillschweigend ändern.

  1. Beschädigter Index. Sehr selten wird ein Index beschädigt und die Daten aus einem Index stimmen nicht mit den Daten aus einer Tabelle überein. Dies führt zu unerwarteten Ergebnissen, wenn sich der Abfrageplan ändert und ein Index verwendet wird, aber für verschiedene Abfragen, die Tabellenzugriff verwenden, sieht alles normal aus. Manchmal kann dies einfach behoben werden, indem Objekte neu erstellt werden. Wenn dies nicht der Fall ist, müssen Sie einen vollständig reproduzierbaren Testfall (einschließlich Daten) erstellen. entweder hier posten oder an Oracle Support senden. Es kann viele Stunden dauern, dies aufzuspüren.
  2. Fehler. Sehr selten kann ein Fehler dazu führen, dass Abfragen beim Zurückgeben oder Ändern von Daten fehlschlagen. Auch hier ist ein vollständig reproduzierbarer Testfall erforderlich, um dies zu diagnostizieren, und es kann eine Weile dauern.
  3. Funktion, die SQL wechselt Es gibt einige Möglichkeiten, SQL-Anweisungen transparent zu ändern. Sehen Sie sich Virtual Private Database (VPD), DBMS_ADVANCED_REWRITE und das SQL Translation Framework an.

Um Nr. 3 auszuschließen, zeigt Ihnen der folgende Code einen der bösen Wege, dies zu tun, und wie Sie ihn erkennen können. Erstellen Sie zuerst das Schema und einige Daten:

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;

Zunächst funktioniert alles wie erwartet:

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

Dann tut jemand Folgendes:

begin
  sys.dbms_advanced_rewrite.declare_rewrite_equivalence(
    'april_fools',
    'SELECT COUNT(1) FROM TRACKING',
    'SELECT 0 FROM TRACKING WHERE ROWNUM = 1',
    false);
end;
/

Jetzt sind die Ergebnisse "falsch":

SQL> ALTER SESSION SET query_rewrite_integrity = trusted;

Session altered.

SQL> SELECT COUNT(1) FROM TRACKING;

  COUNT(1)
----------
         0

Dies kann wahrscheinlich anhand des Erklärungsplans festgestellt werden. Im Beispiel unten das Prädikat 2 - filter(ROWNUM=1) ist ein Hinweis darauf, dass etwas nicht stimmt, da dieses Prädikat nicht in der ursprünglichen Abfrage enthalten ist. Manchmal sagt Ihnen der Abschnitt "Anmerkungen" des Erklärplans genau, warum er transformiert wurde, aber manchmal gibt er nur Hinweise.

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.

(Nebenbei bemerkt – verwenden Sie immer COUNT(*) statt COUNT(1) . COUNT(1) ist ein alter Mythos, der wie Cargo-Kult-Programmierung aussieht.)