Oracle
 sql >> Baza danych >  >> RDS >> Oracle

Oracle Select * zwraca wiersze, ale Select count(1) zwraca 0

Nieprawidłowe wyniki mogą być spowodowane przez uszkodzenie, błędy i funkcje, które po cichu zmieniają instrukcje SQL.

  1. 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.
  2. 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ć.
  3. 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.)



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Generuj losowy ciąg alfanumeryczny z wielkich i małych liter w Oracle

  2. Regex101 a Oracle Regex

  3. Jak zwiększyć liczbę miejsc dziesiętnych do minimum w Oracle PLSQL?

  4. Oracle 11g — Znajdź rekordy w CLOB z kanałem zwrotu karetki

  5. Oracle SQL:wyodrębnianie tygodnia roku od daty daje losowe wyniki